Fix new color propagation method (#6109)

* Fixed artifacts thanks to Alberto

* Added blur to Color propagation

* Clean format code - small improvments

* color propagation: Enable old mode at blur = 0

* Improve GUI

* color propagation: smooth progress bar for blur > 0

* change label

* Some cleanups

* color propagation: small speedup for blur > 0

* color propagation: speedup for blur > 0 when region with clipped highlights is small

* Speed-up for blur=1 - clean GUI code

* color propagation: cleanups

* Harmonize events in tonecurve.cc

* tonecurve.cc : cleanup

* Highlight reconstruction: small changes to gui

* Use Gtk::Box instead of Gtk::VBox

* Change maximum number of blur levels to 4

* Suppress BENCHFUN

* Suppress bad commit locallabtools

Co-authored-by: Desmis <jdesmis@gmail.com>
Co-authored-by: Ingo Weyrich <heckflosse67@gmx.de>
This commit is contained in:
Thanatomanic
2021-02-18 13:36:54 +01:00
committed by GitHub
parent d29d5e144b
commit de15da1d59
14 changed files with 527 additions and 449 deletions

View File

@@ -32,8 +32,8 @@
#include "opthelper.h"
#include "rawimagesource.h"
#include "rt_math.h"
#define BENCHMARK
#include "StopWatch.h"
//#define BENCHMARK
//#include "StopWatch.h"
#include "guidedfilter.h"
#include "settings.h"
#include "gauss.h"
@@ -299,9 +299,9 @@ extern const Settings *settings;
using namespace procparams;
const ProcParams params;
void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue)
void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue, int blur)
{
BENCHFUN
// BENCHFUN
double progress = 0.0;
if (plistener) {
@@ -318,7 +318,7 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue
constexpr float threshpct = 0.25f;
constexpr float maxpct = 0.95f;
constexpr float epsilon = 0.00001f;
//%%%%%%%%%%%%%%%%%%%%
//for blend algorithm:
constexpr float blendthresh = 1.0;
// Transform matrixes rgb>lab and back
@@ -424,11 +424,6 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue
return;
}
// if (plistener) {
// progress += 0.05;
// plistener->setProgress(progress);
// }
constexpr int blurBorder = 256;
minx = std::max(0, minx - blurBorder);
miny = std::max(0, miny - blurBorder);
@@ -442,21 +437,8 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue
array2D<float> temp(bufferWidth, blurHeight); // allocate temporary buffer
// blur RGB channels
boxblur2(red, channelblur[0], temp, miny, minx, blurHeight, blurWidth, bufferWidth, 4);
// if (plistener) {
// progress += 0.07;
// plistener->setProgress(progress);
// }
boxblur2(green, channelblur[1], temp, miny, minx, blurHeight, blurWidth, bufferWidth, 4);
// if (plistener) {
// progress += 0.07;
// plistener->setProgress(progress);
// }
boxblur2(blue, channelblur[2], temp, miny, minx, blurHeight, blurWidth, bufferWidth, 4);
if (plistener) {
@@ -470,7 +452,7 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue
#endif
for (int i = 0; i < blurHeight; ++i) {
for (int j = 0; j < blurWidth; ++j) {
channelblur[0][i][j] = fabsf(channelblur[0][i][j] - red[i + miny][j + minx]) + fabsf(channelblur[1][i][j] - green[i + miny][j + minx]) + fabsf(channelblur[2][i][j] - blue[i + miny][j + minx]);
channelblur[0][i][j] = std::fabs(channelblur[0][i][j] - red[i + miny][j + minx]) + std::fabs(channelblur[1][i][j] - green[i + miny][j + minx]) + std::fabs(channelblur[2][i][j] - blue[i + miny][j + minx]);
}
}
@@ -529,7 +511,7 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue
}
array2D<float> hilite_full4(bufferWidth, blurHeight);
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//blur highlight data
boxblur2(hilite_full[3], hilite_full4, temp, 0, 0, blurHeight, blurWidth, bufferWidth, 1);
@@ -566,9 +548,7 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue
multi_array2D<float, 4> hilite(hfw + 1, hfh + 1, ARRAY2D_CLEAR_DATA, 48);
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// blur and resample highlight data; range=size of blur, pitch=sample spacing
array2D<float> temp2(blurWidth / pitch + (blurWidth % pitch == 0 ? 0 : 1), blurHeight);
for (int m = 0; m < 4; ++m) {
@@ -651,11 +631,11 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue
}
if (hilite[3][2][j] <= epsilon) {
hilite_dir[0 + c][0][j] = hilite_dir0[c][j][2];
hilite_dir[0 + c][0][j] = hilite_dir0[c][j][2];
}
if (hilite[3][3][j] <= epsilon) {
hilite_dir[0 + c][1][j] = hilite_dir0[c][j][3];
hilite_dir[0 + c][1][j] = hilite_dir0[c][j][3];
}
if (hilite[3][hfh - 3][j] <= epsilon) {
@@ -938,38 +918,43 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue
hilite[c].free();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// now reconstruct clipped channels using color ratios
//using code from ART - thanks to Alberto Griggio
const int W2 = float(W) / 2.f + 0.5f;
const int H2 = float(H) / 2.f + 0.5f;
const int W2 = blur > 0 ? blurWidth / 2.f + 0.5f : 0;
const int H2 = blur > 0 ? blurHeight / 2.f + 0.5f : 0;
array2D<float> mask(W2, H2, ARRAY2D_CLEAR_DATA);
array2D<float> rbuf(W2, H2);
array2D<float> gbuf(W2, H2);
array2D<float> bbuf(W2, H2);
array2D<float> guide(W2, H2);
using rtengine::TMatrix;
TMatrix ws = ICCStore::getInstance()->workingSpaceMatrix(params.icm.workingProfile);
{
array2D<float> rsrc(W, H, red, ARRAY2D_BYREFERENCE);
array2D<float> gsrc(W, H, green, ARRAY2D_BYREFERENCE);
array2D<float> bsrc(W, H, blue, ARRAY2D_BYREFERENCE);
rescaleNearest(rsrc, rbuf, true);
rescaleNearest(gsrc, gbuf, true);
rescaleNearest(bsrc, bbuf, true);
if (blur > 0) {
array2D<float> rbuffer(blurWidth, blurHeight, minx, miny, red, ARRAY2D_BYREFERENCE);
rescaleNearest(rbuffer, rbuf, true);
array2D<float> gbuffer(blurWidth, blurHeight, minx, miny, green, ARRAY2D_BYREFERENCE);
rescaleNearest(gbuffer, gbuf, true);
array2D<float> bbuffer(blurWidth, blurHeight, minx, miny, blue, ARRAY2D_BYREFERENCE);
rescaleNearest(bbuffer, bbuf, true);
LUTf gamma(65536);
#ifdef _OPENMP
# pragma omp parallel for
#pragma omp parallel for
#endif
for (int i = 0; i < 65536; ++i) {
gamma[i] = pow_F(i / 65535.f, 2.2f);
}
const float xyzcam[3] = {static_cast<float>(imatrices.xyz_cam[1][0]), static_cast<float>(imatrices.xyz_cam[1][1]), static_cast<float>(imatrices.xyz_cam[1][2])};
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int y = 0; y < H2; ++y) {
for (int x = 0; x < W2; ++x) {
guide[y][x] = Color::igamma_srgb(Color::rgbLuminance(static_cast<double>(rbuf[y][x]), static_cast<double>(gbuf[y][x]), static_cast<double>(bbuf[y][x]), ws));
guide[y][x] = gamma[Color::rgbLuminance(rbuf[y][x], gbuf[y][x], bbuf[y][x], xyzcam)];
}
}
}
//end addind code ART
//end adding code ART
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic,16)
@@ -1050,21 +1035,20 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue
// Copy converted pixel back
if (pixel[0] > blendpt) {
const float rfrac = LIM01(medFactor[0] * (pixel[0] - blendpt));
rgb_blend[0] = rfrac * rgb[0] + (1.f - rfrac) * pixel[0];
rgb_blend[0] = intp(rfrac, rgb[0], pixel[0]);
}
if (pixel[1] > blendpt) {
const float gfrac = LIM01(medFactor[1] * (pixel[1] - blendpt));
rgb_blend[1] = gfrac * rgb[1] + (1.f - gfrac) * pixel[1];
rgb_blend[1] = intp(gfrac, rgb[1], pixel[1]);
}
if (pixel[2] > blendpt) {
const float bfrac = LIM01(medFactor[2] * (pixel[2] - blendpt));
rgb_blend[2] = bfrac * rgb[2] + (1.f - bfrac) * pixel[2];
rgb_blend[2] = intp(bfrac, rgb[2], pixel[2]);
}
//end of HLRecovery_blend estimation
//%%%%%%%%%%%%%%%%%%%%%%%
//there are clipped highlights
//first, determine weighted average of unclipped extensions (weighting is by 'hue' proximity)
@@ -1090,7 +1074,7 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue
}
for (int dir = 0; dir < 2; ++dir) {
const float Yhi2 = 1.f / ( hilite_dir[dir * 4 + 0][i1][j1] + hilite_dir[dir * 4 + 1][i1][j1] + hilite_dir[dir * 4 + 2][i1][j1]);
const float Yhi2 = 1.f / (hilite_dir[dir * 4 + 0][i1][j1] + hilite_dir[dir * 4 + 1][i1][j1] + hilite_dir[dir * 4 + 2][i1][j1]);
if (Yhi2 < 2.f) {
const float dirwt = 1.f / ((1.f + 65535.f * (SQR(rgb_blend[0] - hilite_dir[dir * 4 + 0][i1][j1] * Yhi2) +
@@ -1119,10 +1103,11 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue
if (UNLIKELY(!totwt)) {
continue;
}
//using code from ART - thanks to Alberto Griggio
float maskval = 1.f;
int yy = i + miny;
int xx = j + minx;
const int yy = i + miny;
const int xx = j + minx;
//now correct clipped channels
if (pixel[0] > max_f[0] && pixel[1] > max_f[1] && pixel[2] > max_f[2]) {
@@ -1160,63 +1145,81 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue
if (Y > whitept) {
const float mult = whitept / Y;
red[yy][xx] *= mult;
red[yy][xx] *= mult;
green[yy][xx] *= mult;
blue[yy][xx] *= mult;
blue[yy][xx] *= mult;
}
int ii = (yy) / 2;
int jj = (xx) / 2;
rbuf[ii][jj] = red[yy][xx];
gbuf[ii][jj] = green[yy][xx];
bbuf[ii][jj] = blue[yy][xx];
mask[ii][jj] = maskval;
if (blur > 0) {
const int ii = i / 2;
const int jj = j / 2;
rbuf[ii][jj] = red[yy][xx];
gbuf[ii][jj] = green[yy][xx];
bbuf[ii][jj] = blue[yy][xx];
mask[ii][jj] = maskval;
}
}
}
if (plistener) {
progress += 0.05;
plistener->setProgress(progress);
}
// #ifdef _OPENMP
// #pragma omp parallel
// #endif
{
//gaussianBlur(mask, mask, W/2, H/2, 5);
// gaussianBlur(rbuf, rbuf, W/2, H/2, 1);
// gaussianBlur(gbuf, gbuf, W/2, H/2, 1);
// gaussianBlur(bbuf, bbuf, W/2, H/2, 1);
guidedFilter(guide, mask, mask, 2, 0.001f, true, 1);
guidedFilter(guide, rbuf, rbuf, 3, 0.01f * 65535.f, true, 1);
guidedFilter(guide, gbuf, gbuf, 3, 0.01f * 65535.f, true, 1);
guidedFilter(guide, bbuf, bbuf, 3, 0.01f * 65535.f, true, 1);
}
if (blur > 0) {
if (plistener) {
progress += 0.05;
plistener->setProgress(progress);
}
blur = rtengine::LIM(blur - 1, 0, 3);
{
constexpr float vals[4][3] = {{4.0f, 0.3f, 0.3f},
// {3.5f, 0.5f, 0.2f},
{3.0f, 1.0f, 0.1f},
{3.0f, 2.0f, 0.01f},
{2.0f, 3.0f, 0.001f}
};
const float rad1 = vals[blur][0];
const float rad2 = vals[blur][1];
const float th = vals[blur][2];
guidedFilter(guide, mask, mask, rad1, th, true, 1);
if (plistener) {
progress += 0.03;
plistener->setProgress(progress);
}
if (blur > 0) { //no use of 2nd guidedFilter if Blur = 0 (slider to 1)..speed-up and very small differences.
guidedFilter(guide, rbuf, rbuf, rad2, 0.01f * 65535.f, true, 1);
if (plistener) {
progress += 0.03;
plistener->setProgress(progress);
}
guidedFilter(guide, gbuf, gbuf, rad2, 0.01f * 65535.f, true, 1);
if (plistener) {
progress += 0.03;
plistener->setProgress(progress);
}
guidedFilter(guide, bbuf, bbuf, rad2, 0.01f * 65535.f, true, 1);
if (plistener) {
progress += 0.03;
plistener->setProgress(progress);
}
}
#ifdef _OPENMP
#pragma omp parallel for
#pragma omp parallel for schedule(dynamic,16)
#endif
for (int y = 0; y < H; ++y) {
float fy = y * 0.5f;
int yy = y / 2;
for (int x = 0; x < W; ++x) {
float fx = x * 0.5f;
int xx = x / 2;
float m = mask[yy][xx];
for (int y = 0; y < blurHeight; ++y) {
const float fy = y * 0.5f;
const int yy = y / 2;
for (int x = 0; x < blurWidth; ++x) {
const int xx = x / 2;
const float m = mask[yy][xx];
if (m > 0.f) {
red[y][x] = intp(m, getBilinearValue(rbuf, fx, fy), red[y][x]);
green[y][x] = intp(m, getBilinearValue(gbuf, fx, fy), green[y][x]);
blue[y][x] = intp(m, getBilinearValue(bbuf, fx, fy), blue[y][x]);
const float fx = x * 0.5f;
red[y + miny][x + minx] = intp(m, getBilinearValue(rbuf, fx, fy), red[y + miny][x + minx]);
green[y + miny][x + minx] = intp(m, getBilinearValue(gbuf, fx, fy), green[y + miny][x + minx]);
blue[y + miny][x + minx] = intp(m, getBilinearValue(bbuf, fx, fy), blue[y + miny][x + minx]);
}
}
}
}
if (plistener) {
plistener->setProgress(1.00);
}