Move tone equalizer after exposure

Place it between the shadows curve (black and shadow compression) and
DCP tone curve and look table. Moving it after exposure makes it
possible to easily adjust the exposure to the ball-park range before
applying the tone equalizer. Keeping it before the tone curves allows it
to affect the image before clipping occurs.
This commit is contained in:
Lawrence Lee
2023-04-15 16:53:58 -07:00
parent 12ef477a6d
commit 9893e02aab

View File

@@ -1979,7 +1979,9 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
stop.reset(new StopWatch("rgb processing"));
}
Imagefloat *tmpImage = nullptr;
const bool split_tiled_parts_1_2 = params->toneEqualizer.enabled;
std::unique_ptr<Imagefloat> tmpImage;
Imagefloat* editImgFloat = nullptr;
PlanarWhateverData<float>* editWhatever = nullptr;
@@ -2139,6 +2141,7 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
const float comp = (max(0.0, expcomp) + 1.0) * hlcompr / 100.0;
const float shoulder = ((65536.f / max(1.0f, exp_scale)) * (hlcomprthresh / 200.f)) + 0.1f;
const float hlrange = 65536.f - shoulder;
const int tone_curve_black = params->toneCurve.black;
const bool isProPhoto = (params->icm.workingProfile == "ProPhoto");
// extracting data from 'params' to avoid cache flush (to be confirmed)
ToneCurveMode curveMode = params->toneCurve.curveMode;
@@ -2247,8 +2250,8 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
}
bool hasgammabw = gammabwr != 1.f || gammabwg != 1.f || gammabwb != 1.f;
if (hasColorToning || blackwhite || (params->dirpyrequalizer.cbdlMethod == "bef" && params->dirpyrequalizer.enabled)) {
tmpImage = new Imagefloat(working->getWidth(), working->getHeight());
if (hasColorToning || blackwhite || (params->dirpyrequalizer.cbdlMethod == "bef" && params->dirpyrequalizer.enabled) || split_tiled_parts_1_2) {
tmpImage.reset(new Imagefloat(working->getWidth(), working->getHeight()));
}
// For tonecurve histogram
@@ -2263,14 +2266,52 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
// For tonecurve histogram
const float lumimulf[3] = {static_cast<float>(lumimul[0]), static_cast<float>(lumimul[1]), static_cast<float>(lumimul[2])};
std::unique_ptr<Imagefloat> workimg_copy;
if (params->toneEqualizer.enabled) {
working = working->copy();
workimg_copy.reset(working);
toneEqualizer(working);
#define TS 112
const auto tiled_part_1 =
[working,
mixchannels,
&hltonecurve, &shtonecurve,
chMixRR, chMixRG, chMixRB,
chMixGR, chMixGG, chMixGB,
chMixBR, chMixBG, chMixBB,
exp_scale, comp, hlrange, tone_curve_black](
int istart, int jstart, int tH, int tW,
float *rtemp, float *gtemp, float *btemp) {
for (int i = istart, ti = 0; i < tH; i++, ti++) {
for (int j = jstart, tj = 0; j < tW; j++, tj++) {
rtemp[ti * TS + tj] = working->r(i, j);
gtemp[ti * TS + tj] = working->g(i, j);
btemp[ti * TS + tj] = working->b(i, j);
}
}
#define TS 112
if (mixchannels) {
for (int i = istart, ti = 0; i < tH; i++, ti++) {
for (int j = jstart, tj = 0; j < tW; j++, tj++) {
float r = rtemp[ti * TS + tj];
float g = gtemp[ti * TS + tj];
float b = btemp[ti * TS + tj];
// if (i==100 & j==100) printf("rgbProc input R= %f G= %f B= %f \n",r,g,b);
float rmix = (r * chMixRR + g * chMixRG + b * chMixRB) / 100.f;
float gmix = (r * chMixGR + g * chMixGG + b * chMixGB) / 100.f;
float bmix = (r * chMixBR + g * chMixBG + b * chMixBB) / 100.f;
rtemp[ti * TS + tj] = rmix;
gtemp[ti * TS + tj] = gmix;
btemp[ti * TS + tj] = bmix;
}
}
}
highlightToneCurve(hltonecurve, rtemp, gtemp, btemp, istart, tH, jstart, tW, TS, exp_scale, comp, hlrange);
if (tone_curve_black != 0) {
shadowToneCurve(shtonecurve, rtemp, gtemp, btemp, istart, tH, jstart, tW, TS);
}
};
#ifdef _OPENMP
#pragma omp parallel if (multiThread)
@@ -2322,6 +2363,41 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
histToneCurveThr.clear();
}
if (split_tiled_parts_1_2) {
#ifdef _OPENMP
#pragma omp for schedule(dynamic, chunkSize) collapse(2)
#endif
for (int ii = 0; ii < working->getHeight(); ii += TS) {
for (int jj = 0; jj < working->getWidth(); jj += TS) {
istart = ii;
jstart = jj;
tH = min(ii + TS, working->getHeight());
tW = min(jj + TS, working->getWidth());
tiled_part_1(istart, jstart, tH, tW, rtemp, gtemp, btemp);
// Copy tile to image.
for (int i = istart, ti = 0; i < tH; i++, ti++) {
for (int j = jstart, tj = 0; j < tW; j++, tj++) {
tmpImage->r(i, j) = rtemp[ti * TS + tj];
tmpImage->g(i, j) = gtemp[ti * TS + tj];
tmpImage->b(i, j) = btemp[ti * TS + tj];
}
}
}
}
}
#ifdef _OPENMP
#pragma omp single
#endif
if (params->toneEqualizer.enabled) {
toneEqualizer(tmpImage.get());
}
#ifdef _OPENMP
#pragma omp for schedule(dynamic, chunkSize) collapse(2)
#endif
@@ -2333,38 +2409,16 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
tH = min(ii + TS, working->getHeight());
tW = min(jj + TS, working->getWidth());
if (split_tiled_parts_1_2) {
for (int i = istart, ti = 0; i < tH; i++, ti++) {
for (int j = jstart, tj = 0; j < tW; j++, tj++) {
rtemp[ti * TS + tj] = working->r(i, j);
gtemp[ti * TS + tj] = working->g(i, j);
btemp[ti * TS + tj] = working->b(i, j);
rtemp[ti * TS + tj] = tmpImage->r(i, j);
gtemp[ti * TS + tj] = tmpImage->g(i, j);
btemp[ti * TS + tj] = tmpImage->b(i, j);
}
}
if (mixchannels) {
for (int i = istart, ti = 0; i < tH; i++, ti++) {
for (int j = jstart, tj = 0; j < tW; j++, tj++) {
float r = rtemp[ti * TS + tj];
float g = gtemp[ti * TS + tj];
float b = btemp[ti * TS + tj];
//if (i==100 & j==100) printf("rgbProc input R= %f G= %f B= %f \n",r,g,b);
float rmix = (r * chMixRR + g * chMixRG + b * chMixRB) / 100.f;
float gmix = (r * chMixGR + g * chMixGG + b * chMixGB) / 100.f;
float bmix = (r * chMixBR + g * chMixBG + b * chMixBB) / 100.f;
rtemp[ti * TS + tj] = rmix;
gtemp[ti * TS + tj] = gmix;
btemp[ti * TS + tj] = bmix;
}
}
}
highlightToneCurve(hltonecurve, rtemp, gtemp, btemp, istart, tH, jstart, tW, TS, exp_scale, comp, hlrange);
if (params->toneCurve.black != 0.0) {
shadowToneCurve(shtonecurve, rtemp, gtemp, btemp, istart, tH, jstart, tW, TS);
} else {
tiled_part_1(istart, jstart, tH, tW, rtemp, gtemp, btemp);
}
if (dcpProf) {
@@ -3515,10 +3569,6 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
}
if (tmpImage) {
delete tmpImage;
}
if (hCurveEnabled) {
delete hCurve;
}