diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 309e5c029..05bd2081d 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -54,9 +54,13 @@ class ImProcFunctions void calcVignettingParams (int oW, int oH, const VignettingParams& vignetting, double &w2, double &h2, double& maxRadius, double &v, double &b, double &mul); - void transformPreview (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LCPMapper *pLCPMap); + enum TransformMode { + TRANSFORM_PREVIEW, + TRANSFORM_HIGH_QUALITY, + TRANSFORM_HIGH_QUALITY_FULLIMAGE + }; void transformLuminanceOnly (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH, int fW, int fH); - void transformHighQuality (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LCPMapper *pLCPMap, bool fullImage); + void transformGeneral(TransformMode mode, Imagefloat *original, Imagefloat *transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LCPMapper *pLCPMap); void sharpenHaloCtrl (float** luminance, float** blurmap, float** base, int W, int H, const SharpeningParams &sharpenParam); void sharpenHaloCtrl (LabImage* lab, float** blurmap, float** base, int W, int H, SharpeningParams &sharpenParam); diff --git a/rtengine/iptransform.cc b/rtengine/iptransform.cc index ee14c80c2..3ee42a684 100644 --- a/rtengine/iptransform.cc +++ b/rtengine/iptransform.cc @@ -325,10 +325,16 @@ void ImProcFunctions::transform (Imagefloat* original, Imagefloat* transformed, if (! (needsCA() || needsDistortion() || needsRotation() || needsPerspective() || needsLCP()) && (needsVignetting() || needsPCVignetting() || needsGradient())) { transformLuminanceOnly (original, transformed, cx, cy, oW, oH, fW, fH); - } else if (!needsCA() && scale != 1) { - transformPreview (original, transformed, cx, cy, sx, sy, oW, oH, fW, fH, pLCPMap); } else { - transformHighQuality (original, transformed, cx, cy, sx, sy, oW, oH, fW, fH, pLCPMap, fullImage); + TransformMode mode; + if (!needsCA() && scale != 1) { + mode = TRANSFORM_PREVIEW; + } else if (!fullImage) { + mode = TRANSFORM_HIGH_QUALITY; + } else { + mode = TRANSFORM_HIGH_QUALITY_FULLIMAGE; + } + transformGeneral(mode, original, transformed, cx, cy, sx, sy, oW, oH, fW, fH, pLCPMap); } if (pLCPMap) { @@ -721,9 +727,8 @@ void ImProcFunctions::transformLuminanceOnly (Imagefloat* original, Imagefloat* } } -// Transform WITH scaling (opt.) and CA, cubic interpolation -void ImProcFunctions::transformHighQuality (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, - const LCPMapper *pLCPMap, bool fullImage) + +void ImProcFunctions::transformGeneral(ImProcFunctions::TransformMode mode, Imagefloat *original, Imagefloat *transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LCPMapper *pLCPMap) { double w2 = (double) oW / 2.0 - 0.5; double h2 = (double) oH / 2.0 - 0.5; @@ -781,17 +786,31 @@ void ImProcFunctions::transformHighQuality (Imagefloat* original, Imagefloat* tr oH * tan (hpalpha) * sqrt (SQR (4 * maxRadius) + SQR (oH * tan (hpalpha)))) / (SQR (maxRadius) * 8))); double hpcospt = (hpdeg >= 0 ? 1.0 : -1.0) * cos (hpteta), hptanpt = tan (hpteta); - double ascale = params->commonTrans.autofill ? getTransformAutoFill (oW, oH, true /*fullImage*/ ? pLCPMap : nullptr) : 1.0; + double ascale = params->commonTrans.autofill ? getTransformAutoFill (oW, oH, pLCPMap) : 1.0; // smaller crop images are a problem, so only when processing fully - bool enableLCPCA = pLCPMap && params->lensProf.useCA && fullImage && pLCPMap->enableCA; - bool enableLCPDist = pLCPMap && params->lensProf.useDist; // && fullImage; + bool enableLCPCA = false; + bool enableLCPDist = false; + bool enableCA = false; - if (enableLCPCA) { - enableLCPDist = false; + switch (mode) { + case ImProcFunctions::TRANSFORM_HIGH_QUALITY_FULLIMAGE: + enableLCPCA = pLCPMap && params->lensProf.useCA && pLCPMap->enableCA; + // no break on purpose + case ImProcFunctions::TRANSFORM_HIGH_QUALITY: + enableLCPDist = pLCPMap && params->lensProf.useDist; + if (enableLCPCA) { + enableLCPDist = false; + } + enableCA = enableLCPCA || needsCA(); + default: // ImProcFunctions::TRANSFORM_PREVIEW + enableLCPDist = pLCPMap && params->lensProf.useDist; + break; } - bool enableCA = enableLCPCA || needsCA(); + if (!enableCA) { + chDist[0] = 0.0; + } // main cycle bool darkening = (params->vignetting.amount <= 0.0); @@ -895,6 +914,10 @@ void ImProcFunctions::transformHighQuality (Imagefloat* original, Imagefloat* tr // all interpolation pixels inside image if (enableCA) { interpolateTransformChannelsCubic (chOrig[c], xc - 1, yc - 1, Dx, Dy, & (chTrans[c][y][x]), vignmul); + } else if (mode == ImProcFunctions::TRANSFORM_PREVIEW) { + transformed->r (y, x) = vignmul * (original->r (yc, xc) * (1.0 - Dx) * (1.0 - Dy) + original->r (yc, xc + 1) * Dx * (1.0 - Dy) + original->r (yc + 1, xc) * (1.0 - Dx) * Dy + original->r (yc + 1, xc + 1) * Dx * Dy); + transformed->g (y, x) = vignmul * (original->g (yc, xc) * (1.0 - Dx) * (1.0 - Dy) + original->g (yc, xc + 1) * Dx * (1.0 - Dy) + original->g (yc + 1, xc) * (1.0 - Dx) * Dy + original->g (yc + 1, xc + 1) * Dx * Dy); + transformed->b (y, x) = vignmul * (original->b (yc, xc) * (1.0 - Dx) * (1.0 - Dy) + original->b (yc, xc + 1) * Dx * (1.0 - Dy) + original->b (yc + 1, xc) * (1.0 - Dx) * Dy + original->b (yc + 1, xc + 1) * Dx * Dy); } else { interpolateTransformCubic (original, xc - 1, yc - 1, Dx, Dy, & (transformed->r (y, x)), & (transformed->g (y, x)), & (transformed->b (y, x)), vignmul); } @@ -928,166 +951,6 @@ void ImProcFunctions::transformHighQuality (Imagefloat* original, Imagefloat* tr } } -// Transform WITH scaling, WITHOUT CA, simple (and fast) interpolation. Used for preview -void ImProcFunctions::transformPreview (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LCPMapper *pLCPMap) -{ - - double w2 = (double) oW / 2.0 - 0.5; - double h2 = (double) oH / 2.0 - 0.5; - - double vig_w2, vig_h2, maxRadius, v, b, mul; - calcVignettingParams (oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul); - - struct grad_params gp; - - if (needsGradient()) { - calcGradientParams (oW, oH, params->gradient, gp); - } - - struct pcv_params pcv; - - if (needsPCVignetting()) { - calcPCVignetteParams (fW, fH, oW, oH, params->pcvignette, params->crop, pcv); - } - - // auxiliary variables for distortion correction - bool needsDist = needsDistortion(); // for performance - double distAmount = params->distortion.amount; - - // auxiliary variables for rotation - double cost = cos (params->rotate.degree * rtengine::RT_PI / 180.0); - double sint = sin (params->rotate.degree * rtengine::RT_PI / 180.0); - - // auxiliary variables for vertical perspective correction - double vpdeg = params->perspective.vertical / 100.0 * 45.0; - double vpalpha = (90 - vpdeg) / 180.0 * rtengine::RT_PI; - double vpteta = fabs (vpalpha - rtengine::RT_PI / 2) < 3e-4 ? 0.0 : acos ((vpdeg > 0 ? 1.0 : -1.0) * sqrt ((-oW * oW * tan (vpalpha) * tan (vpalpha) + (vpdeg > 0 ? 1.0 : -1.0) * oW * tan (vpalpha) * sqrt (16 * maxRadius * maxRadius + oW * oW * tan (vpalpha) * tan (vpalpha))) / (maxRadius * maxRadius * 8))); - double vpcospt = (vpdeg >= 0 ? 1.0 : -1.0) * cos (vpteta), vptanpt = tan (vpteta); - - // auxiliary variables for horizontal perspective correction - double hpdeg = params->perspective.horizontal / 100.0 * 45.0; - double hpalpha = (90 - hpdeg) / 180.0 * rtengine::RT_PI; - double hpteta = fabs (hpalpha - rtengine::RT_PI / 2) < 3e-4 ? 0.0 : acos ((hpdeg > 0 ? 1.0 : -1.0) * sqrt ((-oH * oH * tan (hpalpha) * tan (hpalpha) + (hpdeg > 0 ? 1.0 : -1.0) * oH * tan (hpalpha) * sqrt (16 * maxRadius * maxRadius + oH * oH * tan (hpalpha) * tan (hpalpha))) / (maxRadius * maxRadius * 8))); - double hpcospt = (hpdeg >= 0 ? 1.0 : -1.0) * cos (hpteta), hptanpt = tan (hpteta); - - double ascale = params->commonTrans.autofill ? getTransformAutoFill (oW, oH, pLCPMap) : 1.0; - - bool darkening = (params->vignetting.amount <= 0.0); - - // main cycle - #pragma omp parallel for if (multiThread) - - for (int y = 0; y < transformed->getHeight(); y++) { - for (int x = 0; x < transformed->getWidth(); x++) { - double x_d = x, y_d = y; - - if (pLCPMap && params->lensProf.useDist) { - correct_distortion(pLCPMap, x_d, y_d, cx, cy, ascale); // must be first transform - } else { - x_d *= ascale; - y_d *= ascale; - } - - x_d += ascale * (cx - w2); // centering x coord & scale - y_d += ascale * (cy - h2); // centering y coord & scale - - double vig_x_d = 0., vig_y_d = 0.; - - if (needsVignetting()) { - vig_x_d = ascale * (x + cx - vig_w2); // centering x coord & scale - vig_y_d = ascale * (y + cy - vig_h2); // centering y coord & scale - } - - if (needsPerspective()) { - // horizontal perspective transformation - y_d *= maxRadius / (maxRadius + x_d * hptanpt); - x_d *= maxRadius * hpcospt / (maxRadius + x_d * hptanpt); - - // vertical perspective transformation - x_d *= maxRadius / (maxRadius - y_d * vptanpt); - y_d *= maxRadius * vpcospt / (maxRadius - y_d * vptanpt); - } - - // rotate - double Dx = x_d * cost - y_d * sint; - double Dy = x_d * sint + y_d * cost; - - // distortion correction - double s = 1; - - if (needsDist) { - double r = sqrt (Dx * Dx + Dy * Dy) / maxRadius; // sqrt is slow - s = 1.0 - distAmount + distAmount * r ; - Dx *= s; - Dy *= s; - } - - double r2 = 0.; - - if (needsVignetting()) { - double vig_Dx = vig_x_d * cost - vig_y_d * sint; - double vig_Dy = vig_x_d * sint + vig_y_d * cost; - r2 = sqrt (vig_Dx * vig_Dx + vig_Dy * vig_Dy); - } - - // de-center - Dx += w2; - Dy += h2; - - // Extract integer and fractions of source screen coordinates - int xc = (int)Dx; - Dx -= (double)xc; - xc -= sx; - int yc = (int)Dy; - Dy -= (double)yc; - yc -= sy; - - // Convert only valid pixels - if (yc >= 0 && yc < original->getHeight() && xc >= 0 && xc < original->getWidth()) { - - // multiplier for vignetting correction - double vignmul = 1.0; - - if (needsVignetting()) { - if (darkening) { - vignmul /= std::max (v + mul * tanh (b * (maxRadius - s * r2) / maxRadius), 0.001); - } else { - vignmul = v + mul * tanh (b * (maxRadius - s * r2) / maxRadius); - } - } - - if (needsGradient()) { - vignmul *= calcGradientFactor (gp, cx + x, cy + y); - } - - if (needsPCVignetting()) { - vignmul *= calcPCVignetteFactor (pcv, cx + x, cy + y); - } - - if (yc < original->getHeight() - 1 && xc < original->getWidth() - 1) { - // all interpolation pixels inside image - transformed->r (y, x) = vignmul * (original->r (yc, xc) * (1.0 - Dx) * (1.0 - Dy) + original->r (yc, xc + 1) * Dx * (1.0 - Dy) + original->r (yc + 1, xc) * (1.0 - Dx) * Dy + original->r (yc + 1, xc + 1) * Dx * Dy); - transformed->g (y, x) = vignmul * (original->g (yc, xc) * (1.0 - Dx) * (1.0 - Dy) + original->g (yc, xc + 1) * Dx * (1.0 - Dy) + original->g (yc + 1, xc) * (1.0 - Dx) * Dy + original->g (yc + 1, xc + 1) * Dx * Dy); - transformed->b (y, x) = vignmul * (original->b (yc, xc) * (1.0 - Dx) * (1.0 - Dy) + original->b (yc, xc + 1) * Dx * (1.0 - Dy) + original->b (yc + 1, xc) * (1.0 - Dx) * Dy + original->b (yc + 1, xc + 1) * Dx * Dy); - } else { - // edge pixels - int y1 = LIM (yc, 0, original->getHeight() - 1); - int y2 = LIM (yc + 1, 0, original->getHeight() - 1); - int x1 = LIM (xc, 0, original->getWidth() - 1); - int x2 = LIM (xc + 1, 0, original->getWidth() - 1); - transformed->r (y, x) = vignmul * (original->r (y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->r (y1, x2) * Dx * (1.0 - Dy) + original->r (y2, x1) * (1.0 - Dx) * Dy + original->r (y2, x2) * Dx * Dy); - transformed->g (y, x) = vignmul * (original->g (y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->g (y1, x2) * Dx * (1.0 - Dy) + original->g (y2, x1) * (1.0 - Dx) * Dy + original->g (y2, x2) * Dx * Dy); - transformed->b (y, x) = vignmul * (original->b (y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->b (y1, x2) * Dx * (1.0 - Dy) + original->b (y2, x1) * (1.0 - Dx) * Dy + original->b (y2, x2) * Dx * Dy); - } - } else { - // not valid (source pixel x,y not inside source image, etc.) - transformed->r (y, x) = 0; - transformed->g (y, x) = 0; - transformed->b (y, x) = 0; - } - } - } -} double ImProcFunctions::getTransformAutoFill (int oW, int oH, const LCPMapper *pLCPMap) {