LCP: filter out bad vignetting correction entries

Candidate fix for regression #4062
This commit is contained in:
Alberto Griggio 2017-09-06 15:27:54 +02:00
parent ae9afd31f1
commit 5656d16e64
2 changed files with 83 additions and 68 deletions

View File

@ -134,11 +134,20 @@ LCPPersModel::LCPPersModel()
} }
// mode: 0=distortion, 1=vignette, 2=CA // mode: 0=distortion, 1=vignette, 2=CA
bool LCPPersModel::hasModeData(int mode) const bool LCPPersModel::hasModeData(LCPCorrectionMode mode) const
{ {
return (mode == 0 && !vignette.empty() && !vignette.bad_error) || (mode == 1 && !base.empty() && !base.bad_error) switch (mode) {
|| (mode == 2 && !chromRG.empty() && !chromG.empty() && !chromBG.empty() && case LCP_MODE_VIGNETTE:
!chromRG.bad_error && !chromG.bad_error && !chromBG.bad_error); return !vignette.empty() && !vignette.bad_error;
case LCP_MODE_DISTORTION:
return !base.empty() && !base.bad_error;
case LCP_MODE_CA:
return !chromRG.empty() && !chromG.empty() && !chromBG.empty() &&
!chromRG.bad_error && !chromG.bad_error && !chromBG.bad_error;
default:
assert(false);
return false;
}
} }
void LCPPersModel::print() const void LCPPersModel::print() const
@ -195,11 +204,11 @@ LCPMapper::LCPMapper(LCPProfile* pProf, float focalLength, float focalLength35mm
printf("Vign: %i, fullWidth: %i/%i, focLen %g SwapXY: %i / MirX/Y %i / %i on rot:%i from %i\n",vignette, fullWidth, fullHeight, focalLength, swapXY, mirrorX, mirrorY, rot, rawRotationDeg); printf("Vign: %i, fullWidth: %i/%i, focLen %g SwapXY: %i / MirX/Y %i / %i on rot:%i from %i\n",vignette, fullWidth, fullHeight, focalLength, swapXY, mirrorX, mirrorY, rot, rawRotationDeg);
} }
pProf->calcParams(vignette ? 0 : 1, focalLength, focusDist, aperture, &mc, nullptr, nullptr); pProf->calcParams(vignette ? LCP_MODE_VIGNETTE : LCP_MODE_DISTORTION, focalLength, focusDist, aperture, &mc, nullptr, nullptr);
mc.prepareParams(fullWidth, fullHeight, focalLength, focalLength35mm, pProf->sensorFormatFactor, swapXY, mirrorX, mirrorY); mc.prepareParams(fullWidth, fullHeight, focalLength, focalLength35mm, pProf->sensorFormatFactor, swapXY, mirrorX, mirrorY);
if (!vignette) { if (!vignette) {
pProf->calcParams(2, focalLength, focusDist, aperture, &chrom[0], &chrom[1], &chrom[2]); pProf->calcParams(LCP_MODE_CA, focalLength, focusDist, aperture, &chrom[0], &chrom[1], &chrom[2]);
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
chrom[i].prepareParams(fullWidth, fullHeight, focalLength, focalLength35mm, pProf->sensorFormatFactor, swapXY, mirrorX, mirrorY); chrom[i].prepareParams(fullWidth, fullHeight, focalLength, focalLength35mm, pProf->sensorFormatFactor, swapXY, mirrorX, mirrorY);
@ -410,9 +419,11 @@ LCPProfile::LCPProfile(const Glib::ustring &fname)
} }
// Two phase filter: first filter out the very rough ones, that distord the average a lot // Two phase filter: first filter out the very rough ones, that distord the average a lot
// force it, even if there are few frames (community profiles) // force it, even if there are few frames (community profiles)
// filterBadFrames(2.0, 0); filterBadFrames(LCP_MODE_VIGNETTE, 2.0, 0);
filterBadFrames(LCP_MODE_CA, 2.0, 0);
// from the non-distorded, filter again on new average basis, but only if there are enough frames left // from the non-distorded, filter again on new average basis, but only if there are enough frames left
// filterBadFrames(1.5, 100); filterBadFrames(LCP_MODE_VIGNETTE, 1.5, 50);
filterBadFrames(LCP_MODE_CA, 1.5, 50);
} }
@ -429,67 +440,66 @@ LCPProfile::~LCPProfile()
} }
// from all frames not marked as bad already, take average and filter out frames with higher deviation than this if there are enough values // from all frames not marked as bad already, take average and filter out frames with higher deviation than this if there are enough values
int LCPProfile::filterBadFrames(double maxAvgDevFac, int minFramesLeft) int LCPProfile::filterBadFrames(LCPCorrectionMode mode, double maxAvgDevFac, int minFramesLeft)
{ {
// take average error per type, then calculated the maximum deviation allowed // take average error, then calculated the maximum deviation allowed
double errBase = 0, errChrom = 0, errVignette = 0; double err = 0;
int baseCount = 0, chromCount = 0, vignetteCount = 0; int count = 0;
for (int pm = 0; pm < MaxPersModelCount && aPersModel[pm]; pm++) { for (int pm = 0; pm < MaxPersModelCount && aPersModel[pm]; pm++) {
if (aPersModel[pm]->hasModeData(0)) { if (aPersModel[pm]->hasModeData(mode)) {
errVignette += aPersModel[pm]->vignette.mean_error; count++;
vignetteCount++; switch (mode) {
} case LCP_MODE_VIGNETTE:
err += aPersModel[pm]->vignette.mean_error;
if (aPersModel[pm]->hasModeData(1)) { break;
errBase += aPersModel[pm]->base.mean_error; case LCP_MODE_DISTORTION:
baseCount++; err += aPersModel[pm]->base.mean_error;
} break;
case LCP_MODE_CA:
if (aPersModel[pm]->hasModeData(2)) { err += rtengine::max(aPersModel[pm]->chromRG.mean_error, aPersModel[pm]->chromG.mean_error, aPersModel[pm]->chromBG.mean_error);
errChrom += rtengine::max(aPersModel[pm]->chromRG.mean_error, aPersModel[pm]->chromG.mean_error, aPersModel[pm]->chromBG.mean_error); break;
chromCount++; }
} }
} }
// Only if we have enough frames, filter out errors // Only if we have enough frames, filter out errors
int filtered = 0; int filtered = 0;
if (baseCount + chromCount + vignetteCount >= minFramesLeft) { if (count >= minFramesLeft) {
if (baseCount > 0) { if (count > 0) {
errBase /= (double)baseCount; err /= (double)count;
}
if (chromCount > 0) {
errChrom /= (double)chromCount;
}
if (vignetteCount > 0) {
errVignette /= (double)vignetteCount;
} }
// Now mark all the bad ones as bad, and hasModeData will return false; // Now mark all the bad ones as bad, and hasModeData will return false;
for (int pm = 0; pm < MaxPersModelCount && aPersModel[pm]; pm++) { for (int pm = 0; pm < MaxPersModelCount && aPersModel[pm]; pm++) {
if (aPersModel[pm]->hasModeData(0) && aPersModel[pm]->vignette.mean_error > maxAvgDevFac * errVignette) { if (aPersModel[pm]->hasModeData(mode)) {
aPersModel[pm]->vignette.bad_error = true; switch (mode) {
filtered++; case LCP_MODE_VIGNETTE:
} if (aPersModel[pm]->vignette.mean_error > maxAvgDevFac * err) {
aPersModel[pm]->vignette.bad_error = true;
if (aPersModel[pm]->hasModeData(1) && aPersModel[pm]->base.mean_error > maxAvgDevFac * errBase) { filtered++;
aPersModel[pm]->base.bad_error = true; }
filtered++; break;
} case LCP_MODE_DISTORTION:
if (aPersModel[pm]->base.mean_error > maxAvgDevFac * err) {
if (aPersModel[pm]->hasModeData(2) && aPersModel[pm]->base.bad_error = true;
(aPersModel[pm]->chromRG.mean_error > maxAvgDevFac * errChrom || aPersModel[pm]->chromG.mean_error > maxAvgDevFac * errChrom filtered++;
|| aPersModel[pm]->chromBG.mean_error > maxAvgDevFac * errChrom)) { }
aPersModel[pm]->chromRG.bad_error = aPersModel[pm]->chromG.bad_error = aPersModel[pm]->chromBG.bad_error = true; break;
filtered++; case LCP_MODE_CA:
if ((aPersModel[pm]->chromRG.mean_error > maxAvgDevFac * err || aPersModel[pm]->chromG.mean_error > maxAvgDevFac * err
|| aPersModel[pm]->chromBG.mean_error > maxAvgDevFac * err)) {
aPersModel[pm]->chromRG.bad_error = aPersModel[pm]->chromG.bad_error = aPersModel[pm]->chromBG.bad_error = true;
filtered++;
}
break;
}
} }
} }
if (settings->verbose) { if (settings->verbose) {
printf("Filtered %.1f%% frames for maxAvgDevFac %g leaving %i\n", filtered*100./(baseCount+chromCount+vignetteCount), maxAvgDevFac, baseCount+chromCount+vignetteCount-filtered); printf("Filtered %.1f%% frames for maxAvgDevFac %g leaving %i\n", filtered*100./count, maxAvgDevFac, count-filtered);
} }
} }
@ -497,8 +507,7 @@ int LCPProfile::filterBadFrames(double maxAvgDevFac, int minFramesLeft)
} }
// mode: 0=vignette, 1=distortion, 2=CA void LCPProfile::calcParams(LCPCorrectionMode mode, float focalLength, float focusDist, float aperture, LCPModelCommon *pCorr1, LCPModelCommon *pCorr2, LCPModelCommon *pCorr3) const
void LCPProfile::calcParams(int mode, float focalLength, float focusDist, float aperture, LCPModelCommon *pCorr1, LCPModelCommon *pCorr2, LCPModelCommon *pCorr3) const
{ {
float euler = exp(1.0); float euler = exp(1.0);
@ -541,24 +550,24 @@ void LCPProfile::calcParams(int mode, float focalLength, float focusDist, float
if (aPersModel[pm]->hasModeData(mode)) { if (aPersModel[pm]->hasModeData(mode)) {
double lowMeanErr, highMeanErr; double lowMeanErr, highMeanErr;
switch (mode) { switch (mode) {
case 0: case LCP_MODE_VIGNETTE:
meanErr = aPersModel[pm]->vignette.mean_error; meanErr = aPersModel[pm]->vignette.mean_error;
lowMeanErr = pLow->vignette.mean_error; lowMeanErr = pLow->vignette.mean_error;
highMeanErr = pHigh->vignette.mean_error; highMeanErr = pHigh->vignette.mean_error;
break; break;
case 1: case LCP_MODE_DISTORTION:
meanErr = aPersModel[pm]->base.mean_error; meanErr = aPersModel[pm]->base.mean_error;
lowMeanErr = pLow->base.mean_error; lowMeanErr = pLow->base.mean_error;
highMeanErr = pHigh->base.mean_error; highMeanErr = pHigh->base.mean_error;
break; break;
default: //case 2: default: // LCP_MODE_CA
meanErr = aPersModel[pm]->chromG.mean_error; meanErr = aPersModel[pm]->chromG.mean_error;
lowMeanErr = pLow->chromG.mean_error; lowMeanErr = pLow->chromG.mean_error;
highMeanErr = pHigh->chromG.mean_error; highMeanErr = pHigh->chromG.mean_error;
break; break;
} }
if (aperture > 0 && mode != 2) { if (aperture > 0 && mode != LCP_MODE_CA) {
if (aPersModel[pm]->focLen == bestFocLenLow && ( if (aPersModel[pm]->focLen == bestFocLenLow && (
(aper == aperture && lowMeanErr > meanErr) (aper == aperture && lowMeanErr > meanErr)
|| (aper >= aperture && aper < pLow->aperture && pLow->aperture > aperture) || (aper >= aperture && aper < pLow->aperture && pLow->aperture > aperture)
@ -572,7 +581,7 @@ void LCPProfile::calcParams(int mode, float focalLength, float focusDist, float
|| (aper >= aperture && (pHigh->aperture < aperture || fabs(aperture - aper) < fabs(aperture - pHigh->aperture))))) { || (aper >= aperture && (pHigh->aperture < aperture || fabs(aperture - aper) < fabs(aperture - pHigh->aperture))))) {
pHigh = aPersModel[pm]; pHigh = aPersModel[pm];
} }
} else if (focusDist > 0 && mode != 0) { } else if (focusDist > 0 && mode != LCP_MODE_VIGNETTE) {
// by focus distance // by focus distance
if (aPersModel[pm]->focLen == bestFocLenLow && ( if (aPersModel[pm]->focLen == bestFocLenLow && (
(focDist == focusDist && lowMeanErr > meanErr) (focDist == focusDist && lowMeanErr > meanErr)
@ -615,26 +624,26 @@ void LCPProfile::calcParams(int mode, float focalLength, float focusDist, float
} }
// and average the other factor if available // and average the other factor if available
if (mode == 0 && pLow->aperture < aperture && pHigh->aperture > aperture) { if (mode == LCP_MODE_VIGNETTE && pLow->aperture < aperture && pHigh->aperture > aperture) {
// Mix in aperture // Mix in aperture
float facAperLow = (pHigh->aperture - aperture) / (pHigh->aperture - pLow->aperture); float facAperLow = (pHigh->aperture - aperture) / (pHigh->aperture - pLow->aperture);
facLow = focLenOnSpot ? facAperLow : (0.5 * facLow + 0.5 * facAperLow); facLow = focLenOnSpot ? facAperLow : (0.5 * facLow + 0.5 * facAperLow);
} else if (mode != 0 && focusDist > 0 && pLow->focDist < focusDist && pHigh->focDist > focusDist) { } else if (mode != LCP_MODE_VIGNETTE && focusDist > 0 && pLow->focDist < focusDist && pHigh->focDist > focusDist) {
// focus distance for all else (if focus distance is given) // focus distance for all else (if focus distance is given)
float facDistLow = (log(pHigh->focDist) + euler - focusDistLog) / (log(pHigh->focDist) - log(pLow->focDist)); float facDistLow = (log(pHigh->focDist) + euler - focusDistLog) / (log(pHigh->focDist) - log(pLow->focDist));
facLow = focLenOnSpot ? facDistLow : (0.8 * facLow + 0.2 * facDistLow); facLow = focLenOnSpot ? facDistLow : (0.8 * facLow + 0.2 * facDistLow);
} }
switch (mode) { switch (mode) {
case 0: // vignette case LCP_MODE_VIGNETTE:
pCorr1->merge(pLow->vignette, pHigh->vignette, facLow); pCorr1->merge(pLow->vignette, pHigh->vignette, facLow);
break; break;
case 1: // distortion case LCP_MODE_DISTORTION:
pCorr1->merge(pLow->base, pHigh->base, facLow); pCorr1->merge(pLow->base, pHigh->base, facLow);
break; break;
case 2: // CA case LCP_MODE_CA:
pCorr1->merge(pLow->chromRG, pHigh->chromRG, facLow); pCorr1->merge(pLow->chromRG, pHigh->chromRG, facLow);
pCorr2->merge(pLow->chromG, pHigh->chromG, facLow); pCorr2->merge(pLow->chromG, pHigh->chromG, facLow);
pCorr3->merge(pLow->chromBG, pHigh->chromBG, facLow); pCorr3->merge(pLow->chromBG, pHigh->chromBG, facLow);
@ -646,7 +655,7 @@ void LCPProfile::calcParams(int mode, float focalLength, float focusDist, float
} }
} else { } else {
if (settings->verbose) { if (settings->verbose) {
printf("Error: LCP file contained no %s parameters\n", mode == 0 ? "vignette" : mode == 1 ? "distortion" : "CA" ); printf("Error: LCP file contained no %s parameters\n", mode == LCP_MODE_VIGNETTE ? "vignette" : mode == LCP_MODE_DISTORTION ? "distortion" : "CA" );
} }
} }
} }

View File

@ -33,6 +33,12 @@
namespace rtengine namespace rtengine
{ {
enum LCPCorrectionMode {
LCP_MODE_VIGNETTE = 0,
LCP_MODE_DISTORTION = 1,
LCP_MODE_CA = 2
};
// Perspective model common data, also used for Vignette and Fisheye // Perspective model common data, also used for Vignette and Fisheye
class LCPModelCommon final class LCPModelCommon final
{ {
@ -76,7 +82,7 @@ public:
LCPModelCommon vignette; // vignette (may be empty) LCPModelCommon vignette; // vignette (may be empty)
LCPPersModel(); LCPPersModel();
bool hasModeData(int mode) const; bool hasModeData(LCPCorrectionMode mode) const;
void print() const; void print() const;
}; };
@ -93,7 +99,7 @@ class LCPProfile
static void XMLCALL XmlTextHandler (void *pLCPProfile, const XML_Char *s, int len); static void XMLCALL XmlTextHandler (void *pLCPProfile, const XML_Char *s, int len);
static void XMLCALL XmlEndHandler (void *pLCPProfile, const char *el); static void XMLCALL XmlEndHandler (void *pLCPProfile, const char *el);
int filterBadFrames(double maxAvgDevFac, int minFramesLeft); int filterBadFrames(LCPCorrectionMode mode, double maxAvgDevFac, int minFramesLeft);
void handle_text(std::string text); void handle_text(std::string text);
std::ostringstream textbuf; std::ostringstream textbuf;
@ -112,7 +118,7 @@ public:
explicit LCPProfile(const Glib::ustring &fname); explicit LCPProfile(const Glib::ustring &fname);
~LCPProfile(); ~LCPProfile();
void calcParams(int mode, float focalLength, float focusDist, float aperture, LCPModelCommon *pCorr1, LCPModelCommon *pCorr2, LCPModelCommon *pCorr3) const; // Interpolates between the persModels frames void calcParams(LCPCorrectionMode mode, float focalLength, float focusDist, float aperture, LCPModelCommon *pCorr1, LCPModelCommon *pCorr2, LCPModelCommon *pCorr3) const; // Interpolates between the persModels frames
void print() const; void print() const;
}; };