LCP (Lens Correction Profile) support

see issue 1343
This commit is contained in:
Oliver Duis 2012-05-17 21:41:48 +02:00
parent f38752bd00
commit 2d59057d57
28 changed files with 665 additions and 74 deletions

View File

@ -183,6 +183,7 @@ if (WIN32)
endif (WIN32) endif (WIN32)
# you may need lcms v1.xx for older version : pkg_check_modules (LCMS REQUIRED lcms<=1.99) # you may need lcms v1.xx for older version : pkg_check_modules (LCMS REQUIRED lcms<=1.99)
pkg_check_modules (LCMS REQUIRED lcms2) pkg_check_modules (LCMS REQUIRED lcms2)
pkg_check_modules (EXPAT REQUIRED expat>=2.0)
pkg_check_modules (IPTCDATA REQUIRED libiptcdata) pkg_check_modules (IPTCDATA REQUIRED libiptcdata)
find_package (JPEG REQUIRED) find_package (JPEG REQUIRED)
find_package (PNG REQUIRED) find_package (PNG REQUIRED)

View File

@ -960,6 +960,8 @@ TP_LABCURVE_SATURATION;Sättigung
TP_LENSGEOM_AUTOCROP;Auto-Schneiden TP_LENSGEOM_AUTOCROP;Auto-Schneiden
TP_LENSGEOM_FILL;Auto-Füllen TP_LENSGEOM_FILL;Auto-Füllen
TP_LENSGEOM_LABEL;Objektivkorrekturen TP_LENSGEOM_LABEL;Objektivkorrekturen
TP_LENSPROFILE_FILEDLGFILTERLCP;Linsen-Korrekturdateien
TP_LENSPROFILE_LABEL;Linsen-Korrekturprofil
TP_LUMADENOISE_EDGETOLERANCE;Kantentoleranz TP_LUMADENOISE_EDGETOLERANCE;Kantentoleranz
TP_LUMADENOISE_LABEL;Luminanz-Rauschfilter TP_LUMADENOISE_LABEL;Luminanz-Rauschfilter
TP_LUMADENOISE_RADIUS;Radius TP_LUMADENOISE_RADIUS;Radius

View File

@ -960,6 +960,8 @@ TP_LABCURVE_SATURATION;Saturation
TP_LENSGEOM_AUTOCROP; Auto Crop TP_LENSGEOM_AUTOCROP; Auto Crop
TP_LENSGEOM_FILL;Auto Fill TP_LENSGEOM_FILL;Auto Fill
TP_LENSGEOM_LABEL;Lens / Geometry TP_LENSGEOM_LABEL;Lens / Geometry
TP_LENSPROFILE_FILEDLGFILTERLCP;Lens correction files
TP_LENSPROFILE_LABEL;Lens Correction Profile
TP_LUMADENOISE_EDGETOLERANCE;Edge Tolerance TP_LUMADENOISE_EDGETOLERANCE;Edge Tolerance
TP_LUMADENOISE_LABEL;Luminance Noise Reduction TP_LUMADENOISE_LABEL;Luminance Noise Reduction
TP_LUMADENOISE_RADIUS;Radius TP_LUMADENOISE_RADIUS;Radius

View File

@ -1,9 +1,9 @@
include_directories (${EXTRA_INCDIR} ${GTHREAD_INCLUDE_DIRS} ${GOBJECT_INCLUDE_DIRS} ${GLIB2_INCLUDE_DIRS} include_directories (${EXTRA_INCDIR} ${GTHREAD_INCLUDE_DIRS} ${GOBJECT_INCLUDE_DIRS} ${GLIB2_INCLUDE_DIRS}
${GLIBMM_INCLUDE_DIRS} ${IPTCDATA_INCLUDE_DIRS} ${LCMS_INCLUDE_DIRS} ${GLIBMM_INCLUDE_DIRS} ${IPTCDATA_INCLUDE_DIRS} ${LCMS_INCLUDE_DIRS} ${EXPAT_INCLUDE_DIRS}
${GTKMM_INCLUDE_DIRS} ${GTK_INCLUDE_DIRS}) ${GTKMM_INCLUDE_DIRS} ${GTK_INCLUDE_DIRS})
link_directories (${CMAKE_CURRENT_SOURCE_DIR}/../rtexif ${EXTRA_LIBDIR} ${GTHREAD_LIBRARY_DIRS} link_directories (${CMAKE_CURRENT_SOURCE_DIR}/../rtexif ${EXTRA_LIBDIR} ${GTHREAD_LIBRARY_DIRS}
${GOBJECT_LIBRARY_DIRS} ${GLIB2_LIBRARY_DIRS} ${GLIBMM_LIBRARY_DIRS} ${GOBJECT_LIBRARY_DIRS} ${GLIB2_LIBRARY_DIRS} ${GLIBMM_LIBRARY_DIRS}
${IPTCDATA_LIBRARY_DIRS} ${LCMS_LIBRARY_DIRS}) ${IPTCDATA_LIBRARY_DIRS} ${LCMS_LIBRARY_DIRS} ${EXPAT_LIBRARY_DIRS})
set (RTENGINESOURCEFILES safegtk.cc colortemp.cc curves.cc flatcurves.cc diagonalcurves.cc dcraw.cc iccstore.cc set (RTENGINESOURCEFILES safegtk.cc colortemp.cc curves.cc flatcurves.cc diagonalcurves.cc dcraw.cc iccstore.cc
dfmanager.cc ffmanager.cc rawimage.cc image8.cc image16.cc imagefloat.cc imagedata.cc imageio.cc improcfun.cc init.cc dcrop.cc dfmanager.cc ffmanager.cc rawimage.cc image8.cc image16.cc imagefloat.cc imagedata.cc imageio.cc improcfun.cc init.cc dcrop.cc
@ -14,7 +14,7 @@ set (RTENGINESOURCEFILES safegtk.cc colortemp.cc curves.cc flatcurves.cc diagona
jpeg_memsrc.cc jdatasrc.cc jpeg_memsrc.cc jdatasrc.cc
PF_correct_RT.cc PF_correct_RT.cc
dirpyrLab_denoise.cc dirpyrLab_equalizer.cc dirpyr_equalizer.cc dirpyrLab_denoise.cc dirpyrLab_equalizer.cc dirpyr_equalizer.cc
calc_distort.cc dcp.cc calc_distort.cc lcp.cc dcp.cc
klt/convolve.cc klt/error.cc klt/klt.cc klt/klt_util.cc klt/pnmio.cc klt/pyramid.cc klt/selectGoodFeatures.cc klt/convolve.cc klt/error.cc klt/klt.cc klt/klt_util.cc klt/pnmio.cc klt/pyramid.cc klt/selectGoodFeatures.cc
klt/storeFeatures.cc klt/trackFeatures.cc klt/writeFeatures.cc klt/storeFeatures.cc klt/trackFeatures.cc klt/writeFeatures.cc
) )
@ -28,5 +28,5 @@ ENDIF (BUILD_SHARED_LIBS)
set_target_properties (rtengine PROPERTIES COMPILE_FLAGS "${RTENGINE_CXX_FLAGS}") set_target_properties (rtengine PROPERTIES COMPILE_FLAGS "${RTENGINE_CXX_FLAGS}")
target_link_libraries (rtengine rtexif ${EXTRA_LIB} ${GOBJECT_LIBRARIES} ${GTHREAD_LIBRARIES} target_link_libraries (rtengine rtexif ${EXTRA_LIB} ${GOBJECT_LIBRARIES} ${GTHREAD_LIBRARIES}
${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${LCMS_LIBRARIES} ${IPTCDATA_LIBRARIES} ${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${LCMS_LIBRARIES} ${EXPAT_LIBRARIES} ${IPTCDATA_LIBRARIES}
${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${TIFF_LIBRARIES} ${ZLIB_LIBRARIES}) ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${TIFF_LIBRARIES} ${ZLIB_LIBRARIES})

View File

@ -111,7 +111,8 @@ void Crop::update (int todo) {
if (needstransform && !transCrop) if (needstransform && !transCrop)
transCrop = new Imagefloat (cropw, croph); transCrop = new Imagefloat (cropw, croph);
if ((todo & M_TRANSFORM) && needstransform) if ((todo & M_TRANSFORM) && needstransform)
parent->ipf.transform (baseCrop, transCrop, cropx/skip, cropy/skip, trafx/skip, trafy/skip, SKIPS(parent->fw,skip), SKIPS(parent->fh,skip)); parent->ipf.transform (baseCrop, transCrop, cropx/skip, cropy/skip, trafx/skip, trafy/skip, SKIPS(parent->fw,skip), SKIPS(parent->fh,skip),
parent->imgsrc->getMetaData()->getFocalLen(), parent->imgsrc->getRotateDegree());
if (transCrop) if (transCrop)
baseCrop = transCrop; baseCrop = transCrop;

View File

@ -68,7 +68,7 @@ class ImageSource : public InitialImage {
virtual ~ImageSource () {} virtual ~ImageSource () {}
virtual int load (Glib::ustring fname, bool batch = false) =0; virtual int load (Glib::ustring fname, bool batch = false) =0;
virtual void preprocess (const RAWParams &raw){}; virtual void preprocess (const RAWParams &raw, const LensProfParams &lensProf, const CoarseTransformParams& coarse){};
virtual void demosaic (const RAWParams &raw){}; virtual void demosaic (const RAWParams &raw){};
virtual void flushRawData (){}; virtual void flushRawData (){};
virtual void flushRGB (){}; virtual void flushRGB (){};
@ -91,6 +91,7 @@ class ImageSource : public InitialImage {
virtual void getFullSize (int& w, int& h, int tr = TR_NONE) {} virtual void getFullSize (int& w, int& h, int tr = TR_NONE) {}
virtual void getSize (int tran, PreviewProps pp, int& w, int& h) {} virtual void getSize (int tran, PreviewProps pp, int& w, int& h) {}
virtual int getRotateDegree() const { return 0; }
virtual ImageData* getImageData () =0; virtual ImageData* getImageData () =0;
virtual void setProgressListener (ProgressListener* pl) {} virtual void setProgressListener (ProgressListener* pl) {}

View File

@ -122,7 +122,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
progress ("Applying white balance, color correction & sRGB conversion...",100*readyphase/numofphases); progress ("Applying white balance, color correction & sRGB conversion...",100*readyphase/numofphases);
if ( todo & M_PREPROC) { if ( todo & M_PREPROC) {
imgsrc->preprocess( rp ); imgsrc->preprocess( rp, params.lensProf, params.coarse );
imgsrc->getRAWHistogram( histRedRaw, histGreenRaw, histBlueRaw ); imgsrc->getRAWHistogram( histRedRaw, histGreenRaw, histBlueRaw );
} }
@ -193,7 +193,7 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall) {
if (needstransform && orig_prev==oprevi) if (needstransform && orig_prev==oprevi)
oprevi = new Imagefloat (pW, pH); oprevi = new Imagefloat (pW, pH);
if ((todo & M_TRANSFORM) && needstransform) if ((todo & M_TRANSFORM) && needstransform)
ipf.transform (orig_prev, oprevi, 0, 0, 0, 0, pW, pH); ipf.transform (orig_prev, oprevi, 0, 0, 0, 0, pW, pH, imgsrc->getMetaData()->getFocalLen(), imgsrc->getRotateDegree());
readyphase++; readyphase++;
@ -579,7 +579,7 @@ void ImProcCoordinator::saveInputICCReference (const Glib::ustring& fname) {
ppar.icm.input = "(none)"; ppar.icm.input = "(none)";
Imagefloat* im = new Imagefloat (fW, fH); Imagefloat* im = new Imagefloat (fW, fH);
Image16* im16 = new Image16 (fW, fH); Image16* im16 = new Image16 (fW, fH);
imgsrc->preprocess( ppar.raw ); imgsrc->preprocess( ppar.raw, ppar.lensProf, ppar.coarse );
imgsrc->demosaic(ppar.raw ); imgsrc->demosaic(ppar.raw );
//imgsrc->getImage (imgsrc->getWB(), 0, im, pp, ppar.hlrecovery, ppar.icm, ppar.raw); //imgsrc->getImage (imgsrc->getWB(), 0, im, pp, ppar.hlrecovery, ppar.icm, ppar.raw);
ColorTemp currWB = ColorTemp (params.wb.temperature, params.wb.green, params.wb.method); ColorTemp currWB = ColorTemp (params.wb.temperature, params.wb.green, params.wb.method);

View File

@ -27,6 +27,7 @@
#include "coord2d.h" #include "coord2d.h"
#include "labimage.h" #include "labimage.h"
#include "LUT.h" #include "LUT.h"
#include "lcp.h"
namespace rtengine { namespace rtengine {
@ -43,10 +44,10 @@ class ImProcFunctions {
bool multiThread; bool multiThread;
float g; float g;
void simpltransform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH); void simpltransform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, const LCPMapper *pLCPMap);
void vignetting (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH); void vignetting (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH);
void transformNonSep (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH); void transformNonSep (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, const LCPMapper *pLCPMap);
void transformSep (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH); void transformSep (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, const LCPMapper *pLCPMap);
void sharpenHaloCtrl (LabImage* lab, float** blurmap, float** base, int W, int H); void sharpenHaloCtrl (LabImage* lab, float** blurmap, float** base, int W, int H);
void firstAnalysisThread(Imagefloat* original, Glib::ustring wprofile, unsigned int* histogram, int row_from, int row_to); void firstAnalysisThread(Imagefloat* original, Glib::ustring wprofile, unsigned int* histogram, int row_from, int row_to);
void dcdamping (float** aI, float** aO, float damping, int W, int H); void dcdamping (float** aI, float** aO, float damping, int W, int H);
@ -56,6 +57,7 @@ class ImProcFunctions {
bool needsRotation (); bool needsRotation ();
bool needsPerspective (); bool needsPerspective ();
bool needsVignetting (); bool needsVignetting ();
bool needsLCP ();
// static cmsUInt8Number* Mempro = NULL; // static cmsUInt8Number* Mempro = NULL;
@ -120,7 +122,8 @@ class ImProcFunctions {
void MunsellLch (float lum, float hue, float chrom, float memChprov, float &correction, int zone);//jacques: Munsell correction void MunsellLch (float lum, float hue, float chrom, float memChprov, float &correction, int zone);//jacques: Munsell correction
void colorCurve (LabImage* lold, LabImage* lnew); void colorCurve (LabImage* lold, LabImage* lnew);
void sharpening (LabImage* lab, float** buffer); void sharpening (LabImage* lab, float** buffer);
void transform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH); void transform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH,
double focalLen, int rawRotationDeg);
void lab2monitorRgb (LabImage* lab, Image8* image); void lab2monitorRgb (LabImage* lab, Image8* image);
void resize (Image16* src, Image16* dst, float dScale); void resize (Image16* src, Image16* dst, float dScale);
void deconvsharpening (LabImage* lab, float** buffer); void deconvsharpening (LabImage* lab, float** buffer);

View File

@ -176,18 +176,24 @@ bool ImProcFunctions::transCoord (int W, int H, int x, int y, int w, int h, int&
return result; return result;
} }
void ImProcFunctions::transform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH) { void ImProcFunctions::transform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH,
double focalLen, int rawRotationDeg) {
LCPMapper *pLCPMap=NULL;
if (needsLCP() && focalLen>0) {
LCPProfile *pLCPProf=lcpStore->getProfile(params->lensProf.lcpFile);
if (pLCPProf) pLCPMap=new LCPMapper(pLCPProf, focalLen, false, original->width, original->height, params->coarse, rawRotationDeg);
}
if (!(needsCA() || needsDistortion() || needsRotation() || needsPerspective()) && needsVignetting()) if (!(needsCA() || needsDistortion() || needsRotation() || needsPerspective() || needsLCP()) && needsVignetting())
vignetting (original, transformed, cx, cy, oW, oH); vignetting (original, transformed, cx, cy, oW, oH);
else if (!needsCA()) { else if (!needsCA()) {
if (scale==1) if (scale==1)
transformNonSep (original, transformed, cx, cy, sx, sy, oW, oH); transformNonSep (original, transformed, cx, cy, sx, sy, oW, oH, pLCPMap);
else else
simpltransform (original, transformed, cx, cy, sx, sy, oW, oH); simpltransform (original, transformed, cx, cy, sx, sy, oW, oH, pLCPMap);
} }
else else
transformSep (original, transformed, cx, cy, sx, sy, oW, oH); transformSep (original, transformed, cx, cy, sx, sy, oW, oH, pLCPMap);
} }
void calcVignettingParams(int oW, int oH, const VignettingParams& vignetting, double &w2, double &h2, double& maxRadius, double &v, double &b, double &mul) void calcVignettingParams(int oW, int oH, const VignettingParams& vignetting, double &w2, double &h2, double& maxRadius, double &v, double &b, double &mul)
@ -209,6 +215,7 @@ void calcVignettingParams(int oW, int oH, const VignettingParams& vignetting, do
mul = (1.0-v) / tanh(b); mul = (1.0-v) / tanh(b);
} }
// Transform vignetting only
void ImProcFunctions::vignetting (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH) { void ImProcFunctions::vignetting (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH) {
double vig_w2; double vig_w2;
@ -234,7 +241,8 @@ void ImProcFunctions::vignetting (Imagefloat* original, Imagefloat* transformed,
} }
#include "cubint.cc" #include "cubint.cc"
void ImProcFunctions::transformNonSep (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH) { // Transform WITHOUT scaling or CA, cubic interpolation
void ImProcFunctions::transformNonSep (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, const LCPMapper *pLCPMap) {
double w2 = (double) oW / 2.0 - 0.5; double w2 = (double) oW / 2.0 - 0.5;
double h2 = (double) oH / 2.0 - 0.5; double h2 = (double) oH / 2.0 - 0.5;
@ -247,14 +255,13 @@ void ImProcFunctions::transformNonSep (Imagefloat* original, Imagefloat* transfo
calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul); calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul);
// auxiliary variables for distortion correction // auxiliary variables for distortion correction
bool needsDist = needsDistortion(); // for performance
double a = params->distortion.amount; double a = params->distortion.amount;
// auxiliary variables for rotation // auxiliary variables for rotation
double cost = cos(params->rotate.degree * RT_PI/180.0); double cost = cos(params->rotate.degree * RT_PI/180.0);
double sint = sin(params->rotate.degree * RT_PI/180.0); double sint = sin(params->rotate.degree * RT_PI/180.0);
bool dovign = params->vignetting.amount != 0;
// auxiliary variables for vertical perspective correction // auxiliary variables for vertical perspective correction
double vpdeg = params->perspective.vertical / 100.0 * 45.0; double vpdeg = params->perspective.vertical / 100.0 * 45.0;
double vpalpha = (90.0 - vpdeg) / 180.0 * RT_PI; double vpalpha = (90.0 - vpdeg) / 180.0 * RT_PI;
@ -273,8 +280,11 @@ void ImProcFunctions::transformNonSep (Imagefloat* original, Imagefloat* transfo
#pragma omp parallel for if (multiThread) #pragma omp parallel for if (multiThread)
for (int y=0; y<transformed->height; y++) { for (int y=0; y<transformed->height; y++) {
for (int x=0; x<transformed->width; x++) { for (int x=0; x<transformed->width; x++) {
double x_d = ascale * (x + cx - w2); // centering x coord & scale double x_d=x,y_d=y;
double y_d = ascale * (y + cy - h2); // centering y coord & scale if (pLCPMap) pLCPMap->correctDistortion(x_d,y_d); // must be first transform
x_d = ascale * (x_d + cx - w2); // centering x coord & scale
y_d = ascale * (y_d + cy - h2); // centering y coord & scale
double vig_x_d = ascale * (x + cx - vig_w2); // centering x coord & scale double vig_x_d = ascale * (x + cx - vig_w2); // centering x coord & scale
double vig_y_d = ascale * (y + cy - vig_h2); // centering y coord & scale double vig_y_d = ascale * (y + cy - vig_h2); // centering y coord & scale
@ -291,14 +301,18 @@ void ImProcFunctions::transformNonSep (Imagefloat* original, Imagefloat* transfo
double Dy = x_d * sint + y_d * cost; double Dy = x_d * sint + y_d * cost;
// distortion correction // distortion correction
double r = sqrt(Dx*Dx + Dy*Dy) / maxRadius; double s = 1;
double s = 1.0 - a + a * r ; if (needsDist) {
double r = sqrt(Dx*Dx + Dy*Dy) / maxRadius; // sqrt is slow
s = 1.0 - a + a * r ;
Dx *= s; Dx *= s;
Dy *= s; Dy *= s;
}
double vig_Dx = vig_x_d * cost - vig_y_d * sint; double vig_Dx = vig_x_d * cost - vig_y_d * sint;
double vig_Dy = vig_x_d * sint + vig_y_d * cost; double vig_Dy = vig_x_d * sint + vig_y_d * cost;
double r2 = sqrt(vig_Dx*vig_Dx + vig_Dy*vig_Dy);
double r2 = needsVignetting() ? sqrt(vig_Dx*vig_Dx + vig_Dy*vig_Dy) : 0;
// de-center // de-center
Dx += w2; Dx += w2;
@ -313,7 +327,7 @@ void ImProcFunctions::transformNonSep (Imagefloat* original, Imagefloat* transfo
// multiplier for vignetting correction // multiplier for vignetting correction
double vignmul = 1.0; double vignmul = 1.0;
if (dovign) if (needsVignetting())
vignmul /= (v + mul * tanh (b*(maxRadius-s*r2) / maxRadius)); vignmul /= (v + mul * tanh (b*(maxRadius-s*r2) / maxRadius));
if (yc > 0 && yc < original->height-2 && xc > 0 && xc < original->width-2) // all interpolation pixels inside image if (yc > 0 && yc < original->height-2 && xc > 0 && xc < original->width-2) // all interpolation pixels inside image
@ -338,9 +352,9 @@ void ImProcFunctions::transformNonSep (Imagefloat* original, Imagefloat* transfo
} }
} }
// Transform WITH scaling (opt.) and CA, cubic interpolation
#include "cubintch.cc" #include "cubintch.cc"
void ImProcFunctions::transformSep (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH) { void ImProcFunctions::transformSep (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, const LCPMapper *pLCPMap) {
double w2 = (double) oW / 2.0 - 0.5; double w2 = (double) oW / 2.0 - 0.5;
double h2 = (double) oH / 2.0 - 0.5; double h2 = (double) oH / 2.0 - 0.5;
@ -367,14 +381,13 @@ void ImProcFunctions::transformSep (Imagefloat* original, Imagefloat* transforme
chtrans[2] = transformed->b; chtrans[2] = transformed->b;
// auxiliary variables for distortion correction // auxiliary variables for distortion correction
bool needsDist = needsDistortion(); // for performance
double a = params->distortion.amount; double a = params->distortion.amount;
// auxiliary variables for rotation // auxiliary variables for rotation
double cost = cos(params->rotate.degree * RT_PI/180.0); double cost = cos(params->rotate.degree * RT_PI/180.0);
double sint = sin(params->rotate.degree * RT_PI/180.0); double sint = sin(params->rotate.degree * RT_PI/180.0);
bool dovign = params->vignetting.amount != 0;
// auxiliary variables for vertical perspective correction // auxiliary variables for vertical perspective correction
double vpdeg = params->perspective.vertical / 100.0 * 45.0; double vpdeg = params->perspective.vertical / 100.0 * 45.0;
double vpalpha = (90.0 - vpdeg) / 180.0 * RT_PI; double vpalpha = (90.0 - vpdeg) / 180.0 * RT_PI;
@ -395,8 +408,11 @@ void ImProcFunctions::transformSep (Imagefloat* original, Imagefloat* transforme
#pragma omp parallel for if (multiThread) #pragma omp parallel for if (multiThread)
for (int y=0; y<transformed->height; y++) { for (int y=0; y<transformed->height; y++) {
for (int x=0; x<transformed->width; x++) { for (int x=0; x<transformed->width; x++) {
double x_d = ascale * (x + cx - w2); // centering x coord & scale double x_d=x,y_d=y;
double y_d = ascale * (y + cy - h2); // centering y coord & scale if (pLCPMap) pLCPMap->correctDistortion(x_d,y_d); // must be first transform
x_d = ascale * (x_d + cx - w2); // centering x coord & scale
y_d = ascale * (y_d + cy - h2); // centering y coord & scale
double vig_x_d = ascale * (x + cx - vig_w2); // centering x coord & scale double vig_x_d = ascale * (x + cx - vig_w2); // centering x coord & scale
double vig_y_d = ascale * (y + cy - vig_h2); // centering y coord & scale double vig_y_d = ascale * (y + cy - vig_h2); // centering y coord & scale
@ -413,12 +429,15 @@ void ImProcFunctions::transformSep (Imagefloat* original, Imagefloat* transforme
double Dyc = x_d * sint + y_d * cost; double Dyc = x_d * sint + y_d * cost;
// distortion correction // distortion correction
double r = sqrt(Dxc*Dxc + Dyc*Dyc) / maxRadius; double s = 1;
double s = 1.0 - a + a * r ; if (needsDist) {
double r = sqrt(Dxc*Dxc + Dyc*Dyc) / maxRadius; // sqrt is slow
s = 1.0 - a + a * r ;
}
double vig_Dx = vig_x_d * cost - vig_y_d * sint; double vig_Dx = vig_x_d * cost - vig_y_d * sint;
double vig_Dy = vig_x_d * sint + vig_y_d * cost; double vig_Dy = vig_x_d * sint + vig_y_d * cost;
double r2 = sqrt(vig_Dx*vig_Dx + vig_Dy*vig_Dy); double r2 = needsVignetting() ? sqrt(vig_Dx*vig_Dx + vig_Dy*vig_Dy) : 0;
for (int c=0; c<3; c++) { for (int c=0; c<3; c++) {
@ -438,7 +457,7 @@ void ImProcFunctions::transformSep (Imagefloat* original, Imagefloat* transforme
// multiplier for vignetting correction // multiplier for vignetting correction
double vignmul = 1.0; double vignmul = 1.0;
if (dovign) if (needsVignetting())
vignmul /= (v + mul * tanh (b*(maxRadius-s*r2) / maxRadius)); vignmul /= (v + mul * tanh (b*(maxRadius-s*r2) / maxRadius));
if (yc > 0 && yc < original->height-2 && xc > 0 && xc < original->width-2) // all interpolation pixels inside image if (yc > 0 && yc < original->height-2 && xc > 0 && xc < original->width-2) // all interpolation pixels inside image
@ -459,8 +478,8 @@ void ImProcFunctions::transformSep (Imagefloat* original, Imagefloat* transforme
} }
} }
void ImProcFunctions::simpltransform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH) { // Transform WITH scaling, WITHOUT CA, simple (and fast) interpolation. Used for preview
void ImProcFunctions::simpltransform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, const LCPMapper *pLCPMap) {
double w2 = (double) oW / 2.0 - 0.5; double w2 = (double) oW / 2.0 - 0.5;
double h2 = (double) oH / 2.0 - 0.5; double h2 = (double) oH / 2.0 - 0.5;
@ -473,14 +492,13 @@ void ImProcFunctions::simpltransform (Imagefloat* original, Imagefloat* transfor
calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul); calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul);
// auxiliary variables for distortion correction // auxiliary variables for distortion correction
bool needsDist = needsDistortion(); // for performance
double a = params->distortion.amount; double a = params->distortion.amount;
// auxiliary variables for rotation // auxiliary variables for rotation
double cost = cos(params->rotate.degree * RT_PI/180.0); double cost = cos(params->rotate.degree * RT_PI/180.0);
double sint = sin(params->rotate.degree * RT_PI/180.0); double sint = sin(params->rotate.degree * RT_PI/180.0);
bool dovign = params->vignetting.amount != 0;
// auxiliary variables for vertical perspective correction // auxiliary variables for vertical perspective correction
double vpdeg = params->perspective.vertical / 100.0 * 45.0; double vpdeg = params->perspective.vertical / 100.0 * 45.0;
double vpalpha = (90 - vpdeg) / 180.0 * RT_PI; double vpalpha = (90 - vpdeg) / 180.0 * RT_PI;
@ -499,8 +517,11 @@ void ImProcFunctions::simpltransform (Imagefloat* original, Imagefloat* transfor
#pragma omp parallel for if (multiThread) #pragma omp parallel for if (multiThread)
for (int y=0; y<transformed->height; y++) { for (int y=0; y<transformed->height; y++) {
for (int x=0; x<transformed->width; x++) { for (int x=0; x<transformed->width; x++) {
double y_d = ascale * (y + cy - h2); // centering y coord & scale double x_d=x,y_d=y;
double x_d = ascale * (x + cx - w2); // centering x coord & scale if (pLCPMap) pLCPMap->correctDistortion(x_d,y_d); // must be first transform
y_d = ascale * (y_d + cy - h2); // centering y coord & scale
x_d = ascale * (x_d + cx - w2); // centering x coord & scale
double vig_x_d = ascale * (x + cx - vig_w2); // centering x coord & scale double vig_x_d = ascale * (x + cx - vig_w2); // centering x coord & scale
double vig_y_d = ascale * (y + cy - vig_h2); // centering y coord & scale double vig_y_d = ascale * (y + cy - vig_h2); // centering y coord & scale
@ -517,14 +538,17 @@ void ImProcFunctions::simpltransform (Imagefloat* original, Imagefloat* transfor
double Dy = x_d * sint + y_d * cost; double Dy = x_d * sint + y_d * cost;
// distortion correction // distortion correction
double r = sqrt(Dx*Dx + Dy*Dy) / maxRadius; double s = 1;
double s = 1.0 - a + a * r ; if (needsDist) {
double r = sqrt(Dx*Dx + Dy*Dy) / maxRadius; // sqrt is slow
s = 1.0 - a + a * r ;
Dx *= s; Dx *= s;
Dy *= s; Dy *= s;
}
double vig_Dx = vig_x_d * cost - vig_y_d * sint; double vig_Dx = vig_x_d * cost - vig_y_d * sint;
double vig_Dy = vig_x_d * sint + vig_y_d * cost; double vig_Dy = vig_x_d * sint + vig_y_d * cost;
double r2 = sqrt(vig_Dx*vig_Dx + vig_Dy*vig_Dy); double r2 = needsVignetting() ? sqrt(vig_Dx*vig_Dx + vig_Dy*vig_Dy) : 0;
// de-center // de-center
Dx += w2; Dx += w2;
@ -539,7 +563,7 @@ void ImProcFunctions::simpltransform (Imagefloat* original, Imagefloat* transfor
// multiplier for vignetting correction // multiplier for vignetting correction
double vignmul = 1.0; double vignmul = 1.0;
if (dovign) if (needsVignetting())
vignmul /= (v + mul * tanh (b*(maxRadius-s*r2) / maxRadius)); vignmul /= (v + mul * tanh (b*(maxRadius-s*r2) / maxRadius));
if (yc < original->height-1 && xc < original->width-1) { // all interpolation pixels inside image if (yc < original->height-1 && xc < original->width-1) { // all interpolation pixels inside image
@ -605,8 +629,12 @@ bool ImProcFunctions::needsVignetting () {
return params->vignetting.amount; return params->vignetting.amount;
} }
bool ImProcFunctions::needsLCP () {
return params->lensProf.lcpFile.length()>0;
}
bool ImProcFunctions::needsTransform () { bool ImProcFunctions::needsTransform () {
return needsCA () || needsDistortion () || needsRotation () || needsPerspective () || needsVignetting (); return needsCA () || needsDistortion () || needsRotation () || needsPerspective () || needsVignetting () || needsLCP();
} }

389
rtengine/lcp.cc Normal file
View File

@ -0,0 +1,389 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2012 Oliver Duis <www.oliverduis.de>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cstring>
#include "lcp.h"
#include "safegtk.h"
#include "iccmatrices.h"
#include "iccstore.h"
#include "rawimagesource.h"
#include "improcfun.h"
#include "rt_math.h"
#ifdef WIN32
#include <windows.h>
// for GCC32
#ifndef _WIN32_IE
#define _WIN32_IE 0x0600
#endif
#include <shlobj.h>
#endif
using namespace std;
using namespace rtengine;
using namespace rtexif;
LCPModelCommon::LCPModelCommon() {
focLenX=focLenY=-1; imgXCenter=imgYCenter=0.5;
for (int i=0;i<5;i++) param[i]=0;
scaleFac=1;
}
bool LCPModelCommon::empty() const {
return focLenX<0 && focLenY<0;
}
void LCPModelCommon::print() const {
printf("focLen %g/%g; imgCenter %g/%g; scale %g\n",focLenX,focLenY,imgXCenter,imgYCenter,scaleFac);
printf("param: %g/%g/%g/%g/%g\n",param[0],param[1],param[2],param[3],param[4]);
}
LCPPersModel::LCPPersModel() {
focLen=focDist=aperture=0;
}
void LCPPersModel::print() const {
printf("--- PersModel focLen %g; focDist %g; aperture %g\n", focLen, focDist, aperture);
printf("Base:\n"); base.print();
if (!chromRG.empty()) { printf("ChromRG:\n"); chromRG.print(); }
if (!chromG.empty()) { printf("ChromG:\n"); chromG.print(); }
if (!chromBG.empty()) { printf("ChromBG:\n"); chromBG.print(); }
if (!vignette.empty()) { printf("Vignette:\n"); vignette.print(); }
printf("\n");
}
// if !vignette then geometric
LCPMapper::LCPMapper(LCPProfile* pProf, float focalLength, bool vignette, int fullWidth, int fullHeight, const CoarseTransformParams& coarse, int rawRotationDeg)
{
if (pProf==NULL) return;
pProf-> calcBasePerspectiveParams(focalLength, vignette, mc);
// determine in what the image with the RAW landscape in comparison (calibration target)
int rot = (coarse.rotate+rawRotationDeg) % 360;
swapXY = (rot==90 || rot==270);
mirrorX = (rot==90 || rot==180);
mirrorY = (rot==180 || rot==270);
// 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;
if (swapXY) {
x0 = (mirrorX ? 1-mc.imgYCenter : mc.imgYCenter) * fullWidth;
y0 = (mirrorY ? 1-mc.imgXCenter : mc.imgXCenter) * fullHeight;
fx = mc.focLenY * Dmax;
fy = mc.focLenX * Dmax;
} else {
x0 = (mirrorX ? 1-mc.imgXCenter : mc.imgXCenter) * fullWidth;
y0 = (mirrorY ? 1-mc.imgYCenter : mc.imgYCenter) * fullHeight;
fx = mc.focLenX * Dmax;
fy = mc.focLenY * Dmax;
}
}
void LCPMapper::correctDistortion(double& x, double& y) const {
double xd=(x-x0)/fx, yd=(y-y0)/fy;
double rsqr = xd*xd+yd*yd;
double rsqrrsqr = rsqr*rsqr; // speed
double commonFac = (mc.param[2]*rsqrrsqr*rsqr + mc.param[1]*rsqrrsqr + mc.param[0]*rsqr + 1.)
+ 2 * (mc.param[3] * yd + mc.param[4] * xd);
double xnew = xd * commonFac + mc.param[4] * rsqr;
double ynew = yd * commonFac + mc.param[3] * rsqr;
x = xnew * fx + x0;
y = ynew * fy + y0;
}
float LCPMapper::correctVignette(double x, double y) const {
double xd=(x-x0)/fx, yd=(y-y0)/fy;
double rsqr = xd*xd+yd*yd;
double rsqrrsqr = rsqr*rsqr; // speed
double param0Sqr = mc.param[0]*mc.param[0];
return 1. - mc.param[0]*rsqr + (param0Sqr - mc.param[1]) *rsqrrsqr
- (param0Sqr*mc.param[0] - 2*mc.param[0]*mc.param[1] + mc.param[2]) *rsqrrsqr*rsqr
+ (param0Sqr*param0Sqr + mc.param[1]*mc.param[1]
+ 2*mc.param[0]*mc.param[2] - 3*mc.param[0]*mc.param[0]*mc.param[1]) *rsqrrsqr*rsqrrsqr;
}
LCPProfile::LCPProfile(Glib::ustring fname) {
const int BufferSize=8192;
char buf[BufferSize];
XML_Parser parser = XML_ParserCreate(NULL);
if (!parser) throw "Couldn't allocate memory for XML parser";
XML_SetElementHandler(parser, XmlStartHandler, XmlEndHandler);
XML_SetCharacterDataHandler(parser, XmlTextHandler);
XML_SetUserData(parser, (void *)this);
isFisheye=inCamProfiles=firstLIDone=inPerspect=false;
FILE *pFile = safe_g_fopen(fname, "rb");
bool done;
do {
int bytesRead = (int)fread(buf, 1, BufferSize, pFile);
done=feof(pFile);
if (XML_Parse(parser, buf, bytesRead, done) == XML_STATUS_ERROR)
throw "Invalid XML in LCP file";
} while (!done);
XML_ParserFree(parser);
}
void LCPProfile::calcBasePerspectiveParams(float focalLength, bool vignette, LCPModelCommon& corr) {
// find the frames with the least distance, focal length wise
LCPPersModel *pLow=NULL, *pHigh=NULL;
std::list<LCPPersModel*>::const_iterator it;
for (it=persModels.begin(); it!=persModels.end(); ++it) {
float f=(*it)->focLen;
if ((!vignette && !(*it)->base.empty()) || (vignette && !(*it)->vignette.empty())) {
if (f <= focalLength && (pLow ==NULL || f > pLow->focLen)) pLow= (*it);
if (f >= focalLength && (pHigh==NULL || f < pHigh->focLen)) pHigh=(*it);
}
}
if (!pLow) pLow=pHigh; if (!pHigh) pHigh=pLow;
// average out the factors, linear interpolation
float facLow = 0, facHigh=0;
if (pLow && pHigh && pLow->focLen < pHigh->focLen) {
facLow = (pHigh->focLen-focalLength) / (pHigh->focLen-pLow->focLen);
facHigh = (focalLength-pLow->focLen) / (pHigh->focLen-pLow->focLen);
} else {
facLow=pHigh?0:1; facHigh=pHigh?1:0;
}
LCPModelCommon& mLow =(vignette?pLow->vignette :pLow->base);
LCPModelCommon& mHigh=(vignette?pHigh->vignette:pHigh->base);
corr.focLenX = facLow * mLow.focLenX + facHigh * mHigh.focLenX;
corr.focLenY = facLow * mLow.focLenY + facHigh * mHigh.focLenY;
corr.imgXCenter = facLow * mLow.imgXCenter + facHigh * mHigh.imgXCenter;
corr.imgYCenter = facLow * mLow.imgYCenter + facHigh * mHigh.imgYCenter;
corr.scaleFac = facLow * mLow.scaleFac + facHigh * mHigh.scaleFac;
for (int i=0;i<5;i++) corr.param[i]= facLow * mLow.param[i] + facHigh * mHigh.param[i];
}
void LCPProfile::print() const {
printf("=== Profile %s\n", profileName.c_str());
printf("RAW: %i; Fisheye: %i\n",isRaw,isFisheye);
std::list<LCPPersModel*>::const_iterator it;
for (it=persModels.begin(); it!=persModels.end(); ++it) (*it)->print();
}
void XMLCALL LCPProfile::XmlStartHandler(void *pLCPProfile, const char *el, const char **attr) {
LCPProfile *pProf=static_cast<LCPProfile*>(pLCPProfile);
// clean up tagname
char* src=strrchr(el,':');
if (src==NULL) src=const_cast<char*>(el); else src++;
strcpy(pProf->lastTag,src);
if (!strcmp("CameraProfiles",src)) pProf->inCamProfiles=true;
if (!pProf->inCamProfiles) return;
if (!strcmp("li",src)) {
pProf->pCurPersModel=new LCPPersModel();
pProf->pCurCommon=&pProf->pCurPersModel->base; // iterated to next tags within persModel
return;
}
if (!strcmp("PerspectiveModel",src)) {
pProf->firstLIDone=true; pProf->inPerspect=true;
return;
} else if (!strcmp("FisheyeModel",src)) {
pProf->firstLIDone=true; pProf->inPerspect=true;
pProf->isFisheye=true; // just misses third param, and different path, rest is the same
return;
}
// Move pointer to general section
if (pProf->inPerspect) {
if (!strcmp("ChromaticRedGreenModel",src))
pProf->pCurCommon=&pProf->pCurPersModel->chromRG;
else if (!strcmp("ChromaticGreenModel",src))
pProf->pCurCommon=&pProf->pCurPersModel->chromG;
else if (!strcmp("ChromaticBlueGreenModel",src))
pProf->pCurCommon=&pProf->pCurPersModel->chromBG;
else if (!strcmp("VignetteModel",src))
pProf->pCurCommon=&pProf->pCurPersModel->vignette;
}
}
void XMLCALL LCPProfile::XmlTextHandler(void *pLCPProfile, const XML_Char *s, int len) {
LCPProfile *pProf=static_cast<LCPProfile*>(pLCPProfile);
if (!pProf->inCamProfiles) return;
// Check if it contains non-whitespaces (there are several calls to this for one tag unfortunately)
bool onlyWhiteSpace=true;
int i=0;
while (i<len && onlyWhiteSpace) { onlyWhiteSpace=isspace(s[i]); i++; }
if (onlyWhiteSpace) return;
// convert to null terminated
char raw[len+1]; memcpy(raw,s,len); raw[len]=0;
char* tag=pProf->lastTag;
//printf("%s : %s\n",tag,raw);
// Common data section
if (!pProf->firstLIDone) {
// Generic tags are the same for all
if (!strcmp("ProfileName",tag))
pProf->profileName=Glib::ustring(raw);
else if (!strcmp("Model",tag))
pProf->camera=Glib::ustring(raw);
else if (!strcmp("Lens",tag))
pProf->lens=Glib::ustring(raw);
else if (!strcmp("CameraPrettyName",tag))
pProf->cameraPrettyName=Glib::ustring(raw);
else if (!strcmp("LensPrettyName",tag))
pProf->lensPrettyName=Glib::ustring(raw);
else if (!strcmp("CameraRawProfile",tag))
pProf->isRaw=!strcmp("True",raw);
}
// --- Now all floating points. Must replace local dot characters
struct lconv * lc=localeconv();
char* p=raw;
while (*p) {
if (*p=='.') *p=lc->decimal_point[0];
p++;
}
// Perspective model base data
if (!strcmp("FocalLength",tag))
pProf->pCurPersModel->focLen=atof(raw);
else if (!strcmp("FocusDistance",tag))
pProf->pCurPersModel->focDist=atof(raw);
else if (!strcmp("ApertureValue",tag))
pProf->pCurPersModel->aperture=atof(raw);
// Section depended
if (!strcmp("FocalLengthX",tag))
pProf->pCurCommon->focLenX=atof(raw);
else if (!strcmp("FocalLengthY",tag))
pProf->pCurCommon->focLenY=atof(raw);
else if (!strcmp("ImageXCenter",tag))
pProf->pCurCommon->imgXCenter=atof(raw);
else if (!strcmp("ImageYCenter",tag))
pProf->pCurCommon->imgYCenter=atof(raw);
else if (!strcmp("ScaleFactor",tag))
pProf->pCurCommon->scaleFac=atof(raw);
else if (!strcmp("RadialDistortParam1",tag) || !strcmp("VignetteModelParam1",tag))
pProf->pCurCommon->param[0]=atof(raw);
else if (!strcmp("RadialDistortParam2",tag) || !strcmp("VignetteModelParam2",tag))
pProf->pCurCommon->param[1]=atof(raw);
else if (!strcmp("RadialDistortParam3",tag) || !strcmp("VignetteModelParam3",tag))
pProf->pCurCommon->param[2]=atof(raw);
else if (!strcmp("TangentialDistortParam1",tag))
pProf->pCurCommon->param[3]=atof(raw);
else if (!strcmp("TangentialDistortParam2",tag))
pProf->pCurCommon->param[4]=atof(raw);
}
void XMLCALL LCPProfile::XmlEndHandler(void *pLCPProfile, const char *el) {
LCPProfile *pProf=static_cast<LCPProfile*>(pLCPProfile);
if (strstr(el,":CameraProfiles")) pProf->inCamProfiles=false;
if (!pProf->inCamProfiles) return;
if (strstr(el,":PerspectiveModel") || strstr(el,":FisheyeModel"))
pProf->inPerspect=false;
else if (strstr(el, ":li")) {
pProf->persModels.push_back(pProf->pCurPersModel);
pProf->pCurPersModel=NULL;
}
}
// Generates as singleton
LCPStore* LCPStore::getInstance()
{
static LCPStore* instance_ = 0;
if ( instance_ == 0 )
{
static Glib::Mutex smutex_;
Glib::Mutex::Lock lock(smutex_);
if ( instance_ == 0 )
{
instance_ = new LCPStore();
}
}
return instance_;
}
LCPProfile* LCPStore::getProfile (Glib::ustring filename) {
if (filename.length()==0) return NULL;
Glib::Mutex::Lock lock(mtx);
std::map<Glib::ustring, LCPProfile*>::iterator r = profileCache.find (filename);
if (r!=profileCache.end()) return r->second;
// Add profile
profileCache[filename]=new LCPProfile(filename);
//profileCache[filename]->print();
return profileCache[filename];
}
bool LCPStore::isValidLCPFileName(Glib::ustring filename) const {
if (!safe_file_test (filename, Glib::FILE_TEST_EXISTS) || safe_file_test (filename, Glib::FILE_TEST_IS_DIR)) return false;
size_t pos=filename.find_last_of ('.');
return pos>0 && !filename.casefold().compare (pos, 4, ".lcp");
}
Glib::ustring LCPStore::getDefaultCommonDirectory() const {
Glib::ustring dir;
#ifdef WIN32
WCHAR pathW[MAX_PATH]={0}; char pathA[MAX_PATH];
if (SHGetSpecialFolderPathW(NULL,pathW,CSIDL_COMMON_APPDATA,false)) {
char pathA[MAX_PATH];
WideCharToMultiByte(CP_UTF8,0,pathW,-1,pathA,MAX_PATH,0,0);
Glib::ustring fullDir=Glib::ustring(pathA)+Glib::ustring("\\Adobe\\CameraRaw\\LensProfiles\\1.0");
if (safe_file_test(fullDir, Glib::FILE_TEST_IS_DIR)) dir=fullDir;
}
#else
printf("Sorry, default LCP directory are currently only configured on Windows\n");
#endif
return dir;
}

116
rtengine/lcp.h Normal file
View File

@ -0,0 +1,116 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2012 Oliver Duis <www.oliverduis.de>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _LCP_
#define _LCP_
#include "imagefloat.h"
#include <glibmm.h>
#include <map>
#include <list>
#include <string>
#include <expat.h>
namespace rtengine {
// Perspective model common data, also used for Vignette and Fisheye
class LCPModelCommon {
public:
float focLenX, focLenY, imgXCenter, imgYCenter;
float param[5]; // k1..k5
float scaleFac;
LCPModelCommon();
bool empty() const; // is it empty?
void print() const; // printf all values
};
class LCPPersModel {
public:
float focLen, focDist, aperture; // this is what it refers to
LCPModelCommon base; // base perspective correction
LCPModelCommon chromRG, chromG, chromBG; // red/green, green, blue/green (may be empty)
LCPModelCommon vignette; // vignette (may be empty)
LCPPersModel();
void print() const;
};
class LCPProfile {
// Temporary data for parsing
bool inCamProfiles,firstLIDone,inPerspect;
char lastTag[256];
LCPPersModel* pCurPersModel;
LCPModelCommon* pCurCommon;
static void XMLCALL XmlStartHandler(void *pLCPProfile, const char *el, const char **attr);
static void XMLCALL XmlTextHandler (void *pLCPProfile, const XML_Char *s, int len);
static void XMLCALL XmlEndHandler (void *pLCPProfile, const char *el);
public:
// Common data
Glib::ustring profileName, lensPrettyName, cameraPrettyName, lens, camera; // lens/camera(=model) can be auto-matched with DNG
bool isRaw,isFisheye;
// The correction frames
std::list<LCPPersModel*> persModels;
LCPProfile(Glib::ustring fname);
void calcBasePerspectiveParams(float focalLength, bool vignette, LCPModelCommon& corr); // Interpolates between the persModels frames
void print() const;
};
class LCPStore {
Glib::Mutex mtx;
// Maps file name to profile as cache
std::map<Glib::ustring, LCPProfile*> profileCache;
public:
Glib::ustring getDefaultCommonDirectory() const;
bool isValidLCPFileName(Glib::ustring filename) const;
LCPProfile* getProfile(Glib::ustring filename);
static LCPStore* getInstance();
};
#define lcpStore LCPStore::getInstance()
// Once precalculated class to correct a point
class LCPMapper {
double x0,y0,fx,fy;
LCPModelCommon mc;
bool swapXY;
bool mirrorX, mirrorY;
public:
// precalculates the mapper.
LCPMapper(LCPProfile* pProf, float focalLength, bool vignette, int fullWidth, int fullHeight,
const CoarseTransformParams& coarse, int rawRotationDeg);
void correctDistortion(double& x, double& y) const; // MUST be the first stage
float correctVignette (double x, double y) const; // MUST be in RAW
};
}
#endif

View File

@ -106,7 +106,7 @@ enum ProcEvent {
EvProfileChangeNotification=81, EvProfileChangeNotification=81,
EvSHHighQuality=82, EvSHHighQuality=82,
EvPerspCorr=83, EvPerspCorr=83,
EvEqualizer=84, // obsolete EvLCPFile=84,
EvEqlEnabled=85,// obsolete EvEqlEnabled=85,// obsolete
EvIDNEnabled=86, EvIDNEnabled=86,
EvIDNThresh=87, EvIDNThresh=87,

View File

@ -259,7 +259,6 @@ void ProcParams::setDefaults () {
rotate.degree = 0; rotate.degree = 0;
distortion.amount = 0; distortion.amount = 0;
distortion.uselensfun = false;
perspective.horizontal = 0; perspective.horizontal = 0;
perspective.vertical = 0; perspective.vertical = 0;
@ -540,7 +539,9 @@ int ProcParams::save (Glib::ustring fname, Glib::ustring fname2, ParamsEdited* p
// save distortion // save distortion
if (!pedited || pedited->distortion.amount) keyFile.set_double ("Distortion", "Amount", distortion.amount); if (!pedited || pedited->distortion.amount) keyFile.set_double ("Distortion", "Amount", distortion.amount);
if (!pedited || pedited->distortion.uselensfun) keyFile.set_boolean ("Distortion", "UseLensFun", distortion.uselensfun);
// lens profile
if (!pedited || pedited->lensProf.lcpFile) keyFile.set_string ("LensProfile", "LCPFile", lensProf.lcpFile);
// save perspective correction // save perspective correction
if (!pedited || pedited->perspective.horizontal) keyFile.set_integer ("Perspective", "Horizontal", perspective.horizontal); if (!pedited || pedited->perspective.horizontal) keyFile.set_integer ("Perspective", "Horizontal", perspective.horizontal);
@ -939,7 +940,11 @@ if (keyFile.has_group ("Common Properties for Transformations")) {
// load distortion // load distortion
if (keyFile.has_group ("Distortion")) { if (keyFile.has_group ("Distortion")) {
if (keyFile.has_key ("Distortion", "Amount")) { distortion.amount = keyFile.get_double ("Distortion", "Amount"); if (pedited) pedited->distortion.amount = true; } if (keyFile.has_key ("Distortion", "Amount")) { distortion.amount = keyFile.get_double ("Distortion", "Amount"); if (pedited) pedited->distortion.amount = true; }
if (keyFile.has_key ("Distortion", "UseLensFun")) { distortion.uselensfun = keyFile.get_boolean ("Distortion", "UseLensFun"); if (pedited) pedited->distortion.uselensfun = true; } }
// lens profile
if (keyFile.has_group ("LensProfile")) {
if (keyFile.has_key ("LensProfile", "LCPFile")) { lensProf.lcpFile = keyFile.get_string ("LensProfile", "LCPFile"); if (pedited) pedited->lensProf.lcpFile = true; }
} }
// load perspective correction // load perspective correction
@ -1234,8 +1239,8 @@ bool ProcParams::operator== (const ProcParams& other) {
&& coarse.vflip == other.coarse.vflip && coarse.vflip == other.coarse.vflip
&& rotate.degree == other.rotate.degree && rotate.degree == other.rotate.degree
&& commonTrans.autofill == other.commonTrans.autofill && commonTrans.autofill == other.commonTrans.autofill
&& distortion.uselensfun == other.distortion.uselensfun
&& distortion.amount == other.distortion.amount && distortion.amount == other.distortion.amount
&& lensProf.lcpFile == other.lensProf.lcpFile
&& perspective.horizontal == other.perspective.horizontal && perspective.horizontal == other.perspective.horizontal
&& perspective.vertical == other.perspective.vertical && perspective.vertical == other.perspective.vertical
&& cacorrection.red == other.cacorrection.red && cacorrection.red == other.cacorrection.red

View File

@ -326,10 +326,16 @@ class RotateParams {
class DistortionParams { class DistortionParams {
public: public:
bool uselensfun;
double amount; double amount;
}; };
// Lens profile correction parameters
class LensProfParams {
public:
Glib::ustring lcpFile;
};
/** /**
* Parameters of the perspective correction * Parameters of the perspective correction
*/ */
@ -527,6 +533,7 @@ class ProcParams {
CommonTransformParams commonTrans; ///< Common transformation parameters (autofill) CommonTransformParams commonTrans; ///< Common transformation parameters (autofill)
RotateParams rotate; ///< Rotation parameters RotateParams rotate; ///< Rotation parameters
DistortionParams distortion; ///< Lens distortion correction parameters DistortionParams distortion; ///< Lens distortion correction parameters
LensProfParams lensProf; ///< Lens correction profile parameters
PerspectiveParams perspective; ///< Perspective correction parameters PerspectiveParams perspective; ///< Perspective correction parameters
CACorrParams cacorrection; ///< Lens c/a correction parameters CACorrParams cacorrection; ///< Lens c/a correction parameters
VignettingParams vignetting; ///< Lens vignetting correction parameters VignettingParams vignetting; ///< Lens vignetting correction parameters

View File

@ -953,7 +953,7 @@ int RawImageSource::load (Glib::ustring fname, bool batch) {
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void RawImageSource::preprocess (const RAWParams &raw) void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &lensProf, const CoarseTransformParams& coarse)
{ {
MyTime t1,t2; MyTime t1,t2;
t1.set(); t1.set();
@ -979,7 +979,9 @@ void RawImageSource::preprocess (const RAWParams &raw)
} else { } else {
rif = ffm.searchFlatField( idata->getMake(), idata->getModel(),idata->getLens(),idata->getFocalLen(), idata->getFNumber(), idata->getDateTimeAsTS()); rif = ffm.searchFlatField( idata->getMake(), idata->getModel(),idata->getLens(),idata->getFocalLen(), idata->getFNumber(), idata->getDateTimeAsTS());
} }
if( rif && settings->verbose) {
bool hasFlatField = (rif!=NULL);
if( hasFlatField && settings->verbose) {
printf( "Flat Field Correction:%s\n",rif->get_filename().c_str()); printf( "Flat Field Correction:%s\n",rif->get_filename().c_str());
} }
copyOriginalPixels(raw, ri, rid, rif); copyOriginalPixels(raw, ri, rid, rif);
@ -1012,6 +1014,22 @@ void RawImageSource::preprocess (const RAWParams &raw)
} }
} }
// Correct vignetting of lens profile
if (!hasFlatField) {
LCPProfile *pLCPProf=lcpStore->getProfile(lensProf.lcpFile);
if (pLCPProf) {
LCPMapper *pLCPMap=new LCPMapper(pLCPProf, idata->getFocalLen(), true, W, H, coarse, ri->get_rotateDegree());
#pragma omp parallel
for (int y=0; y<H; y++) {
for (int x=0; x<W; x++) {
rawData[y][x]*=pLCPMap->correctVignette(x,y);
}
}
}
}
scaleColors( 0,0, W, H, raw);//+ + raw parameters for black level(raw.blackxx) scaleColors( 0,0, W, H, raw);//+ + raw parameters for black level(raw.blackxx)
defGain = 0.0;//log(initialGain) / log(2.0); defGain = 0.0;//log(initialGain) / log(2.0);

View File

@ -135,7 +135,7 @@ class RawImageSource : public ImageSource {
~RawImageSource (); ~RawImageSource ();
int load (Glib::ustring fname, bool batch = false); int load (Glib::ustring fname, bool batch = false);
void preprocess (const RAWParams &raw); void preprocess (const RAWParams &raw, const LensProfParams &lensProf, const CoarseTransformParams& coarse);
void demosaic (const RAWParams &raw); void demosaic (const RAWParams &raw);
void flushRawData (); void flushRawData ();
void flushRGB (); void flushRGB ();
@ -160,6 +160,7 @@ class RawImageSource : public ImageSource {
void getFullSize (int& w, int& h, int tr = TR_NONE); void getFullSize (int& w, int& h, int tr = TR_NONE);
void getSize (int tran, PreviewProps pp, int& w, int& h); void getSize (int tran, PreviewProps pp, int& w, int& h);
int getRotateDegree() const { return ri->get_rotateDegree(); }
ImageData* getImageData () { return idata; } ImageData* getImageData () { return idata; }
void setProgressListener (ProgressListener* pl) { plistener = pl; } void setProgressListener (ProgressListener* pl) { plistener = pl; }

View File

@ -104,7 +104,7 @@ RESIZE, // EvResizeEnabled
ALL, // EvProfileChangeNotification ALL, // EvProfileChangeNotification
RETINEX, // EvShrHighQuality RETINEX, // EvShrHighQuality
TRANSFORM, // EvPerspCorr TRANSFORM, // EvPerspCorr
0, // EvEqualizer: obsolete DARKFRAME, // EvLCPFile
0, // EvEqlEnabled:obsolete 0, // EvEqlEnabled:obsolete
IMPULSEDENOISE, // EvIDNEnabled, IMPULSEDENOISE, // EvIDNEnabled,
IMPULSEDENOISE, // EvIDNThresh, IMPULSEDENOISE, // EvIDNThresh,

View File

@ -576,7 +576,7 @@ IImage8* Thumbnail::quickProcessImage (const procparams::ProcParams& params, int
} }
// Full thumbnail processing, second stage if complete profile exists // Full thumbnail processing, second stage if complete profile exists
IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rheight, TypeInterpolation interp, std::string camName, double& myscale) { IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rheight, TypeInterpolation interp, std::string camName, double focalLen, double& myscale) {
// compute WB multipliers // compute WB multipliers
ColorTemp currWB = ColorTemp (params.wb.temperature, params.wb.green, params.wb.method); ColorTemp currWB = ColorTemp (params.wb.temperature, params.wb.green, params.wb.method);
@ -698,7 +698,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei
// perform transform // perform transform
if (ipf.needsTransform()) { if (ipf.needsTransform()) {
Imagefloat* trImg = new Imagefloat (fw, fh); Imagefloat* trImg = new Imagefloat (fw, fh);
ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh); ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh, focalLen, 0); // Raw rotate degree not detectable here
delete baseImg; delete baseImg;
baseImg = trImg; baseImg = trImg;
} }

View File

@ -70,7 +70,7 @@ namespace rtengine {
static void cleanupGamma (); static void cleanupGamma ();
void init (); void init ();
IImage8* processImage (const procparams::ProcParams& pparams, int rheight, TypeInterpolation interp, std::string camName, double& scale); IImage8* processImage (const procparams::ProcParams& pparams, int rheight, TypeInterpolation interp, std::string camName, double focalLen, double& scale);
IImage8* quickProcessImage (const procparams::ProcParams& pparams, int rheight, TypeInterpolation interp, double& scale); IImage8* quickProcessImage (const procparams::ProcParams& pparams, int rheight, TypeInterpolation interp, double& scale);
int getImageWidth (const procparams::ProcParams& pparams, int rheight, float &ratio); int getImageWidth (const procparams::ProcParams& pparams, int rheight, float &ratio);
void getDimensions (int& w, int& h, double& scaleFac); void getDimensions (int& w, int& h, double& scaleFac);

View File

@ -91,7 +91,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p
ImProcFunctions ipf (&params, true); ImProcFunctions ipf (&params, true);
PreviewProps pp (0, 0, fw, fh, 1); PreviewProps pp (0, 0, fw, fh, 1);
imgsrc->preprocess( params.raw); imgsrc->preprocess( params.raw, params.lensProf, params.coarse);
if (pl) pl->setProgress (0.20); if (pl) pl->setProgress (0.20);
imgsrc->demosaic( params.raw); imgsrc->demosaic( params.raw);
if (pl) pl->setProgress (0.30); if (pl) pl->setProgress (0.30);
@ -115,7 +115,7 @@ IImage16* processImage (ProcessingJob* pjob, int& errorCode, ProgressListener* p
// perform transform (excepted resizing) // perform transform (excepted resizing)
if (ipf.needsTransform()) { if (ipf.needsTransform()) {
Imagefloat* trImg = new Imagefloat (fw, fh); Imagefloat* trImg = new Imagefloat (fw, fh);
ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh); ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh, imgsrc->getMetaData()->getFocalLen(), imgsrc->getRotateDegree());
delete baseImg; delete baseImg;
baseImg = trImg; baseImg = trImg;
} }

View File

@ -8,7 +8,7 @@ set (BASESOURCEFILES
coarsepanel.cc cacorrection.cc hlrec.cc chmixer.cc coarsepanel.cc cacorrection.cc hlrec.cc chmixer.cc
resize.cc icmpanel.cc crop.cc shadowshighlights.cc resize.cc icmpanel.cc crop.cc shadowshighlights.cc
impulsedenoise.cc dirpyrdenoise.cc epd.cc impulsedenoise.cc dirpyrdenoise.cc epd.cc
exifpanel.cc toolpanel.cc exifpanel.cc toolpanel.cc lensprofile.cc
sharpening.cc vibrance.cc rgbcurves.cc sharpening.cc vibrance.cc rgbcurves.cc
whitebalance.cc vignetting.cc rotate.cc distortion.cc whitebalance.cc vignetting.cc rotate.cc distortion.cc
crophandler.cc dirbrowser.cc crophandler.cc dirbrowser.cc
@ -40,9 +40,9 @@ if (WIN32)
#set_target_properties (rth PROPERTIES LINK_FLAGS "-mwindows") #set_target_properties (rth PROPERTIES LINK_FLAGS "-mwindows")
else (WIN32) else (WIN32)
include_directories (${EXTRA_INCDIR} ${GLIB2_INCLUDE_DIRS} ${GLIBMM_INCLUDE_DIRS} include_directories (${EXTRA_INCDIR} ${GLIB2_INCLUDE_DIRS} ${GLIBMM_INCLUDE_DIRS}
${GTK_INCLUDE_DIRS} ${GTKMM_INCLUDE_DIRS} ${GIO_INCLUDE_DIRS} ${GIOMM_INCLUDE_DIRS} ${IPTCDATA_INCLUDE_DIRS} ${LCMS_INCLUDE_DIRS} ${GTHREAD_INCLUDE_DIRS} ${GOBJECT_INCLUDE_DIRS} ) ${GTK_INCLUDE_DIRS} ${GTKMM_INCLUDE_DIRS} ${GIO_INCLUDE_DIRS} ${GIOMM_INCLUDE_DIRS} ${IPTCDATA_INCLUDE_DIRS} ${LCMS_INCLUDE_DIRS} ${EXPAT_INCLUDE_DIRS} ${GTHREAD_INCLUDE_DIRS} ${GOBJECT_INCLUDE_DIRS} )
link_directories (${EXTRA_LIBDIR} ${GLIB2_LIBRARY_DIRS} ${GLIBMM_LIBRARY_DIRS} link_directories (${EXTRA_LIBDIR} ${GLIB2_LIBRARY_DIRS} ${GLIBMM_LIBRARY_DIRS}
${GTK_LIBRARY_DIRS} ${GTKMM_LIBRARY_DIRS} ${GIO_LIBRARY_DIRS} ${GIOMM_LIBRARY_DIRS} ${IPTCDATA_LIBRARY_DIRS} ${LCMS_LIBRARY_DIRS} ${GTHREAD_LIBRARY_DIRS} ${GOBJECT_LIBRARY_DIRS}) ${GTK_LIBRARY_DIRS} ${GTKMM_LIBRARY_DIRS} ${GIO_LIBRARY_DIRS} ${GIOMM_LIBRARY_DIRS} ${IPTCDATA_LIBRARY_DIRS} ${LCMS_LIBRARY_DIRS} ${EXPAT_LIBRARY_DIRS} ${GTHREAD_LIBRARY_DIRS} ${GOBJECT_LIBRARY_DIRS})
endif (WIN32) endif (WIN32)
# create config.h which defines where data are stored # create config.h which defines where data are stored
configure_file (${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/config.h) configure_file (${CMAKE_CURRENT_SOURCE_DIR}/config.h.in ${CMAKE_CURRENT_SOURCE_DIR}/config.h)
@ -53,6 +53,6 @@ set_target_properties (rth PROPERTIES COMPILE_FLAGS "${CMAKE_CXX_FLAGS}" OUTPUT_
#target_link_libraries (rth rtengine ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${TIFF_LIBRARIES} ${EXTRA_LIB} ${GOBJECT_LIBRARIES} ${GTHREAD_LIBRARIES} #target_link_libraries (rth rtengine ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${TIFF_LIBRARIES} ${EXTRA_LIB} ${GOBJECT_LIBRARIES} ${GTHREAD_LIBRARIES}
# ${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${GTK_LIBRARIES} ${GTKMM_LIBRARIES} ${GIO_LIBRARIES} ${GIOMM_LIBRARIES} ${LCMS_LIBRARIES} ${IPTCDATA_LIBRARIES}) # ${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${GTK_LIBRARIES} ${GTKMM_LIBRARIES} ${GIO_LIBRARIES} ${GIOMM_LIBRARIES} ${LCMS_LIBRARIES} ${IPTCDATA_LIBRARIES})
target_link_libraries (rth rtengine ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${TIFF_LIBRARIES} ${GOBJECT_LIBRARIES} ${GTHREAD_LIBRARIES} target_link_libraries (rth rtengine ${JPEG_LIBRARIES} ${PNG_LIBRARIES} ${ZLIB_LIBRARIES} ${TIFF_LIBRARIES} ${GOBJECT_LIBRARIES} ${GTHREAD_LIBRARIES}
${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${GTK_LIBRARIES} ${GTKMM_LIBRARIES} ${GIO_LIBRARIES} ${GIOMM_LIBRARIES} ${LCMS_LIBRARIES} ${IPTCDATA_LIBRARIES} ${EXTRA_LIB_RTGUI}) ${GLIB2_LIBRARIES} ${GLIBMM_LIBRARIES} ${GTK_LIBRARIES} ${GTKMM_LIBRARIES} ${GIO_LIBRARIES} ${GIOMM_LIBRARIES} ${LCMS_LIBRARIES} ${EXPAT_LIBRARIES} ${IPTCDATA_LIBRARIES} ${EXTRA_LIB_RTGUI})
install (TARGETS rth DESTINATION ${BINDIR}) install (TARGETS rth DESTINATION ${BINDIR})

View File

@ -134,8 +134,8 @@ void ParamsEdited::set (bool v) {
coarse.vflip = v; coarse.vflip = v;
commonTrans.autofill = v; commonTrans.autofill = v;
rotate.degree = v; rotate.degree = v;
distortion.uselensfun = v;
distortion.amount = v; distortion.amount = v;
lensProf.lcpFile = v;
perspective.horizontal = v; perspective.horizontal = v;
perspective.vertical = v; perspective.vertical = v;
cacorrection.red = v; cacorrection.red = v;
@ -327,8 +327,8 @@ void ParamsEdited::initFrom (const std::vector<rtengine::procparams::ProcParams>
coarse.vflip = coarse.vflip && p.coarse.vflip == other.coarse.vflip; coarse.vflip = coarse.vflip && p.coarse.vflip == other.coarse.vflip;
commonTrans.autofill = commonTrans.autofill && p.commonTrans.autofill == other.commonTrans.autofill; commonTrans.autofill = commonTrans.autofill && p.commonTrans.autofill == other.commonTrans.autofill;
rotate.degree = rotate.degree && p.rotate.degree == other.rotate.degree; rotate.degree = rotate.degree && p.rotate.degree == other.rotate.degree;
distortion.uselensfun = distortion.uselensfun && p.distortion.uselensfun == other.distortion.uselensfun;
distortion.amount = distortion.amount && p.distortion.amount == other.distortion.amount; distortion.amount = distortion.amount && p.distortion.amount == other.distortion.amount;
lensProf.lcpFile = lensProf.lcpFile && p.lensProf.lcpFile == other.lensProf.lcpFile;
perspective.horizontal = perspective.horizontal && p.perspective.horizontal == other.perspective.horizontal; perspective.horizontal = perspective.horizontal && p.perspective.horizontal == other.perspective.horizontal;
perspective.vertical = perspective.vertical && p.perspective.vertical == other.perspective.vertical; perspective.vertical = perspective.vertical && p.perspective.vertical == other.perspective.vertical;
cacorrection.red = cacorrection.red && p.cacorrection.red == other.cacorrection.red; cacorrection.red = cacorrection.red && p.cacorrection.red == other.cacorrection.red;
@ -519,8 +519,8 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten
if (coarse.vflip) toEdit.coarse.vflip = mods.coarse.vflip ? !toEdit.coarse.vflip : toEdit.coarse.vflip; if (coarse.vflip) toEdit.coarse.vflip = mods.coarse.vflip ? !toEdit.coarse.vflip : toEdit.coarse.vflip;
if (commonTrans.autofill) toEdit.commonTrans.autofill = mods.commonTrans.autofill; if (commonTrans.autofill) toEdit.commonTrans.autofill = mods.commonTrans.autofill;
if (rotate.degree) toEdit.rotate.degree = dontforceSet && options.baBehav[ADDSET_ROTATE_DEGREE] ? toEdit.rotate.degree + mods.rotate.degree : mods.rotate.degree; if (rotate.degree) toEdit.rotate.degree = dontforceSet && options.baBehav[ADDSET_ROTATE_DEGREE] ? toEdit.rotate.degree + mods.rotate.degree : mods.rotate.degree;
if (distortion.uselensfun) toEdit.distortion.uselensfun = mods.distortion.uselensfun;
if (distortion.amount) toEdit.distortion.amount = dontforceSet && options.baBehav[ADDSET_DIST_AMOUNT] ? toEdit.distortion.amount + mods.distortion.amount : mods.distortion.amount; if (distortion.amount) toEdit.distortion.amount = dontforceSet && options.baBehav[ADDSET_DIST_AMOUNT] ? toEdit.distortion.amount + mods.distortion.amount : mods.distortion.amount;
if (lensProf.lcpFile) toEdit.lensProf.lcpFile = mods.lensProf.lcpFile;
if (perspective.horizontal) toEdit.perspective.horizontal = dontforceSet && options.baBehav[ADDSET_PERSPECTIVE] ? toEdit.perspective.horizontal + mods.perspective.horizontal : mods.perspective.horizontal; if (perspective.horizontal) toEdit.perspective.horizontal = dontforceSet && options.baBehav[ADDSET_PERSPECTIVE] ? toEdit.perspective.horizontal + mods.perspective.horizontal : mods.perspective.horizontal;
if (perspective.vertical) toEdit.perspective.vertical = dontforceSet && options.baBehav[ADDSET_PERSPECTIVE] ? toEdit.perspective.vertical + mods.perspective.vertical : mods.perspective.vertical; if (perspective.vertical) toEdit.perspective.vertical = dontforceSet && options.baBehav[ADDSET_PERSPECTIVE] ? toEdit.perspective.vertical + mods.perspective.vertical : mods.perspective.vertical;
if (cacorrection.red) toEdit.cacorrection.red = dontforceSet && options.baBehav[ADDSET_CA] ? toEdit.cacorrection.red + mods.cacorrection.red : mods.cacorrection.red; if (cacorrection.red) toEdit.cacorrection.red = dontforceSet && options.baBehav[ADDSET_CA] ? toEdit.cacorrection.red + mods.cacorrection.red : mods.cacorrection.red;

View File

@ -243,10 +243,14 @@ class RotateParamsEdited {
class DistortionParamsEdited { class DistortionParamsEdited {
public: public:
bool uselensfun;
bool amount; bool amount;
}; };
class LensProfParamsEdited {
public:
bool lcpFile;
};
class PerspectiveParamsEdited { class PerspectiveParamsEdited {
public: public:
@ -386,6 +390,7 @@ class ParamsEdited {
CommonTransformParamsEdited commonTrans; CommonTransformParamsEdited commonTrans;
RotateParamsEdited rotate; RotateParamsEdited rotate;
DistortionParamsEdited distortion; DistortionParamsEdited distortion;
LensProfParamsEdited lensProf;
PerspectiveParamsEdited perspective; PerspectiveParamsEdited perspective;
CACorrParamsEdited cacorrection; CACorrParamsEdited cacorrection;
VignettingParamsEdited vignetting; VignettingParamsEdited vignetting;

View File

@ -70,6 +70,7 @@ PartialPasteDlg::PartialPasteDlg (Glib::ustring title) {
distortion = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_DISTORTION"))); distortion = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_DISTORTION")));
cacorr = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_CACORRECTION"))); cacorr = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_CACORRECTION")));
vignetting = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_VIGNETTING"))); vignetting = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_VIGNETTING")));
lcp = Gtk::manage (new Gtk::CheckButton (M("TP_LENSPROFILE_LABEL")));
// options in composition: // options in composition:
coarserot = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_COARSETRANS"))); coarserot = Gtk::manage (new Gtk::CheckButton (M("PARTIALPASTE_COARSETRANS")));
@ -149,6 +150,7 @@ PartialPasteDlg::PartialPasteDlg (Glib::ustring title) {
vboxes[3]->pack_start (*distortion, Gtk::PACK_SHRINK, 2); vboxes[3]->pack_start (*distortion, Gtk::PACK_SHRINK, 2);
vboxes[3]->pack_start (*cacorr, Gtk::PACK_SHRINK, 2); vboxes[3]->pack_start (*cacorr, Gtk::PACK_SHRINK, 2);
vboxes[3]->pack_start (*vignetting, Gtk::PACK_SHRINK, 2); vboxes[3]->pack_start (*vignetting, Gtk::PACK_SHRINK, 2);
vboxes[3]->pack_start (*lcp, Gtk::PACK_SHRINK, 2);
vboxes[4]->pack_start (*composition, Gtk::PACK_SHRINK, 2); vboxes[4]->pack_start (*composition, Gtk::PACK_SHRINK, 2);
vboxes[4]->pack_start (*hseps[4], Gtk::PACK_SHRINK, 2); vboxes[4]->pack_start (*hseps[4], Gtk::PACK_SHRINK, 2);
@ -260,6 +262,7 @@ PartialPasteDlg::PartialPasteDlg (Glib::ustring title) {
distortionConn = distortion->signal_toggled().connect (sigc::bind (sigc::mem_fun(*lens, &Gtk::CheckButton::set_inconsistent), true)); distortionConn = distortion->signal_toggled().connect (sigc::bind (sigc::mem_fun(*lens, &Gtk::CheckButton::set_inconsistent), true));
cacorrConn = cacorr->signal_toggled().connect (sigc::bind (sigc::mem_fun(*lens, &Gtk::CheckButton::set_inconsistent), true)); cacorrConn = cacorr->signal_toggled().connect (sigc::bind (sigc::mem_fun(*lens, &Gtk::CheckButton::set_inconsistent), true));
vignettingConn = vignetting->signal_toggled().connect (sigc::bind (sigc::mem_fun(*lens, &Gtk::CheckButton::set_inconsistent), true)); vignettingConn = vignetting->signal_toggled().connect (sigc::bind (sigc::mem_fun(*lens, &Gtk::CheckButton::set_inconsistent), true));
lcpConn = lcp->signal_toggled().connect (sigc::bind (sigc::mem_fun(*lens, &Gtk::CheckButton::set_inconsistent), true));
coarserotConn = coarserot->signal_toggled().connect (sigc::bind (sigc::mem_fun(*composition, &Gtk::CheckButton::set_inconsistent), true)); coarserotConn = coarserot->signal_toggled().connect (sigc::bind (sigc::mem_fun(*composition, &Gtk::CheckButton::set_inconsistent), true));
finerotConn = finerot->signal_toggled().connect (sigc::bind (sigc::mem_fun(*composition, &Gtk::CheckButton::set_inconsistent), true)); finerotConn = finerot->signal_toggled().connect (sigc::bind (sigc::mem_fun(*composition, &Gtk::CheckButton::set_inconsistent), true));
@ -495,16 +498,19 @@ void PartialPasteDlg::lensToggled () {
distortionConn.block (true); distortionConn.block (true);
cacorrConn.block (true); cacorrConn.block (true);
vignettingConn.block (true); vignettingConn.block (true);
lcpConn.block (true);
lens->set_inconsistent (false); lens->set_inconsistent (false);
distortion->set_active (lens->get_active ()); distortion->set_active (lens->get_active ());
cacorr->set_active (lens->get_active ()); cacorr->set_active (lens->get_active ());
vignetting->set_active (lens->get_active ()); vignetting->set_active (lens->get_active ());
lcp->set_active (lens->get_active ());
distortionConn.block (false); distortionConn.block (false);
cacorrConn.block (false); cacorrConn.block (false);
vignettingConn.block (false); vignettingConn.block (false);
lcpConn.block (false);
} }
void PartialPasteDlg::compositionToggled () { void PartialPasteDlg::compositionToggled () {
@ -600,6 +606,7 @@ void PartialPasteDlg::applyPaste (rtengine::procparams::ProcParams* dstPP, Param
if (!distortion->get_active ()) filterPE.distortion = falsePE.distortion; if (!distortion->get_active ()) filterPE.distortion = falsePE.distortion;
if (!cacorr->get_active ()) filterPE.cacorrection = falsePE.cacorrection; if (!cacorr->get_active ()) filterPE.cacorrection = falsePE.cacorrection;
if (!vignetting->get_active ()) filterPE.vignetting = falsePE.vignetting; if (!vignetting->get_active ()) filterPE.vignetting = falsePE.vignetting;
if (!lcp->get_active ()) filterPE.lensProf = falsePE.lensProf;
if (!coarserot->get_active ()) filterPE.coarse = falsePE.coarse; if (!coarserot->get_active ()) filterPE.coarse = falsePE.coarse;
if (!finerot->get_active ()) filterPE.rotate = falsePE.rotate; if (!finerot->get_active ()) filterPE.rotate = falsePE.rotate;

View File

@ -66,6 +66,7 @@ class PartialPasteDlg : public Gtk::Dialog {
Gtk::CheckButton* distortion; Gtk::CheckButton* distortion;
Gtk::CheckButton* cacorr; Gtk::CheckButton* cacorr;
Gtk::CheckButton* vignetting; Gtk::CheckButton* vignetting;
Gtk::CheckButton* lcp;
// options in composition: // options in composition:
Gtk::CheckButton* coarserot; Gtk::CheckButton* coarserot;
@ -109,7 +110,7 @@ class PartialPasteDlg : public Gtk::Dialog {
sigc::connection wbConn, exposureConn, hlrecConn, shConn, labcurveConn; sigc::connection wbConn, exposureConn, hlrecConn, shConn, labcurveConn;
sigc::connection sharpenConn, gradsharpenConn, microcontrastConn, impdenConn, dirpyrdenConn, waveqConn, defringeConn, epdConn, dirpyreqConn; sigc::connection sharpenConn, gradsharpenConn, microcontrastConn, impdenConn, dirpyrdenConn, waveqConn, defringeConn, epdConn, dirpyreqConn;
sigc::connection vibranceConn, chmixerConn, hsveqConn, rgbcurvesConn; sigc::connection vibranceConn, chmixerConn, hsveqConn, rgbcurvesConn;
sigc::connection distortionConn, cacorrConn, vignettingConn; sigc::connection distortionConn, cacorrConn, vignettingConn, lcpConn;
sigc::connection coarserotConn, finerotConn, cropConn, resizeConn, perspectiveConn, commonTransConn; sigc::connection coarserotConn, finerotConn, cropConn, resizeConn, perspectiveConn, commonTransConn;
sigc::connection exifchConn, iptcConn, icmConn, gamcsconn; sigc::connection exifchConn, iptcConn, icmConn, gamcsconn;
sigc::connection df_fileConn, df_AutoSelectConn, ff_fileConn, ff_AutoSelectConn, ff_BlurRadiusConn, ff_BlurTypeConn; sigc::connection df_fileConn, df_AutoSelectConn, ff_fileConn, ff_AutoSelectConn, ff_BlurRadiusConn, ff_BlurTypeConn;

View File

@ -468,7 +468,7 @@ rtengine::IImage8* Thumbnail::processThumbImage (const rtengine::procparams::Pro
else else
{ {
// Full thumbnail: apply profile // Full thumbnail: apply profile
image = tpp->processImage (pparams, h, rtengine::TI_Bilinear, cfs.camera, scale ); image = tpp->processImage (pparams, h, rtengine::TI_Bilinear, cfs.camera, cfs.focalLen, scale );
} }
tpp->getDimensions(lastW,lastH,lastScale); tpp->getDimensions(lastW,lastH,lastScale);
@ -493,7 +493,7 @@ rtengine::IImage8* Thumbnail::upgradeThumbImage (const rtengine::procparams::Pro
return 0; return 0;
} }
rtengine::IImage8* image = tpp->processImage (pparams, h, rtengine::TI_Bilinear, cfs.camera, scale ); rtengine::IImage8* image = tpp->processImage (pparams, h, rtengine::TI_Bilinear, cfs.camera, cfs.focalLen, scale );
tpp->getDimensions(lastW,lastH,lastScale); tpp->getDimensions(lastW,lastH,lastScale);
delete tpp; delete tpp;

View File

@ -52,6 +52,7 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) {
lcurve = Gtk::manage (new LCurve ()); lcurve = Gtk::manage (new LCurve ());
rgbcurves = Gtk::manage (new RGBCurves ()); rgbcurves = Gtk::manage (new RGBCurves ());
lensgeom = Gtk::manage (new LensGeometry ()); lensgeom = Gtk::manage (new LensGeometry ());
lensProf = Gtk::manage (new LensProfilePanel ());
distortion = Gtk::manage (new Distortion ()); distortion = Gtk::manage (new Distortion ());
rotate = Gtk::manage (new Rotate ()); rotate = Gtk::manage (new Rotate ());
vibrance = Gtk::manage (new Vibrance ()); vibrance = Gtk::manage (new Vibrance ());
@ -97,6 +98,7 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc(NULL) {
addPanel (transformPanel, lensgeom, M("TP_LENSGEOM_LABEL")); toolPanels.push_back (lensgeom); addPanel (transformPanel, lensgeom, M("TP_LENSGEOM_LABEL")); toolPanels.push_back (lensgeom);
addPanel (lensgeom->getPackBox(), rotate, M("TP_ROTATE_LABEL")); toolPanels.push_back (rotate); addPanel (lensgeom->getPackBox(), rotate, M("TP_ROTATE_LABEL")); toolPanels.push_back (rotate);
addPanel (lensgeom->getPackBox(), perspective, M("TP_PERSPECTIVE_LABEL")); toolPanels.push_back (perspective); addPanel (lensgeom->getPackBox(), perspective, M("TP_PERSPECTIVE_LABEL")); toolPanels.push_back (perspective);
addPanel (lensgeom->getPackBox(), lensProf, M("TP_LENSPROFILE_LABEL")); toolPanels.push_back (lensProf);
addPanel (lensgeom->getPackBox(), distortion, M("TP_DISTORTION_LABEL")); toolPanels.push_back (distortion); addPanel (lensgeom->getPackBox(), distortion, M("TP_DISTORTION_LABEL")); toolPanels.push_back (distortion);
addPanel (lensgeom->getPackBox(), cacorrection, M("TP_CACORRECTION_LABEL")); toolPanels.push_back (cacorrection); addPanel (lensgeom->getPackBox(), cacorrection, M("TP_CACORRECTION_LABEL")); toolPanels.push_back (cacorrection);
addPanel (lensgeom->getPackBox(), vignetting, M("TP_VIGNETTING_LABEL")); toolPanels.push_back (vignetting); addPanel (lensgeom->getPackBox(), vignetting, M("TP_VIGNETTING_LABEL")); toolPanels.push_back (vignetting);

View File

@ -45,6 +45,7 @@
#include "chmixer.h" #include "chmixer.h"
#include "hlrec.h" #include "hlrec.h"
#include "cacorrection.h" #include "cacorrection.h"
#include "lensprofile.h"
#include "distortion.h" #include "distortion.h"
#include "perspective.h" #include "perspective.h"
#include "rotate.h" #include "rotate.h"
@ -83,6 +84,7 @@ class ToolPanelCoordinator : public ToolPanelListener,
WhiteBalance* whitebalance; WhiteBalance* whitebalance;
Vignetting* vignetting; Vignetting* vignetting;
LensGeometry* lensgeom; LensGeometry* lensgeom;
LensProfilePanel* lensProf;
Rotate* rotate; Rotate* rotate;
Distortion* distortion; Distortion* distortion;
PerspCorrection* perspective; PerspCorrection* perspective;