From 99309aa4ace072af51ce74614153c805ad13db9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fl=C3=B6ssie?= Date: Tue, 21 Feb 2017 21:10:33 +0100 Subject: [PATCH] Preliminary cleanup for `LCPModelCommon` --- rtengine/lcp.cc | 166 ++++++++++++++++++++++++------------------------ rtengine/lcp.h | 50 ++++++++++----- 2 files changed, 117 insertions(+), 99 deletions(-) diff --git a/rtengine/lcp.cc b/rtengine/lcp.cc index 5dd51b58f..ff53ad30e 100644 --- a/rtengine/lcp.cc +++ b/rtengine/lcp.cc @@ -16,6 +16,8 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ + +#include #include #include "lcp.h" @@ -31,29 +33,33 @@ using namespace std; using namespace rtengine; -LCPModelCommon::LCPModelCommon() +LCPModelCommon::LCPModelCommon() : + foc_len_x(-1.0f), + foc_len_y(-1.0f), + img_center_x(0.5f), + img_center_y(0.5f), + param{{}}, + scale_factor(1.0f), + mean_error(0.0), + bad_error(false), + x0(0.0f), + y0(0.0f), + fx(0.0f), + fy(0.0f), + rfx(0.0f), + rfy(0.0f), + vign_param{{}} { - focLenX = focLenY = -1; - imgXCenter = imgYCenter = 0.5; - x0 = y0 = fx = fy = rfx = rfy = meanErr = 0; - - badErr = false; - - for (int i = 0; i < 5; i++) { - param[i] = 0; - } - - scaleFac = 1; } bool LCPModelCommon::empty() const { - return param[0] == 0 && param[1] == 0 && param[2] == 0; + return param[0] == 0.0f && param[1] == 0.0f && param[2] == 0.0f; } void LCPModelCommon::print() const { - printf("focLen %g/%g; imgCenter %g/%g; scale %g; err %g\n", focLenX, focLenY, imgXCenter, imgYCenter, scaleFac, meanErr); + printf("focLen %g/%g; imgCenter %g/%g; scale %g; err %g\n", foc_len_x, foc_len_y, img_center_x, img_center_y, scale_factor, mean_error); printf("xy0 %g/%g fxy %g/%g\n", x0, y0, fx, fy); printf("param: %g/%g/%g/%g/%g\n", param[0], param[1], param[2], param[3], param[4]); } @@ -61,60 +67,56 @@ void LCPModelCommon::print() const // weighted merge two parameters void LCPModelCommon::merge(const LCPModelCommon& a, const LCPModelCommon& b, float facA) { - float facB = 1 - facA; + const float facB = 1.0f - facA; - focLenX = facA * a.focLenX + facB * b.focLenX; - focLenY = facA * a.focLenY + facB * b.focLenY; - imgXCenter = facA * a.imgXCenter + facB * b.imgXCenter; - imgYCenter = facA * a.imgYCenter + facB * b.imgYCenter; - scaleFac = facA * a.scaleFac + facB * b.scaleFac; - meanErr = facA * a.meanErr + facB * b.meanErr; + foc_len_x = facA * a.foc_len_x + facB * b.foc_len_x; + foc_len_y = facA * a.foc_len_y + facB * b.foc_len_y; + img_center_x = facA * a.img_center_x + facB * b.img_center_x; + img_center_y = facA * a.img_center_y + facB * b.img_center_y; + scale_factor = facA * a.scale_factor + facB * b.scale_factor; + mean_error = facA * a.mean_error + facB * b.mean_error; for (int i = 0; i < 5; i++) { param[i] = facA * a.param[i] + facB * b.param[i]; } - double param0Sqr = param[0] * param[0]; + const float param0Sqr = param[0] * param[0]; - vignParam[0] = - param[0]; - vignParam[1] = param0Sqr - param[1]; - vignParam[2] = param0Sqr * param[0] - 2. * param[0] * param[1] + param[2]; - vignParam[3] = param0Sqr * param0Sqr + param[1] * param[1] + 2. * param[0] * param[2] - 3. * param0Sqr * param[1]; + vign_param[0] = -param[0]; + vign_param[1] = param0Sqr - param[1]; + vign_param[2] = param0Sqr * param[0] - 2.0f * param[0] * param[1] + param[2]; + vign_param[3] = param0Sqr * param0Sqr + param[1] * param[1] + 2.0f * param[0] * param[2] - 3.0f * param0Sqr * param[1]; } void LCPModelCommon::prepareParams(int fullWidth, int fullHeight, float focalLength, float focalLength35mm, float sensorFormatFactor, bool swapXY, bool mirrorX, bool mirrorY) { // Mention that the Adobe technical paper has a bug here, the DMAX is handled differently for focLen and imgCenter - int Dmax = fullWidth; - - if (fullHeight > fullWidth) { - Dmax = fullHeight; - } + const int Dmax = std::max(fullWidth, fullHeight); // correct focLens - if (focLenX < 0) { // they may not be given + if (foc_len_x < 0.0f) { // they may not be given // and 35mm may not be given either - if (focalLength35mm < 1) { + if (focalLength35mm < 1.0f) { focalLength35mm = focalLength * sensorFormatFactor; } - focLenX = focLenY = focalLength / ( 35 * focalLength / focalLength35mm); // focLen must be calculated in pixels + foc_len_x = foc_len_y = focalLength / (35.0f * focalLength / focalLength35mm); // focLen must be calculated in pixels } if (swapXY) { - x0 = (mirrorX ? 1. - imgYCenter : imgYCenter) * fullWidth; - y0 = (mirrorY ? 1. - imgXCenter : imgXCenter) * fullHeight; - fx = focLenY * Dmax; - fy = focLenX * Dmax; + x0 = (mirrorX ? 1.0f - img_center_y : img_center_y) * fullWidth; + y0 = (mirrorY ? 1.0f - img_center_x : img_center_x) * fullHeight; + fx = foc_len_y * Dmax; + fy = foc_len_x * Dmax; } else { - x0 = (mirrorX ? 1. - imgXCenter : imgXCenter) * fullWidth; - y0 = (mirrorY ? 1. - imgYCenter : imgYCenter) * fullHeight; - fx = focLenX * Dmax; - fy = focLenY * Dmax; + x0 = (mirrorX ? 1.0f - img_center_x : img_center_x) * fullWidth; + y0 = (mirrorY ? 1.0f - img_center_y : img_center_y) * fullHeight; + fx = foc_len_x * Dmax; + fy = foc_len_y * Dmax; } - rfx = 1.0 / fx; - rfy = 1.0 / fy; + rfx = 1.0f / fx; + rfy = 1.0f / fy; //printf("FW %i /X0 %g FH %i /Y0 %g %g\n",fullWidth,x0,fullHeight,y0, imgYCenter); } @@ -127,9 +129,9 @@ LCPPersModel::LCPPersModel() // mode: 0=distortion, 1=vignette, 2=CA bool LCPPersModel::hasModeData(int mode) const { - return (mode == 0 && !vignette.empty() && !vignette.badErr) || (mode == 1 && !base.empty() && !base.badErr) + return (mode == 0 && !vignette.empty() && !vignette.bad_error) || (mode == 1 && !base.empty() && !base.bad_error) || (mode == 2 && !chromRG.empty() && !chromG.empty() && !chromBG.empty() && - !chromRG.badErr && !chromG.badErr && !chromBG.badErr); + !chromRG.bad_error && !chromG.bad_error && !chromBG.bad_error); } void LCPPersModel::print() const @@ -202,7 +204,7 @@ void LCPMapper::correctDistortion(double& x, double& y) const { double xd = (x - mc.x0) / mc.fx, yd = (y - mc.y0) / mc.fy; - const float* aDist = mc.param; + const LCPModelCommon::Param aDist = mc.param; double rsqr = xd * xd + yd * yd; double xfac = aDist[swapXY ? 3 : 4], yfac = aDist[swapXY ? 4 : 3]; @@ -230,7 +232,7 @@ void LCPMapper::correctCA(double& x, double& y, int channel) const // Green contains main distortion, just like base if (useCADist) { - const float* aDist = chrom[1].param; + const LCPModelCommon::Param aDist = chrom[1].param; double rsqr = xd * xd + yd * yd; double xfac = aDist[swapXY ? 3 : 4], yfac = aDist[swapXY ? 4 : 3]; @@ -254,12 +256,12 @@ void LCPMapper::correctCA(double& x, double& y, int channel) const yd = ygreen; rsqr = xd * xd + yd * yd; - const float* aCA = chrom[channel].param; + const LCPModelCommon::Param aCA = chrom[channel].param; double xfac = aCA[swapXY ? 3 : 4], yfac = aCA[swapXY ? 4 : 3]; double commonSum = 1. + rsqr * (aCA[0] + rsqr * (aCA[1] + aCA[2] * rsqr)) + 2. * (yfac * yd + xfac * xd); - x = (chrom[channel].scaleFac * ( xd * commonSum + xfac * rsqr )) * chrom[channel].fx + chrom[channel].x0; - y = (chrom[channel].scaleFac * ( yd * commonSum + yfac * rsqr )) * chrom[channel].fy + chrom[channel].y0; + x = (chrom[channel].scale_factor * ( xd * commonSum + xfac * rsqr )) * chrom[channel].fx + chrom[channel].x0; + y = (chrom[channel].scale_factor * ( yd * commonSum + yfac * rsqr )) * chrom[channel].fy + chrom[channel].y0; } } @@ -268,7 +270,7 @@ float LCPMapper::calcVignetteFac(int x, int y) const // No need for swapXY, since vignette is in RAW and always before rotation float xd = ((float)x - mc.x0) * mc.rfx, yd = ((float)y - mc.y0) * mc.rfy; - const float* vignParam = mc.vignParam; + const LCPModelCommon::VignParam vignParam = mc.vign_param; float rsqr = xd * xd + yd * yd; return rsqr * (vignParam[0] + rsqr * ((vignParam[1]) - (vignParam[2]) * rsqr + (vignParam[3]) * rsqr * rsqr)); @@ -284,10 +286,10 @@ SSEFUNCTION void LCPMapper::processVignetteLine(int width, int y, float *line) c const vfloat fourv = F2V(4.f); const vfloat zerov = F2V(0.f); const vfloat ydv = F2V(yd); - const vfloat p0 = F2V(mc.vignParam[0]); - const vfloat p1 = F2V(mc.vignParam[1]); - const vfloat p2 = F2V(mc.vignParam[2]); - const vfloat p3 = F2V(mc.vignParam[3]); + const vfloat p0 = F2V(mc.vign_param[0]); + const vfloat p1 = F2V(mc.vign_param[1]); + const vfloat p2 = F2V(mc.vign_param[2]); + const vfloat p3 = F2V(mc.vign_param[3]); const vfloat x0v = F2V(mc.x0); const vfloat rfxv = F2V(mc.rfx); @@ -305,7 +307,7 @@ SSEFUNCTION void LCPMapper::processVignetteLine(int width, int y, float *line) c for (; x < width; x++) { if (line[x] > 0) { float xd = ((float)x - mc.x0) * mc.rfx; - const float* vignParam = mc.vignParam; + const LCPModelCommon::VignParam vignParam = mc.vign_param; float rsqr = xd * xd + yd; line[x] += line[x] * rsqr * (vignParam[0] + rsqr * ((vignParam[1]) - (vignParam[2]) * rsqr + (vignParam[3]) * rsqr * rsqr)); } @@ -317,7 +319,7 @@ SSEFUNCTION void LCPMapper::processVignetteLine3Channels(int width, int y, float // No need for swapXY, since vignette is in RAW and always before rotation float yd = ((float)y - mc.y0) * mc.rfy; yd *= yd; - const float* vignParam = mc.vignParam; + const LCPModelCommon::VignParam vignParam = mc.vign_param; for (int x = 0; x < width; x++) { float xd = ((float)x - mc.x0) * mc.rfx; float rsqr = xd * xd + yd; @@ -391,17 +393,17 @@ int LCPProfile::filterBadFrames(double maxAvgDevFac, int minFramesLeft) for (int pm = 0; pm < MaxPersModelCount && aPersModel[pm]; pm++) { if (aPersModel[pm]->hasModeData(0)) { - errVignette += aPersModel[pm]->vignette.meanErr; + errVignette += aPersModel[pm]->vignette.mean_error; vignetteCount++; } if (aPersModel[pm]->hasModeData(1)) { - errBase += aPersModel[pm]->base.meanErr; + errBase += aPersModel[pm]->base.mean_error; baseCount++; } if (aPersModel[pm]->hasModeData(2)) { - errChrom += std::max(std::max(aPersModel[pm]->chromRG.meanErr, aPersModel[pm]->chromG.meanErr), aPersModel[pm]->chromBG.meanErr); + errChrom += std::max(std::max(aPersModel[pm]->chromRG.mean_error, aPersModel[pm]->chromG.mean_error), aPersModel[pm]->chromBG.mean_error); chromCount++; } } @@ -424,20 +426,20 @@ int LCPProfile::filterBadFrames(double maxAvgDevFac, int minFramesLeft) // Now mark all the bad ones as bad, and hasModeData will return false; for (int pm = 0; pm < MaxPersModelCount && aPersModel[pm]; pm++) { - if (aPersModel[pm]->hasModeData(0) && aPersModel[pm]->vignette.meanErr > maxAvgDevFac * errVignette) { - aPersModel[pm]->vignette.badErr = true; + if (aPersModel[pm]->hasModeData(0) && aPersModel[pm]->vignette.mean_error > maxAvgDevFac * errVignette) { + aPersModel[pm]->vignette.bad_error = true; filtered++; } - if (aPersModel[pm]->hasModeData(1) && aPersModel[pm]->base.meanErr > maxAvgDevFac * errBase) { - aPersModel[pm]->base.badErr = true; + if (aPersModel[pm]->hasModeData(1) && aPersModel[pm]->base.mean_error > maxAvgDevFac * errBase) { + aPersModel[pm]->base.bad_error = true; filtered++; } if (aPersModel[pm]->hasModeData(2) && - (aPersModel[pm]->chromRG.meanErr > maxAvgDevFac * errChrom || aPersModel[pm]->chromG.meanErr > maxAvgDevFac * errChrom - || aPersModel[pm]->chromBG.meanErr > maxAvgDevFac * errChrom)) { - aPersModel[pm]->chromRG.badErr = aPersModel[pm]->chromG.badErr = aPersModel[pm]->chromBG.badErr = true; + (aPersModel[pm]->chromRG.mean_error > maxAvgDevFac * errChrom || aPersModel[pm]->chromG.mean_error > maxAvgDevFac * errChrom + || aPersModel[pm]->chromBG.mean_error > maxAvgDevFac * errChrom)) { + aPersModel[pm]->chromRG.bad_error = aPersModel[pm]->chromG.bad_error = aPersModel[pm]->chromBG.bad_error = true; filtered++; } } @@ -493,48 +495,48 @@ void LCPProfile::calcParams(int mode, float focalLength, float focusDist, float if (aPersModel[pm]->hasModeData(mode)) { if (mode == 0) { - meanErr = aPersModel[pm]->vignette.meanErr; + meanErr = aPersModel[pm]->vignette.mean_error; // by aperture (vignette), and max out focus distance // tests showed doing this by log(aperture) is not as advisable if (aPersModel[pm]->focLen == bestFocLenLow && ( - (aper == aperture && pLow->vignette.meanErr > meanErr) + (aper == aperture && pLow->vignette.mean_error > meanErr) || (aper >= aperture && aper < pLow->aperture && pLow->aperture > aperture) || (aper <= aperture && (pLow->aperture > aperture || fabs(aperture - aper) < fabs(aperture - pLow->aperture))))) { pLow = aPersModel[pm]; } if (aPersModel[pm]->focLen == bestFocLenHigh && ( - (aper == aperture && pHigh->vignette.meanErr > meanErr) + (aper == aperture && pHigh->vignette.mean_error > meanErr) || (aper <= aperture && aper > pHigh->aperture && pHigh->aperture < aperture) || (aper >= aperture && (pHigh->aperture < aperture || fabs(aperture - aper) < fabs(aperture - pHigh->aperture))))) { pHigh = aPersModel[pm]; } } else { - meanErr = (mode == 1 ? aPersModel[pm]->base.meanErr : aPersModel[pm]->chromG.meanErr); + meanErr = (mode == 1 ? aPersModel[pm]->base.mean_error : aPersModel[pm]->chromG.mean_error); if (focusDist > 0) { // by focus distance if (aPersModel[pm]->focLen == bestFocLenLow && ( - (focDist == focusDist && (mode == 1 ? pLow->base.meanErr : pLow->chromG.meanErr) > meanErr) + (focDist == focusDist && (mode == 1 ? pLow->base.mean_error : pLow->chromG.mean_error) > meanErr) || (focDist >= focusDist && focDist < pLow->focDist && pLow->focDist > focusDist) || (focDist <= focusDist && (pLow->focDist > focusDist || fabs(focusDistLog - focDistLog) < fabs(focusDistLog - (log(pLow->focDist) + euler)))))) { pLow = aPersModel[pm]; } if (aPersModel[pm]->focLen == bestFocLenHigh && ( - (focDist == focusDist && (mode == 1 ? pHigh->base.meanErr : pHigh->chromG.meanErr) > meanErr) + (focDist == focusDist && (mode == 1 ? pHigh->base.mean_error : pHigh->chromG.mean_error) > meanErr) || (focDist <= focusDist && focDist > pHigh->focDist && pHigh->focDist < focusDist) || (focDist >= focusDist && (pHigh->focDist < focusDist || fabs(focusDistLog - focDistLog) < fabs(focusDistLog - (log(pHigh->focDist) + euler)))))) { pHigh = aPersModel[pm]; } } else { // no focus distance available, just error - if (aPersModel[pm]->focLen == bestFocLenLow && (mode == 1 ? pLow->base.meanErr : pLow->chromG.meanErr) > meanErr) { + if (aPersModel[pm]->focLen == bestFocLenLow && (mode == 1 ? pLow->base.mean_error : pLow->chromG.mean_error) > meanErr) { pLow = aPersModel[pm]; } - if (aPersModel[pm]->focLen == bestFocLenHigh && (mode == 1 ? pHigh->base.meanErr : pHigh->chromG.meanErr) > meanErr) { + if (aPersModel[pm]->focLen == bestFocLenHigh && (mode == 1 ? pHigh->base.mean_error : pHigh->chromG.mean_error) > meanErr) { pHigh = aPersModel[pm]; } } @@ -770,17 +772,17 @@ void XMLCALL LCPProfile::XmlTextHandler(void *pLCPProfile, const XML_Char *s, in // Section depended if (!strcmp("FocalLengthX", tag)) { - pProf->pCurCommon->focLenX = atof(raw); + pProf->pCurCommon->foc_len_x = atof(raw); } else if (!strcmp("FocalLengthY", tag)) { - pProf->pCurCommon->focLenY = atof(raw); + pProf->pCurCommon->foc_len_y = atof(raw); } else if (!strcmp("ImageXCenter", tag)) { - pProf->pCurCommon->imgXCenter = atof(raw); + pProf->pCurCommon->img_center_x = atof(raw); } else if (!strcmp("ImageYCenter", tag)) { - pProf->pCurCommon->imgYCenter = atof(raw); + pProf->pCurCommon->img_center_y = atof(raw); } else if (!strcmp("ScaleFactor", tag)) { - pProf->pCurCommon->scaleFac = atof(raw); + pProf->pCurCommon->scale_factor = atof(raw); } else if (!strcmp("ResidualMeanError", tag)) { - pProf->pCurCommon->meanErr = atof(raw); + pProf->pCurCommon->mean_error = atof(raw); } else if (!strcmp("RadialDistortParam1", tag) || !strcmp("VignetteModelParam1", tag)) { pProf->pCurCommon->param[0] = atof(raw); } else if (!strcmp("RadialDistortParam2", tag) || !strcmp("VignetteModelParam2", tag)) { diff --git a/rtengine/lcp.h b/rtengine/lcp.h index 449add15c..92c984921 100644 --- a/rtengine/lcp.h +++ b/rtengine/lcp.h @@ -17,36 +17,52 @@ * along with RawTherapee. If not, see . */ -#ifndef _LCP_ -#define _LCP_ +#pragma once + +#include +#include +#include + +#include +#include #include "imagefloat.h" #include "opthelper.h" -#include -#include -#include -#include namespace rtengine { + // Perspective model common data, also used for Vignette and Fisheye -class LCPModelCommon +class LCPModelCommon final { public: - float focLenX, focLenY, imgXCenter, imgYCenter; - float param[5]; // k1..k5, resp. alpha1..5 - float scaleFac; // alpha0 - double meanErr; - bool badErr; - - float x0, y0, fx, fy; // prepared params - float rfx, rfy; - float vignParam[4]; LCPModelCommon(); bool empty() const; // is it empty void print() const; // printf all values void merge(const LCPModelCommon& a, const LCPModelCommon& b, float facA); void prepareParams(int fullWidth, int fullHeight, float focalLength, float focalLength35mm, float sensorFormatFactor, bool swapXY, bool mirrorX, bool mirrorY); + +//private: + using Param = std::array; + using VignParam = std::array; + + float foc_len_x; + float foc_len_y; + float img_center_x; + float img_center_y; + Param param; // k1..k5, resp. alpha1..5 + float scale_factor; // alpha0 + double mean_error; + bool bad_error; + + // prepared params + float x0; + float y0; + float fx; + float fy; + float rfx; + float rfy; + VignParam vign_param; }; class LCPPersModel @@ -136,5 +152,5 @@ public: void processVignetteLine(int width, int y, float *line) const; void processVignetteLine3Channels(int width, int y, float *line) const; }; + } -#endif