1 /*
2 * This file is part of RawTherapee.
3 *
4 * Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
5 *
6 * RawTherapee is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * RawTherapee is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
18 */
19 #include <cmath>
20 #include <glib.h>
21 #include <glibmm.h>
22 #ifdef _OPENMP
23 #include <omp.h>
24 #endif
25
26 #include "alignedbuffer.h"
27 #include "rtengine.h"
28 #include "improcfun.h"
29 #include "curves.h"
30 #include "mytime.h"
31 #include "iccstore.h"
32 #include "imagesource.h"
33 #include "rtthumbnail.h"
34 #include "utils.h"
35 #include "iccmatrices.h"
36 #include "color.h"
37 #include "calc_distort.h"
38 #include "rt_math.h"
39 #include "improccoordinator.h"
40 #include "clutstore.h"
41 #include "StopWatch.h"
42 #include "../rtgui/ppversion.h"
43 #include "../rtgui/guiutils.h"
44 #include "refreshmap.h"
45
46 namespace rtengine {
47
48 using namespace procparams;
49
50 extern const Settings* settings;
51
ImProcFunctions(const ProcParams * iparams,bool imultiThread)52 ImProcFunctions::ImProcFunctions(const ProcParams* iparams, bool imultiThread):
53 monitor(nullptr),
54 monitorTransform(nullptr),
55 params(iparams),
56 scale(1),
57 multiThread(imultiThread),
58 cur_pipeline(Pipeline::OUTPUT),
59 dcpProf(nullptr),
60 dcpApplyState(nullptr),
61 pipetteBuffer(nullptr),
62 lumimul{},
63 offset_x(0),
64 offset_y(0),
65 full_width(-1),
66 full_height(-1),
67 histToneCurve(nullptr),
68 histCCurve(nullptr),
69 histLCurve(nullptr),
70 show_sharpening_mask(false),
71 plistener(nullptr),
72 progress_step(0),
73 progress_end(1)
74 {
75 }
76
77
~ImProcFunctions()78 ImProcFunctions::~ImProcFunctions ()
79 {
80 if (monitorTransform) {
81 cmsDeleteTransform (monitorTransform);
82 }
83 }
84
setScale(double iscale)85 void ImProcFunctions::setScale (double iscale)
86 {
87 scale = iscale;
88 }
89
90
updateColorProfiles(const Glib::ustring & monitorProfile,RenderingIntent monitorIntent,bool softProof,bool gamutCheck)91 void ImProcFunctions::updateColorProfiles (const Glib::ustring& monitorProfile, RenderingIntent monitorIntent, bool softProof, bool gamutCheck)
92 {
93 // set up monitor transform
94 if (monitorTransform) {
95 cmsDeleteTransform (monitorTransform);
96 }
97 gamutWarning.reset(nullptr);
98
99 monitorTransform = nullptr;
100 monitor = nullptr;
101
102 if (!monitorProfile.empty()) {
103 #if !defined(__APPLE__) // No support for monitor profiles on OS X, all data is sRGB
104 monitor = ICCStore::getInstance()->getProfile (monitorProfile);
105 #else
106 monitor = ICCStore::getInstance()->getProfile (options.rtSettings.srgb);
107 #endif
108 }
109
110 if (monitor) {
111 MyMutex::MyLock lcmsLock (*lcmsMutex);
112
113 cmsUInt32Number flags;
114 cmsHPROFILE iprof = cmsCreateLab4Profile (nullptr);
115 cmsHPROFILE gamutprof = nullptr;
116 cmsUInt32Number gamutbpc = 0;
117 RenderingIntent gamutintent = RI_RELATIVE;
118
119 bool softProofCreated = false;
120
121 if (softProof) {
122 cmsHPROFILE oprof = nullptr;
123 RenderingIntent outIntent;
124
125 flags = cmsFLAGS_SOFTPROOFING | cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE;
126
127 if (!settings->printerProfile.empty()) {
128 oprof = ICCStore::getInstance()->getProfile (settings->printerProfile);
129 if (settings->printerBPC) {
130 flags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
131 }
132 outIntent = settings->printerIntent;
133 } else {
134 oprof = ICCStore::getInstance()->getProfile(params->icm.outputProfile);
135 if (params->icm.outputBPC) {
136 flags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
137 }
138 outIntent = params->icm.outputIntent;
139 }
140
141 if (oprof) {
142 // NOCACHE is for thread safety, NOOPTIMIZE for precision
143
144 // if (gamutCheck) {
145 // flags |= cmsFLAGS_GAMUTCHECK;
146 // }
147
148 const auto make_gamma_table =
149 [](cmsHPROFILE prof, cmsTagSignature tag) -> void
150 {
151 cmsToneCurve *tc = static_cast<cmsToneCurve *>(cmsReadTag(prof, tag));
152 if (tc) {
153 const cmsUInt16Number *table = cmsGetToneCurveEstimatedTable(tc);
154 cmsToneCurve *tc16 = cmsBuildTabulatedToneCurve16(nullptr, cmsGetToneCurveEstimatedTableEntries(tc), table);
155 if (tc16) {
156 cmsWriteTag(prof, tag, tc16);
157 cmsFreeToneCurve(tc16);
158 }
159 }
160 };
161
162 cmsHPROFILE softproof = ProfileContent(oprof).toProfile();
163 if (softproof) {
164 make_gamma_table(softproof, cmsSigRedTRCTag);
165 make_gamma_table(softproof, cmsSigGreenTRCTag);
166 make_gamma_table(softproof, cmsSigBlueTRCTag);
167 }
168
169 monitorTransform = cmsCreateProofingTransform (
170 iprof, TYPE_Lab_FLT,
171 monitor, TYPE_RGB_FLT,
172 softproof,
173 monitorIntent, outIntent,
174 flags
175 );
176
177 if (softproof) {
178 cmsCloseProfile(softproof);
179 }
180
181 if (monitorTransform) {
182 softProofCreated = true;
183 }
184
185 if (gamutCheck) {
186 gamutprof = oprof;
187 if (params->icm.outputBPC) {
188 gamutbpc = cmsFLAGS_BLACKPOINTCOMPENSATION;
189 }
190 gamutintent = outIntent;
191 }
192 }
193 } else if (gamutCheck) {
194 gamutprof = monitor;
195 if (settings->monitorBPC) {
196 gamutbpc = cmsFLAGS_BLACKPOINTCOMPENSATION;
197 }
198 gamutintent = monitorIntent;
199 }
200
201 if (!softProofCreated) {
202 flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE;
203
204 if (settings->monitorBPC) {
205 flags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
206 }
207
208 monitorTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, monitor, TYPE_RGB_FLT, monitorIntent, flags);
209 }
210
211 if (gamutCheck && gamutprof) {
212 gamutWarning.reset(new GamutWarning(iprof, gamutprof, gamutintent, gamutbpc));
213 }
214
215 cmsCloseProfile (iprof);
216 }
217 }
218
firstAnalysis(const Imagefloat * const original,const ProcParams & params,LUTu & histogram)219 void ImProcFunctions::firstAnalysis (const Imagefloat* const original, const ProcParams ¶ms, LUTu & histogram)
220 {
221
222 TMatrix wprof = ICCStore::getInstance()->workingSpaceMatrix (params.icm.workingProfile);
223
224 lumimul[0] = wprof[1][0];
225 lumimul[1] = wprof[1][1];
226 lumimul[2] = wprof[1][2];
227 int W = original->getWidth();
228 int H = original->getHeight();
229
230 float lumimulf[3] = {static_cast<float> (lumimul[0]), static_cast<float> (lumimul[1]), static_cast<float> (lumimul[2])};
231
232 // calculate histogram of the y channel needed for contrast curve calculation in exposure adjustments
233 histogram.clear();
234
235 if (multiThread) {
236
237 #ifdef _OPENMP
238 const int numThreads = min (max (W * H / (int)histogram.getSize(), 1), omp_get_max_threads());
239 #pragma omp parallel num_threads(numThreads) if(numThreads>1)
240 #endif
241 {
242 LUTu hist (histogram.getSize());
243 hist.clear();
244 #ifdef _OPENMP
245 #pragma omp for nowait
246 #endif
247
248 for (int i = 0; i < H; i++) {
249 for (int j = 0; j < W; j++) {
250
251 float r = original->r (i, j);
252 float g = original->g (i, j);
253 float b = original->b (i, j);
254
255 int y = (lumimulf[0] * r + lumimulf[1] * g + lumimulf[2] * b);
256 hist[y]++;
257 }
258 }
259
260 #ifdef _OPENMP
261 #pragma omp critical
262 #endif
263 histogram += hist;
264
265 }
266 #ifdef _OPENMP
267 static_cast<void> (numThreads); // to silence cppcheck warning
268 #endif
269 } else {
270 for (int i = 0; i < H; i++) {
271 for (int j = 0; j < W; j++) {
272
273 float r = original->r (i, j);
274 float g = original->g (i, j);
275 float b = original->b (i, j);
276
277 int y = (lumimulf[0] * r + lumimulf[1] * g + lumimulf[2] * b);
278 histogram[y]++;
279 }
280 }
281 }
282 }
283
284
285 namespace {
286
proPhotoBlue(Imagefloat * rgb,bool multiThread)287 void proPhotoBlue(Imagefloat *rgb, bool multiThread)
288 {
289 // TODO
290 const int W = rgb->getWidth();
291 const int H = rgb->getHeight();
292 #ifdef _OPENMP
293 # pragma omp parallel for if (multiThread)
294 #endif
295 for (int y = 0; y < H; ++y) {
296 int x = 0;
297 #ifdef __SSE2__
298 for (; x < W - 3; x += 4) {
299 vfloat rv = LVF(rgb->r(y, x));
300 vfloat gv = LVF(rgb->g(y, x));
301 vmask zeromask = vorm(vmaskf_eq(rv, ZEROV), vmaskf_eq(gv, ZEROV));
302 if (_mm_movemask_ps((vfloat)zeromask)) {
303 for (int k = 0; k < 4; ++k) {
304 float r = rgb->r(y, x+k);
305 float g = rgb->g(y, x+k);
306 float b = rgb->b(y, x+k);
307
308 if ((r == 0.0f || g == 0.0f) && rtengine::min(r, g, b) >= 0.f) {
309 float h, s, v;
310 Color::rgb2hsv(r, g, b, h, s, v);
311 s *= 0.99f;
312 Color::hsv2rgb(h, s, v, rgb->r(y, x+k), rgb->g(y, x+k), rgb->b(y, x+k));
313 }
314 }
315 }
316 }
317 #endif
318 for (; x < W; ++x) {
319 float r = rgb->r(y, x);
320 float g = rgb->g(y, x);
321 float b = rgb->b(y, x);
322
323 if ((r == 0.0f || g == 0.0f) && rtengine::min(r, g, b) >= 0.f) {
324 float h, s, v;
325 Color::rgb2hsv(r, g, b, h, s, v);
326 s *= 0.99f;
327 Color::hsv2rgb(h, s, v, rgb->r(y, x), rgb->g(y, x), rgb->b(y, x));
328 }
329 }
330 }
331 }
332
333
dcpProfile(Imagefloat * img,DCPProfile * dcp,const DCPProfile::ApplyState * as,bool multithread)334 void dcpProfile(Imagefloat *img, DCPProfile *dcp, const DCPProfile::ApplyState *as, bool multithread)
335 {
336 if (dcp && as) {
337 img->setMode(Imagefloat::Mode::RGB, multithread);
338
339 const int H = img->getHeight();
340 const int W = img->getWidth();
341 #ifdef _OPENMP
342 # pragma omp parallel for if (multithread)
343 #endif
344 for (int y = 0; y < H; ++y) {
345 float *r = img->r(y);
346 float *g = img->g(y);
347 float *b = img->b(y);
348 dcp->step2ApplyTile(r, g, b, W, 1, 1, *as);
349 }
350 }
351 }
352
353 } // namespace
354
355
getAutoExp(const LUTu & histogram,int histcompr,double clip,double & expcomp,int & bright,int & contr,int & black,int & hlcompr,int & hlcomprthresh)356 void ImProcFunctions::getAutoExp (const LUTu &histogram, int histcompr, double clip,
357 double& expcomp, int& bright, int& contr, int& black, int& hlcompr, int& hlcomprthresh)
358 {
359
360 float scale = 65536.0f;
361 float midgray = 0.1842f; //middle gray in linear gamma =1 50% luminance
362
363 int imax = 65536 >> histcompr;
364 int overex = 0;
365 float sum = 0.f, hisum = 0.f, losum = 0.f;
366 float ave = 0.f, hidev = 0.f, lodev = 0.f;
367
368 //find average luminance
369 histogram.getSumAndAverage (sum, ave);
370
371 //find median of luminance
372 size_t median = 0, count = histogram[0];
373
374 while (count < sum / 2) {
375 median++;
376 count += histogram[median];
377 }
378
379 if (median == 0 || ave < 1.f) { //probably the image is a blackframe
380 expcomp = 0.;
381 black = 0;
382 bright = 0;
383 contr = 0;
384 hlcompr = 0;
385 hlcomprthresh = 0;
386 return;
387 }
388
389 // compute std dev on the high and low side of median
390 // and octiles of histogram
391 float octile[8] = {0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f}, ospread = 0.f;
392 count = 0;
393
394 int i = 0;
395
396 for (; i < min ((int)ave, imax); i++) {
397 if (count < 8) {
398 octile[count] += histogram[i];
399
400 if (octile[count] > sum / 8.f || (count == 7 && octile[count] > sum / 16.f)) {
401 octile[count] = xlog (1. + (float)i) / log (2.f);
402 count++;// = min(count+1,7);
403 }
404 }
405
406 //lodev += SQR(ave-i)*histogram[i];
407 lodev += (xlog (ave + 1.f) - xlog ((float)i + 1.)) * histogram[i];
408 losum += histogram[i];
409 }
410
411 for (; i < imax; i++) {
412 if (count < 8) {
413 octile[count] += histogram[i];
414
415 if (octile[count] > sum / 8.f || (count == 7 && octile[count] > sum / 16.f)) {
416 octile[count] = xlog (1. + (float)i) / log (2.f);
417 count++;// = min(count+1,7);
418 }
419 }
420
421 //hidev += SQR(i-ave)*histogram[i];
422 hidev += (xlog ((float)i + 1.) - xlog (ave + 1.f)) * histogram[i];
423 hisum += histogram[i];
424
425 }
426
427 if (losum == 0 || hisum == 0) { //probably the image is a blackframe
428 expcomp = 0.;
429 black = 0;
430 bright = 0;
431 contr = 0;
432 hlcompr = 0;
433 hlcomprthresh = 0;
434 return;
435 }
436
437 // lodev = (lodev / (log(2.f) * losum));
438 // hidev = (hidev / (log(2.f) * hisum));
439
440 if (octile[6] > log1p ((float)imax) / log2 (2.f)) { //if very overxposed image
441 octile[6] = 1.5f * octile[5] - 0.5f * octile[4];
442 overex = 2;
443 }
444
445 if (octile[7] > log1p ((float)imax) / log2 (2.f)) { //if overexposed
446 octile[7] = 1.5f * octile[6] - 0.5f * octile[5];
447 overex = 1;
448 }
449
450 // store values of octile[6] and octile[7] for calculation of exposure compensation
451 // if we don't do this and the pixture is underexposed, calculation of exposure compensation assumes
452 // that it's overexposed and calculates the wrong direction
453 float oct6, oct7;
454 oct6 = octile[6];
455 oct7 = octile[7];
456
457
458 for (int i = 1; i < 8; i++) {
459 if (octile[i] == 0.0f) {
460 octile[i] = octile[i - 1];
461 }
462 }
463
464 // compute weighted average separation of octiles
465 // for future use in contrast setting
466 for (int i = 1; i < 6; i++) {
467 ospread += (octile[i + 1] - octile[i]) / max (0.5f, (i > 2 ? (octile[i + 1] - octile[3]) : (octile[3] - octile[i])));
468 }
469
470 ospread /= 5.f;
471
472 if (ospread <= 0.f) { //probably the image is a blackframe
473 expcomp = 0.;
474 black = 0;
475 bright = 0;
476 contr = 0;
477 hlcompr = 0;
478 hlcomprthresh = 0;
479 return;
480 }
481
482
483 // compute clipping points based on the original histograms (linear, without exp comp.)
484 unsigned int clipped = 0;
485 int rawmax = (imax) - 1;
486
487 while (histogram[rawmax] + clipped <= 0 && rawmax > 1) {
488 clipped += histogram[rawmax];
489 rawmax--;
490 }
491
492 //compute clipped white point
493 unsigned int clippable = (int) (sum * clip / 100.f );
494 clipped = 0;
495 int whiteclip = (imax) - 1;
496
497 while (whiteclip > 1 && (histogram[whiteclip] + clipped) <= clippable) {
498 clipped += histogram[whiteclip];
499 whiteclip--;
500 }
501
502 //compute clipped black point
503 clipped = 0;
504 int shc = 0;
505
506 while (shc < whiteclip - 1 && histogram[shc] + clipped <= clippable) {
507 clipped += histogram[shc];
508 shc++;
509 }
510
511 //rescale to 65535 max
512 rawmax <<= histcompr;
513 whiteclip <<= histcompr;
514 ave = ave * (1 << histcompr);
515 median <<= histcompr;
516 shc <<= histcompr;
517
518 // //prevent division by 0
519 // if (lodev == 0.f) {
520 // lodev = 1.f;
521 // }
522
523 //compute exposure compensation as geometric mean of the amount that
524 //sets the mean or median at middle gray, and the amount that sets the estimated top
525 //of the histogram at or near clipping.
526 //float expcomp1 = (log(/*(median/ave)*//*(hidev/lodev)*/midgray*scale/(ave-shc+midgray*shc))+log((hidev/lodev)))/log(2.f);
527 float expcomp1 = (log (/*(median/ave)*//*(hidev/lodev)*/midgray * scale / (ave - shc + midgray * shc))) / log (2.f);
528 float expcomp2;
529
530 if (overex == 0) { // image is not overexposed
531 expcomp2 = 0.5f * ( (15.5f - histcompr - (2.f * oct7 - oct6)) + log (scale / rawmax) / log (2.f) );
532 } else {
533 expcomp2 = 0.5f * ( (15.5f - histcompr - (2.f * octile[7] - octile[6])) + log (scale / rawmax) / log (2.f) );
534 }
535
536 if (fabs (expcomp1) - fabs (expcomp2) > 1.f) { //for great expcomp
537 expcomp = (expcomp1 * fabs (expcomp2) + expcomp2 * fabs (expcomp1)) / (fabs (expcomp1) + fabs (expcomp2));
538 } else {
539 expcomp = 0.5 * (double)expcomp1 + 0.5 * (double) expcomp2; //for small expcomp
540 }
541
542 float gain = exp ((float)expcomp * log (2.f));
543
544 float corr = sqrt (gain * scale / rawmax);
545 black = (int) shc * corr;
546
547
548 //now tune hlcompr to bring back rawmax to 65535
549 hlcomprthresh = 0;
550 //this is a series approximation of the actual formula for comp,
551 //which is a transcendental equation
552 float comp = (gain * ((float)whiteclip) / scale - 1.f) * 2.3f; // 2.3 instead of 2 to increase slightly comp
553 hlcompr = (int) (100.*comp / (max (0.0, expcomp) + 1.0));
554 hlcompr = max (0, min (100, hlcompr));
555
556 //now find brightness if gain didn't bring ave to midgray using
557 //the envelope of the actual 'control cage' brightness curve for simplicity
558 float midtmp = gain * sqrt (median * ave) / scale;
559
560 if (midtmp < 0.1f) {
561 bright = (midgray - midtmp) * 15.0 / (midtmp);
562 } else {
563 bright = (midgray - midtmp) * 15.0 / (0.10833 - 0.0833 * midtmp);
564 }
565
566 bright = 0.25 */*(median/ave)*(hidev/lodev)*/max (0, bright);
567
568 //compute contrast that spreads the average spacing of octiles
569 contr = (int) 50.0f * (1.1f - ospread);
570 contr = max (0, min (100, contr));
571 //take gamma into account
572 double whiteclipg = (int) (CurveFactory::gamma2 (whiteclip * corr / 65536.0) * 65536.0);
573
574 float gavg = 0.;
575
576 float val = 0.f;
577 float increment = corr * (1 << histcompr);
578
579 for (int i = 0; i < 65536 >> histcompr; i++) {
580 gavg += histogram[i] * Color::gamma2curve[val];
581 val += increment;
582 }
583
584 gavg /= sum;
585
586 if (black < gavg) {
587 int maxwhiteclip = (gavg - black) * 4 / 3 + black; // don't let whiteclip be such large that the histogram average goes above 3/4
588
589 if (whiteclipg < maxwhiteclip) {
590 whiteclipg = maxwhiteclip;
591 }
592 }
593
594 whiteclipg = CurveFactory::igamma2 ((float) (whiteclipg / 65535.0)) * 65535.0; //need to inverse gamma transform to get correct exposure compensation parameter
595
596 //corection with gamma
597 black = (int) ((65535 * black) / whiteclipg);
598 //expcomp = log(65535.0 / (whiteclipg)) / log(2.0);
599
600 //diagnostics
601 //printf ("**************** AUTO LEVELS ****************\n");
602 /*
603 if (settings->verbose) {
604 printf("sum=%i clip=%f clippable=%i clipWh=%i clipBl=%i\n",somm, clip, clippable,clipwh, clipbl);
605 printf ("expcomp1= %f expcomp2= %f gain= %f expcomp=%f\n",expcomp1,expcomp2,gain,expcomp);
606 printf ("expo=%f\n",expo);
607 printf ("median: %i average: %f median/average: %f\n",median,ave, median/ave);
608 printf ("average: %f\n",ave);
609 printf("comp=%f hlcomp: %i\n",comp, hlcompr);
610 printf ("median/average: %f\n",median/ave);
611 printf ("lodev: %f hidev: %f hidev/lodev: %f\n",lodev,hidev,hidev/lodev);
612 printf ("lodev: %f\n",lodev);
613 printf ("hidev: %f\n",hidev);
614 printf ("imax=%d rawmax= %d whiteclip= %d gain= %f\n",imax,rawmax,whiteclip,gain);
615 printf ("octiles: %f %f %f %f %f %f %f %f\n",octile[0],octile[1],octile[2],octile[3],octile[4],octile[5],octile[6],octile[7]);
616 printf ("ospread= %f\n",ospread);
617 printf ("overexp= %i\n",overex);
618 }
619 */
620 /*
621 // %%%%%%%%%% LEGACY AUTOEXPOSURE CODE %%%%%%%%%%%%%
622 // black point selection is based on the linear result (yielding better visual results)
623 black = (int)(shc * corr);
624 // compute the white point of the exp. compensated gamma corrected image
625 double whiteclipg = (int)(CurveFactory::gamma2 (whiteclip * corr / 65536.0) * 65536.0);
626
627 // compute average intensity of the exp compensated, gamma corrected image
628 double gavg = 0;
629 for (int i=0; i<65536>>histcompr; i++)
630 gavg += histogram[i] * CurveFactory::gamma2((int)(corr*(i<<histcompr)<65535 ? corr*(i<<histcompr) : 65535)) / sum;
631
632 if (black < gavg) {
633 int maxwhiteclip = (gavg - black) * 4 / 3 + black; // don't let whiteclip be such large that the histogram average goes above 3/4
634 //double mavg = 65536.0 / (whiteclipg-black) * (gavg - black);
635 if (whiteclipg < maxwhiteclip)
636 whiteclipg = maxwhiteclip;
637 }
638
639 whiteclipg = CurveFactory::igamma2 ((float)(whiteclipg/65535.0)) * 65535.0; //need to inverse gamma transform to get correct exposure compensation parameter
640
641 black = (int)((65535*black)/whiteclipg);
642 expcomp = log(65535.0 / (whiteclipg)) / log(2.0);
643
644 if (expcomp<0.0) expcomp = 0.0;*/
645 if (expcomp < -5.0) {
646 expcomp = -5.0;
647 }
648
649 if (expcomp > 12.0) {
650 expcomp = 12.0;
651 }
652
653 bright = max (-100, min (bright, 100));
654
655 }
656
657
658 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
659
getAutoDistor(const Glib::ustring & fname,int thumb_size)660 double ImProcFunctions::getAutoDistor (const Glib::ustring &fname, int thumb_size)
661 {
662 if (fname != "") {
663 int w_raw = -1, h_raw = thumb_size;
664 int w_thumb = -1, h_thumb = thumb_size;
665
666 eSensorType sensorType = rtengine::ST_NONE;
667 Thumbnail* thumb = rtengine::Thumbnail::loadQuickFromRaw (fname, sensorType, w_thumb, h_thumb, 1, FALSE);
668
669 if (!thumb) {
670 return 0.0;
671 }
672
673 Thumbnail* raw = rtengine::Thumbnail::loadFromRaw(fname, sensorType, w_raw, h_raw, 1, 1.0, FALSE);
674
675 if (!raw) {
676 delete thumb;
677 return 0.0;
678 }
679
680 if (h_thumb != h_raw) {
681 delete thumb;
682 delete raw;
683 return 0.0;
684 }
685
686 int width;
687
688 if (w_thumb > w_raw) {
689 width = w_raw;
690 } else {
691 width = w_thumb;
692 }
693
694 unsigned char* thumbGray;
695 unsigned char* rawGray;
696 thumbGray = thumb->getGrayscaleHistEQ (width);
697 rawGray = raw->getGrayscaleHistEQ (width);
698
699 if (!thumbGray || !rawGray) {
700 if (thumbGray) {
701 delete thumbGray;
702 }
703
704 if (rawGray) {
705 delete rawGray;
706 }
707
708 delete thumb;
709 delete raw;
710 return 0.0;
711 }
712
713 double dist_amount;
714 int dist_result = calcDistortion (thumbGray, rawGray, width, h_thumb, 1, dist_amount);
715
716 if (dist_result == -1) { // not enough features found, try increasing max. number of features by factor 4
717 calcDistortion (thumbGray, rawGray, width, h_thumb, 4, dist_amount);
718 }
719
720 delete[] thumbGray;
721 delete[] rawGray;
722 delete thumb;
723 delete raw;
724 return dist_amount;
725 } else {
726 return 0.0;
727 }
728 }
729
rgb2lab(Imagefloat & src,LabImage & dst,const Glib::ustring & workingSpace)730 void ImProcFunctions::rgb2lab (Imagefloat &src, LabImage &dst, const Glib::ustring &workingSpace)
731 {
732 src.assignColorSpace(workingSpace);
733 src.toLab(dst, true);
734 }
735
lab2rgb(const LabImage & src,Imagefloat & dst,const Glib::ustring & workingSpace)736 void ImProcFunctions::lab2rgb (const LabImage &src, Imagefloat &dst, const Glib::ustring &workingSpace)
737 {
738 dst.assignColorSpace(workingSpace);
739 dst.assignMode(Imagefloat::Mode::RGB);
740
741 TMatrix wiprof = ICCStore::getInstance()->workingSpaceInverseMatrix ( workingSpace );
742 const float wip[3][3] = {
743 {static_cast<float> (wiprof[0][0]), static_cast<float> (wiprof[0][1]), static_cast<float> (wiprof[0][2])},
744 {static_cast<float> (wiprof[1][0]), static_cast<float> (wiprof[1][1]), static_cast<float> (wiprof[1][2])},
745 {static_cast<float> (wiprof[2][0]), static_cast<float> (wiprof[2][1]), static_cast<float> (wiprof[2][2])}
746 };
747
748 const int W = dst.getWidth();
749 const int H = dst.getHeight();
750 #ifdef __SSE2__
751 vfloat wipv[3][3];
752
753 for (int i = 0; i < 3; i++) {
754 for (int j = 0; j < 3; j++) {
755 wipv[i][j] = F2V (wiprof[i][j]);
756 }
757 }
758
759 #endif
760
761 #ifdef _OPENMP
762 #pragma omp parallel for schedule(dynamic,16)
763 #endif
764
765 for (int i = 0; i < H; i++) {
766 int j = 0;
767 #ifdef __SSE2__
768
769 for (; j < W - 3; j += 4) {
770 vfloat X, Y, Z;
771 vfloat R, G, B;
772 Color::Lab2XYZ (LVFU (src.L[i][j]), LVFU (src.a[i][j]), LVFU (src.b[i][j]), X, Y, Z);
773 Color::xyz2rgb (X, Y, Z, R, G, B, wipv);
774 STVFU (dst.r (i, j), R);
775 STVFU (dst.g (i, j), G);
776 STVFU (dst.b (i, j), B);
777 }
778
779 #endif
780
781 for (; j < W; j++) {
782 float X, Y, Z;
783 Color::Lab2XYZ (src.L[i][j], src.a[i][j], src.b[i][j], X, Y, Z);
784 Color::xyz2rgb (X, Y, Z, dst.r (i, j), dst.g (i, j), dst.b (i, j), wip);
785 }
786 }
787 }
788
789 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
790
791
setViewport(int ox,int oy,int fw,int fh)792 void ImProcFunctions::setViewport(int ox, int oy, int fw, int fh)
793 {
794 offset_x = ox;
795 offset_y = oy;
796 full_width = fw;
797 full_height = fh;
798 }
799
800
setOutputHistograms(LUTu * histToneCurve,LUTu * histCCurve,LUTu * histLCurve)801 void ImProcFunctions::setOutputHistograms(LUTu *histToneCurve, LUTu *histCCurve, LUTu *histLCurve)
802 {
803 this->histToneCurve = histToneCurve;
804 this->histCCurve = histCCurve;
805 this->histLCurve = histLCurve;
806 }
807
808
setShowSharpeningMask(bool yes)809 void ImProcFunctions::setShowSharpeningMask(bool yes)
810 {
811 show_sharpening_mask = yes;
812 }
813
814
815 namespace {
816
817 constexpr int NUM_PIPELINE_STEPS = 23;
818
819 } // namespace
820
setProgressListener(ProgressListener * pl,int num_previews)821 void ImProcFunctions::setProgressListener(ProgressListener *pl, int num_previews)
822 {
823 plistener = pl;
824 progress_step = 0;
825 progress_end = NUM_PIPELINE_STEPS * std::max(num_previews, 1);
826 if (plistener) {
827 plistener->setProgressStr("PROGRESSBAR_PROCESSING");
828 plistener->setProgress(0);
829 }
830 }
831
832
833 template <class Ret, class Method>
834 Ret ImProcFunctions::apply(Method op, Imagefloat *img)
835 {
836 if (plistener) {
837 float percent = float(++progress_step) / float(progress_end);
838 plistener->setProgress(percent);
839 }
840 return (this->*op)(img);
841 }
842
843
process(Pipeline pipeline,Stage stage,Imagefloat * img)844 bool ImProcFunctions::process(Pipeline pipeline, Stage stage, Imagefloat *img)
845 {
846 bool stop = false;
847 cur_pipeline = pipeline;
848
849 #define STEP_(op) apply<void>(&ImProcFunctions::op, img)
850 #define STEP_s_(op) apply<bool>(&ImProcFunctions::op, img)
851
852 switch (stage) {
853 case Stage::STAGE_0:
854 STEP_(dehaze);
855 STEP_(dynamicRangeCompression);
856 break;
857 case Stage::STAGE_1:
858 STEP_(channelMixer);
859 STEP_(exposure);
860 STEP_(hslEqualizer);
861 stop = STEP_s_(toneEqualizer);
862 if (params->icm.workingProfile == "ProPhoto") {
863 proPhotoBlue(img, multiThread);
864 }
865 break;
866 case Stage::STAGE_2:
867 if (pipeline == Pipeline::OUTPUT ||
868 (pipeline == Pipeline::PREVIEW /*&& scale == 1*/)) {
869 stop = STEP_s_(sharpening);
870 if (!stop) {
871 STEP_(impulsedenoise);
872 STEP_(defringe);
873 }
874 }
875 stop = stop || STEP_s_(colorCorrection);
876 stop = stop || STEP_s_(guidedSmoothing);
877 break;
878 case Stage::STAGE_3:
879 STEP_(creativeGradients);
880 stop = stop || STEP_s_(textureBoost);
881 if (!stop) {
882 STEP_(logEncoding);
883 STEP_(saturationVibrance);
884 dcpProfile(img, dcpProf, dcpApplyState, multiThread);
885 STEP_(toneCurve);
886 STEP_(rgbCurves);
887 STEP_(labAdjustments);
888 // stop = stop || STEP_s_(textureBoost);
889 STEP_(softLight);
890 }
891 stop = stop || STEP_s_(localContrast);
892 if (!stop) {
893 STEP_(filmSimulation);
894 STEP_(blackAndWhite);
895 STEP_(filmGrain);
896 }
897 if (pipeline == Pipeline::PREVIEW && params->prsharpening.enabled) {
898 double s = scale;
899 int fw = full_width * s, fh = full_height * s;
900 int imw, imh;
901 double s2 = resizeScale(params, fw, fh, imw, imh);
902 scale = s * s2;
903 STEP_s_(prsharpening);
904 scale = s;
905 }
906 break;
907 }
908 return stop;
909 }
910
911
setDeltaEData(EditUniqueID id,double x,double y)912 int ImProcFunctions::setDeltaEData(EditUniqueID id, double x, double y)
913 {
914 deltaE.ok = false;
915 deltaE.x = x;
916 deltaE.y = y;
917 deltaE.L = 0;
918 deltaE.C = 0;
919 deltaE.H = 0;
920
921 switch (id) {
922 case EUID_LabMasks_DE1:
923 return LUMINANCECURVE | M_LUMACURVE;
924 case EUID_LabMasks_DE2:
925 return DISPLAY;
926 case EUID_LabMasks_DE3:
927 return LUMINANCECURVE | M_LUMACURVE;
928 case EUID_LabMasks_DE4:
929 return DISPLAY;
930 default:
931 return 0;
932 }
933 }
934
935
936 } // namespace rtengine
937