merge with dev

This commit is contained in:
Desmis 2017-09-14 09:09:18 +02:00
commit 9786ec0687
40 changed files with 2861 additions and 1388 deletions

View File

@ -7,6 +7,7 @@ Processor: ${PROC_LABEL}
System: ${SYSTEM}
Bit depth: ${PROC_BIT_DEPTH}
Gtkmm: V${GTKMM_VERSION}
Lensfun: V${LENSFUN_VERSION}
Build type: ${BUILD_TYPE}
Build flags: ${CXX_FLAGS}
Link flags: ${LFLAGS}

View File

@ -272,6 +272,7 @@ pkg_check_modules (GIOMM REQUIRED giomm-2.4>=2.44)
pkg_check_modules (GTHREAD REQUIRED gthread-2.0>=2.44)
pkg_check_modules (GOBJECT REQUIRED gobject-2.0>=2.44)
pkg_check_modules (SIGC REQUIRED sigc++-2.0>=2.3.1)
pkg_check_modules (LENSFUN REQUIRED lensfun>=0.2)
if(WIN32)
add_definitions(-DWIN32)
@ -389,7 +390,8 @@ set(ABOUT_COMMAND_WITH_ARGS ${CMAKE_COMMAND}
-DBUILD_TYPE:STRING=${CMAKE_BUILD_TYPE}
-DGTKMM_VERSION:STRING=${GTKMM_VERSION}
-DOPTION_OMP:STRING=${OPTION_OMP}
-DWITH_MYFILE_MMAP:STRING=${WITH_MYFILE_MMAP})
-DWITH_MYFILE_MMAP:STRING=${WITH_MYFILE_MMAP}
-DLENSFUN_VERSION:STRING=${LENSFUN_VERSION})
if(WIN32)
list(APPEND ABOUT_COMMAND_WITH_ARGS -DSYSTEM:STRING=Windows

View File

@ -281,9 +281,9 @@ HISTORY_MSG_30;RLD - Radius
HISTORY_MSG_31;RLD - Amount
HISTORY_MSG_32;RLD - Damping
HISTORY_MSG_33;RLD - Iterations
HISTORY_MSG_34;LCP distortion correction
HISTORY_MSG_35;LCP vignetting correction
HISTORY_MSG_36;LCP CA correction
HISTORY_MSG_34;Lens Correction - Distortion
HISTORY_MSG_35;Lens Correction - Vignetting
HISTORY_MSG_36;Lens Correction - CA
HISTORY_MSG_37;Exposure - Auto levels
HISTORY_MSG_38;White Balance - Method
HISTORY_MSG_39;WB - Temperature
@ -332,7 +332,7 @@ HISTORY_MSG_81;Resize
HISTORY_MSG_82;Profile changed
HISTORY_MSG_83;S/H - Sharp mask
HISTORY_MSG_84;Perspective correction
HISTORY_MSG_85;LCP
HISTORY_MSG_85;Lens Correction - LCP file
HISTORY_MSG_86;RGB Curves - Luminosity mode
HISTORY_MSG_87;Impulse Noise Reduction
HISTORY_MSG_88;Impulse NR threshold
@ -731,94 +731,97 @@ HISTORY_MSG_481;CAM02 - Temp scene
HISTORY_MSG_482;CAM02 - Green scene
HISTORY_MSG_483;CAM02 - Yb scene
HISTORY_MSG_484;CAM02 - Auto Yb scene
HISTORY_MSG_485;Local L*a*b*
HISTORY_MSG_486;Local - Bottom
HISTORY_MSG_487;Local - Right
HISTORY_MSG_488;Local - Center
HISTORY_MSG_489;Local - Lightness/
HISTORY_MSG_490;Local - Lightness
HISTORY_MSG_491;Local - Contrast
HISTORY_MSG_492;Local - Chrominance
HISTORY_MSG_493;Local - Transition
HISTORY_MSG_494;Local - Avoid color shift
HISTORY_MSG_495;Local - Top
HISTORY_MSG_496;Local - Left
HISTORY_MSG_497;Local - Method
HISTORY_MSG_498;Local - Color Inverse
HISTORY_MSG_499;Local - Radius
HISTORY_MSG_500;Local - Blur Inverse
HISTORY_MSG_501;Local - Noise
HISTORY_MSG_502;Local - Scope
HISTORY_MSG_503;Local - Retinex method
HISTORY_MSG_504;Local - Retinex strength
HISTORY_MSG_505;Local - Retinex radius
HISTORY_MSG_506;Local - Retinex contrast
HISTORY_MSG_507;Local - Retinex Gain curve
HISTORY_MSG_508;Local - Retinex chroma
HISTORY_MSG_509;Local - Retinex Inverse
HISTORY_MSG_510;Local - Hue scope
HISTORY_MSG_511;Local - Spot
HISTORY_MSG_512;Local - Blur Luminance only
HISTORY_MSG_513;Local - Update GUI and Mip -1
HISTORY_MSG_514;Local - Sh Radius
HISTORY_MSG_515;Local - Sh Amount
HISTORY_MSG_516;Local - Sh Damping
HISTORY_MSG_517;Local - Sh Iterations
HISTORY_MSG_518;Local - Sh Scope
HISTORY_MSG_519;Local - Sh Inverse
HISTORY_MSG_520;Local - Spot size
HISTORY_MSG_521;Local - artifacts theshold
HISTORY_MSG_522;Local - artifacts iterations
HISTORY_MSG_523;Local - Quality
HISTORY_MSG_524;Local - Noise lum f
HISTORY_MSG_525;Local - Noise lum c
HISTORY_MSG_526;Local - Noise chro f
HISTORY_MSG_527;Local - Noise chro c
HISTORY_MSG_528;Local - cbdl threshold
HISTORY_MSG_529;Local - cbdl mult
HISTORY_MSG_530;Local - cbdl scope
HISTORY_MSG_531;Local - Blur scope
HISTORY_MSG_532;Local - TM strength
HISTORY_MSG_533;Local - TM gamma
HISTORY_MSG_534;Local - TM edge stopping
HISTORY_MSG_535;Local - TM scale
HISTORY_MSG_536;Local - TM Reweighting
HISTORY_MSG_537;Local - TM scope
HISTORY_MSG_538;Local - Update GUI and Mip -2
HISTORY_MSG_539;Local - Update GUI and Mip -3
HISTORY_MSG_540;Local - LL Curve
HISTORY_MSG_541;Local - Color and light
HISTORY_MSG_542;Local - Blur and noise
HISTORY_MSG_543;Local - Tone mapping
HISTORY_MSG_544;Local - Retinex
HISTORY_MSG_545;Local - Sharpening
HISTORY_MSG_546;Local - CBDL
HISTORY_MSG_547;Local - Denoise
HISTORY_MSG_548;Local - LH Curve
HISTORY_MSG_549;Local - Enable super
HISTORY_MSG_550;Local - CC curve
HISTORY_MSG_551;Local - curve method
HISTORY_MSG_552;Local - hueref
HISTORY_MSG_553;Local - chromaref
HISTORY_MSG_554;Local - lumaref
HISTORY_MSG_555;Local - H curve
HISTORY_MSG_556;Local - Vibrance
HISTORY_MSG_557;Local - Vib H curve
HISTORY_MSG_558;Local - Vib Protect skin tones
HISTORY_MSG_559;Local - Vib avoid colorshift
HISTORY_MSG_560;Local - Vib link
HISTORY_MSG_561;Local - Vib Pastel
HISTORY_MSG_562;Local - Vib Saturated
HISTORY_MSG_563;Local - Vib Threshold
HISTORY_MSG_564;Local - Vib Scope
HISTORY_MSG_565;Local - Exposure
HISTORY_MSG_566;Local - Exp Compensation
HISTORY_MSG_567;Local - Exp Hlcompr
HISTORY_MSG_568;Local - Exp hlcomprthresh
HISTORY_MSG_569;Local - Exp black
HISTORY_MSG_570;Local - Exp Shcompr
HISTORY_MSG_571;Local - Exp Scope
HISTORY_MSG_572;Local - Exp Contrast curve
HISTORY_MSG_485;Lens Correction
HISTORY_MSG_486;Lens Correction - Camera
HISTORY_MSG_487;Lens Correction - Lens
HISTORY_MSG_488;Local L*a*b*
HISTORY_MSG_489;Local - Bottom
HISTORY_MSG_490;Local - Right
HISTORY_MSG_491;Local - Center
HISTORY_MSG_492;Local - Lightness/
HISTORY_MSG_493;Local - Lightness
HISTORY_MSG_494;Local - Contrast
HISTORY_MSG_495;Local - Chrominance
HISTORY_MSG_496;Local - Transition
HISTORY_MSG_497;Local - Avoid color shift
HISTORY_MSG_498;Local - Top
HISTORY_MSG_499;Local - Left
HISTORY_MSG_500;Local - Method
HISTORY_MSG_501;Local - Color Inverse
HISTORY_MSG_502;Local - Radius
HISTORY_MSG_503;Local - Blur Inverse
HISTORY_MSG_504;Local - Noise
HISTORY_MSG_505;Local - Scope
HISTORY_MSG_506;Local - Retinex method
HISTORY_MSG_507;Local - Retinex strength
HISTORY_MSG_508;Local - Retinex radius
HISTORY_MSG_509;Local - Retinex contrast
HISTORY_MSG_510;Local - Retinex Gain curve
HISTORY_MSG_511;Local - Retinex chroma
HISTORY_MSG_512;Local - Retinex Inverse
HISTORY_MSG_513;Local - Hue scope
HISTORY_MSG_514;Local - Spot
HISTORY_MSG_515;Local - Blur Luminance only
HISTORY_MSG_516;Local - Update GUI and Mip -1
HISTORY_MSG_517;Local - Sh Radius
HISTORY_MSG_518;Local - Sh Amount
HISTORY_MSG_519;Local - Sh Damping
HISTORY_MSG_520;Local - Sh Iterations
HISTORY_MSG_521;Local - Sh Scope
HISTORY_MSG_522;Local - Sh Inverse
HISTORY_MSG_523;Local - Spot size
HISTORY_MSG_524;Local - artifacts theshold
HISTORY_MSG_525;Local - artifacts iterations
HISTORY_MSG_526;Local - Quality
HISTORY_MSG_527;Local - Noise lum f
HISTORY_MSG_528;Local - Noise lum c
HISTORY_MSG_529;Local - Noise chro f
HISTORY_MSG_530;Local - Noise chro c
HISTORY_MSG_531;Local - cbdl threshold
HISTORY_MSG_532;Local - cbdl mult
HISTORY_MSG_533;Local - cbdl scope
HISTORY_MSG_534;Local - Blur scope
HISTORY_MSG_535;Local - TM strength
HISTORY_MSG_536;Local - TM gamma
HISTORY_MSG_537;Local - TM edge stopping
HISTORY_MSG_538;Local - TM scale
HISTORY_MSG_539;Local - TM Reweighting
HISTORY_MSG_540;Local - TM scope
HISTORY_MSG_541;Local - Update GUI and Mip -2
HISTORY_MSG_542;Local - Update GUI and Mip -3
HISTORY_MSG_543;Local - LL Curve
HISTORY_MSG_544;Local - Color and light
HISTORY_MSG_545;Local - Blur and noise
HISTORY_MSG_546;Local - Tone mapping
HISTORY_MSG_547;Local - Retinex
HISTORY_MSG_548;Local - Sharpening
HISTORY_MSG_549;Local - CBDL
HISTORY_MSG_550;Local - Denoise
HISTORY_MSG_551;Local - LH Curve
HISTORY_MSG_552;Local - Enable super
HISTORY_MSG_553;Local - CC curve
HISTORY_MSG_554;Local - curve method
HISTORY_MSG_555;Local - hueref
HISTORY_MSG_556;Local - chromaref
HISTORY_MSG_557;Local - lumaref
HISTORY_MSG_558;Local - H curve
HISTORY_MSG_559;Local - Vibrance
HISTORY_MSG_560;Local - Vib H curve
HISTORY_MSG_561;Local - Vib Protect skin tones
HISTORY_MSG_562;Local - Vib avoid colorshift
HISTORY_MSG_563;Local - Vib link
HISTORY_MSG_564;Local - Vib Pastel
HISTORY_MSG_565;Local - Vib Saturated
HISTORY_MSG_566;Local - Vib Threshold
HISTORY_MSG_567;Local - Vib Scope
HISTORY_MSG_568;Local - Exposure
HISTORY_MSG_569;Local - Exp Compensation
HISTORY_MSG_570;Local - Exp Hlcompr
HISTORY_MSG_571;Local - Exp hlcomprthresh
HISTORY_MSG_572;Local - Exp black
HISTORY_MSG_573;Local - Exp Shcompr
HISTORY_MSG_574;Local - Exp Scope
HISTORY_MSG_575;Local - Exp Contrast curve
HISTORY_NEWSNAPSHOT;Add
HISTORY_NEWSNAPSHOT_TOOLTIP;Shortcut: <b>Alt-s</b>
HISTORY_SNAPSHOT;Snapshot
@ -993,9 +996,9 @@ PARTIALPASTE_IMPULSEDENOISE;Impulse noise reduction
PARTIALPASTE_IPTCINFO;IPTC
PARTIALPASTE_LABCURVE;L*a*b* adjustments
PARTIALPASTE_LENSGROUP;Lens Related Settings
PARTIALPASTE_LENSPROFILE;Lens correction profile
PARTIALPASTE_LOCALLAB;Local L*a*b*
PARTIALPASTE_LOCGROUP;Local
PARTIALPASTE_LENSPROFILE;Profiled lens correction
PARTIALPASTE_METAGROUP;Metadata
PARTIALPASTE_PCVIGNETTE;Vignette filter
PARTIALPASTE_PERSPECTIVE;Perspective
@ -1774,7 +1777,7 @@ TP_LABCURVE_RSTPRO_TOOLTIP;Works on the Chromaticity slider and the CC curve.
TP_LENSGEOM_AUTOCROP;Auto-Crop
TP_LENSGEOM_FILL;Auto-fill
TP_LENSGEOM_LABEL;Lens / Geometry
TP_LENSPROFILE_LABEL;Lens Correction Profile
TP_LENSPROFILE_LABEL;Profiled Lens Correction
TP_LENSPROFILE_USECA;Chromatic aberration correction
TP_LENSPROFILE_USEDIST;Distortion correction
TP_LENSPROFILE_USEVIGN;Vignetting correction
@ -2359,3 +2362,7 @@ ZOOMPANEL_ZOOMFITCROPSCREEN;Fit crop to screen\nShortcut: <b>Alt</b>-<b>f</b>
ZOOMPANEL_ZOOMFITSCREEN;Fit whole image to screen\nShortcut: <b>f</b>
ZOOMPANEL_ZOOMIN;Zoom In\nShortcut: <b>+</b>
ZOOMPANEL_ZOOMOUT;Zoom Out\nShortcut: <b>-</b>
LENSPROFILE_CORRECTION_AUTOMATCH;Auto-matched correction parameters
LENSPROFILE_CORRECTION_MANUAL;Manual correction parameters
LENSPROFILE_CORRECTION_LCPFILE;LCP File
LENSPROFILE_LENS_WARNING;Warning: the crop factor used for lens profiling is larger than the crop factor of the camera, the results might be wrong.

View File

@ -9,6 +9,7 @@ include_directories(${EXTRA_INCDIR}
${GTK_INCLUDE_DIRS}
${IPTCDATA_INCLUDE_DIRS}
${LCMS_INCLUDE_DIRS}
${LENSFUN_INCLUDE_DIRS}
)
link_directories("${PROJECT_SOURCE_DIR}/rtexif"
@ -110,6 +111,7 @@ set(RTENGINESOURCEFILES
slicer.cc
stdimagesource.cc
utils.cc
rtlensfun.cc
)
if(NOT WITH_SYSTEM_KLT)
@ -154,6 +156,7 @@ target_link_libraries(rtengine rtexif
${PNG_LIBRARIES}
${TIFF_LIBRARIES}
${ZLIB_LIBRARIES}
${LENSFUN_LIBRARIES}
)
install(FILES ${CAMCONSTSFILE} DESTINATION "${DATADIR}" PERMISSIONS OWNER_WRITE OWNER_READ GROUP_READ WORLD_READ)

View File

@ -178,6 +178,8 @@ void Ciecam02::curveJ (double br, double contr, int db, LUTf & outCurve, LUTu &
for (int i = 0; i < (db * 32768); i++) {
outCurve[i] = db * 32768.0 * dcurve[i];
}
// printf("double out500=%f out15000=%f\n", outCurve[500], outCurve[15000]);
}
void Ciecam02::curveJfloat (float br, float contr, const LUTu & histogram, LUTf & outCurve)
@ -268,6 +270,8 @@ void Ciecam02::curveJfloat (float br, float contr, const LUTu & histogram, LUTf
}
outCurve *= 32767.f;
//printf("out500=%f out15000=%f\n", outCurve[500], outCurve[15000]);
//outCurve.dump("brig");
}
/**

View File

@ -305,7 +305,7 @@ rtengine::CLUTStore& rtengine::CLUTStore::getInstance()
return instance;
}
std::shared_ptr<rtengine::HaldCLUT> rtengine::CLUTStore::getClut(const Glib::ustring& filename)
std::shared_ptr<rtengine::HaldCLUT> rtengine::CLUTStore::getClut(const Glib::ustring& filename) const
{
std::shared_ptr<rtengine::HaldCLUT> result;

View File

@ -57,14 +57,14 @@ class CLUTStore final :
public:
static CLUTStore& getInstance();
std::shared_ptr<HaldCLUT> getClut(const Glib::ustring& filename);
std::shared_ptr<HaldCLUT> getClut(const Glib::ustring& filename) const;
void clearCache();
private:
CLUTStore();
Cache<Glib::ustring, std::shared_ptr<HaldCLUT>> cache;
mutable Cache<Glib::ustring, std::shared_ptr<HaldCLUT>> cache;
};
}

View File

@ -2562,6 +2562,12 @@ void CLASS kodak_radc_load_raw()
((short *)buf)[i] = 2048;
for (row=0; row < height; row+=4) {
FORC3 mul[c] = getbits(6);
FORC3 {
if (!mul[c]) {
mul[c] = 1;
derror();
}
}
FORC3 {
val = ((0x1000000/last[c] + 0x7ff) >> 12) * mul[c];
s = val > 65564 ? 10:12;
@ -9936,4 +9942,4 @@ struct tiff_hdr {
/*RT*/#undef CLIP
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
#endif

View File

@ -708,9 +708,7 @@ void Crop::update (int todo)
if (needstransform)
parent->ipf.transform (baseCrop, transCrop, cropx / skip, cropy / skip, trafx / skip, trafy / skip, skips (parent->fw, skip), skips (parent->fh, skip), parent->getFullWidth(), parent->getFullHeight(),
parent->imgsrc->getMetaData()->getFocalLen(), parent->imgsrc->getMetaData()->getFocalLen35mm(),
parent->imgsrc->getMetaData()->getFocusDist(),
parent->imgsrc->getMetaData()->getFNumber(),
parent->imgsrc->getMetaData(),
parent->imgsrc->getRotateDegree(), false);
else {
baseCrop->copyData (transCrop);
@ -1754,8 +1752,9 @@ bool check_need_larger_crop_for_lcp_distortion (int fw, int fh, int x, int y, in
return false;
}
return (params.lensProf.lcpFile.length() > 0 &&
params.lensProf.useDist);
return (params.lensProf.useDist &&
(params.lensProf.useLensfun ||
params.lensProf.lcpFile.length() > 0));
}
} // namespace

View File

@ -3,9 +3,10 @@
// Green Equilibration via directional average
//
// copyright (c) 2008-2010 Emil Martinec <ejmartin@uchicago.edu>
// optimized for speed 2017 Ingo Weyrich <heckflosse67@gmx.de>
//
//
// code dated: February 12, 2011
// code dated: August 25, 2017
//
// green_equil_RT.cc is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
@ -21,18 +22,72 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
////////////////////////////////////////////////////////////////
#define TS 256 // Tile size
#include <cmath>
#include <cstdlib>
#include <ctime>
#include "rt_math.h"
#include "rawimagesource.h"
#include "opthelper.h"
namespace rtengine
{
void RawImageSource::green_equilibrate_global(array2D<float> &rawData)
{
// global correction
int ng1 = 0, ng2 = 0;
double avgg1 = 0., avgg2 = 0.;
#ifdef _OPENMP
#pragma omp parallel for reduction(+: ng1, ng2, avgg1, avgg2) schedule(dynamic,16)
#endif
for (int i = border; i < H - border; i++) {
double avgg = 0.;
for (int j = border + ((FC(i, border) & 1) ^ 1); j < W - border; j += 2) {
avgg += rawData[i][j];
}
int ng = (W - 2 * border + (FC(i, border) & 1)) / 2;
if (i & 1) {
avgg2 += avgg;
ng2 += ng;
} else {
avgg1 += avgg;
ng1 += ng;
}
}
// Avoid division by zero
if(ng1 == 0 || avgg1 == 0.0) {
ng1 = 1;
avgg1 = 1.0;
}
if(ng2 == 0 || avgg2 == 0.0) {
ng2 = 1;
avgg2 = 1.0;
}
double corrg1 = (avgg1 / ng1 + avgg2 / ng2) / 2.0 / (avgg1 / ng1);
double corrg2 = (avgg1 / ng1 + avgg2 / ng2) / 2.0 / (avgg2 / ng2);
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic,16)
#endif
for (int i = border; i < H - border; i++) {
double corrg = (i & 1) ? corrg2 : corrg1;
for (int j = border + ((FC(i, border) & 1) ^ 1); j < W - border; j += 2) {
rawData[i][j] *= corrg;
}
}
}
//void green_equilibrate()//for dcraw implementation
void RawImageSource::green_equilibrate(float thresh, array2D<float> &rawData)
{
@ -42,15 +97,29 @@ void RawImageSource::green_equilibrate(float thresh, array2D<float> &rawData)
int height = H, width = W;
// local variables
float** rawptr = rawData;
array2D<float> cfa (width, height, rawptr);
//array2D<int> checker (width,height,ARRAY2D_CLEAR_DATA);
array2D<float> cfa(width / 2 + (width & 1), height);
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic,16)
#endif
//int verbose=1;
for (int i = 0; i < height; ++i) {
int j = (FC(i, 0) & 1) ^ 1;
#ifdef __SSE2__
static const float eps = 1.0; //tolerance to avoid dividing by zero
for (; j < width - 7; j += 8) {
STVFU(cfa[i][j >> 1], LC2VFU(rawData[i][j]));
}
#endif
for (; j < width; j += 2) {
cfa[i][j >> 1] = rawData[i][j];
}
}
constexpr float eps = 1.f; //tolerance to avoid dividing by zero
const float thresh6 = 6 * thresh;
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Fill G interpolated values with border interpolation and input values
@ -59,94 +128,118 @@ void RawImageSource::green_equilibrate(float thresh, array2D<float> &rawData)
//int counter, vtest;
//The green equilibration algorithm starts here
/*
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int rr=1; rr < height-1; rr++)
for (int cc=3-(FC(rr,2)&1); cc < width-2; cc+=2) {
float pcorr = (cfa[rr+1][cc+1]-cfa[rr][cc])*(cfa[rr-1][cc-1]-cfa[rr][cc]);
float mcorr = (cfa[rr-1][cc+1]-cfa[rr][cc])*(cfa[rr+1][cc-1]-cfa[rr][cc]);
if (pcorr>0 && mcorr>0) {checker[rr][cc]=1;} else {checker[rr][cc]=0;}
checker[rr][cc]=1;//test what happens if we always interpolate
}
counter=vtest=0;
*/
//now smooth the cfa data
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic,16)
#pragma omp parallel
#endif
{
#ifdef __SSE2__
vfloat zd5v = F2V(0.5f);
vfloat onev = F2V(1.f);
vfloat threshv = F2V(thresh);
vfloat thresh6v = F2V(thresh6);
vfloat epsv = F2V(eps);
#endif
#ifdef _OPENMP
#pragma omp for schedule(dynamic,16)
#endif
for (int rr = 4; rr < height - 4; rr++)
for (int cc = 5 - (FC(rr, 2) & 1); cc < width - 6; cc += 2) {
//if (checker[rr][cc]) {
//%%%%%%%%%%%%%%%%%%%%%%
//neighbor checking code from Manuel Llorens Garcia
float o1_1 = cfa[(rr - 1)][cc - 1];
float o1_2 = cfa[(rr - 1)][cc + 1];
float o1_3 = cfa[(rr + 1)][cc - 1];
float o1_4 = cfa[(rr + 1)][cc + 1];
float o2_1 = cfa[(rr - 2)][cc];
float o2_2 = cfa[(rr + 2)][cc];
float o2_3 = cfa[(rr)][cc - 2];
float o2_4 = cfa[(rr)][cc + 2];
for (int rr = 4; rr < height - 4; rr++) {
int cc = 5 - (FC(rr, 2) & 1);
#ifdef __SSE2__
float d1 = (o1_1 + o1_2 + o1_3 + o1_4) * 0.25f;
float d2 = (o2_1 + o2_2 + o2_3 + o2_4) * 0.25f;
for (; cc < width - 12; cc += 8) {
//neighbour checking code from Manuel Llorens Garcia
vfloat o1_1 = LVFU(cfa[rr - 1][(cc - 1) >> 1]);
vfloat o1_2 = LVFU(cfa[rr - 1][(cc + 1) >> 1]);
vfloat o1_3 = LVFU(cfa[rr + 1][(cc - 1) >> 1]);
vfloat o1_4 = LVFU(cfa[rr + 1][(cc + 1) >> 1]);
vfloat o2_1 = LVFU(cfa[rr - 2][cc >> 1]);
vfloat o2_2 = LVFU(cfa[rr + 2][cc >> 1]);
vfloat o2_3 = LVFU(cfa[rr][(cc >> 1) - 1]);
vfloat o2_4 = LVFU(cfa[rr][(cc >> 1) + 1]);
float c1 = (fabs(o1_1 - o1_2) + fabs(o1_1 - o1_3) + fabs(o1_1 - o1_4) + fabs(o1_2 - o1_3) + fabs(o1_3 - o1_4) + fabs(o1_2 - o1_4)) / 6.f;
float c2 = (fabs(o2_1 - o2_2) + fabs(o2_1 - o2_3) + fabs(o2_1 - o2_4) + fabs(o2_2 - o2_3) + fabs(o2_3 - o2_4) + fabs(o2_2 - o2_4)) / 6.f;
//%%%%%%%%%%%%%%%%%%%%%%
vfloat d1 = (o1_1 + o1_2 + o1_3 + o1_4);
vfloat d2 = (o2_1 + o2_2 + o2_3 + o2_4);
//vote1=(checker[rr-2][cc]+checker[rr][cc-2]+checker[rr][cc+2]+checker[rr+2][cc]);
//vote2=(checker[rr+1][cc-1]+checker[rr+1][cc+1]+checker[rr-1][cc-1]+checker[rr-1][cc+1]);
//if ((vote1==0 || vote2==0) && (c1+c2)<2*thresh*fabs(d1-d2)) vtest++;
//if (vote1>0 && vote2>0 && (c1+c2)<4*thresh*fabs(d1-d2)) {
if ((c1 + c2) < 4 * thresh * fabs(d1 - d2)) {
//pixel interpolation
float gin = cfa[rr][cc];
vfloat c1 = (vabsf(o1_1 - o1_2) + vabsf(o1_1 - o1_3) + vabsf(o1_1 - o1_4) + vabsf(o1_2 - o1_3) + vabsf(o1_3 - o1_4) + vabsf(o1_2 - o1_4));
vfloat c2 = (vabsf(o2_1 - o2_2) + vabsf(o2_1 - o2_3) + vabsf(o2_1 - o2_4) + vabsf(o2_2 - o2_3) + vabsf(o2_3 - o2_4) + vabsf(o2_2 - o2_4));
float gse = (cfa[rr + 1][cc + 1]) + 0.5f * (cfa[rr][cc] - cfa[rr + 2][cc + 2]);
float gnw = (cfa[rr - 1][cc - 1]) + 0.5f * (cfa[rr][cc] - cfa[rr - 2][cc - 2]);
float gne = (cfa[rr - 1][cc + 1]) + 0.5f * (cfa[rr][cc] - cfa[rr - 2][cc + 2]);
float gsw = (cfa[rr + 1][cc - 1]) + 0.5f * (cfa[rr][cc] - cfa[rr + 2][cc - 2]);
vmask mask1 = vmaskf_lt(c1 + c2, thresh6v * vabsf(d1 - d2));
if (_mm_movemask_ps((vfloat)mask1)) { // if for any of the 4 pixels the condition is true, do the maths for all 4 pixels and mask the unused out at the end
//pixel interpolation
vfloat gin = LVFU(cfa[rr][cc >> 1]);
vfloat gmp2p2 = gin - LVFU(cfa[rr + 2][(cc >> 1) + 1]);
vfloat gmm2m2 = gin - LVFU(cfa[rr - 2][(cc >> 1) - 1]);
vfloat gmm2p2 = gin - LVFU(cfa[rr - 2][(cc >> 1) + 1]);
vfloat gmp2m2 = gin - LVFU(cfa[rr + 2][(cc >> 1) - 1]);
float wtse = 1.0f / (eps + SQR(cfa[rr + 2][cc + 2] - cfa[rr][cc]) + SQR(cfa[rr + 3][cc + 3] - cfa[rr + 1][cc + 1]));
float wtnw = 1.0f / (eps + SQR(cfa[rr - 2][cc - 2] - cfa[rr][cc]) + SQR(cfa[rr - 3][cc - 3] - cfa[rr - 1][cc - 1]));
float wtne = 1.0f / (eps + SQR(cfa[rr - 2][cc + 2] - cfa[rr][cc]) + SQR(cfa[rr - 3][cc + 3] - cfa[rr - 1][cc + 1]));
float wtsw = 1.0f / (eps + SQR(cfa[rr + 2][cc - 2] - cfa[rr][cc]) + SQR(cfa[rr + 3][cc - 3] - cfa[rr + 1][cc - 1]));
vfloat gse = o1_4 + zd5v * gmp2p2;
vfloat gnw = o1_1 + zd5v * gmm2m2;
vfloat gne = o1_2 + zd5v * gmm2p2;
vfloat gsw = o1_3 + zd5v * gmp2m2;
float ginterp = (gse * wtse + gnw * wtnw + gne * wtne + gsw * wtsw) / (wtse + wtnw + wtne + wtsw);
vfloat wtse = onev / (epsv + SQRV(gmp2p2) + SQRV(LVFU(cfa[rr + 3][(cc + 3) >> 1]) - o1_4));
vfloat wtnw = onev / (epsv + SQRV(gmm2m2) + SQRV(LVFU(cfa[rr - 3][(cc - 3) >> 1]) - o1_1));
vfloat wtne = onev / (epsv + SQRV(gmm2p2) + SQRV(LVFU(cfa[rr - 3][(cc + 3) >> 1]) - o1_2));
vfloat wtsw = onev / (epsv + SQRV(gmp2m2) + SQRV(LVFU(cfa[rr + 3][(cc - 3) >> 1]) - o1_3));
if ( ((ginterp - gin) < thresh * (ginterp + gin)) ) {
rawData[rr][cc] = 0.5f * (ginterp + gin);
//counter++;
vfloat ginterp = (gse * wtse + gnw * wtnw + gne * wtne + gsw * wtsw) / (wtse + wtnw + wtne + wtsw);
vfloat val = vself(vmaskf_lt(ginterp - gin, threshv * (ginterp + gin)), zd5v * (ginterp + gin), gin);
val = vself(mask1, val, gin);
STC2VFU(rawData[rr][cc], val);
}
}
// }
#endif
for (; cc < width - 6; cc += 2) {
//neighbour checking code from Manuel Llorens Garcia
float o1_1 = cfa[rr - 1][(cc - 1) >> 1];
float o1_2 = cfa[rr - 1][(cc + 1) >> 1];
float o1_3 = cfa[rr + 1][(cc - 1) >> 1];
float o1_4 = cfa[rr + 1][(cc + 1) >> 1];
float o2_1 = cfa[rr - 2][cc >> 1];
float o2_2 = cfa[rr + 2][cc >> 1];
float o2_3 = cfa[rr][(cc - 2) >> 1];
float o2_4 = cfa[rr][(cc + 2) >> 1];
float d1 = (o1_1 + o1_2) + (o1_3 + o1_4);
float d2 = (o2_1 + o2_2) + (o2_3 + o2_4);
float c1 = (fabs(o1_1 - o1_2) + fabs(o1_1 - o1_3) + fabs(o1_1 - o1_4) + fabs(o1_2 - o1_3) + fabs(o1_3 - o1_4) + fabs(o1_2 - o1_4));
float c2 = (fabs(o2_1 - o2_2) + fabs(o2_1 - o2_3) + fabs(o2_1 - o2_4) + fabs(o2_2 - o2_3) + fabs(o2_3 - o2_4) + fabs(o2_2 - o2_4));
if (c1 + c2 < thresh6 * fabs(d1 - d2)) {
//pixel interpolation
float gin = cfa[rr][cc >> 1];
float gmp2p2 = gin - cfa[rr + 2][(cc + 2) >> 1];
float gmm2m2 = gin - cfa[rr - 2][(cc - 2) >> 1];
float gmm2p2 = gin - cfa[rr - 2][(cc + 2) >> 1];
float gmp2m2 = gin - cfa[rr + 2][(cc - 2) >> 1];
float gse = o1_4 + 0.5f * gmp2p2;
float gnw = o1_1 + 0.5f * gmm2m2;
float gne = o1_2 + 0.5f * gmm2p2;
float gsw = o1_3 + 0.5f * gmp2m2;
float wtse = 1.f / (eps + SQR(gmp2p2) + SQR(cfa[rr + 3][(cc + 3) >> 1] - o1_4));
float wtnw = 1.f / (eps + SQR(gmm2m2) + SQR(cfa[rr - 3][(cc - 3) >> 1] - o1_1));
float wtne = 1.f / (eps + SQR(gmm2p2) + SQR(cfa[rr - 3][(cc + 3) >> 1] - o1_2));
float wtsw = 1.f / (eps + SQR(gmp2m2) + SQR(cfa[rr + 3][(cc - 3) >> 1] - o1_3));
float ginterp = (gse * wtse + gnw * wtnw + gne * wtne + gsw * wtsw) / (wtse + wtnw + wtne + wtsw);
if (ginterp - gin < thresh * (ginterp + gin)) {
rawData[rr][cc] = 0.5f * (ginterp + gin);
}
}
}
}
//printf("pixfix count= %d; vtest= %d \n",counter,vtest);
// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// done
/*t2 = clock();
dt = ((double)(t2-t1)) / CLOCKS_PER_SEC;
if (verbose) {
fprintf(stderr,_("elapsed time = %5.3fs\n"),dt);
}*/
}
}
}
#undef TS

View File

@ -512,8 +512,8 @@ void ImProcCoordinator::updatePreviewImage (int todo, Crop* cropCall)
}
if (needstransform)
ipf.transform (orig_prev, oprevi, 0, 0, 0, 0, pW, pH, fw, fh, imgsrc->getMetaData()->getFocalLen(),
imgsrc->getMetaData()->getFocalLen35mm(), imgsrc->getMetaData()->getFocusDist(), imgsrc->getMetaData()->getFNumber(), imgsrc->getRotateDegree(), false);
ipf.transform (orig_prev, oprevi, 0, 0, 0, 0, pW, pH, fw, fh,
imgsrc->getMetaData(), imgsrc->getRotateDegree(), false);
else {
orig_prev->copyData (oprevi);
}
@ -3820,10 +3820,10 @@ void ImProcCoordinator::getAutoCrop (double ratio, int &x, int &y, int &w, int &
MyMutex::MyLock lock (mProcessing);
LCPMapper *pLCPMap = nullptr;
LensCorrection *pLCPMap = nullptr;
if (params.lensProf.lcpFile.length() && imgsrc->getMetaData()->getFocalLen() > 0) {
LCPProfile *pLCPProf = lcpStore->getProfile (params.lensProf.lcpFile);
const std::shared_ptr<LCPProfile> pLCPProf = LCPStore::getInstance()->getProfile (params.lensProf.lcpFile);
if (pLCPProf) pLCPMap = new LCPMapper (pLCPProf, imgsrc->getMetaData()->getFocalLen(), imgsrc->getMetaData()->getFocalLen35mm(), imgsrc->getMetaData()->getFocusDist(),
0, false, params.lensProf.useDist, fullw, fullh, params.coarse, imgsrc->getRotateDegree());
@ -3921,8 +3921,8 @@ void ImProcCoordinator::saveInputICCReference (const Glib::ustring & fname, bool
if (ipf.needsTransform()) {
Imagefloat* trImg = new Imagefloat (fW, fH);
ipf.transform (im, trImg, 0, 0, 0, 0, fW, fH, fW, fH, imgsrc->getMetaData()->getFocalLen(), imgsrc->getMetaData()->getFocalLen35mm(),
imgsrc->getMetaData()->getFocusDist(), imgsrc->getMetaData()->getFNumber(), imgsrc->getRotateDegree(), true);
ipf.transform (im, trImg, 0, 0, 0, 0, fW, fH, fW, fH,
imgsrc->getMetaData(), imgsrc->getRotateDegree(), true);
delete im;
im = trImg;
}

View File

@ -847,6 +847,7 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh
} else if (curveMode == ColorAppearanceParams::TC_MODE_BRIGHT) {
//attention! Brightness curves are open - unlike Lightness or Lab or RGB==> rendering and algoritms will be different
float coef = ((aw + 4.f) * (4.f / c)) / 100.f;
float Qanc = Qpro;
float Qq = (float) Qpro * 327.68f * (1.f / coef);
float Qold100 = (float) Qpro / coef;
@ -872,8 +873,15 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh
Qq = 0.7f * (Qq - Qold) + Qold; // not zero ==>artifacts
}
Qpro = (double) (Qq * (coef) / 327.68f);
Jpro = 100.* (Qpro * Qpro) / ((4.0 / c) * (4.0 / c) * (aw + 4.0) * (aw + 4.0));
if (Qold == 0.f) {
Qold = 0.001f;
}
Qpro = Qanc * (Qq / Qold);
Jpro = Jpro * SQR (Qq / Qold);
// Qpro = (double) (Qq * (coef) / 327.68f);
// Jpro = 100.* (Qpro * Qpro) / ((4.0 / c) * (4.0 / c) * (aw + 4.0) * (aw + 4.0));
t1B = true;
if (Jpro < 1.) {
@ -928,6 +936,7 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh
}
} else if (curveMode2 == ColorAppearanceParams::TC_MODE_BRIGHT) { //
float Qanc = Qpro;
float coef = ((aw + 4.f) * (4.f / c)) / 100.f;
float Qq = (float) Qpro * 327.68f * (1.f / coef);
float Qold100 = (float) Qpro / coef;
@ -954,8 +963,16 @@ void ImProcFunctions::ciecam_02 (CieImage* ncie, double adap, int begh, int endh
Qq = 0.7f * (Qq - Qold) + Qold; // not zero ==>artifacts
}
Qpro = (double) (Qq * (coef) / 327.68f);
Jpro = 100.* (Qpro * Qpro) / ((4.0 / c) * (4.0 / c) * (aw + 4.0) * (aw + 4.0));
if (Qold == 0.f) {
Qold = 0.001f;
}
// Qpro = (float) (Qq * (coef) / 327.68f);
Qpro = Qanc * (Qq / Qold);
Jpro = Jpro * SQR (Qq / Qold);
// Qpro = (double) (Qq * (coef) / 327.68f);
// Jpro = 100.* (Qpro * Qpro) / ((4.0 / c) * (4.0 / c) * (aw + 4.0) * (aw + 4.0));
t2B = true;
if (t1L) { //to workaround the problem if we modify curve1-lightnees after curve2 brightness(the cat that bites its own tail!) in fact it's another type of curve only for this case
@ -1682,10 +1699,11 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int
}
}
if (alg >= 2 && la < 200.f) {
la = 200.f;
}
/*
if (alg >= 2 && la < 200.f) {
la = 200.f;
}
*/
const float la2 = float (params->colorappearance.adaplum);
// level of adaptation
@ -1776,6 +1794,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int
}
float sum = 0.f;
float sumQ = 0.f;
#ifdef _OPENMP
const int numThreads = min (max (width * height / 65536, 1), omp_get_max_threads());
@ -1795,7 +1814,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int
hist16Qthr.clear();
}
#pragma omp for reduction(+:sum)
#pragma omp for reduction(+:sum,sumQ)
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++) { //rough correspondence between L and J
@ -1840,11 +1859,26 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int
hist16Jthr[ (int) ((koef * lab->L[i][j]))]++; //evaluate histogram luminance L # J
}
//estimation of wh only with La
float whestim = 500.f;
if (la < 200.f) {
whestim = 200.f;
} else if (la < 2500.f) {
whestim = 350.f;
} else {
whestim = 500.f;
}
if (needQ) {
hist16Qthr[ (int) (sqrtf ((koef * (lab->L[i][j])) * 32768.f))]++; //for brightness Q : approximation for Q=wh*sqrt(J/100) J not equal L
hist16Qthr[CLIP ((int) (32768.f * sqrt ((koef * (lab->L[i][j])) / 32768.f)))]++; //for brightness Q : approximation for Q=wh*sqrt(J/100) J not equal L
//perhaps needs to introduce whestim ??
// hist16Qthr[ (int) (sqrtf ((koef * (lab->L[i][j])) * 32768.f))]++; //for brightness Q : approximation for Q=wh*sqrt(J/100) J not equal L
}
sum += koef * lab->L[i][j]; //evaluate mean J to calculate Yb
sumQ += whestim * sqrt ((koef * (lab->L[i][j])) / 32768.f);
//can be used in case of...
}
#pragma omp critical
@ -1858,14 +1892,16 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int
}
}
float meanQ;
if (std::isnan (mean)) {
mean = (sum / ((height) * width)) / 327.68f; //for Yb for all image...if one day "pipette" we can adapt Yb for each zone
meanQ = (sumQ / ((height) * width));//in case of
}
}
//evaluate lightness, contrast
}
@ -1938,6 +1974,8 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int
float cz, wh, pfl;
Ciecam02::initcam1float (gamu, yb, pilot, f, la, xw, yw, zw, n, d, nbb, ncb, cz, aw, wh, pfl, fl, c);
//printf ("wh=%f \n", wh);
const float pow1 = pow_F ( 1.64f - pow_F ( 0.29f, n ), 0.73f );
float nj, nbbj, ncbj, czj, awj, flj;
Ciecam02::initcam2float (gamu, yb2, pilotout, f2, la2, xw2, yw2, zw2, nj, dj, nbbj, ncbj, czj, awj, flj);
@ -1955,7 +1993,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int
const bool LabPassOne = ! ((params->colorappearance.tonecie && (epdEnabled)) || (params->sharpening.enabled && settings->autocielab && execsharp)
|| (params->dirpyrequalizer.enabled && settings->autocielab) || (params->defringe.enabled && settings->autocielab) || (params->sharpenMicro.enabled && settings->autocielab)
|| (params->impulseDenoise.enabled && settings->autocielab) || (params->colorappearance.badpixsl > 0 && settings->autocielab));
//printf("coQ=%f\n", coefQ);
if (needJ) {
if (!CAMBrightCurveJ) {
@ -1976,7 +2014,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int
if (CAMBrightCurveQ.dirty) {
Ciecam02::curveJfloat (params->colorappearance.qbright, params->colorappearance.qcontrast, hist16Q, CAMBrightCurveQ);//brightness and contrast Q
CAMBrightCurveQ /= coefQ;
// CAMBrightCurveQ /= coefQ;
CAMBrightCurveQ.dirty = false;
}
}
@ -2126,7 +2164,11 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int
Qpro = QproFactor * sqrtf (Jpro);
Cpro = (spro * spro * Qpro) / (10000.0f);
} else if (alg == 2) {
Qpro = CAMBrightCurveQ[ (float) (Qpro * coefQ)]; //brightness and contrast
//printf("Qp0=%f ", Qpro);
Qpro = CAMBrightCurveQ[ (float) (Qpro * coefQ)] / coefQ; //brightness and contrast
//printf("Qpaf=%f ", Qpro);
float Mp, sres;
Mp = Mpro / 100.0f;
Ciecam02::curvecolorfloat (mchr, Mp, sres, 2.5f);
@ -2140,7 +2182,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int
Qpro = (Qpro == 0.f ? epsil : Qpro); // avoid division by zero
spro = 100.0f * sqrtf ( Mpro / Qpro );
} else { /*if(alg == 3) */
Qpro = CAMBrightCurveQ[ (float) (Qpro * coefQ)]; //brightness and contrast
Qpro = CAMBrightCurveQ[ (float) (Qpro * coefQ)] / coefQ; //brightness and contrast
float Mp, sres;
Mp = Mpro / 100.0f;
@ -2217,6 +2259,7 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int
} else if (curveMode == ColorAppearanceParams::TC_MODE_BRIGHT) {
//attention! Brightness curves are open - unlike Lightness or Lab or RGB==> rendering and algoritms will be different
float coef = ((aw + 4.f) * (4.f / c)) / 100.f;
float Qanc = Qpro;
float Qq = (float) Qpro * 327.68f * (1.f / coef);
float Qold100 = (float) Qpro / coef;
@ -2242,8 +2285,13 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int
Qq = 0.7f * (Qq - Qold) + Qold; // not zero ==>artifacts
}
Qpro = (float) (Qq * (coef) / 327.68f);
Jpro = 100.f * (Qpro * Qpro) / ((4.0f / c) * (4.0f / c) * (aw + 4.0f) * (aw + 4.0f));
if (Qold == 0.f) {
Qold = 0.001f;
}
Qpro = Qanc * (Qq / Qold);
// Jpro = 100.f * (Qpro * Qpro) / ((4.0f / c) * (4.0f / c) * (aw + 4.0f) * (aw + 4.0f));
Jpro = Jpro * SQR (Qq / Qold);
if (Jpro < 1.f) {
Jpro = 1.f;
@ -2291,6 +2339,8 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int
}
} else if (curveMode2 == ColorAppearanceParams::TC_MODE_BRIGHT) { //
float Qanc = Qpro;
float coef = ((aw + 4.f) * (4.f / c)) / 100.f;
float Qq = (float) Qpro * 327.68f * (1.f / coef);
float Qold100 = (float) Qpro / coef;
@ -2317,8 +2367,15 @@ void ImProcFunctions::ciecam_02float (CieImage* ncie, float adap, int begh, int
Qq = 0.7f * (Qq - Qold) + Qold; // not zero ==>artifacts
}
Qpro = (float) (Qq * (coef) / 327.68f);
Jpro = 100.f * (Qpro * Qpro) / ((4.0f / c) * (4.0f / c) * (aw + 4.0f) * (aw + 4.0f));
if (Qold == 0.f) {
Qold = 0.001f;
}
// Qpro = (float) (Qq * (coef) / 327.68f);
Qpro = Qanc * (Qq / Qold);
Jpro = Jpro * SQR (Qq / Qold);
// Jpro = 100.f * (Qpro * Qpro) / ((4.0f / c) * (4.0f / c) * (aw + 4.0f) * (aw + 4.0f));
if (t1L) { //to workaround the problem if we modify curve1-lightnees after curve2 brightness(the cat that bites its own tail!) in fact it's another type of curve only for this case
coef = 2.f; //adapt Q to J approximation

View File

@ -54,9 +54,13 @@ class ImProcFunctions
void calcVignettingParams (int oW, int oH, const VignettingParams& vignetting, double &w2, double &h2, double& maxRadius, double &v, double &b, double &mul);
void transformPreview (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LCPMapper *pLCPMap);
enum TransformMode {
TRANSFORM_PREVIEW,
TRANSFORM_HIGH_QUALITY,
TRANSFORM_HIGH_QUALITY_FULLIMAGE
};
void transformLuminanceOnly (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int oW, int oH, int fW, int fH);
void transformHighQuality (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LCPMapper *pLCPMap, bool fullImage);
void transformGeneral(TransformMode mode, Imagefloat *original, Imagefloat *transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LensCorrection *pLCPMap);
void sharpenHaloCtrl (float** luminance, float** blurmap, float** base, int W, int H, const SharpeningParams &sharpenParam);
void sharpenHaloCtrl (LabImage* lab, float** blurmap, float** base, int W, int H, SharpeningParams &sharpenParam);
@ -70,6 +74,7 @@ class ImProcFunctions
bool needsGradient ();
bool needsVignetting ();
bool needsLCP ();
bool needsLensfun();
// static cmsUInt8Number* Mempro = NULL;
@ -236,8 +241,7 @@ public:
void colorCurve (LabImage* lold, LabImage* lnew);
void sharpening (LabImage* lab, float** buffer, SharpeningParams &sharpenParam);
void sharpeningcam (CieImage* ncie, float** buffer);
void transform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH,
double focalLen, double focalLen35mm, float focusDist, double fNumber, int rawRotationDeg, bool fullImage);
void transform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const ImageMetaData *metadata, int rawRotationDeg, bool fullImage);
float resizeScale (const ProcParams* params, int fw, int fh, int &imw, int &imh);
void lab2monitorRgb (LabImage* lab, Image8* image);
void resize (Image16* src, Image16* dst, float dScale);
@ -381,11 +385,11 @@ public:
Image16* lab2rgb16 (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool bw, GammaValues *ga = nullptr);
// CieImage *ciec;
bool transCoord (int W, int H, int x, int y, int w, int h, int& xv, int& yv, int& wv, int& hv, double ascaleDef = -1, const LCPMapper *pLCPMap = nullptr);
bool transCoord (int W, int H, const std::vector<Coord2D> &src, std::vector<Coord2D> &red, std::vector<Coord2D> &green, std::vector<Coord2D> &blue, double ascaleDef = -1, const LCPMapper *pLCPMap = nullptr);
bool transCoord (int W, int H, int x, int y, int w, int h, int& xv, int& yv, int& wv, int& hv, double ascaleDef = -1, const LensCorrection *pLCPMap = nullptr);
bool transCoord (int W, int H, const std::vector<Coord2D> &src, std::vector<Coord2D> &red, std::vector<Coord2D> &green, std::vector<Coord2D> &blue, double ascaleDef = -1, const LensCorrection *pLCPMap = nullptr);
static void getAutoExp (const LUTu & histogram, int histcompr, double defgain, double clip, double& expcomp, int& bright, int& contr, int& black, int& hlcompr, int& hlcomprthresh);
static double getAutoDistor (const Glib::ustring& fname, int thumb_size);
double getTransformAutoFill (int oW, int oH, const LCPMapper *pLCPMap = nullptr);
double getTransformAutoFill (int oW, int oH, const LensCorrection *pLCPMap = nullptr);
void rgb2lab (const Imagefloat &src, LabImage &dst, const Glib::ustring &workingSpace);
void lab2rgb (const LabImage &src, Imagefloat &dst, const Glib::ustring &workingSpace);
};

View File

@ -30,6 +30,7 @@
#include "rtthumbnail.h"
#include "profilestore.h"
#include "../rtgui/threadutils.h"
#include "rtlensfun.h"
namespace rtengine
{
@ -50,6 +51,7 @@ int init (const Settings* s, Glib::ustring baseDir, Glib::ustring userSettingsDi
Color::init ();
PerceptualToneCurve::init ();
RawImageSource::init ();
LFDatabase::init();
delete lcmsMutex;
lcmsMutex = new MyMutex;
dfm.init( s->darkFramesPath );

View File

@ -24,6 +24,7 @@
#include "mytime.h"
#include "rt_math.h"
#include "sleef.c"
#include "rtlensfun.h"
using namespace std;
@ -86,18 +87,6 @@ float normn (float a, float b, int n)
}
void correct_distortion(const rtengine::LCPMapper *lcp, double &x, double &y,
int cx, int cy, double scale)
{
assert (lcp);
x += cx;
y += cy;
lcp->correctDistortion(x, y, scale);
x -= (cx * scale);
y -= (cy * scale);
}
}
namespace rtengine
@ -107,7 +96,7 @@ namespace rtengine
#define CLIPTOC(a,b,c,d) ((a)>=(b)?((a)<=(c)?(a):(d=true,(c))):(d=true,(b)))
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 LCPMapper *pLCPMap)
const LensCorrection *pLCPMap)
{
bool clipped = false;
@ -157,7 +146,7 @@ bool ImProcFunctions::transCoord (int W, int H, const std::vector<Coord2D> &src,
double x_d = src[i].x, y_d = src[i].y;
if (pLCPMap && params->lensProf.useDist) {
correct_distortion (pLCPMap, x_d, y_d, 0, 0, ascale);
pLCPMap->correctDistortion(x_d, y_d, 0, 0, ascale);
} else {
x_d *= ascale;
y_d *= ascale;
@ -209,7 +198,7 @@ bool ImProcFunctions::transCoord (int W, int H, const std::vector<Coord2D> &src,
}
// Transform all corners and critical sidelines of an image
bool ImProcFunctions::transCoord (int W, int H, int x, int y, int w, int h, int& xv, int& yv, int& wv, int& hv, double ascaleDef, const LCPMapper *pLCPMap)
bool ImProcFunctions::transCoord (int W, int H, int x, int y, int w, int h, int& xv, int& yv, int& wv, int& hv, double ascaleDef, const LensCorrection *pLCPMap)
{
const int DivisionsPerBorder = 32;
@ -307,32 +296,44 @@ bool ImProcFunctions::transCoord (int W, int H, int x, int y, int w, int h, int&
}
void ImProcFunctions::transform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH,
double focalLen, double focalLen35mm, float focusDist, double fNumber, int rawRotationDeg, bool fullImage)
const ImageMetaData *metadata,
int rawRotationDeg, bool fullImage)
{
double focalLen = metadata->getFocalLen();
double focalLen35mm = metadata->getFocalLen35mm();
float focusDist = metadata->getFocusDist();
double fNumber = metadata->getFNumber();
LCPMapper *pLCPMap = nullptr;
std::unique_ptr<const LensCorrection> pLCPMap;
if (needsLCP()) { // don't check focal length to allow distortion correction for lenses without chip
LCPProfile *pLCPProf = lcpStore->getProfile (params->lensProf.lcpFile);
if (needsLensfun()) {
pLCPMap = std::move(LFDatabase::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);
if (pLCPProf) {
pLCPMap = new LCPMapper (pLCPProf, focalLen, focalLen35mm,
focusDist, fNumber, false,
params->lensProf.useDist,
oW, oH, params->coarse, rawRotationDeg);
pLCPMap.reset(
new LCPMapper (pLCPProf, focalLen, focalLen35mm,
focusDist, fNumber, false,
params->lensProf.useDist,
oW, oH, params->coarse, rawRotationDeg
)
);
}
}
if (! (needsCA() || needsDistortion() || needsRotation() || needsPerspective() || needsLCP()) && (needsVignetting() || needsPCVignetting() || needsGradient())) {
if (! (needsCA() || needsDistortion() || needsRotation() || needsPerspective() || needsLCP() || needsLensfun()) && (needsVignetting() || needsPCVignetting() || needsGradient())) {
transformLuminanceOnly (original, transformed, cx, cy, oW, oH, fW, fH);
} else if (!needsCA() && scale != 1) {
transformPreview (original, transformed, cx, cy, sx, sy, oW, oH, fW, fH, pLCPMap);
} else {
transformHighQuality (original, transformed, cx, cy, sx, sy, oW, oH, fW, fH, pLCPMap, fullImage);
}
if (pLCPMap) {
delete pLCPMap;
TransformMode mode;
if (!needsCA() && scale != 1) {
mode = TRANSFORM_PREVIEW;
} else if (!fullImage) {
mode = TRANSFORM_HIGH_QUALITY;
} else {
mode = TRANSFORM_HIGH_QUALITY_FULLIMAGE;
}
transformGeneral(mode, original, transformed, cx, cy, sx, sy, oW, oH, fW, fH, pLCPMap.get());
}
}
@ -721,9 +722,8 @@ void ImProcFunctions::transformLuminanceOnly (Imagefloat* original, Imagefloat*
}
}
// Transform WITH scaling (opt.) and CA, cubic interpolation
void ImProcFunctions::transformHighQuality (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH,
const LCPMapper *pLCPMap, bool fullImage)
void ImProcFunctions::transformGeneral(ImProcFunctions::TransformMode mode, Imagefloat *original, Imagefloat *transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LensCorrection *pLCPMap)
{
double w2 = (double) oW / 2.0 - 0.5;
double h2 = (double) oH / 2.0 - 0.5;
@ -781,17 +781,38 @@ void ImProcFunctions::transformHighQuality (Imagefloat* original, Imagefloat* tr
oH * tan (hpalpha) * sqrt (SQR (4 * maxRadius) + SQR (oH * tan (hpalpha)))) / (SQR (maxRadius) * 8)));
double hpcospt = (hpdeg >= 0 ? 1.0 : -1.0) * cos (hpteta), hptanpt = tan (hpteta);
double ascale = params->commonTrans.autofill ? getTransformAutoFill (oW, oH, true /*fullImage*/ ? pLCPMap : nullptr) : 1.0;
double ascale = params->commonTrans.autofill ? getTransformAutoFill (oW, oH, pLCPMap) : 1.0;
// smaller crop images are a problem, so only when processing fully
bool enableLCPCA = pLCPMap && params->lensProf.useCA && fullImage && pLCPMap->enableCA;
bool enableLCPDist = pLCPMap && params->lensProf.useDist; // && fullImage;
bool enableLCPCA = false;
bool enableLCPDist = false;
bool enableCA = false;
if (enableLCPCA) {
enableLCPDist = false;
switch (mode) {
case ImProcFunctions::TRANSFORM_HIGH_QUALITY_FULLIMAGE: {
enableLCPCA = pLCPMap && params->lensProf.useCA && pLCPMap->isCACorrectionAvailable();
}
//no break on purpose
case ImProcFunctions::TRANSFORM_HIGH_QUALITY: {
enableLCPDist = pLCPMap && params->lensProf.useDist;
if (enableLCPCA) {
enableLCPDist = false;
}
enableCA = enableLCPCA || needsCA();
}
//no break on purpose
default:
case ImProcFunctions::TRANSFORM_PREVIEW: {
enableLCPDist = pLCPMap && params->lensProf.useDist;
break;
}
}
bool enableCA = enableLCPCA || needsCA();
if (!enableCA) {
chDist[0] = 0.0;
}
// main cycle
bool darkening = (params->vignetting.amount <= 0.0);
@ -802,7 +823,7 @@ void ImProcFunctions::transformHighQuality (Imagefloat* original, Imagefloat* tr
double x_d = x, y_d = y;
if (enableLCPDist) {
correct_distortion(pLCPMap, x_d, y_d, cx, cy, ascale); // must be first transform
pLCPMap->correctDistortion(x_d, y_d, cx, cy, ascale); // must be first transform
} else {
x_d *= ascale;
y_d *= ascale;
@ -895,6 +916,10 @@ void ImProcFunctions::transformHighQuality (Imagefloat* original, Imagefloat* tr
// all interpolation pixels inside image
if (enableCA) {
interpolateTransformChannelsCubic (chOrig[c], xc - 1, yc - 1, Dx, Dy, & (chTrans[c][y][x]), vignmul);
} else if (mode == ImProcFunctions::TRANSFORM_PREVIEW) {
transformed->r (y, x) = vignmul * (original->r (yc, xc) * (1.0 - Dx) * (1.0 - Dy) + original->r (yc, xc + 1) * Dx * (1.0 - Dy) + original->r (yc + 1, xc) * (1.0 - Dx) * Dy + original->r (yc + 1, xc + 1) * Dx * Dy);
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 {
interpolateTransformCubic (original, xc - 1, yc - 1, Dx, Dy, & (transformed->r (y, x)), & (transformed->g (y, x)), & (transformed->b (y, x)), vignmul);
}
@ -928,168 +953,8 @@ void ImProcFunctions::transformHighQuality (Imagefloat* original, Imagefloat* tr
}
}
// Transform WITH scaling, WITHOUT CA, simple (and fast) interpolation. Used for preview
void ImProcFunctions::transformPreview (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH, int fW, int fH, const LCPMapper *pLCPMap)
{
double w2 = (double) oW / 2.0 - 0.5;
double h2 = (double) oH / 2.0 - 0.5;
double vig_w2, vig_h2, maxRadius, v, b, mul;
calcVignettingParams (oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul);
struct grad_params gp;
if (needsGradient()) {
calcGradientParams (oW, oH, params->gradient, gp);
}
struct pcv_params pcv;
if (needsPCVignetting()) {
calcPCVignetteParams (fW, fH, oW, oH, params->pcvignette, params->crop, pcv);
}
// auxiliary variables for distortion correction
bool needsDist = needsDistortion(); // for performance
double distAmount = params->distortion.amount;
// auxiliary variables for rotation
double cost = cos (params->rotate.degree * rtengine::RT_PI / 180.0);
double sint = sin (params->rotate.degree * rtengine::RT_PI / 180.0);
// auxiliary variables for vertical perspective correction
double vpdeg = params->perspective.vertical / 100.0 * 45.0;
double vpalpha = (90 - vpdeg) / 180.0 * rtengine::RT_PI;
double vpteta = fabs (vpalpha - rtengine::RT_PI / 2) < 3e-4 ? 0.0 : acos ((vpdeg > 0 ? 1.0 : -1.0) * sqrt ((-oW * oW * tan (vpalpha) * tan (vpalpha) + (vpdeg > 0 ? 1.0 : -1.0) * oW * tan (vpalpha) * sqrt (16 * maxRadius * maxRadius + oW * oW * tan (vpalpha) * tan (vpalpha))) / (maxRadius * maxRadius * 8)));
double vpcospt = (vpdeg >= 0 ? 1.0 : -1.0) * cos (vpteta), vptanpt = tan (vpteta);
// auxiliary variables for horizontal perspective correction
double hpdeg = params->perspective.horizontal / 100.0 * 45.0;
double hpalpha = (90 - hpdeg) / 180.0 * rtengine::RT_PI;
double hpteta = fabs (hpalpha - rtengine::RT_PI / 2) < 3e-4 ? 0.0 : acos ((hpdeg > 0 ? 1.0 : -1.0) * sqrt ((-oH * oH * tan (hpalpha) * tan (hpalpha) + (hpdeg > 0 ? 1.0 : -1.0) * oH * tan (hpalpha) * sqrt (16 * maxRadius * maxRadius + oH * oH * tan (hpalpha) * tan (hpalpha))) / (maxRadius * maxRadius * 8)));
double hpcospt = (hpdeg >= 0 ? 1.0 : -1.0) * cos (hpteta), hptanpt = tan (hpteta);
double ascale = params->commonTrans.autofill ? getTransformAutoFill (oW, oH, pLCPMap) : 1.0;
bool darkening = (params->vignetting.amount <= 0.0);
// main cycle
#pragma omp parallel for if (multiThread)
for (int y = 0; y < transformed->getHeight(); y++) {
for (int x = 0; x < transformed->getWidth(); x++) {
double x_d = x, y_d = y;
if (pLCPMap && params->lensProf.useDist) {
correct_distortion(pLCPMap, x_d, y_d, cx, cy, ascale); // must be first transform
} else {
x_d *= ascale;
y_d *= ascale;
}
x_d += ascale * (cx - w2); // centering x coord & scale
y_d += ascale * (cy - h2); // centering y coord & scale
double vig_x_d = 0., vig_y_d = 0.;
if (needsVignetting()) {
vig_x_d = ascale * (x + cx - vig_w2); // centering x coord & scale
vig_y_d = ascale * (y + cy - vig_h2); // centering y coord & scale
}
if (needsPerspective()) {
// horizontal perspective transformation
y_d *= maxRadius / (maxRadius + x_d * hptanpt);
x_d *= maxRadius * hpcospt / (maxRadius + x_d * hptanpt);
// vertical perspective transformation
x_d *= maxRadius / (maxRadius - y_d * vptanpt);
y_d *= maxRadius * vpcospt / (maxRadius - y_d * vptanpt);
}
// rotate
double Dx = x_d * cost - y_d * sint;
double Dy = x_d * sint + y_d * cost;
// distortion correction
double s = 1;
if (needsDist) {
double r = sqrt (Dx * Dx + Dy * Dy) / maxRadius; // sqrt is slow
s = 1.0 - distAmount + distAmount * r ;
Dx *= s;
Dy *= s;
}
double r2 = 0.;
if (needsVignetting()) {
double vig_Dx = vig_x_d * cost - vig_y_d * sint;
double vig_Dy = vig_x_d * sint + vig_y_d * cost;
r2 = sqrt (vig_Dx * vig_Dx + vig_Dy * vig_Dy);
}
// de-center
Dx += w2;
Dy += h2;
// Extract integer and fractions of source screen coordinates
int xc = (int)Dx;
Dx -= (double)xc;
xc -= sx;
int yc = (int)Dy;
Dy -= (double)yc;
yc -= sy;
// Convert only valid pixels
if (yc >= 0 && yc < original->getHeight() && xc >= 0 && xc < original->getWidth()) {
// multiplier for vignetting correction
double vignmul = 1.0;
if (needsVignetting()) {
if (darkening) {
vignmul /= std::max (v + mul * tanh (b * (maxRadius - s * r2) / maxRadius), 0.001);
} else {
vignmul = v + mul * tanh (b * (maxRadius - s * r2) / maxRadius);
}
}
if (needsGradient()) {
vignmul *= calcGradientFactor (gp, cx + x, cy + y);
}
if (needsPCVignetting()) {
vignmul *= calcPCVignetteFactor (pcv, cx + x, cy + y);
}
if (yc < original->getHeight() - 1 && xc < original->getWidth() - 1) {
// all interpolation pixels inside image
transformed->r (y, x) = vignmul * (original->r (yc, xc) * (1.0 - Dx) * (1.0 - Dy) + original->r (yc, xc + 1) * Dx * (1.0 - Dy) + original->r (yc + 1, xc) * (1.0 - Dx) * Dy + original->r (yc + 1, xc + 1) * Dx * Dy);
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 {
// 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);
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);
transformed->g (y, x) = vignmul * (original->g (y1, x1) * (1.0 - Dx) * (1.0 - Dy) + original->g (y1, x2) * Dx * (1.0 - Dy) + original->g (y2, x1) * (1.0 - Dx) * Dy + original->g (y2, x2) * Dx * Dy);
transformed->b (y, x) = vignmul * (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 {
// not valid (source pixel x,y not inside source image, etc.)
transformed->r (y, x) = 0;
transformed->g (y, x) = 0;
transformed->b (y, x) = 0;
}
}
}
}
double ImProcFunctions::getTransformAutoFill (int oW, int oH, const LCPMapper *pLCPMap)
double ImProcFunctions::getTransformAutoFill (int oW, int oH, const LensCorrection *pLCPMap)
{
if (!needsCA() && !needsDistortion() && !needsRotation() && !needsPerspective() && (!params->lensProf.useDist || pLCPMap == nullptr)) {
return 1;
@ -1150,12 +1015,17 @@ bool ImProcFunctions::needsVignetting ()
bool ImProcFunctions::needsLCP ()
{
return params->lensProf.lcpFile.length() > 0;
return params->lensProf.lcpFile.length() > 0 && !needsLensfun();
}
bool ImProcFunctions::needsLensfun()
{
return params->lensProf.useLensfun;
}
bool ImProcFunctions::needsTransform ()
{
return needsCA () || needsDistortion () || needsRotation () || needsPerspective () || needsGradient () || needsPCVignetting () || needsVignetting () || needsLCP();
return needsCA () || needsDistortion () || needsRotation () || needsPerspective () || needsGradient () || needsPCVignetting () || needsVignetting () || needsLCP() || needsLensfun();
}

File diff suppressed because it is too large Load Diff

View File

@ -21,27 +21,45 @@
#include <array>
#include <map>
#include <memory>
#include <string>
#include <sstream>
#include <glibmm.h>
#include <expat.h>
#include "cache.h"
#include "imagefloat.h"
#include "opthelper.h"
namespace rtengine
{
enum class LCPCorrectionMode {
VIGNETTE,
DISTORTION,
CA
};
// Perspective model common data, also used for Vignette and Fisheye
class LCPModelCommon final
{
public:
LCPModelCommon();
bool empty() const; // is it empty
void print() const; // printf all values
void merge(const LCPModelCommon& a, const LCPModelCommon& b, float facA);
void prepareParams(int fullWidth, int fullHeight, float focalLength, float focalLength35mm, float sensorFormatFactor, bool swapXY, bool mirrorX, bool mirrorY);
void prepareParams(
int fullWidth,
int fullHeight,
float focalLength,
float focalLength35mm,
float sensorFormatFactor,
bool swapXY,
bool mirrorX,
bool mirrorY
);
//private:
using Param = std::array<float, 5>;
@ -66,97 +84,125 @@ public:
VignParam vign_param;
};
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();
bool hasModeData(int mode) const;
void print() const;
};
class LCPProfile
{
// Temporary data for parsing
bool inCamProfiles, firstLIDone, inPerspect, inAlternateLensID, inAlternateLensNames;
char lastTag[256], inInvalidTag[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);
int filterBadFrames(double maxAvgDevFac, int minFramesLeft);
void handle_text(std::string text);
std::ostringstream textbuf;
public:
explicit LCPProfile(const Glib::ustring& fname);
~LCPProfile();
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;
//private:
// Common data
Glib::ustring profileName, lensPrettyName, cameraPrettyName, lens, camera; // lens/camera(=model) can be auto-matched with DNG
bool isRaw, isFisheye;
Glib::ustring profileName;
Glib::ustring lensPrettyName;
Glib::ustring cameraPrettyName;
Glib::ustring lens;
Glib::ustring camera; // lens/camera(=model) can be auto-matched with DNG
bool isRaw;
bool isFisheye;
float sensorFormatFactor;
int persModelCount;
private:
class LCPPersModel;
int filterBadFrames(LCPCorrectionMode mode, double maxAvgDevFac, int minFramesLeft);
void handle_text(const std::string& text);
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);
// Temporary data for parsing
bool inCamProfiles;
bool firstLIDone;
bool inPerspect;
bool inAlternateLensID;
bool inAlternateLensNames;
char lastTag[256];
char inInvalidTag[256];
LCPPersModel* pCurPersModel;
LCPModelCommon* pCurCommon;
std::ostringstream textbuf;
// The correction frames
static const int MaxPersModelCount = 3000;
static constexpr int MaxPersModelCount = 3000;
LCPPersModel* aPersModel[MaxPersModelCount]; // Do NOT use std::list or something, it's buggy in GCC!
explicit LCPProfile(const Glib::ustring &fname);
~LCPProfile();
void calcParams(int mode, float focalLength, float focusDist, float aperture, LCPModelCommon *pCorr1, LCPModelCommon *pCorr2, LCPModelCommon *pCorr3) const; // Interpolates between the persModels frames
void print() const;
};
class LCPStore
{
MyMutex mtx;
public:
static LCPStore* getInstance();
bool isValidLCPFileName(const Glib::ustring& filename) const;
std::shared_ptr<LCPProfile> getProfile(const Glib::ustring& filename) const;
Glib::ustring getDefaultCommonDirectory() const;
private:
LCPStore(unsigned int _cache_size = 32);
// Maps file name to profile as cache
std::map<Glib::ustring, LCPProfile*> profileCache;
public:
~LCPStore();
Glib::ustring getDefaultCommonDirectory() const;
bool isValidLCPFileName(Glib::ustring filename) const;
LCPProfile* getProfile(Glib::ustring filename);
static LCPStore* getInstance();
mutable Cache<Glib::ustring, std::shared_ptr<LCPProfile>> cache;
};
#define lcpStore LCPStore::getInstance()
class LensCorrection {
public:
virtual ~LensCorrection() {}
virtual void correctDistortion(double &x, double &y, int cx, int cy, double scale) const = 0;
virtual bool isCACorrectionAvailable() const = 0;
virtual void correctCA(double &x, double &y, int channel) const = 0;
virtual void processVignetteLine(int width, int y, float *line) const = 0;
virtual void processVignetteLine3Channels(int width, int y, float *line) const = 0;
};
// Once precalculated class to correct a point
class LCPMapper
class LCPMapper: public LensCorrection
{
public:
// Precalculates the mapper
LCPMapper(
const std::shared_ptr<LCPProfile>& pProf,
float focalLength,
float focalLength35mm,
float focusDist,
float aperture,
bool vignette,
bool useCADistP,
int fullWidth,
int fullHeight,
const CoarseTransformParams& coarse,
int rawRotationDeg
);
void correctDistortion(double &x, double &y, int cx, int cy, double scale) const; // MUST be the first stage
bool isCACorrectionAvailable() const;
void correctCA(double& x, double& y, int channel) const;
void processVignetteLine(int width, int y, float* line) const;
void processVignetteLine3Channels(int width, int y, float* line) const;
private:
bool enableCA; // is the mapper capable if CA correction?
bool useCADist; // should the distortion in the CA info be used?
bool swapXY;
LCPModelCommon mc;
LCPModelCommon chrom[3]; // in order RedGreen/Green/BlueGreen
bool isFisheye;
public:
bool enableCA; // is the mapper capable if CA correction?
// precalculates the mapper.
LCPMapper(LCPProfile* pProf, float focalLength, float focalLength35mm, float focusDist, float aperture, bool vignette, bool useCADistP, int fullWidth, int fullHeight,
const CoarseTransformParams& coarse, int rawRotationDeg);
void correctDistortion(double& x, double& y, double scale) const; // MUST be the first stage
void correctCA(double& x, double& y, int channel) const;
void processVignetteLine(int width, int y, float *line) const;
void processVignetteLine3Channels(int width, int y, float *line) const;
};
}

View File

@ -511,94 +511,97 @@ enum ProcEvent {
EvCATgreensc = 481,
EvCATybscen = 482,
EvCATAutoyb = 483,
EvlocallabEnabled = 484,
EvlocallablocY = 485,
EvlocallablocX = 486,
EvlocallabCenter = 487,
EvlocallabDegree = 488,
Evlocallablightness = 489,
Evlocallabcontrast = 490,
Evlocallabchroma = 491,
Evlocallabtransit = 492,
Evlocallabavoid = 493,
EvlocallablocYT = 494,
EvlocallablocXL = 495,
EvlocallabSmet = 496,
Evlocallabinvers = 497,
Evlocallabradius = 498,
Evlocallabinversrad = 499,
Evlocallabstrength = 500,
Evlocallabsensi = 501,
EvlocallabretinexMethod = 502,
Evlocallabstr = 503,
Evlocallabneigh = 504,
Evlocallabvart = 505,
EvlocallabCTgainCurve = 506,
Evlocallabchrrt = 507,
Evlocallabinversret = 508,
Evlocallabsensih = 509,
Evlocallabnbspot = 510,
Evlocallabactivlum = 511,
Evlocallabanbspot = 512,
Evlocallabsharradius = 513,
Evlocallabsharamount = 514,
Evlocallabshardamping = 515,
Evlocallabshariter = 516,
Evlocallabsensis = 517,
Evlocallabinverssha = 518,
Evlocallabcircrad = 519,
Evlocallabthres = 520,
Evlocallabproxi = 521,
EvlocallabqualityMethod = 522,
Evlocallabnoiselumf = 523,
Evlocallabnoiselumc = 524,
Evlocallabnoisechrof = 525,
Evlocallabnoisechroc = 526,
EvlocallabThresho = 527,
EvlocallabEqualizer = 528,
Evlocallabsensicb = 529,
Evlocallabsensibn = 530,
Evlocallabstren = 531,
Evlocallabgamma = 532,
Evlocallabestop = 533,
Evlocallabscaltm = 534,
Evlocallabrewei = 535,
Evlocallabsensitm = 536,
EvlocallabCTgainCurverab = 537,
Evlocallabretrab = 538,
Evlocallabllshape = 539,
EvLocenacolor = 540,
EvLocenablur = 541,
EvLocenatonemap = 542,
EvLocenareti = 543,
EvLocenasharp = 544,
EvLocenacbdl = 545,
EvLocenadenoi = 546,
EvlocallabLHshape = 547,
Evlocallabcurvactiv = 548,
Evlocallabccshape = 549,
EvlocallabqualitycurveMethod = 550,
Evlocallabhueref = 551,
Evlocallabchromaref = 552,
Evlocallablumaref = 553,
EvlocallabHHshape = 554,
EvLocenavibrance = 555,
EvlocallabSkinTonesCurve = 556,
EvlocallabProtectSkins = 557,
EvlocallabAvoidColorShift = 558,
EvlocallabPastSatTog = 559,
EvlocallabPastels = 560,
EvlocallabSaturated = 561,
EvlocallabPastSatThreshold = 562,
Evlocallabsensiv = 563,
EvLocenaexpose = 564,
Evlocallabexpcomp = 565,
Evlocallabhlcompr = 566,
Evlocallabhlcomprthresh = 567,
Evlocallabblack = 568,
Evlocallabshcompr = 569,
Evlocallabsensiex = 570,
Evlocallabshape = 571,
EvLensCorrMode = 484,
EvLensCorrLensfunCamera = 485,
EvLensCorrLensfunLens = 486,
EvlocallabEnabled = 487,
EvlocallablocY = 488,
EvlocallablocX = 489,
EvlocallabCenter = 490,
EvlocallabDegree = 491,
Evlocallablightness = 492,
Evlocallabcontrast = 493,
Evlocallabchroma = 494,
Evlocallabtransit = 495,
Evlocallabavoid = 496,
EvlocallablocYT = 497,
EvlocallablocXL = 498,
EvlocallabSmet = 499,
Evlocallabinvers = 500,
Evlocallabradius = 501,
Evlocallabinversrad = 502,
Evlocallabstrength = 503,
Evlocallabsensi = 504,
EvlocallabretinexMethod = 505,
Evlocallabstr = 506,
Evlocallabneigh = 507,
Evlocallabvart = 508,
EvlocallabCTgainCurve = 509,
Evlocallabchrrt = 510,
Evlocallabinversret = 511,
Evlocallabsensih = 512,
Evlocallabnbspot = 513,
Evlocallabactivlum = 514,
Evlocallabanbspot = 515,
Evlocallabsharradius = 516,
Evlocallabsharamount = 517,
Evlocallabshardamping = 518,
Evlocallabshariter = 519,
Evlocallabsensis = 520,
Evlocallabinverssha = 521,
Evlocallabcircrad = 522,
Evlocallabthres = 523,
Evlocallabproxi = 524,
EvlocallabqualityMethod = 525,
Evlocallabnoiselumf = 526,
Evlocallabnoiselumc = 527,
Evlocallabnoisechrof = 528,
Evlocallabnoisechroc = 529,
EvlocallabThresho = 530,
EvlocallabEqualizer = 531,
Evlocallabsensicb = 532,
Evlocallabsensibn = 533,
Evlocallabstren = 534,
Evlocallabgamma = 535,
Evlocallabestop = 536,
Evlocallabscaltm = 537,
Evlocallabrewei = 538,
Evlocallabsensitm = 539,
EvlocallabCTgainCurverab = 540,
Evlocallabretrab = 541,
Evlocallabllshape = 542,
EvLocenacolor = 543,
EvLocenablur = 544,
EvLocenatonemap = 545,
EvLocenareti = 546,
EvLocenasharp = 547,
EvLocenacbdl = 548,
EvLocenadenoi = 549,
EvlocallabLHshape = 550,
Evlocallabcurvactiv = 551,
Evlocallabccshape = 552,
EvlocallabqualitycurveMethod = 553,
Evlocallabhueref = 554,
Evlocallabchromaref = 555,
Evlocallablumaref = 556,
EvlocallabHHshape = 557,
EvLocenavibrance = 558,
EvlocallabSkinTonesCurve = 559,
EvlocallabProtectSkins = 560,
EvlocallabAvoidColorShift = 561,
EvlocallabPastSatTog = 562,
EvlocallabPastels = 563,
EvlocallabSaturated = 564,
EvlocallabPastSatThreshold = 565,
Evlocallabsensiv = 566,
EvLocenaexpose = 567,
Evlocallabexpcomp = 568,
Evlocallabhlcompr = 569,
Evlocallabhlcomprthresh = 570,
Evlocallabblack = 571,
Evlocallabshcompr = 572,
Evlocallabsensiex = 573,
Evlocallabshape = 574,
NUMOFEVENTS

View File

@ -922,6 +922,11 @@ void LensProfParams::setDefaults()
lcpFile = "";
useDist = useVign = true;
useCA = false;
useLensfun = false;
lfAutoMatch = true;
lfCameraMake = "";
lfCameraModel = "";
lfLens = "";
}
void CoarseTransformParams::setDefaults()
@ -2827,6 +2832,22 @@ int ProcParams::save (const Glib::ustring &fname, const Glib::ustring &fname2, b
keyFile.set_boolean ("LensProfile", "UseCA", lensProf.useCA);
}
if (!pedited || pedited->lensProf.useLensfun) {
keyFile.set_boolean("LensProfile", "UseLensfun", lensProf.useLensfun);
}
if (!pedited || pedited->lensProf.lfAutoMatch) {
keyFile.set_boolean("LensProfile", "LFAutoMatch", lensProf.lfAutoMatch);
}
if (!pedited || pedited->lensProf.lfCameraMake) {
keyFile.set_string("LensProfile", "LFCameraMake", lensProf.lfCameraMake);
}
if (!pedited || pedited->lensProf.lfCameraModel) {
keyFile.set_string("LensProfile", "LFCameraModel", lensProf.lfCameraModel);
}
if (!pedited || pedited->lensProf.lfLens) {
keyFile.set_string("LensProfile", "LFLens", lensProf.lfLens);
}
// save perspective correction
if (!pedited || pedited->perspective.horizontal) {
keyFile.set_double ("Perspective", "Horizontal", perspective.horizontal);
@ -7197,6 +7218,41 @@ int ProcParams::load (const Glib::ustring &fname, ParamsEdited* pedited)
pedited->lensProf.useCA = true;
}
}
if (keyFile.has_key("LensProfile", "UseLensfun")) {
lensProf.useLensfun = keyFile.get_boolean("LensProfile", "UseLensfun");
if (pedited) {
pedited->lensProf.useLensfun = true;
}
}
if (keyFile.has_key("LensProfile", "LFAutoMatch")) {
lensProf.lfAutoMatch = keyFile.get_boolean("LensProfile", "LFAutoMatch");
if (pedited) {
pedited->lensProf.lfAutoMatch = true;
}
}
if (keyFile.has_key("LensProfile", "LFCameraMake")) {
lensProf.lfCameraMake = keyFile.get_string("LensProfile", "LFCameraMake");
if (pedited) {
pedited->lensProf.lfCameraMake = true;
}
}
if (keyFile.has_key("LensProfile", "LFCameraModel")) {
lensProf.lfCameraModel = keyFile.get_string("LensProfile", "LFCameraModel");
if (pedited) {
pedited->lensProf.lfCameraModel = true;
}
}
if (keyFile.has_key("LensProfile", "LFLens")) {
lensProf.lfLens = keyFile.get_string("LensProfile", "LFLens");
if (pedited) {
pedited->lensProf.lfLens = true;
}
}
}
// load perspective correction
@ -9813,6 +9869,11 @@ bool ProcParams::operator== (const ProcParams& other)
&& lensProf.useDist == other.lensProf.useDist
&& lensProf.useVign == other.lensProf.useVign
&& lensProf.useCA == other.lensProf.useCA
&& lensProf.useLensfun == other.lensProf.useLensfun
&& lensProf.lfAutoMatch == other.lensProf.lfAutoMatch
&& lensProf.lfCameraMake == other.lensProf.lfCameraMake
&& lensProf.lfCameraModel == other.lensProf.lfCameraModel
&& lensProf.lfLens == other.lensProf.lfLens
&& perspective.horizontal == other.perspective.horizontal
&& perspective.vertical == other.perspective.vertical
&& gradient.enabled == other.gradient.enabled

View File

@ -836,6 +836,11 @@ class LensProfParams
public:
Glib::ustring lcpFile;
bool useDist, useVign, useCA;
bool useLensfun;
bool lfAutoMatch;
Glib::ustring lfCameraMake;
Glib::ustring lfCameraModel;
Glib::ustring lfLens;
LensProfParams()
{
@ -844,6 +849,7 @@ public:
void setDefaults();
};
/**
* Parameters of the perspective correction
*/

View File

@ -33,6 +33,7 @@
#include "dcp.h"
#include "rt_math.h"
#include "improcfun.h"
#include "rtlensfun.h"
#ifdef _OPENMP
#include <omp.h>
#endif
@ -1863,11 +1864,19 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le
// Correct vignetting of lens profile
if (!hasFlatField && lensProf.useVign) {
LCPProfile *pLCPProf = lcpStore->getProfile (lensProf.lcpFile);
std::unique_ptr<LensCorrection> pmap;
if (lensProf.useLensfun) {
pmap = std::move(LFDatabase::findModifier(lensProf, idata, W, H, coarse, -1));
} else {
const std::shared_ptr<LCPProfile> pLCPProf = LCPStore::getInstance()->getProfile(lensProf.lcpFile);
if (pLCPProf) { // don't check focal length to allow distortion correction for lenses without chip, also pass dummy focal length 1 in case of 0
LCPMapper map (pLCPProf, max (idata->getFocalLen(), 1.0), idata->getFocalLen35mm(), idata->getFocusDist(), idata->getFNumber(), true, false, W, H, coarse, -1);
if (pLCPProf) { // don't check focal length to allow distortion correction for lenses without chip, also pass dummy focal length 1 in case of 0
pmap.reset(new LCPMapper(pLCPProf, max(idata->getFocalLen(), 1.0), idata->getFocalLen35mm(), idata->getFocusDist(), idata->getFNumber(), true, false, W, H, coarse, -1));
}
}
if (pmap) {
LensCorrection &map = *pmap;
if (ri->getSensorType() == ST_BAYER || ri->getSensorType() == ST_FUJI_XTRANS || ri->get_colors() == 1) {
if (numFrames == 4) {
for (int i = 0; i < 4; ++i) {
@ -1921,42 +1930,16 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le
}
}
// check if it is an olympus E camera, if yes, compute G channel pre-compensation factors
if ( ri->getSensorType() == ST_BAYER && (raw.bayersensor.greenthresh || (((idata->getMake().size() >= 7 && idata->getMake().substr (0, 7) == "OLYMPUS" && idata->getModel()[0] == 'E') || (idata->getMake().size() >= 9 && idata->getMake().substr (0, 9) == "Panasonic")) && raw.bayersensor.method != RAWParams::BayerSensor::methodstring[ RAWParams::BayerSensor::vng4])) ) {
// check if it is an olympus E camera or green equilibration is enabled. If yes, compute G channel pre-compensation factors
if ( ri->getSensorType() == ST_BAYER && (raw.bayersensor.greenthresh || (((idata->getMake().size() >= 7 && idata->getMake().substr(0, 7) == "OLYMPUS" && idata->getModel()[0] == 'E') || (idata->getMake().size() >= 9 && idata->getMake().substr(0, 9) == "Panasonic")) && raw.bayersensor.method != RAWParams::BayerSensor::methodstring[ RAWParams::BayerSensor::vng4])) ) {
// global correction
int ng1 = 0, ng2 = 0, i = 0;
double avgg1 = 0., avgg2 = 0.;
#ifdef _OPENMP
#pragma omp parallel for default(shared) private(i) reduction(+: ng1, ng2, avgg1, avgg2)
#endif
for (i = border; i < H - border; i++)
for (int j = border; j < W - border; j++)
if (ri->ISGREEN (i, j)) {
if (i & 1) {
avgg2 += rawData[i][j];
ng2++;
} else {
avgg1 += rawData[i][j];
ng1++;
}
}
double corrg1 = ((double)avgg1 / ng1 + (double)avgg2 / ng2) / 2.0 / ((double)avgg1 / ng1);
double corrg2 = ((double)avgg1 / ng1 + (double)avgg2 / ng2) / 2.0 / ((double)avgg2 / ng2);
#ifdef _OPENMP
#pragma omp parallel for default(shared)
#endif
for (int i = border; i < H - border; i++)
for (int j = border; j < W - border; j++)
if (ri->ISGREEN (i, j)) {
float currData;
currData = (float) (rawData[i][j] * ((i & 1) ? corrg2 : corrg1));
rawData[i][j] = (currData);
}
if(numFrames == 4) {
for(int i = 0; i < 4; ++i) {
green_equilibrate_global(*rawDataFrames[i]);
}
} else {
green_equilibrate_global(rawData);
}
}
if ( ri->getSensorType() == ST_BAYER && raw.bayersensor.greenthresh > 0) {
@ -1965,12 +1948,12 @@ void RawImageSource::preprocess (const RAWParams &raw, const LensProfParams &le
plistener->setProgress (0.0);
}
if (numFrames == 4) {
for (int i = 0; i < 4; ++i) {
green_equilibrate (0.01 * (raw.bayersensor.greenthresh), *rawDataFrames[i]);
if(numFrames == 4) {
for(int i = 0; i < 4; ++i) {
green_equilibrate(0.01 * raw.bayersensor.greenthresh, *rawDataFrames[i]);
}
} else {
green_equilibrate (0.01 * (raw.bayersensor.greenthresh), rawData);
green_equilibrate(0.01 * raw.bayersensor.greenthresh, rawData);
}
}

View File

@ -233,6 +233,7 @@ protected:
void cfa_linedn (float linenoiselevel);//Emil's line denoise
void green_equilibrate_global (array2D<float> &rawData);
void green_equilibrate (float greenthresh, array2D<float> &rawData);//Emil's green equilibration
void nodemosaic(bool bw);

View File

@ -511,6 +511,9 @@ int refreshmap[rtengine::NUMOFEVENTS] = {
LUMINANCECURVE, // EvCATgreensc
LUMINANCECURVE, // EvCATybscen
LUMINANCECURVE, // EvCATAutoyb
DARKFRAME, // EvLensCorrMode
DARKFRAME, // EvLensCorrLensfunCamera
DARKFRAME, // EvLensCorrLensfunLens
LUMINANCECURVE, // EvlocallabEnabled
LUMINANCECURVE, // EvlocallablocY
LUMINANCECURVE, // EvlocallablocX
@ -600,6 +603,5 @@ int refreshmap[rtengine::NUMOFEVENTS] = {
LUMINANCECURVE, //Evlocallabsensiex
LUMINANCECURVE //Evlocallabshape
};

View File

@ -49,6 +49,7 @@ class IImage8;
class IImage16;
class IImagefloat;
/**
* This class represents provides functions to obtain exif and IPTC metadata information
* from the image file

424
rtengine/rtlensfun.cc Normal file
View File

@ -0,0 +1,424 @@
/* -*- C++ -*-
*
* This file is part of RawTherapee.
*
* Copyright (c) 2017 Alberto Griggio <alberto.griggio@gmail.com>
*
* 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 "rtlensfun.h"
#include "settings.h"
#include <iostream>
namespace rtengine {
extern const Settings *settings;
//-----------------------------------------------------------------------------
// LFModifier
//-----------------------------------------------------------------------------
LFModifier::~LFModifier()
{
if (data_) {
data_->Destroy();
}
}
LFModifier::operator bool() const
{
return data_;
}
void LFModifier::correctDistortion(double &x, double &y, int cx, int cy, double scale) const
{
if (!data_) {
return;
}
float pos[2];
float xx = x + cx;
float yy = y + cy;
if (swap_xy_) {
std::swap(xx, yy);
}
if (data_->ApplyGeometryDistortion(xx, yy, 1, 1, pos)) {
x = pos[0];
y = pos[1];
if (swap_xy_) {
std::swap(x, y);
}
x -= cx;
y -= cy;
}
x *= scale;
y *= scale;
}
bool LFModifier::isCACorrectionAvailable() const
{
return false;
}
void LFModifier::correctCA(double &x, double &y, int channel) const
{
}
void LFModifier::processVignetteLine(int width, int y, float *line) const
{
data_->ApplyColorModification(line, 0, y, width, 1, LF_CR_1(INTENSITY), 0);
}
void LFModifier::processVignetteLine3Channels(int width, int y, float *line) const
{
data_->ApplyColorModification(line, 0, y, width, 1, LF_CR_3(RED, GREEN, BLUE), 0);
}
Glib::ustring LFModifier::getDisplayString() const
{
if (!data_) {
return "NONE";
} else {
Glib::ustring ret;
Glib::ustring sep = "";
if (flags_ & LF_MODIFY_DISTORTION) {
ret += "distortion";
sep = ", ";
}
if (flags_ & LF_MODIFY_VIGNETTING) {
ret += sep;
ret += "vignetting";
sep = ", ";
}
if (flags_ & LF_MODIFY_SCALE) {
ret += sep;
ret += "autoscaling";
}
return ret;
}
}
LFModifier::LFModifier(lfModifier *m, bool swap_xy, int flags):
data_(m),
swap_xy_(swap_xy),
flags_(flags)
{
}
//-----------------------------------------------------------------------------
// LFCamera
//-----------------------------------------------------------------------------
LFCamera::LFCamera():
data_(nullptr)
{
}
LFCamera::operator bool() const
{
return data_;
}
Glib::ustring LFCamera::getMake() const
{
if (data_) {
return data_->Maker;
} else {
return "";
}
}
Glib::ustring LFCamera::getModel() const
{
if (data_) {
return data_->Model;
} else {
return "";
}
}
float LFCamera::getCropFactor() const
{
if (data_) {
return data_->CropFactor;
} else {
return 0;
}
}
Glib::ustring LFCamera::getDisplayString() const
{
if (data_) {
return Glib::ustring::compose("%1 %2", getMake(), getModel());
} else {
return "---";
}
}
//-----------------------------------------------------------------------------
// LFLens
//-----------------------------------------------------------------------------
LFLens::LFLens():
data_(nullptr)
{
}
LFLens::operator bool() const
{
return data_;
}
Glib::ustring LFLens::getMake() const
{
if (data_) {
return data_->Maker;
} else {
return "";
}
}
Glib::ustring LFLens::getLens() const
{
if (data_) {
return Glib::ustring::compose("%1 %2", data_->Maker, data_->Model);
} else {
return "---";
}
}
float LFLens::getCropFactor() const
{
if (data_) {
return data_->CropFactor;
} else {
return 0;
}
}
bool LFLens::hasVignettingCorrection() const
{
if (data_) {
return data_->CalibVignetting;
} else {
return false;
}
}
bool LFLens::hasDistortionCorrection() const
{
if (data_) {
return data_->CalibDistortion;
} else {
return false;
}
}
//-----------------------------------------------------------------------------
// LFDatabase
//-----------------------------------------------------------------------------
LFDatabase LFDatabase::instance_;
bool LFDatabase::init()
{
instance_.data_ = lfDatabase::Create();
return instance_.data_->Load() != LF_NO_ERROR;
}
LFDatabase::LFDatabase():
data_(nullptr)
{
}
LFDatabase::~LFDatabase()
{
if (data_) {
data_->Destroy();
}
}
const LFDatabase *LFDatabase::getInstance()
{
return &instance_;
}
std::vector<LFCamera> LFDatabase::getCameras() const
{
std::vector<LFCamera> ret;
if (data_) {
auto cams = data_->GetCameras();
while (*cams) {
ret.emplace_back();
ret.back().data_ = *cams;
++cams;
}
}
return ret;
}
std::vector<LFLens> LFDatabase::getLenses() const
{
std::vector<LFLens> ret;
if (data_) {
auto lenses = data_->GetLenses();
while (*lenses) {
ret.emplace_back();
ret.back().data_ = *lenses;
++lenses;
}
}
return ret;
}
LFCamera LFDatabase::findCamera(const Glib::ustring &make, const Glib::ustring &model) const
{
LFCamera ret;
if (data_) {
auto found = data_->FindCamerasExt(make.c_str(), model.c_str());
if (found) {
ret.data_ = found[0];
lf_free(found);
}
}
return ret;
}
LFLens LFDatabase::findLens(const LFCamera &camera, const Glib::ustring &name) const
{
LFLens ret;
if (data_) {
Glib::ustring lname = name;
bool stdlens = camera && (name.empty() || name.find("Unknown") == 0);
if (stdlens) {
lname = camera.getModel(); // "Standard"
}
auto found = data_->FindLenses(camera.data_, nullptr, lname.c_str());
if (!found) {
// try to split the maker from the model of the lens
Glib::ustring make, model;
auto i = name.find_first_of(' ');
if (i != Glib::ustring::npos) {
make = name.substr(0, i);
model = name.substr(i+1);
found = data_->FindLenses(camera.data_, make.c_str(), model.c_str());
}
}
if (found) {
ret.data_ = found[0];
lf_free(found);
}
}
return ret;
}
std::unique_ptr<LFModifier> LFDatabase::getModifier(const LFCamera &camera, const LFLens &lens,
float focalLen, float aperture, float focusDist,
int width, int height, bool swap_xy) const
{
std::unique_ptr<LFModifier> ret;
if (data_) {
if (camera && lens) {
lfModifier *mod = lfModifier::Create(lens.data_, camera.getCropFactor(), width, height);
int flags = LF_MODIFY_DISTORTION | LF_MODIFY_SCALE;
if (aperture > 0) {
flags |= LF_MODIFY_VIGNETTING;
}
flags = mod->Initialize(lens.data_, LF_PF_F32, focalLen, aperture, focusDist > 0 ? focusDist : 1000, 0.0, LF_RECTILINEAR, flags, false);
ret.reset(new LFModifier(mod, swap_xy, flags));
}
}
return ret;
}
std::unique_ptr<LFModifier> LFDatabase::findModifier(const LensProfParams &lensProf, const ImageMetaData *idata, int width, int height, const CoarseTransformParams &coarse, int rawRotationDeg)
{
const LFDatabase *db = getInstance();
Glib::ustring make, model, lens;
float focallen = idata->getFocalLen();
if (lensProf.lfAutoMatch) {
if (focallen <= 0) {
return nullptr;
}
make = idata->getMake();
model = idata->getModel();
lens = idata->getLens();
} else {
make = lensProf.lfCameraMake;
model = lensProf.lfCameraModel;
lens = lensProf.lfLens;
}
LFCamera c = db->findCamera(make, model);
LFLens l = db->findLens(lensProf.lfAutoMatch ? c : LFCamera(), lens);
if (focallen <= 0 && l.data_ && l.data_->MinFocal == l.data_->MaxFocal) {
focallen = l.data_->MinFocal;
}
if (focallen <= 0) {
return nullptr;
}
bool swap_xy = false;
if (rawRotationDeg >= 0) {
int rot = (coarse.rotate + rawRotationDeg) % 360;
swap_xy = (rot == 90 || rot == 270);
if (swap_xy) {
std::swap(width, height);
}
}
std::unique_ptr<LFModifier> ret = db->getModifier(c, l, idata->getFocalLen(), idata->getFNumber(), idata->getFocusDist(), width, height, swap_xy);
if (settings->verbose) {
std::cout << "LENSFUN:\n"
<< " camera: " << c.getDisplayString() << "\n"
<< " lens: " << l.getDisplayString() << "\n"
<< " correction: "
<< (ret ? ret->getDisplayString() : "NONE") << std::endl;
}
return ret;
}
} // namespace rtengine

124
rtengine/rtlensfun.h Normal file
View File

@ -0,0 +1,124 @@
/* -*- C++ -*-
*
* This file is part of RawTherapee.
*
* Copyright (c) 2017 Alberto Griggio <alberto.griggio@gmail.com>
*
* 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/>.
*/
#pragma once
#include <memory>
#include <vector>
#include <glibmm.h>
#include <lensfun.h>
#include "lcp.h"
#include "noncopyable.h"
#include "procparams.h"
namespace rtengine {
class LFModifier final :
public LensCorrection,
public NonCopyable
{
public:
~LFModifier();
explicit operator bool() const;
void correctDistortion(double &x, double &y, int cx, int cy, double scale) const override;
bool isCACorrectionAvailable() const override;
void correctCA(double &x, double &y, int channel) const override;
void processVignetteLine(int width, int y, float *line) const override;
void processVignetteLine3Channels(int width, int y, float *line) const;
Glib::ustring getDisplayString() const;
private:
LFModifier(lfModifier *m, bool swap_xy, int flags);
friend class LFDatabase;
lfModifier *data_;
bool swap_xy_;
int flags_;
};
class LFCamera final
{
public:
LFCamera();
explicit operator bool() const;
Glib::ustring getMake() const;
Glib::ustring getModel() const;
float getCropFactor() const;
Glib::ustring getDisplayString() const;
private:
friend class LFDatabase;
const lfCamera *data_;
};
class LFLens final
{
public:
LFLens();
explicit operator bool() const;
Glib::ustring getMake() const;
Glib::ustring getLens() const;
Glib::ustring getDisplayString() const { return getLens(); }
float getCropFactor() const;
bool hasVignettingCorrection() const;
bool hasDistortionCorrection() const;
private:
friend class LFDatabase;
const lfLens *data_;
};
class LFDatabase final :
public NonCopyable
{
public:
static bool init();
static const LFDatabase *getInstance();
~LFDatabase();
std::vector<LFCamera> getCameras() const;
std::vector<LFLens> getLenses() const;
LFCamera findCamera(const Glib::ustring &make, const Glib::ustring &model) const;
LFLens findLens(const LFCamera &camera, const Glib::ustring &name) const;
static std::unique_ptr<LFModifier> findModifier(const LensProfParams &lensProf, const ImageMetaData *idata, int width, int height, const CoarseTransformParams &coarse, int rawRotationDeg);
private:
std::unique_ptr<LFModifier> getModifier(const LFCamera &camera, const LFLens &lens,
float focalLen, float aperture, float focusDist,
int width, int height, bool swap_xy) const;
LFDatabase();
static LFDatabase instance_;
lfDatabase *data_;
};
} // namespace rtengine

View File

@ -954,9 +954,14 @@ IImage8* Thumbnail::quickProcessImage (const procparams::ProcParams& params, int
}
// Full thumbnail processing, second stage if complete profile exists
IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rheight, TypeInterpolation interp, std::string camName,
double focalLen, double focalLen35mm, float focusDist, float shutter, float fnumber, float iso, std::string expcomp_, double& myscale)
IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rheight, TypeInterpolation interp, const ImageMetaData *metadata, double& myscale)
{
std::string camName = metadata->getCamera();
float shutter = metadata->getShutterSpeed();
float fnumber = metadata->getFNumber();
float iso = metadata->getISOSpeed();
float fcomp = metadata->getExpComp();
// check if the WB's equalizer value has changed
if (wbEqual < (params.wb.equal - 5e-4) || wbEqual > (params.wb.equal + 5e-4) || wbTempBias < (params.wb.tempBias - 5e-4) || wbTempBias > (params.wb.tempBias + 5e-4)) {
wbEqual = params.wb.equal;
@ -1079,7 +1084,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei
int origFH;
double tscale = 0.0;
getDimensions (origFW, origFH, tscale);
ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh, origFW * tscale + 0.5, origFH * tscale + 0.5, focalLen, focalLen35mm, focusDist, fnumber, 0, true); // Raw rotate degree not detectable here
ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh, origFW * tscale + 0.5, origFH * tscale + 0.5, metadata, 0, true); // Raw rotate degree not detectable here
delete baseImg;
baseImg = trImg;
}
@ -1279,11 +1284,6 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, int rhei
float fnum = fnumber;// F number
float fiso = iso;// ISO
float fspeed = shutter;//speed
char * writ = new char[expcomp_.size() + 1];//convert expcomp_ to char
std::copy (expcomp_.begin(), expcomp_.end(), writ);
writ[expcomp_.size()] = '\0';
float fcomp = atof (writ); //compensation + -
delete[] writ;
float adap;
if (fnum < 0.3f || fiso < 5.f || fspeed < 0.00001f)

View File

@ -71,8 +71,7 @@ public:
void init ();
IImage8* processImage (const procparams::ProcParams& pparams, int rheight, TypeInterpolation interp, std::string camName,
double focalLen, double focalLen35mm, float focusDist, float shutter, float fnumber, float iso, std::string expcomp_, double& scale);
IImage8* processImage (const procparams::ProcParams& pparams, int rheight, TypeInterpolation interp, const ImageMetaData *metadata, double& scale);
IImage8* quickProcessImage (const procparams::ProcParams& pparams, int rheight, TypeInterpolation interp, double& scale);
int getImageWidth (const procparams::ProcParams& pparams, int rheight, float &ratio);
void getDimensions (int& w, int& h, double& scaleFac);

View File

@ -820,10 +820,8 @@ private:
// perform transform (excepted resizing)
if (ipf.needsTransform()) {
Imagefloat* trImg = new Imagefloat (fw, fh);
ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh, fw, fh, imgsrc->getMetaData()->getFocalLen(), imgsrc->getMetaData()->getFocalLen35mm(),
imgsrc->getMetaData()->getFocusDist(),
imgsrc->getMetaData()->getFNumber(),
imgsrc->getRotateDegree(), true);
ipf.transform (baseImg, trImg, 0, 0, 0, 0, fw, fh, fw, fh,
imgsrc->getMetaData(), imgsrc->getRotateDegree(), true);
delete baseImg;
baseImg = trImg;
}

View File

@ -170,6 +170,7 @@ if(WIN32)
${GLIBMM_INCLUDE_DIRS}
${GTKMM_INCLUDE_DIRS}
${GTK_INCLUDE_DIRS}
${LENSFUN_INCLUDE_DIRS}
)
link_directories(. "${PROJECT_SOURCE_DIR}/rtexif"
${EXTRA_LIBDIR}
@ -195,6 +196,7 @@ else()
${GTK_INCLUDE_DIRS}
${IPTCDATA_INCLUDE_DIRS}
${LCMS_INCLUDE_DIRS}
${LENSFUN_INCLUDE_DIRS}
)
link_directories(${EXTRA_LIBDIR}
${CANBERRA-GTK_LIBRARY_DIRS}
@ -252,6 +254,7 @@ target_link_libraries(rth rtengine
${PNG_LIBRARIES}
${TIFF_LIBRARIES}
${ZLIB_LIBRARIES}
${LENSFUN_LIBRARIES}
)
target_link_libraries(rth-cli rtengine
@ -271,6 +274,7 @@ target_link_libraries(rth-cli rtengine
${PNG_LIBRARIES}
${TIFF_LIBRARIES}
${ZLIB_LIBRARIES}
${LENSFUN_LIBRARIES}
)
# Install executables

View File

@ -21,8 +21,9 @@
#include <glibmm.h>
#include "options.h"
#include "../rtengine/rtengine.h"
class CacheImageData
class CacheImageData: public rtengine::ImageMetaData
{
public:
@ -76,9 +77,26 @@ public:
int load (const Glib::ustring& fname);
int save (const Glib::ustring& fname);
Glib::ustring getCamera() const
{
return Glib::ustring(camMake + " " + camModel);
}
//-------------------------------------------------------------------------
// ImageMetaData interface
//-------------------------------------------------------------------------
bool hasExif() const { return false; }
const rtexif::TagDirectory *getExifData() const { return NULL; }
bool hasIPTC() const { return false; }
const rtengine::procparams::IPTCPairs getIPTCData () const { return rtengine::procparams::IPTCPairs(); }
tm getDateTime () const { return tm{}; }
time_t getDateTimeAsTS() const { return time_t(-1); }
int getISOSpeed() const { return iso; }
double getFNumber() const { return fnumber; }
double getFocalLen() const { return focalLen; }
double getFocalLen35mm() const { return focalLen35mm; }
float getFocusDist() const { return focusDist; }
double getShutterSpeed() const { return shutter; }
double getExpComp() const { return atof(expcomp.c_str()); }
std::string getMake() const { return camMake; }
std::string getModel() const { return camModel; }
std::string getLens() const { return lens; }
std::string getOrientation() const { return ""; } // TODO
};
#endif

View File

@ -22,15 +22,82 @@
#include "../rtengine/lcp.h"
#include <sstream>
#include "rtimage.h"
#include "../rtengine/rtlensfun.h"
#include <map>
#include <set>
using namespace rtengine;
using namespace rtengine::procparams;
LensProfilePanel::LensProfilePanel () : FoldableToolPanel(this, "lensprof", M("TP_LENSPROFILE_LABEL")), lcpFileChanged(false), useDistChanged(false), useVignChanged(false), useCAChanged(false), isRaw(true), lensgeomLcpFill(nullptr)
{
hbLCPFile = Gtk::manage(new Gtk::HBox());
LensProfilePanel::LFDbHelper *LensProfilePanel::lf(nullptr);
lLCPFileHead = Gtk::manage(new Gtk::Label(M("GENERAL_FILE")));
LensProfilePanel::LensProfilePanel () :
FoldableToolPanel(this, "lensprof", M("TP_LENSPROFILE_LABEL")),
lcpFileChanged(false),
useDistChanged(false),
useVignChanged(false),
useCAChanged(false),
isRaw(true),
metadata(nullptr),
useLensfunChanged(false),
lensfunAutoChanged(false),
lensfunCameraChanged(false),
lensfunLensChanged(false)
{
if (!lf) {
lf = new LFDbHelper();
}
corrUnchanged = Gtk::manage(new Gtk::RadioButton(M("GENERAL_UNCHANGED")));
pack_start(*corrUnchanged);
corrGroup = corrUnchanged->get_group();
corrOff = Gtk::manage(new Gtk::RadioButton(corrGroup, M("GENERAL_NONE")));
pack_start(*corrOff);
corrLensfunAuto = Gtk::manage(new Gtk::RadioButton(corrGroup, M("LENSPROFILE_CORRECTION_AUTOMATCH")));
pack_start(*corrLensfunAuto);
corrLensfunManual = Gtk::manage(new Gtk::RadioButton(corrGroup, M("LENSPROFILE_CORRECTION_MANUAL")));
pack_start(*corrLensfunManual);
lensfunCameras = Gtk::manage(new MyComboBox());
lensfunCameras->set_model(lf->lensfunCameraModel);
lensfunCameras->pack_start(lf->lensfunModelCam.model);
Gtk::CellRendererText* cellRenderer = dynamic_cast<Gtk::CellRendererText*>(lensfunCameras->get_first_cell());
cellRenderer->property_ellipsize() = Pango::ELLIPSIZE_MIDDLE;
cellRenderer->property_ellipsize_set() = true;
lensfunCameras->setPreferredWidth(50, 120);
lensfunLenses = Gtk::manage(new MyComboBox());
lensfunLenses->set_model(lf->lensfunLensModel);
lensfunLenses->pack_start(lf->lensfunModelLens.prettylens);
cellRenderer = dynamic_cast<Gtk::CellRendererText*>(lensfunLenses->get_first_cell());
cellRenderer->property_ellipsize() = Pango::ELLIPSIZE_MIDDLE;
cellRenderer->property_ellipsize_set() = true;
lensfunLenses->setPreferredWidth(50, 120);
Gtk::HBox *hb = Gtk::manage(new Gtk::HBox());
hb->pack_start(*Gtk::manage(new Gtk::Label(M("EXIFFILTER_CAMERA"))), Gtk::PACK_SHRINK, 4);
hb->pack_start(*lensfunCameras);
pack_start(*hb);
hb = Gtk::manage(new Gtk::HBox());
hb->pack_start(*Gtk::manage(new Gtk::Label(M("EXIFFILTER_LENS"))), Gtk::PACK_SHRINK, 4);
hb->pack_start(*lensfunLenses);
warning = Gtk::manage(new Gtk::Image());
warning->set_from_icon_name("dialog-warning", Gtk::ICON_SIZE_LARGE_TOOLBAR);
warning->set_tooltip_text(M("LENSPROFILE_LENS_WARNING"));
warning->hide();
hb->pack_start(*warning, Gtk::PACK_SHRINK, 4);
pack_start(*hb);
corrLcpFile = Gtk::manage(new Gtk::RadioButton(corrGroup));
hbLCPFile = Gtk::manage(new Gtk::HBox());
hbLCPFile->pack_start(*corrLcpFile, Gtk::PACK_SHRINK);
lLCPFileHead = Gtk::manage(new Gtk::Label(M("LENSPROFILE_CORRECTION_LCPFILE")));
hbLCPFile->pack_start(*lLCPFileHead, Gtk::PACK_SHRINK, 4);
fcbLCPFile = Gtk::manage(new MyFileChooserButton(M("TP_LENSPROFILE_LABEL"), Gtk::FILE_CHOOSER_ACTION_OPEN));
@ -41,7 +108,7 @@ LensProfilePanel::LensProfilePanel () : FoldableToolPanel(this, "lensprof", M("T
filterLCP->add_pattern("*.LCP");
fcbLCPFile->add_filter(filterLCP);
Glib::ustring defDir = lcpStore->getDefaultCommonDirectory();
Glib::ustring defDir = LCPStore::getInstance()->getDefaultCommonDirectory();
if (!defDir.empty()) {
#ifdef WIN32
@ -74,6 +141,15 @@ LensProfilePanel::LensProfilePanel () : FoldableToolPanel(this, "lensprof", M("T
ckbUseVign->signal_toggled().connect( sigc::mem_fun(*this, &LensProfilePanel::onUseVignChanged) );
ckbUseCA->signal_toggled().connect( sigc::mem_fun(*this, &LensProfilePanel::onUseCAChanged) );
lensfunCameras->signal_changed().connect(sigc::mem_fun(*this, &LensProfilePanel::onLensfunCameraChanged));
lensfunLenses->signal_changed().connect(sigc::mem_fun(*this, &LensProfilePanel::onLensfunLensChanged));
corrOff->signal_toggled().connect(sigc::mem_fun(*this, &LensProfilePanel::onCorrModeChanged));
corrLensfunAuto->signal_toggled().connect(sigc::mem_fun(*this, &LensProfilePanel::onCorrModeChanged));
corrLensfunManual->signal_toggled().connect(sigc::mem_fun(*this, &LensProfilePanel::onCorrModeChanged));
corrLcpFile->signal_toggled().connect(sigc::mem_fun(*this, &LensProfilePanel::onCorrModeChanged));
corrUnchanged->hide();
allowFocusDep = true;
}
@ -82,7 +158,20 @@ void LensProfilePanel::read(const rtengine::procparams::ProcParams* pp, const Pa
disableListener ();
conUseDist.block(true);
if (!pp->lensProf.lcpFile.empty() && lcpStore->isValidLCPFileName(pp->lensProf.lcpFile)) {
if (!batchMode) {
corrUnchanged->hide();
}
corrLensfunAuto->set_sensitive(true);
if (pp->lensProf.useLensfun) {
if (pp->lensProf.lfAutoMatch) {
corrLensfunAuto->set_active(true);
} else {
corrLensfunManual->set_active(true);
}
} else if (!pp->lensProf.lcpFile.empty() && LCPStore::getInstance()->isValidLCPFileName(pp->lensProf.lcpFile)) {
corrLcpFile->set_active(true);
fcbLCPFile->set_filename (pp->lensProf.lcpFile);
updateDisabled(true);
} else {
@ -98,18 +187,76 @@ void LensProfilePanel::read(const rtengine::procparams::ProcParams* pp, const Pa
}
updateDisabled(false);
corrOff->set_active(true);
}
ckbUseDist->set_active (pp->lensProf.useDist);
ckbUseVign->set_active (pp->lensProf.useVign && isRaw);
ckbUseCA->set_active (pp->lensProf.useCA && isRaw);
const LFDatabase *db = LFDatabase::getInstance();
LFCamera c;
LFLens l;
if (metadata) {
c = db->findCamera(metadata->getMake(), metadata->getModel());
l = db->findLens(c, metadata->getLens());
}
if (!setLensfunCamera(pp->lensProf.lfCameraMake, pp->lensProf.lfCameraModel) && pp->lensProf.lfAutoMatch) {
setLensfunCamera(c.getMake(), c.getModel());
}
if (!setLensfunLens(pp->lensProf.lfLens) && pp->lensProf.lfAutoMatch) {
setLensfunLens(l.getLens());
}
lcpFileChanged = useDistChanged = useVignChanged = useCAChanged = false;
useLensfunChanged = lensfunAutoChanged = lensfunCameraChanged = lensfunLensChanged = false;
if (!batchMode && !checkLensfunCanCorrect(true)) {
if (corrLensfunAuto->get_active()) {
corrOff->set_active(true);
}
corrLensfunAuto->set_sensitive(false);
}
if (corrLensfunManual->get_active() && !checkLensfunCanCorrect(false)) {
corrOff->set_active(true);
}
updateLensfunWarning();
enableListener ();
conUseDist.block(false);
}
void LensProfilePanel::updateLensfunWarning()
{
warning->hide();
if (corrLensfunManual->get_active()) {
const LFDatabase *db = LFDatabase::getInstance();
auto itc = lensfunCameras->get_active();
if (!itc) {
return;
}
LFCamera c = db->findCamera((*itc)[lf->lensfunModelCam.make], (*itc)[lf->lensfunModelCam.model]);
auto itl = lensfunLenses->get_active();
if (!itl) {
return;
}
LFLens l = db->findLens(LFCamera(), (*itl)[lf->lensfunModelLens.lens]);
float lenscrop = l.getCropFactor();
float camcrop = c.getCropFactor();
if (lenscrop <= 0 || camcrop <= 0 || lenscrop / camcrop >= 1.01f) {
warning->show();
}
ckbUseVign->set_sensitive(l.hasVignettingCorrection());
ckbUseDist->set_sensitive(l.hasDistortionCorrection());
}
}
void LensProfilePanel::setRawMeta(bool raw, const rtengine::ImageMetaData* pMeta)
{
if (!raw || pMeta->getFocusDist() <= 0) {
@ -124,11 +271,12 @@ void LensProfilePanel::setRawMeta(bool raw, const rtengine::ImageMetaData* pMeta
}
isRaw = raw;
metadata = pMeta;
}
void LensProfilePanel::write( rtengine::procparams::ProcParams* pp, ParamsEdited* pedited)
{
if (lcpStore->isValidLCPFileName(fcbLCPFile->get_filename())) {
if (corrLcpFile->get_active() && LCPStore::getInstance()->isValidLCPFileName(fcbLCPFile->get_filename())) {
pp->lensProf.lcpFile = fcbLCPFile->get_filename();
} else {
pp->lensProf.lcpFile = "";
@ -138,20 +286,48 @@ void LensProfilePanel::write( rtengine::procparams::ProcParams* pp, ParamsEdited
pp->lensProf.useVign = ckbUseVign->get_active();
pp->lensProf.useCA = ckbUseCA->get_active();
pp->lensProf.useLensfun = corrLensfunAuto->get_active() || corrLensfunManual->get_active();
pp->lensProf.lfAutoMatch = corrLensfunAuto->get_active();
auto itc = lensfunCameras->get_active();
if (itc) {
pp->lensProf.lfCameraMake = (*itc)[lf->lensfunModelCam.make];
pp->lensProf.lfCameraModel = (*itc)[lf->lensfunModelCam.model];
} else {
pp->lensProf.lfCameraMake = "";
pp->lensProf.lfCameraModel = "";
}
auto itl = lensfunLenses->get_active();
if (itl) {
pp->lensProf.lfLens = (*itl)[lf->lensfunModelLens.lens];
} else {
pp->lensProf.lfLens = "";
}
if (pedited) {
pedited->lensProf.lcpFile = lcpFileChanged;
pedited->lensProf.useDist = useDistChanged;
pedited->lensProf.useVign = useVignChanged;
pedited->lensProf.useCA = useCAChanged;
pedited->lensProf.useLensfun = useLensfunChanged;
pedited->lensProf.lfAutoMatch = lensfunAutoChanged;
pedited->lensProf.lfCameraMake = lensfunCameraChanged;
pedited->lensProf.lfCameraModel = lensfunCameraChanged;
pedited->lensProf.lfLens = lensfunLensChanged;
}
}
void LensProfilePanel::onLCPFileChanged()
{
lcpFileChanged = true;
updateDisabled(lcpStore->isValidLCPFileName(fcbLCPFile->get_filename()));
bool valid = LCPStore::getInstance()->isValidLCPFileName(fcbLCPFile->get_filename());
updateDisabled(valid);
if (listener) {
if (valid) {
disableListener();
corrLcpFile->set_active(true);
enableListener();
}
listener->panelChanged (EvLCPFile, Glib::path_get_basename(fcbLCPFile->get_filename()));
}
}
@ -163,7 +339,11 @@ void LensProfilePanel::onLCPFileReset()
fcbLCPFile->unselect_filename(fcbLCPFile->get_filename());
updateDisabled(false);
if (listener) {
disableListener();
corrOff->set_active(true);
enableListener();
listener->panelChanged (EvLCPFile, M("GENERAL_NONE"));
}
}
@ -199,3 +379,280 @@ void LensProfilePanel::updateDisabled(bool enable)
ckbUseVign->set_sensitive(enable && isRaw);
ckbUseCA->set_sensitive(enable && allowFocusDep);
}
void LensProfilePanel::setBatchMode(bool yes)
{
FoldableToolPanel::setBatchMode(yes);
if (yes) {
corrUnchanged->show();
corrUnchanged->set_active(true);
} else {
corrUnchanged->hide();
}
}
bool LensProfilePanel::setLensfunCamera(const Glib::ustring &make, const Glib::ustring &model)
{
if (!make.empty() && !model.empty()) {
auto it = lensfunCameras->get_active();
if (it && (*it)[lf->lensfunModelCam.make] == make && (*it)[lf->lensfunModelCam.model] == model) {
return true;
}
// search for the active row
for (auto row : lf->lensfunCameraModel->children()) {
if (row[lf->lensfunModelCam.make] == make) {
auto &c = row.children();
for (auto it = c.begin(), end = c.end(); it != end; ++it) {
auto &childrow = *it;
if (childrow[lf->lensfunModelCam.model] == model) {
lensfunCameras->set_active(it);
return true;
}
}
break;
}
}
}
lensfunCameras->set_active(-1);
return false;
}
bool LensProfilePanel::setLensfunLens(const Glib::ustring &lens)
{
if (!lens.empty()) {
auto it = lensfunLenses->get_active();
if (it && (*it)[lf->lensfunModelLens.lens] == lens) {
return true;
}
for (auto row : lf->lensfunLensModel->children()) {
if (lens.find(row[lf->lensfunModelLens.lens]) == 0) {
auto &c = row.children();
for (auto it = c.begin(), end = c.end(); it != end; ++it) {
auto &childrow = *it;
if (childrow[lf->lensfunModelLens.lens] == lens) {
lensfunLenses->set_active(it);
return true;
}
}
break;
}
}
}
lensfunLenses->set_active(-1);
return false;
}
void LensProfilePanel::onLensfunCameraChanged()
{
auto iter = lensfunCameras->get_active();
if (iter) {
lensfunCameraChanged = true;
if (listener) {
disableListener();
corrLensfunManual->set_active(true);
enableListener();
Glib::ustring name = (*iter)[lf->lensfunModelCam.model];
listener->panelChanged(EvLensCorrLensfunCamera, name);
}
}
updateLensfunWarning();
}
void LensProfilePanel::onLensfunLensChanged()
{
auto iter = lensfunLenses->get_active();
if (iter) {
lensfunLensChanged = true;
if (listener) {
disableListener();
corrLensfunManual->set_active(true);
enableListener();
Glib::ustring name = (*iter)[lf->lensfunModelLens.prettylens];
listener->panelChanged(EvLensCorrLensfunLens, name);
}
}
updateLensfunWarning();
}
void LensProfilePanel::onCorrModeChanged()
{
Glib::ustring mode;
if (corrOff->get_active()) {
useLensfunChanged = true;
lensfunAutoChanged = true;
lcpFileChanged = true;
ckbUseDist->set_sensitive(false);
ckbUseVign->set_sensitive(false);
ckbUseCA->set_sensitive(false);
mode = M("GENERAL_NONE");
} else if (corrLensfunAuto->get_active()) {
useLensfunChanged = true;
lensfunAutoChanged = true;
lcpFileChanged = true;
useDistChanged = true;
useVignChanged = true;
ckbUseDist->set_sensitive(true);
ckbUseVign->set_sensitive(true);
ckbUseCA->set_sensitive(false);
if (metadata) {
bool b = disableListener();
const LFDatabase *db = LFDatabase::getInstance();
LFCamera c = db->findCamera(metadata->getMake(), metadata->getModel());
LFLens l = db->findLens(c, metadata->getLens());
setLensfunCamera(c.getMake(), c.getModel());
setLensfunLens(l.getLens());
if (b) {
enableListener();
}
}
mode = M("LENSPROFILE_CORRECTION_AUTOMATCH");
} else if (corrLensfunManual->get_active()) {
useLensfunChanged = true;
lensfunAutoChanged = true;
lcpFileChanged = true;
useDistChanged = true;
useVignChanged = true;
ckbUseDist->set_sensitive(true);
ckbUseVign->set_sensitive(true);
ckbUseCA->set_sensitive(false);
mode = M("LENSPROFILE_CORRECTION_MANUAL");
} else if (corrLcpFile->get_active()) {
useLensfunChanged = true;
lensfunAutoChanged = true;
lcpFileChanged = true;
useDistChanged = true;
useVignChanged = true;
updateDisabled(true);
mode = M("LENSPROFILE_CORRECTION_LCPFILE");
} else if (corrUnchanged->get_active()) {
useLensfunChanged = false;
lensfunAutoChanged = false;
lcpFileChanged = false;
lensfunCameraChanged = false;
lensfunLensChanged = false;
ckbUseDist->set_sensitive(true);
ckbUseVign->set_sensitive(true);
ckbUseCA->set_sensitive(true);
mode = M("GENERAL_UNCHANGED");
}
updateLensfunWarning();
if (listener) {
listener->panelChanged(EvLensCorrMode, mode);
}
}
bool LensProfilePanel::checkLensfunCanCorrect(bool automatch)
{
if (!metadata) {
return false;
}
rtengine::procparams::ProcParams lpp;
write(&lpp);
lpp.lensProf.lfAutoMatch = automatch;
std::unique_ptr<LFModifier> mod(LFDatabase::findModifier(lpp.lensProf, metadata, 100, 100, lpp.coarse, -1));
return mod.get() != nullptr;
}
//-----------------------------------------------------------------------------
// LFDbHelper
//-----------------------------------------------------------------------------
LensProfilePanel::LFDbHelper::LFDbHelper()
{
lensfunCameraModel = Gtk::TreeStore::create(lensfunModelCam);
lensfunLensModel = Gtk::TreeStore::create(lensfunModelLens);
fillLensfunCameras();
fillLensfunLenses();
}
void LensProfilePanel::LFDbHelper::fillLensfunCameras()
{
if (options.rtSettings.verbose) {
std::cout << "LENSFUN, scanning cameras:" << std::endl;
}
std::map<Glib::ustring, std::set<Glib::ustring>> camnames;
auto camlist = LFDatabase::getInstance()->getCameras();
for (auto &c : camlist) {
camnames[c.getMake()].insert(c.getModel());
if (options.rtSettings.verbose) {
std::cout << " found: " << c.getDisplayString() << std::endl;
}
}
for (auto &p : camnames) {
Gtk::TreeModel::Row row = *(lensfunCameraModel->append());
row[lensfunModelCam.make] = p.first;
row[lensfunModelCam.model] = p.first;
for (auto &c : p.second) {
Gtk::TreeModel::Row child = *(lensfunCameraModel->append(row.children()));
child[lensfunModelCam.make] = p.first;
child[lensfunModelCam.model] = c;
}
}
}
void LensProfilePanel::LFDbHelper::fillLensfunLenses()
{
if (options.rtSettings.verbose) {
std::cout << "LENSFUN, scanning lenses:" << std::endl;
}
std::map<Glib::ustring, std::set<Glib::ustring>> lenses;
auto lenslist = LFDatabase::getInstance()->getLenses();
for (auto &l : lenslist) {
auto name = l.getLens();
auto make = l.getMake();
lenses[make].insert(name);
if (options.rtSettings.verbose) {
std::cout << " found: " << l.getDisplayString() << std::endl;
}
}
for (auto &p : lenses) {
Gtk::TreeModel::Row row = *(lensfunLensModel->append());
row[lensfunModelLens.lens] = p.first;
row[lensfunModelLens.prettylens] = p.first;
for (auto &c : p.second) {
Gtk::TreeModel::Row child = *(lensfunLensModel->append(row.children()));
child[lensfunModelLens.lens] = c;
if (c.find(p.first, p.first.size()+1) == p.first.size()+1) {
child[lensfunModelLens.prettylens] = c.substr(p.first.size()+1);
} else {
child[lensfunModelLens.prettylens] = c;
}
}
}
}

View File

@ -39,8 +39,56 @@ protected:
void updateDisabled(bool enable);
bool allowFocusDep;
bool isRaw;
LensGeometry *lensgeomLcpFill;
const rtengine::ImageMetaData* metadata;
Gtk::RadioButton::Group corrGroup;
Gtk::RadioButton *corrOff;
Gtk::RadioButton *corrLensfunAuto;
Gtk::RadioButton *corrLensfunManual;
Gtk::RadioButton *corrLcpFile;
Gtk::RadioButton *corrUnchanged;
MyComboBox *lensfunCameras;
MyComboBox *lensfunLenses;
Gtk::Image *warning;
class LFDbHelper {
public:
class LFModelCam: public Gtk::TreeModel::ColumnRecord {
public:
LFModelCam() { add(make); add(model); }
Gtk::TreeModelColumn<Glib::ustring> make;
Gtk::TreeModelColumn<Glib::ustring> model;
};
class LFModelLens: public Gtk::TreeModel::ColumnRecord {
public:
LFModelLens() { add(lens); add(prettylens); }
Gtk::TreeModelColumn<Glib::ustring> lens;
Gtk::TreeModelColumn<Glib::ustring> prettylens;
};
LFModelCam lensfunModelCam;
LFModelLens lensfunModelLens;
Glib::RefPtr<Gtk::TreeStore> lensfunCameraModel;
Glib::RefPtr<Gtk::TreeStore> lensfunLensModel;
LFDbHelper();
void fillLensfunCameras();
void fillLensfunLenses();
};
static LFDbHelper *lf;
bool useLensfunChanged;
bool lensfunAutoChanged;
bool lensfunCameraChanged;
bool lensfunLensChanged;
bool setLensfunCamera(const Glib::ustring &make, const Glib::ustring &model);
bool setLensfunLens(const Glib::ustring &lens);
bool checkLensfunCanCorrect(bool automatch);
void updateLensfunWarning();
public:
LensProfilePanel ();
@ -54,10 +102,12 @@ public:
void onUseDistChanged();
void onUseVignChanged();
void onUseCAChanged();
void setLensGeomRef( LensGeometry *foo)
{
lensgeomLcpFill = foo ;
};
void setBatchMode(bool yes);
void onLensfunCameraChanged();
void onLensfunLensChanged();
void onCorrModeChanged();
};
#endif

View File

@ -33,6 +33,7 @@
#include <cstring>
#include <cstdlib>
#include <locale.h>
#include <lensfun.h>
#include "options.h"
#include "soundman.h"
#include "rtimage.h"
@ -139,6 +140,7 @@ int processLineParams ( int argc, char **argv )
#endif
case 'v':
std::cout << "Using lensfun " << LF_VERSION_MAJOR << "." << LF_VERSION_MINOR << "." << LF_VERSION_MICRO << "." << LF_VERSION_BUGFIX << std::endl;
return 0;
#ifndef __APPLE__ // TODO agriggio - there seems to be already some "single instance app" support for OSX in rtwindow. Disabling it here until I understand how to merge the two

View File

@ -291,6 +291,11 @@ void ParamsEdited::set (bool v)
lensProf.useDist = v;
lensProf.useVign = v;
lensProf.useCA = v;
lensProf.useLensfun = v;
lensProf.lfAutoMatch = v;
lensProf.lfCameraMake = v;
lensProf.lfCameraModel = v;
lensProf.lfLens = v;
perspective.horizontal = v;
perspective.vertical = v;
gradient.enabled = v;
@ -921,6 +926,11 @@ void ParamsEdited::initFrom (const std::vector<rtengine::procparams::ProcParams>
lensProf.useDist = lensProf.useDist && p.lensProf.useDist == other.lensProf.useDist;
lensProf.useVign = lensProf.useVign && p.lensProf.useVign == other.lensProf.useVign;
lensProf.useCA = lensProf.useCA && p.lensProf.useCA == other.lensProf.useCA;
lensProf.useLensfun = lensProf.useLensfun && p.lensProf.useLensfun == other.lensProf.useLensfun;
lensProf.lfAutoMatch = lensProf.lfAutoMatch && p.lensProf.lfAutoMatch == other.lensProf.lfAutoMatch;
lensProf.lfCameraMake = lensProf.lfCameraMake && p.lensProf.lfCameraMake == other.lensProf.lfCameraMake;
lensProf.lfCameraModel = lensProf.lfCameraModel && p.lensProf.lfCameraModel == other.lensProf.lfCameraModel;
lensProf.lfLens = lensProf.lfLens && p.lensProf.lfLens == other.lensProf.lfLens;
perspective.horizontal = perspective.horizontal && p.perspective.horizontal == other.perspective.horizontal;
perspective.vertical = perspective.vertical && p.perspective.vertical == other.perspective.vertical;
gradient.enabled = gradient.enabled && p.gradient.enabled == other.gradient.enabled;
@ -2259,6 +2269,26 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten
toEdit.lensProf.useCA = mods.lensProf.useCA;
}
if (lensProf.useLensfun) {
toEdit.lensProf.useLensfun = mods.lensProf.useLensfun;
}
if (lensProf.lfAutoMatch) {
toEdit.lensProf.lfAutoMatch = mods.lensProf.lfAutoMatch;
}
if (lensProf.lfCameraMake) {
toEdit.lensProf.lfCameraMake = mods.lensProf.lfCameraMake;
}
if (lensProf.lfCameraModel) {
toEdit.lensProf.lfCameraModel = mods.lensProf.lfCameraModel;
}
if (lensProf.lfLens) {
toEdit.lensProf.lfLens = mods.lensProf.lfLens;
}
if (perspective.horizontal) {
toEdit.perspective.horizontal = dontforceSet && options.baBehav[ADDSET_PERSPECTIVE] ? toEdit.perspective.horizontal + mods.perspective.horizontal : mods.perspective.horizontal;
}

View File

@ -525,6 +525,7 @@ class LensProfParamsEdited
{
public:
bool lcpFile, useDist, useVign, useCA;
bool useLensfun, lfAutoMatch, lfCameraMake, lfCameraModel, lfLens;
bool isUnchanged() const;
};

View File

@ -18,7 +18,6 @@
*/
#include <gtkmm.h>
#include <regex>
#include "rtwindow.h"
#include "options.h"
#include "preferences.h"
@ -315,37 +314,27 @@ void RTWindow::on_realize ()
// Display release notes only if new major version.
// Pattern matches "5.1" from "5.1-23-g12345678"
std::string vs[] = {versionString, options.version};
std::regex pat ("(^[0-9.]+).*");
std::smatch sm;
const std::string vs[] = {versionString, options.version};
std::vector<std::string> vMajor;
for (const auto &v : vs) {
if (std::regex_match (v, sm, pat)) {
if (sm.size() == 2) {
std::ssub_match smsub = sm[1];
vMajor.push_back (smsub.str());
}
}
for (const auto& v : vs) {
vMajor.emplace_back(v, 0, v.find_first_not_of("0123456789."));
}
if (vMajor.size() == 2) {
if (vMajor[0] != vMajor[1]) {
if (vMajor.size() == 2 && vMajor[0] != vMajor[1]) {
// Update the version parameter with the right value
options.version = versionString;
// Update the version parameter with the right value
options.version = versionString;
splash = new Splash (*this);
splash->set_transient_for (*this);
splash->signal_delete_event().connect ( sigc::mem_fun (*this, &RTWindow::splashClosed) );
splash = new Splash (*this);
splash->set_transient_for (*this);
splash->signal_delete_event().connect ( sigc::mem_fun (*this, &RTWindow::splashClosed) );
if (splash->hasReleaseNotes()) {
splash->showReleaseNotes();
splash->show ();
} else {
delete splash;
splash = nullptr;
}
if (splash->hasReleaseNotes()) {
splash->showReleaseNotes();
splash->show ();
} else {
delete splash;
splash = nullptr;
}
}
}

View File

@ -603,7 +603,8 @@ rtengine::IImage8* Thumbnail::processThumbImage (const rtengine::procparams::Pro
image = tpp->quickProcessImage (pparams, h, rtengine::TI_Nearest, scale);
} else {
// Full thumbnail: apply profile
image = tpp->processImage (pparams, h, rtengine::TI_Bilinear, cfs.getCamera(), cfs.focalLen, cfs.focalLen35mm, cfs.focusDist, cfs.shutter, cfs.fnumber, cfs.iso, cfs.expcomp, scale );
// image = tpp->processImage (pparams, h, rtengine::TI_Bilinear, cfs.getCamera(), cfs.focalLen, cfs.focalLen35mm, cfs.focusDist, cfs.shutter, cfs.fnumber, cfs.iso, cfs.expcomp, scale );
image = tpp->processImage (pparams, h, rtengine::TI_Bilinear, &cfs, scale );
}
tpp->getDimensions(lastW, lastH, lastScale);
@ -628,7 +629,8 @@ rtengine::IImage8* Thumbnail::upgradeThumbImage (const rtengine::procparams::Pro
return nullptr;
}
rtengine::IImage8* image = tpp->processImage (pparams, h, rtengine::TI_Bilinear, cfs.getCamera(), cfs.focalLen, cfs.focalLen35mm, cfs.focusDist, cfs.shutter, cfs.fnumber, cfs.iso, cfs.expcomp, scale );
// rtengine::IImage8* image = tpp->processImage (pparams, h, rtengine::TI_Bilinear, cfs.getCamera(), cfs.focalLen, cfs.focalLen35mm, cfs.focusDist, cfs.shutter, cfs.fnumber, cfs.iso, cfs.expcomp, scale );
rtengine::IImage8* image = tpp->processImage (pparams, h, rtengine::TI_Bilinear, &cfs, scale );
tpp->getDimensions(lastW, lastH, lastScale);
delete tpp;

View File

@ -54,7 +54,6 @@ ToolPanelCoordinator::ToolPanelCoordinator () : ipc (nullptr), hasChanged (false
colortoning = Gtk::manage (new ColorToning ());
lensgeom = Gtk::manage (new LensGeometry ());
lensProf = Gtk::manage (new LensProfilePanel ());
lensProf->setLensGeomRef (lensgeom);
distortion = Gtk::manage (new Distortion ());
rotate = Gtk::manage (new Rotate ());
vibrance = Gtk::manage (new Vibrance ());

View File

@ -19,7 +19,7 @@
#include "xtransprocess.h"
#include "options.h"
#include "guiutils.h"
#include <regex>
using namespace rtengine;
using namespace rtengine::procparams;
@ -30,8 +30,30 @@ XTransProcess::XTransProcess () : FoldableToolPanel(this, "xtransprocess", M("TP
method = Gtk::manage (new MyComboBoxText ());
for( size_t i = 0; i < procparams::RAWParams::XTransSensor::numMethods; i++) {
static const std::regex what ("[() -]");
const std::string langKey = std::regex_replace (procparams::RAWParams::XTransSensor::methodstring[i], what, "");
const std::string langKey =
[i]() -> std::string
{
const std::string str(procparams::RAWParams::XTransSensor::methodstring[i]);
std::string res;
for (const auto& c : str) {
switch (c) {
case '(':
case ')':
case ' ':
case '-': {
continue;
}
default: {
res += c;
break;
}
}
}
return res;
}();
method->append(M("TP_RAW_" + Glib::ustring(langKey).uppercase()));
}