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:
parent
d29d5e144b
commit
de15da1d59
@ -1322,6 +1322,7 @@ HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative
|
|||||||
HISTORY_MSG_FILMNEGATIVE_REF_SPOT;FN - Reference input
|
HISTORY_MSG_FILMNEGATIVE_REF_SPOT;FN - Reference input
|
||||||
HISTORY_MSG_FILMNEGATIVE_VALUES;Film negative values
|
HISTORY_MSG_FILMNEGATIVE_VALUES;Film negative values
|
||||||
HISTORY_MSG_HISTMATCHING;Auto-matched tone curve
|
HISTORY_MSG_HISTMATCHING;Auto-matched tone curve
|
||||||
|
HISTORY_MSG_HLBL;Color propagation - blur
|
||||||
HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries
|
HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries
|
||||||
HISTORY_MSG_ICM_OUTPUT_TEMP;Output - ICC-v4 illuminant D
|
HISTORY_MSG_ICM_OUTPUT_TEMP;Output - ICC-v4 illuminant D
|
||||||
HISTORY_MSG_ICM_OUTPUT_TYPE;Output - Type
|
HISTORY_MSG_ICM_OUTPUT_TYPE;Output - Type
|
||||||
@ -2367,6 +2368,7 @@ TP_GRADIENT_STRENGTH_TOOLTIP;Filter strength in stops.
|
|||||||
TP_HLREC_BLEND;Blend
|
TP_HLREC_BLEND;Blend
|
||||||
TP_HLREC_CIELAB;CIELab Blending
|
TP_HLREC_CIELAB;CIELab Blending
|
||||||
TP_HLREC_COLOR;Color Propagation
|
TP_HLREC_COLOR;Color Propagation
|
||||||
|
TP_HLREC_HLBLUR;Blur
|
||||||
TP_HLREC_ENA_TOOLTIP;Could be activated by Auto Levels.
|
TP_HLREC_ENA_TOOLTIP;Could be activated by Auto Levels.
|
||||||
TP_HLREC_LABEL;Highlight reconstruction
|
TP_HLREC_LABEL;Highlight reconstruction
|
||||||
TP_HLREC_LUMINANCE;Luminance Recovery
|
TP_HLREC_LUMINANCE;Luminance Recovery
|
||||||
|
@ -124,6 +124,26 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// creator type 3
|
||||||
|
array2D(int w, int h, int startx, int starty, T ** source, unsigned int flags = 0) : width(w)
|
||||||
|
{
|
||||||
|
rows.resize(h);
|
||||||
|
if (!(flags & ARRAY2D_BYREFERENCE)) {
|
||||||
|
buffer.resize(h * width);
|
||||||
|
T* start = buffer.data();
|
||||||
|
for (ssize_t i = 0; i < h; ++i) {
|
||||||
|
rows[i] = start + i * width;
|
||||||
|
for (ssize_t j = 0; j < width; ++j) {
|
||||||
|
rows[i][j] = source[i + starty][j + startx];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (ssize_t i = 0; i < h; ++i) {
|
||||||
|
rows[i] = source[i + starty] + startx;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
array2D(const array2D& other) :
|
array2D(const array2D& other) :
|
||||||
width(other.width),
|
width(other.width),
|
||||||
buffer(other.buffer)
|
buffer(other.buffer)
|
||||||
|
@ -206,6 +206,11 @@ public:
|
|||||||
return static_cast<double>(r) * workingspace[1][0] + static_cast<double>(g) * workingspace[1][1] + static_cast<double>(b) * workingspace[1][2];
|
return static_cast<double>(r) * workingspace[1][0] + static_cast<double>(g) * workingspace[1][1] + static_cast<double>(b) * workingspace[1][2];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static float rgbLuminance(float r, float g, float b, const float workingspace[3])
|
||||||
|
{
|
||||||
|
return r * workingspace[0] + g * workingspace[1] + b * workingspace[2];
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef __SSE2__
|
#ifdef __SSE2__
|
||||||
static vfloat rgbLuminance(vfloat r, vfloat g, vfloat b, const vfloat workingspace[3])
|
static vfloat rgbLuminance(vfloat r, vfloat g, vfloat b, const vfloat workingspace[3])
|
||||||
{
|
{
|
||||||
|
@ -32,8 +32,8 @@
|
|||||||
#include "opthelper.h"
|
#include "opthelper.h"
|
||||||
#include "rawimagesource.h"
|
#include "rawimagesource.h"
|
||||||
#include "rt_math.h"
|
#include "rt_math.h"
|
||||||
#define BENCHMARK
|
//#define BENCHMARK
|
||||||
#include "StopWatch.h"
|
//#include "StopWatch.h"
|
||||||
#include "guidedfilter.h"
|
#include "guidedfilter.h"
|
||||||
#include "settings.h"
|
#include "settings.h"
|
||||||
#include "gauss.h"
|
#include "gauss.h"
|
||||||
@ -299,9 +299,9 @@ extern const Settings *settings;
|
|||||||
using namespace procparams;
|
using namespace procparams;
|
||||||
const ProcParams params;
|
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;
|
double progress = 0.0;
|
||||||
|
|
||||||
if (plistener) {
|
if (plistener) {
|
||||||
@ -318,7 +318,7 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue
|
|||||||
constexpr float threshpct = 0.25f;
|
constexpr float threshpct = 0.25f;
|
||||||
constexpr float maxpct = 0.95f;
|
constexpr float maxpct = 0.95f;
|
||||||
constexpr float epsilon = 0.00001f;
|
constexpr float epsilon = 0.00001f;
|
||||||
//%%%%%%%%%%%%%%%%%%%%
|
|
||||||
//for blend algorithm:
|
//for blend algorithm:
|
||||||
constexpr float blendthresh = 1.0;
|
constexpr float blendthresh = 1.0;
|
||||||
// Transform matrixes rgb>lab and back
|
// Transform matrixes rgb>lab and back
|
||||||
@ -424,11 +424,6 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (plistener) {
|
|
||||||
// progress += 0.05;
|
|
||||||
// plistener->setProgress(progress);
|
|
||||||
// }
|
|
||||||
|
|
||||||
constexpr int blurBorder = 256;
|
constexpr int blurBorder = 256;
|
||||||
minx = std::max(0, minx - blurBorder);
|
minx = std::max(0, minx - blurBorder);
|
||||||
miny = std::max(0, miny - 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
|
array2D<float> temp(bufferWidth, blurHeight); // allocate temporary buffer
|
||||||
|
|
||||||
// blur RGB channels
|
// blur RGB channels
|
||||||
|
|
||||||
boxblur2(red, channelblur[0], temp, miny, minx, blurHeight, blurWidth, bufferWidth, 4);
|
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);
|
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);
|
boxblur2(blue, channelblur[2], temp, miny, minx, blurHeight, blurWidth, bufferWidth, 4);
|
||||||
|
|
||||||
if (plistener) {
|
if (plistener) {
|
||||||
@ -470,7 +452,7 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue
|
|||||||
#endif
|
#endif
|
||||||
for (int i = 0; i < blurHeight; ++i) {
|
for (int i = 0; i < blurHeight; ++i) {
|
||||||
for (int j = 0; j < blurWidth; ++j) {
|
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);
|
array2D<float> hilite_full4(bufferWidth, blurHeight);
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
//blur highlight data
|
//blur highlight data
|
||||||
boxblur2(hilite_full[3], hilite_full4, temp, 0, 0, blurHeight, blurWidth, bufferWidth, 1);
|
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);
|
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
|
// blur and resample highlight data; range=size of blur, pitch=sample spacing
|
||||||
|
|
||||||
array2D<float> temp2(blurWidth / pitch + (blurWidth % pitch == 0 ? 0 : 1), blurHeight);
|
array2D<float> temp2(blurWidth / pitch + (blurWidth % pitch == 0 ? 0 : 1), blurHeight);
|
||||||
|
|
||||||
for (int m = 0; m < 4; ++m) {
|
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) {
|
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) {
|
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) {
|
if (hilite[3][hfh - 3][j] <= epsilon) {
|
||||||
@ -938,38 +918,43 @@ void RawImageSource::HLRecovery_inpaint(float** red, float** green, float** blue
|
|||||||
hilite[c].free();
|
hilite[c].free();
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
// now reconstruct clipped channels using color ratios
|
// now reconstruct clipped channels using color ratios
|
||||||
//using code from ART - thanks to Alberto Griggio
|
//using code from ART - thanks to Alberto Griggio
|
||||||
const int W2 = float(W) / 2.f + 0.5f;
|
const int W2 = blur > 0 ? blurWidth / 2.f + 0.5f : 0;
|
||||||
const int H2 = float(H) / 2.f + 0.5f;
|
const int H2 = blur > 0 ? blurHeight / 2.f + 0.5f : 0;
|
||||||
array2D<float> mask(W2, H2, ARRAY2D_CLEAR_DATA);
|
array2D<float> mask(W2, H2, ARRAY2D_CLEAR_DATA);
|
||||||
array2D<float> rbuf(W2, H2);
|
array2D<float> rbuf(W2, H2);
|
||||||
array2D<float> gbuf(W2, H2);
|
array2D<float> gbuf(W2, H2);
|
||||||
array2D<float> bbuf(W2, H2);
|
array2D<float> bbuf(W2, H2);
|
||||||
array2D<float> guide(W2, H2);
|
array2D<float> guide(W2, H2);
|
||||||
|
|
||||||
using rtengine::TMatrix;
|
if (blur > 0) {
|
||||||
TMatrix ws = ICCStore::getInstance()->workingSpaceMatrix(params.icm.workingProfile);
|
array2D<float> rbuffer(blurWidth, blurHeight, minx, miny, red, ARRAY2D_BYREFERENCE);
|
||||||
|
rescaleNearest(rbuffer, rbuf, true);
|
||||||
{
|
array2D<float> gbuffer(blurWidth, blurHeight, minx, miny, green, ARRAY2D_BYREFERENCE);
|
||||||
array2D<float> rsrc(W, H, red, ARRAY2D_BYREFERENCE);
|
rescaleNearest(gbuffer, gbuf, true);
|
||||||
array2D<float> gsrc(W, H, green, ARRAY2D_BYREFERENCE);
|
array2D<float> bbuffer(blurWidth, blurHeight, minx, miny, blue, ARRAY2D_BYREFERENCE);
|
||||||
array2D<float> bsrc(W, H, blue, ARRAY2D_BYREFERENCE);
|
rescaleNearest(bbuffer, bbuf, true);
|
||||||
rescaleNearest(rsrc, rbuf, true);
|
|
||||||
rescaleNearest(gsrc, gbuf, true);
|
|
||||||
rescaleNearest(bsrc, bbuf, true);
|
|
||||||
|
|
||||||
|
LUTf gamma(65536);
|
||||||
#ifdef _OPENMP
|
#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
|
#endif
|
||||||
for (int y = 0; y < H2; ++y) {
|
for (int y = 0; y < H2; ++y) {
|
||||||
for (int x = 0; x < W2; ++x) {
|
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
|
#ifdef _OPENMP
|
||||||
#pragma omp parallel for schedule(dynamic,16)
|
#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
|
// Copy converted pixel back
|
||||||
if (pixel[0] > blendpt) {
|
if (pixel[0] > blendpt) {
|
||||||
const float rfrac = LIM01(medFactor[0] * (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) {
|
if (pixel[1] > blendpt) {
|
||||||
const float gfrac = LIM01(medFactor[1] * (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) {
|
if (pixel[2] > blendpt) {
|
||||||
const float bfrac = LIM01(medFactor[2] * (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
|
//end of HLRecovery_blend estimation
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
//there are clipped highlights
|
//there are clipped highlights
|
||||||
//first, determine weighted average of unclipped extensions (weighting is by 'hue' proximity)
|
//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) {
|
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) {
|
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) +
|
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)) {
|
if (UNLIKELY(!totwt)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
//using code from ART - thanks to Alberto Griggio
|
//using code from ART - thanks to Alberto Griggio
|
||||||
float maskval = 1.f;
|
float maskval = 1.f;
|
||||||
int yy = i + miny;
|
const int yy = i + miny;
|
||||||
int xx = j + minx;
|
const int xx = j + minx;
|
||||||
|
|
||||||
//now correct clipped channels
|
//now correct clipped channels
|
||||||
if (pixel[0] > max_f[0] && pixel[1] > max_f[1] && pixel[2] > max_f[2]) {
|
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) {
|
if (Y > whitept) {
|
||||||
const float mult = whitept / Y;
|
const float mult = whitept / Y;
|
||||||
|
red[yy][xx] *= mult;
|
||||||
red[yy][xx] *= mult;
|
|
||||||
green[yy][xx] *= mult;
|
green[yy][xx] *= mult;
|
||||||
blue[yy][xx] *= mult;
|
blue[yy][xx] *= mult;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ii = (yy) / 2;
|
if (blur > 0) {
|
||||||
int jj = (xx) / 2;
|
const int ii = i / 2;
|
||||||
rbuf[ii][jj] = red[yy][xx];
|
const int jj = j / 2;
|
||||||
gbuf[ii][jj] = green[yy][xx];
|
rbuf[ii][jj] = red[yy][xx];
|
||||||
bbuf[ii][jj] = blue[yy][xx];
|
gbuf[ii][jj] = green[yy][xx];
|
||||||
mask[ii][jj] = maskval;
|
bbuf[ii][jj] = blue[yy][xx];
|
||||||
|
mask[ii][jj] = maskval;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (plistener) {
|
if (blur > 0) {
|
||||||
progress += 0.05;
|
if (plistener) {
|
||||||
plistener->setProgress(progress);
|
progress += 0.05;
|
||||||
}
|
plistener->setProgress(progress);
|
||||||
|
}
|
||||||
|
blur = rtengine::LIM(blur - 1, 0, 3);
|
||||||
|
|
||||||
// #ifdef _OPENMP
|
constexpr float vals[4][3] = {{4.0f, 0.3f, 0.3f},
|
||||||
// #pragma omp parallel
|
// {3.5f, 0.5f, 0.2f},
|
||||||
// #endif
|
{3.0f, 1.0f, 0.1f},
|
||||||
{
|
{3.0f, 2.0f, 0.01f},
|
||||||
//gaussianBlur(mask, mask, W/2, H/2, 5);
|
{2.0f, 3.0f, 0.001f}
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
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
|
#ifdef _OPENMP
|
||||||
#pragma omp parallel for
|
#pragma omp parallel for schedule(dynamic,16)
|
||||||
#endif
|
#endif
|
||||||
for (int y = 0; y < H; ++y) {
|
for (int y = 0; y < blurHeight; ++y) {
|
||||||
float fy = y * 0.5f;
|
const float fy = y * 0.5f;
|
||||||
int yy = y / 2;
|
const int yy = y / 2;
|
||||||
for (int x = 0; x < W; ++x) {
|
for (int x = 0; x < blurWidth; ++x) {
|
||||||
float fx = x * 0.5f;
|
const int xx = x / 2;
|
||||||
int xx = x / 2;
|
const float m = mask[yy][xx];
|
||||||
float m = mask[yy][xx];
|
|
||||||
if (m > 0.f) {
|
if (m > 0.f) {
|
||||||
red[y][x] = intp(m, getBilinearValue(rbuf, fx, fy), red[y][x]);
|
const float fx = x * 0.5f;
|
||||||
green[y][x] = intp(m, getBilinearValue(gbuf, fx, fy), green[y][x]);
|
red[y + miny][x + minx] = intp(m, getBilinearValue(rbuf, fx, fy), red[y + miny][x + minx]);
|
||||||
blue[y][x] = intp(m, getBilinearValue(bbuf, fx, fy), blue[y][x]);
|
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) {
|
if (plistener) {
|
||||||
plistener->setProgress(1.00);
|
plistener->setProgress(1.00);
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,6 @@ public:
|
|||||||
virtual void retinexPrepareBuffers (const procparams::ColorManagementParams& cmp, const procparams::RetinexParams &retinexParams, multi_array2D<float, 4> &conversionBuffer, LUTu &lhist16RETI) {};
|
virtual void retinexPrepareBuffers (const procparams::ColorManagementParams& cmp, const procparams::RetinexParams &retinexParams, multi_array2D<float, 4> &conversionBuffer, LUTu &lhist16RETI) {};
|
||||||
virtual void flush () = 0;
|
virtual void flush () = 0;
|
||||||
virtual void HLRecovery_Global (const procparams::ToneCurveParams &hrp) {};
|
virtual void HLRecovery_Global (const procparams::ToneCurveParams &hrp) {};
|
||||||
virtual void HLRecovery_inpaint (float** red, float** green, float** blue) {};
|
|
||||||
|
|
||||||
virtual bool isRGBSourceModified () const = 0; // tracks whether cached rgb output of demosaic has been modified
|
virtual bool isRGBSourceModified () const = 0; // tracks whether cached rgb output of demosaic has been modified
|
||||||
|
|
||||||
|
@ -385,6 +385,7 @@ ToneCurveParams::ToneCurveParams() :
|
|||||||
saturation(0),
|
saturation(0),
|
||||||
shcompr(50),
|
shcompr(50),
|
||||||
hlcompr(0),
|
hlcompr(0),
|
||||||
|
hlbl(0),
|
||||||
hlcomprthresh(0),
|
hlcomprthresh(0),
|
||||||
histmatching(false),
|
histmatching(false),
|
||||||
fromHistMatching(false),
|
fromHistMatching(false),
|
||||||
@ -410,6 +411,7 @@ bool ToneCurveParams::isPanningRelatedChange(const ToneCurveParams& other) const
|
|||||||
&& saturation == other.saturation
|
&& saturation == other.saturation
|
||||||
&& shcompr == other.shcompr
|
&& shcompr == other.shcompr
|
||||||
&& hlcompr == other.hlcompr
|
&& hlcompr == other.hlcompr
|
||||||
|
&& hlbl == other.hlbl
|
||||||
&& hlcomprthresh == other.hlcomprthresh
|
&& hlcomprthresh == other.hlcomprthresh
|
||||||
&& histmatching == other.histmatching
|
&& histmatching == other.histmatching
|
||||||
&& clampOOG == other.clampOOG);
|
&& clampOOG == other.clampOOG);
|
||||||
@ -433,6 +435,7 @@ bool ToneCurveParams::operator ==(const ToneCurveParams& other) const
|
|||||||
&& saturation == other.saturation
|
&& saturation == other.saturation
|
||||||
&& shcompr == other.shcompr
|
&& shcompr == other.shcompr
|
||||||
&& hlcompr == other.hlcompr
|
&& hlcompr == other.hlcompr
|
||||||
|
&& hlbl == other.hlbl
|
||||||
&& hlcomprthresh == other.hlcomprthresh
|
&& hlcomprthresh == other.hlcomprthresh
|
||||||
&& histmatching == other.histmatching
|
&& histmatching == other.histmatching
|
||||||
&& fromHistMatching == other.fromHistMatching
|
&& fromHistMatching == other.fromHistMatching
|
||||||
@ -5399,6 +5402,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo
|
|||||||
// Highlight recovery
|
// Highlight recovery
|
||||||
saveToKeyfile(!pedited || pedited->toneCurve.hrenabled, "HLRecovery", "Enabled", toneCurve.hrenabled, keyFile);
|
saveToKeyfile(!pedited || pedited->toneCurve.hrenabled, "HLRecovery", "Enabled", toneCurve.hrenabled, keyFile);
|
||||||
saveToKeyfile(!pedited || pedited->toneCurve.method, "HLRecovery", "Method", toneCurve.method, keyFile);
|
saveToKeyfile(!pedited || pedited->toneCurve.method, "HLRecovery", "Method", toneCurve.method, keyFile);
|
||||||
|
saveToKeyfile(!pedited || pedited->toneCurve.hlbl, "HLRecovery", "Hlbl", toneCurve.hlbl, keyFile);
|
||||||
|
|
||||||
const std::map<ToneCurveMode, const char*> tc_mapping = {
|
const std::map<ToneCurveMode, const char*> tc_mapping = {
|
||||||
{ToneCurveMode::STD, "Standard"},
|
{ToneCurveMode::STD, "Standard"},
|
||||||
@ -6924,6 +6928,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited)
|
|||||||
if (keyFile.has_group("HLRecovery")) {
|
if (keyFile.has_group("HLRecovery")) {
|
||||||
assignFromKeyfile(keyFile, "HLRecovery", "Enabled", pedited, toneCurve.hrenabled, pedited->toneCurve.hrenabled);
|
assignFromKeyfile(keyFile, "HLRecovery", "Enabled", pedited, toneCurve.hrenabled, pedited->toneCurve.hrenabled);
|
||||||
assignFromKeyfile(keyFile, "HLRecovery", "Method", pedited, toneCurve.method, pedited->toneCurve.method);
|
assignFromKeyfile(keyFile, "HLRecovery", "Method", pedited, toneCurve.method, pedited->toneCurve.method);
|
||||||
|
assignFromKeyfile(keyFile, "HLRecovery", "Hlbl", pedited, toneCurve.hlbl, pedited->toneCurve.hlbl);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (keyFile.has_group("Channel Mixer")) {
|
if (keyFile.has_group("Channel Mixer")) {
|
||||||
|
@ -297,6 +297,7 @@ struct ToneCurveParams {
|
|||||||
int saturation;
|
int saturation;
|
||||||
int shcompr;
|
int shcompr;
|
||||||
int hlcompr; // Highlight Recovery's compression
|
int hlcompr; // Highlight Recovery's compression
|
||||||
|
int hlbl; // Highlight Recovery's compression
|
||||||
int hlcomprthresh; // Highlight Recovery's threshold
|
int hlcomprthresh; // Highlight Recovery's threshold
|
||||||
bool histmatching; // histogram matching
|
bool histmatching; // histogram matching
|
||||||
bool fromHistMatching;
|
bool fromHistMatching;
|
||||||
|
@ -2438,7 +2438,7 @@ void RawImageSource::HLRecovery_Global(const ToneCurveParams &hrp)
|
|||||||
printf ("Applying Highlight Recovery: Color propagation...\n");
|
printf ("Applying Highlight Recovery: Color propagation...\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
HLRecovery_inpaint (red, green, blue);
|
HLRecovery_inpaint (red, green, blue, hrp.hlbl);
|
||||||
rgbSourceModified = true;
|
rgbSourceModified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,7 +195,7 @@ public:
|
|||||||
static void inverse33(const double (*coeff)[3], double (*icoeff)[3]);
|
static void inverse33(const double (*coeff)[3], double (*icoeff)[3]);
|
||||||
|
|
||||||
void MSR(float** luminance, float **originalLuminance, float **exLuminance, const LUTf& mapcurve, bool mapcontlutili, int width, int height, const procparams::RetinexParams &deh, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax);
|
void MSR(float** luminance, float **originalLuminance, float **exLuminance, const LUTf& mapcurve, bool mapcontlutili, int width, int height, const procparams::RetinexParams &deh, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax);
|
||||||
void HLRecovery_inpaint (float** red, float** green, float** blue) override;
|
void HLRecovery_inpaint (float** red, float** green, float** blue, int blur);
|
||||||
static void HLRecovery_Luminance (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, int width, float maxval);
|
static void HLRecovery_Luminance (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, int width, float maxval);
|
||||||
static void HLRecovery_CIELab (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, int width, float maxval, double cam[3][3], double icam[3][3]);
|
static void HLRecovery_CIELab (float* rin, float* gin, float* bin, float* rout, float* gout, float* bout, int width, float maxval, double cam[3][3], double icam[3][3]);
|
||||||
static void HLRecovery_blend (float* rin, float* gin, float* bin, int width, float maxval, float* hlmax);
|
static void HLRecovery_blend (float* rin, float* gin, float* bin, int width, float maxval, float* hlmax);
|
||||||
|
@ -35,23 +35,22 @@ inline float getBilinearValue(const array2D<float> &src, float x, float y)
|
|||||||
const int H = src.getHeight();
|
const int H = src.getHeight();
|
||||||
|
|
||||||
// Get integer and fractional parts of numbers
|
// Get integer and fractional parts of numbers
|
||||||
int xi = x;
|
const int xi = x;
|
||||||
int yi = y;
|
const int yi = y;
|
||||||
float xf = x - xi;
|
const float xf = x - xi;
|
||||||
float yf = y - yi;
|
const float yf = y - yi;
|
||||||
int xi1 = std::min(xi + 1, W - 1);
|
const int xi1 = std::min(xi + 1, W - 1);
|
||||||
int yi1 = std::min(yi + 1, H - 1);
|
const int yi1 = std::min(yi + 1, H - 1);
|
||||||
|
|
||||||
float bl = src[yi][xi];
|
const float bl = src[yi][xi];
|
||||||
float br = src[yi][xi1];
|
const float br = src[yi][xi1];
|
||||||
float tl = src[yi1][xi];
|
const float tl = src[yi1][xi];
|
||||||
float tr = src[yi1][xi1];
|
const float tr = src[yi1][xi1];
|
||||||
|
|
||||||
// interpolate
|
// interpolate
|
||||||
float b = xf * br + (1.f - xf) * bl;
|
const float b = intp(xf, br, bl);
|
||||||
float t = xf * tr + (1.f - xf) * tl;
|
const float t = intp(xf, tr, tl);
|
||||||
float pxf = yf * t + (1.f - yf) * b;
|
return intp(yf, t, b);
|
||||||
return pxf;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ void ParamsEdited::set(bool v)
|
|||||||
toneCurve.saturation = v;
|
toneCurve.saturation = v;
|
||||||
toneCurve.shcompr = v;
|
toneCurve.shcompr = v;
|
||||||
toneCurve.hlcompr = v;
|
toneCurve.hlcompr = v;
|
||||||
|
toneCurve.hlbl = v;
|
||||||
toneCurve.hlcomprthresh = v;
|
toneCurve.hlcomprthresh = v;
|
||||||
toneCurve.autoexp = v;
|
toneCurve.autoexp = v;
|
||||||
toneCurve.clip = v;
|
toneCurve.clip = v;
|
||||||
@ -720,6 +721,7 @@ void ParamsEdited::initFrom(const std::vector<rtengine::procparams::ProcParams>&
|
|||||||
toneCurve.saturation = toneCurve.saturation && p.toneCurve.saturation == other.toneCurve.saturation;
|
toneCurve.saturation = toneCurve.saturation && p.toneCurve.saturation == other.toneCurve.saturation;
|
||||||
toneCurve.shcompr = toneCurve.shcompr && p.toneCurve.shcompr == other.toneCurve.shcompr;
|
toneCurve.shcompr = toneCurve.shcompr && p.toneCurve.shcompr == other.toneCurve.shcompr;
|
||||||
toneCurve.hlcompr = toneCurve.hlcompr && p.toneCurve.hlcompr == other.toneCurve.hlcompr;
|
toneCurve.hlcompr = toneCurve.hlcompr && p.toneCurve.hlcompr == other.toneCurve.hlcompr;
|
||||||
|
toneCurve.hlbl = toneCurve.hlbl && p.toneCurve.hlbl == other.toneCurve.hlbl;
|
||||||
toneCurve.hlcomprthresh = toneCurve.hlcomprthresh && p.toneCurve.hlcomprthresh == other.toneCurve.hlcomprthresh;
|
toneCurve.hlcomprthresh = toneCurve.hlcomprthresh && p.toneCurve.hlcomprthresh == other.toneCurve.hlcomprthresh;
|
||||||
toneCurve.autoexp = toneCurve.autoexp && p.toneCurve.autoexp == other.toneCurve.autoexp;
|
toneCurve.autoexp = toneCurve.autoexp && p.toneCurve.autoexp == other.toneCurve.autoexp;
|
||||||
toneCurve.clip = toneCurve.clip && p.toneCurve.clip == other.toneCurve.clip;
|
toneCurve.clip = toneCurve.clip && p.toneCurve.clip == other.toneCurve.clip;
|
||||||
@ -2008,6 +2010,10 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng
|
|||||||
toEdit.toneCurve.method = mods.toneCurve.method;
|
toEdit.toneCurve.method = mods.toneCurve.method;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (toneCurve.hlbl) {
|
||||||
|
toEdit.toneCurve.hlbl = mods.toneCurve.hlbl;
|
||||||
|
}
|
||||||
|
|
||||||
if (toneCurve.histmatching) {
|
if (toneCurve.histmatching) {
|
||||||
toEdit.toneCurve.histmatching = mods.toneCurve.histmatching;
|
toEdit.toneCurve.histmatching = mods.toneCurve.histmatching;
|
||||||
}
|
}
|
||||||
|
@ -51,6 +51,7 @@ struct ToneCurveParamsEdited {
|
|||||||
bool saturation;
|
bool saturation;
|
||||||
bool shcompr;
|
bool shcompr;
|
||||||
bool hlcompr;
|
bool hlcompr;
|
||||||
|
bool hlbl;
|
||||||
bool hlcomprthresh;
|
bool hlcomprthresh;
|
||||||
bool autoexp;
|
bool autoexp;
|
||||||
bool clip;
|
bool clip;
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -47,6 +47,7 @@ protected:
|
|||||||
sigc::connection methconn;
|
sigc::connection methconn;
|
||||||
sigc::connection enaconn;
|
sigc::connection enaconn;
|
||||||
bool lasthrEnabled;
|
bool lasthrEnabled;
|
||||||
|
Adjuster* hlbl;
|
||||||
|
|
||||||
Gtk::Box* abox;
|
Gtk::Box* abox;
|
||||||
Gtk::Box* hlrbox;
|
Gtk::Box* hlrbox;
|
||||||
@ -80,6 +81,7 @@ protected:
|
|||||||
rtengine::ProcEvent EvHistMatching;
|
rtengine::ProcEvent EvHistMatching;
|
||||||
rtengine::ProcEvent EvHistMatchingBatch;
|
rtengine::ProcEvent EvHistMatchingBatch;
|
||||||
rtengine::ProcEvent EvClampOOG;
|
rtengine::ProcEvent EvClampOOG;
|
||||||
|
rtengine::ProcEvent EvHLbl;
|
||||||
|
|
||||||
// used temporarily in eventing
|
// used temporarily in eventing
|
||||||
double nextExpcomp;
|
double nextExpcomp;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user