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:
@@ -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);
|
||||
}
|
||||
|
Reference in New Issue
Block a user