LCP: filter out bad vignetting correction entries
Candidate fix for regression #4062
This commit is contained in:
parent
ae9afd31f1
commit
5656d16e64
139
rtengine/lcp.cc
139
rtengine/lcp.cc
@ -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" );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user