This commit is contained in:
Alexander Brock
2024-07-20 00:15:43 +02:00
81 changed files with 4775 additions and 1021 deletions

View File

@@ -26,6 +26,7 @@
#include "rt_math.h"
#include "rtengine.h"
#include "rtlensfun.h"
#include "lensmetadata.h"
#include "sleef.h"
using namespace std;
@@ -420,7 +421,6 @@ homogeneous::Matrix<double> perspectiveMatrix(double camera_focal_length, double
bool ImProcFunctions::transCoord (int W, int H, const std::vector<Coord2D> &src, std::vector<Coord2D> &red, std::vector<Coord2D> &green, std::vector<Coord2D> &blue, double ascaleDef,
const LensCorrection *pLCPMap) const
{
enum PerspType { NONE, SIMPLE, CAMERA_BASED };
const PerspType perspectiveType = needsPerspective() ? (
(params->perspective.method == "camera_based") ?
@@ -533,14 +533,14 @@ bool ImProcFunctions::transCoord (int W, int H, const std::vector<Coord2D> &src,
y_d *= factor;
}
if (pLCPMap && params->lensProf.useDist) {
pLCPMap->correctDistortion(x_d, y_d, w2, h2);
}
// rotate
double Dx = x_d * cost - y_d * sint;
double Dy = x_d * sint + y_d * cost;
if (pLCPMap && params->lensProf.useDist && pLCPMap->hasDistortionCorrection()) {
pLCPMap->correctDistortion(Dx, Dy, w2, h2);
}
// distortion correction
double s = 1;
@@ -678,7 +678,13 @@ void ImProcFunctions::transform (Imagefloat* original, Imagefloat* transformed,
std::unique_ptr<const LensCorrection> pLCPMap;
if (needsLensfun()) {
if (needsMetadata()) {
auto corr = MetadataLensCorrectionFinder::findCorrection(metadata);
if (corr) {
corr->initCorrections(oW, oH, params->coarse, rawRotationDeg);
pLCPMap = std::move(corr);
}
} else if (needsLensfun()) {
pLCPMap = LFDatabase::getInstance()->findModifier(params->lensProf, metadata, oW, oH, params->coarse, rawRotationDeg);
} else if (needsLCP()) { // don't check focal length to allow distortion correction for lenses without chip
const std::shared_ptr<LCPProfile> pLCPProf = LCPStore::getInstance()->getProfile (params->lensProf.lcpFile);
@@ -694,7 +700,7 @@ void ImProcFunctions::transform (Imagefloat* original, Imagefloat* transformed,
}
}
if (! (needsCA() || needsDistortion() || needsRotation() || needsPerspective() || needsLCP() || needsLensfun()) && (needsVignetting() || needsPCVignetting() || needsGradient())) {
if (! (needsCA() || needsDistortion() || needsRotation() || needsPerspective() || needsLCP() || needsMetadata() || needsLensfun()) && (needsVignetting() || needsPCVignetting() || needsGradient())) {
transformLuminanceOnly (original, transformed, cx, cy, oW, oH, fW, fH);
} else {
bool highQuality;
@@ -704,24 +710,8 @@ void ImProcFunctions::transform (Imagefloat* original, Imagefloat* transformed,
highQuality = false;
} else {
highQuality = true;
// agriggio: CA correction via the lens profile has to be
// performed before separately from the the other transformations
// (except for the coarse rotation/flipping). In order to not
// change the code too much, I simply introduced a new mode
// TRANSFORM_HIGH_QUALITY_CA, which applies *only* profile-based
// CA correction. So, the correction in this case occurs in two
// steps, using an intermediate temporary image. There's room for
// optimization of course...
if (pLCPMap && params->lensProf.useCA && pLCPMap->isCACorrectionAvailable()) {
tmpimg.reset(new Imagefloat(transformed->getWidth(), transformed->getHeight()));
dest = tmpimg.get();
}
}
transformGeneral(highQuality, original, dest, cx, cy, sx, sy, oW, oH, fW, fH, pLCPMap.get(), useOriginalBuffer);
if (highQuality && dest != transformed) {
transformLCPCAOnly(dest, transformed, cx, cy, pLCPMap.get(), useOriginalBuffer);
}
}
}
@@ -1112,8 +1102,10 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I
// set up stuff, depending on the mode we are
enum PerspType { NONE, SIMPLE, CAMERA_BASED };
const bool enableLCPDist = pLCPMap && params->lensProf.useDist;
const bool enableLCPDist = pLCPMap && params->lensProf.useDist && pLCPMap->hasDistortionCorrection();
const bool enableLCPCA = pLCPMap && params->lensProf.useCA && pLCPMap->hasCACorrection();
const bool enableCA = highQuality && needsCA();
const bool doCACorrection = enableCA || enableLCPCA;
const bool enableGradient = needsGradient();
const bool enablePCVignetting = needsPCVignetting();
const bool enableVignetting = needsVignetting();
@@ -1275,25 +1267,33 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I
y_d *= factor;
}
if (enableLCPDist) {
pLCPMap->correctDistortion(x_d, y_d, w2, h2);
}
// rotate
const double Dxc = x_d * cost - y_d * sint;
const double Dyc = x_d * sint + y_d * cost;
const double Dxr = x_d * cost - y_d * sint;
const double Dyr = x_d * sint + y_d * cost;
// distortion correction
double s = 1.0;
for (int c = 0; c < (doCACorrection ? 3 : 1); ++c) {
double Dx = Dxr;
double Dy = Dyr;
if (enableDistortion) {
const double r = sqrt(Dxc * Dxc + Dyc * Dyc) / maxRadius;
s = 1.0 - distAmount + distAmount * r;
}
if (enableLCPDist && enableLCPCA) {
pLCPMap->correctDistortionAndCA(Dx, Dy, w2, h2, c);
} else if (enableLCPDist) {
pLCPMap->correctDistortion(Dx, Dy, w2, h2);
} else if (enableLCPCA) {
pLCPMap->correctCA(Dx, Dy, w2, h2, c);
}
for (int c = 0; c < (enableCA ? 3 : 1); ++c) {
double Dx = Dxc * (s + chDist[c]);
double Dy = Dyc * (s + chDist[c]);
// distortion correction
double s = 1.0;
if (enableDistortion) {
const double r = sqrt(Dx * Dx + Dy * Dy) / maxRadius;
s = 1.0 - distAmount + distAmount * r;
}
// CA correction
Dx *= s + chDist[c];
Dy *= s + chDist[c];
// de-center
Dx += w2;
@@ -1340,13 +1340,13 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I
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 if (!useLog) {
if (enableCA) {
if (doCACorrection) {
interpolateTransformChannelsCubic(chOrig[c], xc - 1, yc - 1, Dx, Dy, chTrans[c][y][x], vignmul);
} else {
interpolateTransformCubic(original, xc - 1, yc - 1, Dx, Dy, transformed->r(y, x), transformed->g(y, x), transformed->b(y, x), vignmul);
}
} else {
if (enableCA) {
if (doCACorrection) {
interpolateTransformChannelsCubicLog(chOrig[c], xc - 1, yc - 1, Dx, Dy, chTrans[c][y][x], vignmul);
} else {
interpolateTransformCubicLog(original, xc - 1, yc - 1, Dx, Dy, transformed->r(y, x), transformed->g(y, x), transformed->b(y, x), vignmul);
@@ -1360,7 +1360,7 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I
const int x2 = LIM(xc + 1, 0, original->getWidth() - 1);
if (useLog) {
if (enableCA) {
if (doCACorrection) {
chTrans[c][y][x] = vignmul * xexpf(chOrig[c][y1][x1] * (1.0 - Dx) * (1.0 - Dy) + chOrig[c][y1][x2] * Dx * (1.0 - Dy) + chOrig[c][y2][x1] * (1.0 - Dx) * Dy + chOrig[c][y2][x2] * Dx * Dy);
} else {
transformed->r(y, x) = vignmul * xexpf(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);
@@ -1368,7 +1368,7 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I
transformed->b(y, x) = vignmul * xexpf(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 {
if (enableCA) {
if (doCACorrection) {
chTrans[c][y][x] = vignmul * (chOrig[c][y1][x1] * (1.0 - Dx) * (1.0 - Dy) + chOrig[c][y1][x2] * Dx * (1.0 - Dy) + chOrig[c][y2][x1] * (1.0 - Dx) * Dy + chOrig[c][y2][x2] * Dx * Dy);
} else {
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);
@@ -1378,7 +1378,7 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I
}
}
} else {
if (enableCA) {
if (doCACorrection) {
// not valid (source pixel x,y not inside source image, etc.)
chTrans[c][y][x] = 0;
} else {
@@ -1392,77 +1392,6 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I
}
}
void ImProcFunctions::transformLCPCAOnly(Imagefloat *original, Imagefloat *transformed, int cx, int cy, const LensCorrection *pLCPMap, bool useOriginalBuffer)
{
assert(pLCPMap && params->lensProf.useCA && pLCPMap->isCACorrectionAvailable());
const bool useLog = params->commonTrans.method == "log";
float** chTrans[3] = {transformed->r.ptrs, transformed->g.ptrs, transformed->b.ptrs};
std::unique_ptr<Imagefloat> tempLog;
if (useLog) {
if (!useOriginalBuffer) {
tempLog.reset(new Imagefloat(original->getWidth(), original->getHeight()));
logEncode(original, tempLog.get(), multiThread);
original = tempLog.get();
} else {
logEncode(original, original, multiThread);
}
}
float** chOrig[3] = {original->r.ptrs, original->g.ptrs, original->b.ptrs};
#ifdef _OPENMP
#pragma omp parallel for if (multiThread)
#endif
for (int y = 0; y < transformed->getHeight(); y++) {
for (int x = 0; x < transformed->getWidth(); x++) {
for (int c = 0; c < 3; c++) {
double Dx = x;
double Dy = y;
pLCPMap->correctCA(Dx, Dy, cx, cy, c);
// Extract integer and fractions of coordinates
int xc = (int)Dx;
Dx -= (double)xc;
int yc = (int)Dy;
Dy -= (double)yc;
// Convert only valid pixels
if (yc >= 0 && yc < original->getHeight() && xc >= 0 && xc < original->getWidth()) {
// multiplier for vignetting correction
if (yc > 0 && yc < original->getHeight() - 2 && xc > 0 && xc < original->getWidth() - 2) {
// all interpolation pixels inside image
if (!useLog) {
interpolateTransformChannelsCubic(chOrig[c], xc - 1, yc - 1, Dx, Dy, chTrans[c][y][x], 1.0);
} else {
interpolateTransformChannelsCubicLog(chOrig[c], xc - 1, yc - 1, Dx, Dy, chTrans[c][y][x], 1.0);
}
} 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);
if (!useLog) {
chTrans[c][y][x] = (chOrig[c][y1][x1] * (1.0 - Dx) * (1.0 - Dy) + chOrig[c][y1][x2] * Dx * (1.0 - Dy) + chOrig[c][y2][x1] * (1.0 - Dx) * Dy + chOrig[c][y2][x2] * Dx * Dy);
} else {
chTrans[c][y][x] = xexpf(chOrig[c][y1][x1] * (1.0 - Dx) * (1.0 - Dy) + chOrig[c][y1][x2] * Dx * (1.0 - Dy) + chOrig[c][y2][x1] * (1.0 - Dx) * Dy + chOrig[c][y2][x2] * Dx * Dy);
}
}
} else {
// not valid (source pixel x,y not inside source image, etc.)
chTrans[c][y][x] = 0;
}
}
}
}
}
double ImProcFunctions::getTransformAutoFill (int oW, int oH, const LensCorrection *pLCPMap) const
{
if (!needsCA() && !needsDistortion() && !needsRotation() && !needsPerspective() && (!params->lensProf.useDist || pLCPMap == nullptr)) {
@@ -1539,6 +1468,11 @@ bool ImProcFunctions::needsVignetting () const
return params->vignetting.amount;
}
bool ImProcFunctions::needsMetadata () const
{
return params->lensProf.useMetadata();
}
bool ImProcFunctions::needsLCP () const
{
return params->lensProf.useLcp();
@@ -1556,17 +1490,8 @@ bool ImProcFunctions::needsTransform (int oW, int oH, int rawRotationDeg, const
std::unique_ptr<const LensCorrection> pLCPMap = LFDatabase::getInstance()->findModifier(params->lensProf, metadata, oW, oH, params->coarse, rawRotationDeg);
needsLf = pLCPMap.get();
}
return needsCA () ||
needsDistortion () ||
needsRotation () ||
needsPerspective () ||
needsGradient () ||
needsPCVignetting () ||
needsVignetting () ||
needsLCP() ||
needsLf;
return needsCA () || needsDistortion () || needsRotation () || needsPerspective () || needsGradient () || needsPCVignetting () || needsVignetting () || needsLCP() || needsMetadata() || needsLf;
}
}