From f64ad13363c340815b67fe74119189126536f40c Mon Sep 17 00:00:00 2001 From: Simone Gotti Date: Thu, 13 Jun 2024 20:23:25 +0200 Subject: [PATCH] lensmetadata: add abstract center radius helper class Add a CenterRadiusMetadataLensCorrection helper class that will be implemented by vendor specific corrections based on center radius. --- rtengine/lensmetadata.cc | 108 +++++++++++++++++++++++++++++++++++++++ rtengine/lensmetadata.h | 42 +++++++++++++++ 2 files changed, 150 insertions(+) diff --git a/rtengine/lensmetadata.cc b/rtengine/lensmetadata.cc index e92fc6cc9..c531de65b 100644 --- a/rtengine/lensmetadata.cc +++ b/rtengine/lensmetadata.cc @@ -24,6 +24,114 @@ namespace rtengine { +CenterRadiusMetadataLensCorrection::CenterRadiusMetadataLensCorrection(const FramesMetaData *meta) : + swap_xy(false) +{ + metadata = Exiv2Metadata(meta->getFileName()); + metadata.load(); +} + +void CenterRadiusMetadataLensCorrection::initCorrections(int width, int height, const procparams::CoarseTransformParams &coarse, int rawRotationDeg) +{ + if (rawRotationDeg >= 0) { + int rot = (coarse.rotate + rawRotationDeg) % 360; + swap_xy = (rot == 90 || rot == 270); + if (swap_xy) { + std::swap(width, height); + } + } + + w2 = width * 0.5f; + h2 = height * 0.5f; + rf = 1 / std::sqrt(SQR(w2) + SQR(h2)); +} + +void CenterRadiusMetadataLensCorrection::process(double &x, double &y, int cx, int cy, int channel, bool dist, bool ca) const +{ + double xx = x + cx; + double yy = y + cy; + if (swap_xy) { + std::swap(xx, yy); + } + + double xc = xx - w2; + double yc = yy - h2; + + double rout = rf * std::sqrt(SQR(xc) + SQR(yc)); + double cf = 1; + if (dist && ca) { + cf = distortionAndCACorrectionFactor(rout, channel); + } else if (dist) { + cf = distortionCorrectionFactor(rout); + } else if (ca) { + cf = caCorrectionFactor(rout, channel); + } + + x = cf * xc + w2; + y = cf * yc + h2; + + if (swap_xy) { + std::swap(x, y); + } + x -= cx; + y -= cy; +} + +void CenterRadiusMetadataLensCorrection::correctDistortionAndCA(double &x, double &y, int cx, int cy, int channel) const +{ + if (!hasDistortionCorrection() || !hasCACorrection()) { + return; + } + + process(x, y, cx, cy, channel, true, true); +} + +void CenterRadiusMetadataLensCorrection::correctDistortion(double &x, double &y, int cx, int cy) const +{ + if (!hasDistortionCorrection()) { + return; + } + + process(x, y, cx, cy, 1, true, false); +} + +void CenterRadiusMetadataLensCorrection::correctCA(double &x, double &y, int cx, int cy, int channel) const +{ + if (!hasCACorrection()) { + return; + } + + process(x, y, cx, cy, channel, false, true); +} + +void CenterRadiusMetadataLensCorrection::processVignetteNChannels(int width, int height, float **rawData, int channels) const +{ + if (!hasVignettingCorrection()) { + return; + } + + for (int y = 0; y < height; ++y) { + for (int x = 0; x < width; ++x) { + double xc = x - w2; + double yc = y - h2; + double sf = vignettingCorrectionFactor(rf * std::sqrt(SQR(xc) + SQR(yc))); + for (int c = 0; c < channels; c++) { + rawData[y][x + c] *= sf; + } + } + } +} + +void CenterRadiusMetadataLensCorrection::processVignette(int width, int height, float **rawData) const +{ + return processVignetteNChannels(width, height, rawData, 1); +} + +void CenterRadiusMetadataLensCorrection::processVignette3Channels(int width, int height, float **rawData) const +{ + return processVignetteNChannels(width, height, rawData, 3); +} + std::unique_ptr MetadataLensCorrectionFinder::findCorrection(const FramesMetaData *meta) { static const std::unordered_set makers = {}; diff --git a/rtengine/lensmetadata.h b/rtengine/lensmetadata.h index 7991af8cd..ac042b7ce 100644 --- a/rtengine/lensmetadata.h +++ b/rtengine/lensmetadata.h @@ -37,6 +37,48 @@ public: virtual void initCorrections(int width, int height, const procparams::CoarseTransformParams &coarse, int rawRotationDeg) = 0; }; +/* CenterRadiusMetadataLensCorrection is an abstract class the extends MetadataLensCorrection to easily handle center radius based corrections */ +class CenterRadiusMetadataLensCorrection : public MetadataLensCorrection +{ +public: + CenterRadiusMetadataLensCorrection(const FramesMetaData *meta); + + void process(double &x, double &y, int cx, int cy, int channel, bool dist, bool ca) const; + + void correctDistortionAndCA(double &x, double &y, int cx, int cy, int channel) const override; + void correctDistortion(double &x, double &y, int cx, int cy) const override; + void correctCA(double &x, double &y, int cx, int cy, int channel) const override; + void processVignette(int width, int height, float **rawData) const override; + void processVignette3Channels(int width, int height, float **rawData) const override; + + void processVignetteNChannels(int width, int height, float **rawData, int channels) const; + void initCorrections(int width, int height, const procparams::CoarseTransformParams &coarse, int rawRotationDeg) override; + + /* Implementers should implement the below methods */ + virtual bool hasDistortionCorrection() const override = 0; + virtual bool hasCACorrection() const override = 0; + virtual bool hasVignettingCorrection() const override = 0; + + /* These methods should return the distortion correction factor (cf) for the + * provided radius rout (radius of the output image (corrected)). + * So rin = rout * cf + * */ + virtual double distortionCorrectionFactor(double rout) const = 0; + virtual double caCorrectionFactor(double rout, int channel) const = 0; + virtual double distortionAndCACorrectionFactor(double rout, int channel) const = 0; + + /* This methods should return the vignetting correction factor (cf) for the + * provided radius */ + virtual double vignettingCorrectionFactor(double r) const = 0; + +protected: + bool swap_xy; + double w2; + double h2; + double rf; + Exiv2Metadata metadata; +}; + /* MetadataLensCorrectionFinder tries to find and return MetadataLensCorrection for the provided metadata */ class MetadataLensCorrectionFinder {