diff --git a/rtdata/languages/default b/rtdata/languages/default index b7d3116fb..3ea3acf2d 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -685,6 +685,10 @@ TP_SHARPENING_USM;Unsharp Mask TP_VIGNETTING_AMOUNT;Amount TP_VIGNETTING_LABEL;Vignetting Correction TP_VIGNETTING_RADIUS;Radius +TP_VIGNETTING_STRENGTH;Strength +TP_VIGNETTING_CENTER_X;Center X +TP_VIGNETTING_CENTER_Y;Center Y +TP_VIGNETTING_CENTER;Center TP_WBALANCE_AUTO;Auto TP_WBALANCE_CAMERA;Camera TP_WBALANCE_CUSTOM;Custom diff --git a/rtengine/iptransform.cc b/rtengine/iptransform.cc index ae053c1e9..682738f16 100644 --- a/rtengine/iptransform.cc +++ b/rtengine/iptransform.cc @@ -223,25 +223,42 @@ void ImProcFunctions::transform (Image16* original, Image16* transformed, int cx transformSep (original, transformed, cx, cy, sx, sy, oW, oH); } +void calcVignettingParams(int oW, int oH, const VignettingParams& vignetting, double &w2, double &h2, double& maxRadius, double &v, double &b, double &mul) +{ + // vignette center is a point with coordinates between -1 and +1 + double x = vignetting.centerX / 100.0; + double y = vignetting.centerY / 100.0; + + // calculate vignette center in pixels + w2 = (double) oW / 2.0 - 0.5 + x * oW; + h2 = (double) oH / 2.0 - 0.5 + y * oH; + + // max vignette radius in pixels + maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2.; + + // vignette variables with applied strength + v = 1.0 - vignetting.strength * vignetting.amount * 3.0 / 400.0; + b = 1.0 + vignetting.radius * 7.0 / 100.0; + mul = (1.0-v) / tanh(b); +} + void ImProcFunctions::vignetting (Image16* original, Image16* transformed, int cx, int cy, int oW, int oH) { - double w2 = (double) oW / 2.0 - 0.5; - double h2 = (double) oH / 2.0 - 0.5; - - double maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2.; - - double v = 1.0 - params->vignetting.amount * 3.0 / 400.0; - double b = 1.0 + params->vignetting.radius * 7.0 / 100.0; - - double mul = (1.0-v) / tanh(b); + double vig_w2; + double vig_h2; + double maxRadius; + double v; + double b; + double mul; + calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul); #pragma omp parallel for if (multiThread) for (int y=0; yheight; y++) { - double y_d = (double) (y + cy) - h2 ; + double vig_y_d = (double) (y + cy) - vig_h2 ; int val; for (int x=0; xwidth; x++) { - double x_d = (double) (x + cx) - w2 ; - double r = sqrt(x_d*x_d + y_d*y_d); + double vig_x_d = (double) (x + cx) - vig_w2 ; + double r = sqrt(vig_x_d*vig_x_d + vig_y_d*vig_y_d); double vign = v + mul * tanh (b*(maxRadius-r) / maxRadius); val = original->r[y][x] / vign; transformed->r[y][x] = CLIP(val); @@ -255,9 +272,16 @@ void ImProcFunctions::vignetting (Image16* original, Image16* transformed, int c #include "cubint.cc" void ImProcFunctions::transformNonSep (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH) { + double w2 = (double) oW / 2.0 - 0.5; + double h2 = (double) oH / 2.0 - 0.5; - double w2 = (double) oW / 2.0 - 0.5; - double h2 = (double) oH / 2.0 - 0.5; + double vig_w2; + double vig_h2; + double maxRadius; + double v; + double b; + double mul; + calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul); // auxiliary variables for distortion correction double a = params->distortion.amount; @@ -266,11 +290,6 @@ void ImProcFunctions::transformNonSep (Image16* original, Image16* transformed, double cost = cos(params->rotate.degree * 3.14/180.0); double sint = sin(params->rotate.degree * 3.14/180.0); - // auxiliary variables for vignetting - double maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2.; - double v = 1.0 - params->vignetting.amount * 3.0 / 400.0; - double b = 1.0 + params->vignetting.radius * 7.0 / 100.0; - double mul = (1.0-v) / tanh(b); bool dovign = params->vignetting.amount != 0; // auxiliary variables for vertical perspective correction @@ -293,6 +312,8 @@ void ImProcFunctions::transformNonSep (Image16* original, Image16* transformed, for (int x=0; xwidth; x++) { double x_d = ascale * (x + cx - w2); // centering x coord & scale double y_d = ascale * (y + cy - h2); // centering y coord & scale + double vig_x_d = ascale * (x + cx - vig_w2); // centering x coord & scale + double vig_y_d = ascale * (y + cy - vig_h2); // centering y coord & scale // horizontal perspective transformation y_d = y_d * maxRadius / (maxRadius + x_d*hptanpt); @@ -308,11 +329,14 @@ void ImProcFunctions::transformNonSep (Image16* original, Image16* transformed, // distortion correction double r = sqrt(Dx*Dx + Dy*Dy) / maxRadius; - double r2 = sqrt(Dx*Dx + Dy*Dy); double s = 1.0 - a + a * r ; Dx *= s; Dy *= s; + double vig_Dx = vig_x_d * cost - vig_y_d * sint; + double vig_Dy = vig_x_d * sint + vig_y_d * cost; + double r2 = sqrt(vig_Dx*vig_Dx + vig_Dy*vig_Dy); + // de-center Dx += w2; Dy += h2; @@ -357,8 +381,16 @@ void ImProcFunctions::transformNonSep (Image16* original, Image16* transformed, #include "cubintch.cc" void ImProcFunctions::transformSep (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH) { - double w2 = (double) oW / 2.0 - 0.5; - double h2 = (double) oH / 2.0 - 0.5; + double w2 = (double) oW / 2.0 - 0.5; + double h2 = (double) oH / 2.0 - 0.5; + + double vig_w2; + double vig_h2; + double maxRadius; + double v; + double b; + double mul; + calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul); // auxiliary variables for c/a correction double cdist[3]; @@ -381,11 +413,6 @@ void ImProcFunctions::transformSep (Image16* original, Image16* transformed, int double cost = cos(params->rotate.degree * 3.14/180.0); double sint = sin(params->rotate.degree * 3.14/180.0); - // auxiliary variables for vignetting - double maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2.; - double v = 1.0 - params->vignetting.amount * 3.0 / 400.0; - double b = 1.0 + params->vignetting.radius * 7.0 / 100.0; - double mul = (1.0-v) / tanh(b); bool dovign = params->vignetting.amount != 0; // auxiliary variables for vertical perspective correction @@ -408,6 +435,8 @@ void ImProcFunctions::transformSep (Image16* original, Image16* transformed, int for (int x=0; xwidth; x++) { double x_d = ascale * (x + cx - w2); // centering x coord & scale double y_d = ascale * (y + cy - h2); // centering y coord & scale + double vig_x_d = ascale * (x + cx - vig_w2); // centering x coord & scale + double vig_y_d = ascale * (y + cy - vig_h2); // centering y coord & scale // horizontal perspective transformation y_d = y_d * maxRadius / (maxRadius + x_d*hptanpt); @@ -423,9 +452,12 @@ void ImProcFunctions::transformSep (Image16* original, Image16* transformed, int // distortion correction double r = sqrt(Dxc*Dxc + Dyc*Dyc) / maxRadius; - double r2 = sqrt(Dxc*Dxc + Dyc*Dyc); double s = 1.0 - a + a * r ; + double vig_Dx = vig_x_d * cost - vig_y_d * sint; + double vig_Dy = vig_x_d * sint + vig_y_d * cost; + double r2 = sqrt(vig_Dx*vig_Dx + vig_Dy*vig_Dy); + for (int c=0; c<3; c++) { double Dx = Dxc * (s + cdist[c]); @@ -468,8 +500,16 @@ void ImProcFunctions::transformSep (Image16* original, Image16* transformed, int void ImProcFunctions::simpltransform (Image16* original, Image16* transformed, int cx, int cy, int sx, int sy, int oW, int oH) { - double w2 = (double) oW / 2.0 - 0.5; - double h2 = (double) oH / 2.0 - 0.5; + double w2 = (double) oW / 2.0 - 0.5; + double h2 = (double) oH / 2.0 - 0.5; + + double vig_w2; + double vig_h2; + double maxRadius; + double v; + double b; + double mul; + calcVignettingParams(oW, oH, params->vignetting, vig_w2, vig_h2, maxRadius, v, b, mul); // auxiliary variables for distortion correction double a = params->distortion.amount; @@ -478,11 +518,6 @@ void ImProcFunctions::simpltransform (Image16* original, Image16* transformed, i double cost = cos(params->rotate.degree * 3.14/180.0); double sint = sin(params->rotate.degree * 3.14/180.0); - // auxiliary variables for vignetting - double maxRadius = sqrt( (double)( oW*oW + oH*oH ) ) / 2.; - double v = 1.0 - params->vignetting.amount * 3.0 / 400.0; - double b = 1.0 + params->vignetting.radius * 7.0 / 100.0; - double mul = (1.0-v) / tanh(b); bool dovign = params->vignetting.amount != 0; // auxiliary variables for vertical perspective correction @@ -505,6 +540,8 @@ void ImProcFunctions::simpltransform (Image16* original, Image16* transformed, i for (int x=0; xwidth; x++) { double y_d = ascale * (y + cy - h2); // centering y coord & scale double x_d = ascale * (x + cx - w2); // centering x coord & scale + double vig_x_d = ascale * (x + cx - vig_w2); // centering x coord & scale + double vig_y_d = ascale * (y + cy - vig_h2); // centering y coord & scale // horizontal perspective transformation y_d = y_d * maxRadius / (maxRadius + x_d*hptanpt); @@ -520,11 +557,14 @@ void ImProcFunctions::simpltransform (Image16* original, Image16* transformed, i // distortion correction double r = sqrt(Dx*Dx + Dy*Dy) / maxRadius; - double r2 = sqrt(Dx*Dx + Dy*Dy); double s = 1.0 - a + a * r ; Dx *= s; Dy *= s; + double vig_Dx = vig_x_d * cost - vig_y_d * sint; + double vig_Dy = vig_x_d * sint + vig_y_d * cost; + double r2 = sqrt(vig_Dx*vig_Dx + vig_Dy*vig_Dy); + // de-center Dx += w2; Dy += h2; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index 40122e65d..a13458019 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -147,6 +147,9 @@ void ProcParams::setDefaults () { vignetting.amount = 0; vignetting.radius = 50; + vignetting.strength = 1; + vignetting.centerX = 0; + vignetting.centerY = 0; chmixer.red[0] = 100; chmixer.red[1] = 0; @@ -326,6 +329,9 @@ int ProcParams::save (Glib::ustring fname) const { // save vignetting correction keyFile.set_integer ("Vignetting Correction", "Amount", vignetting.amount); keyFile.set_integer ("Vignetting Correction", "Radius", vignetting.radius); + keyFile.set_integer ("Vignetting Correction", "Strength", vignetting.strength); + keyFile.set_integer ("Vignetting Correction", "CenterX", vignetting.centerX); + keyFile.set_integer ("Vignetting Correction", "CenterY", vignetting.centerY); // save highlight recovery settings keyFile.set_boolean ("HLRecovery", "Enabled", hlrecovery.enabled); @@ -580,6 +586,9 @@ if (keyFile.has_group ("CACorrection")) { if (keyFile.has_group ("Vignetting Correction")) { if (keyFile.has_key ("Vignetting Correction", "Amount")) vignetting.amount = keyFile.get_integer ("Vignetting Correction", "Amount"); if (keyFile.has_key ("Vignetting Correction", "Radius")) vignetting.radius = keyFile.get_integer ("Vignetting Correction", "Radius"); + if (keyFile.has_key ("Vignetting Correction", "Strength")) vignetting.strength = keyFile.get_integer ("Vignetting Correction", "Strength"); + if (keyFile.has_key ("Vignetting Correction", "CenterX")) vignetting.centerX = keyFile.get_integer ("Vignetting Correction", "CenterX"); + if (keyFile.has_key ("Vignetting Correction", "CenterY")) vignetting.centerY = keyFile.get_integer ("Vignetting Correction", "CenterY"); } // load highlight recovery settings @@ -775,6 +784,9 @@ bool ProcParams::operator== (const ProcParams& other) { && cacorrection.blue == other.cacorrection.blue && vignetting.amount == other.vignetting.amount && vignetting.radius == other.vignetting.radius + && vignetting.strength == other.vignetting.strength + && vignetting.centerX == other.vignetting.centerX + && vignetting.centerY == other.vignetting.centerY && !memcmp (&chmixer.red, &other.chmixer.red, 3*sizeof(int)) && !memcmp (&chmixer.green, &other.chmixer.green, 3*sizeof(int)) && !memcmp (&chmixer.blue, &other.chmixer.blue, 3*sizeof(int)) diff --git a/rtengine/procparams.h b/rtengine/procparams.h index cb7d0253c..884fc4468 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -249,6 +249,9 @@ class VignettingParams { public: int amount; int radius; + int strength; + int centerX; + int centerY; }; /** diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 41ddd4a68..ced7e0dde 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -107,6 +107,9 @@ void ParamsEdited::set (bool v) { cacorrection.blue = v; vignetting.amount = v; vignetting.radius = v; + vignetting.strength = v; + vignetting.centerX = v; + vignetting.centerY = v; chmixer.red[0] = v; chmixer.red[1] = v; chmixer.red[2] = v; @@ -234,6 +237,9 @@ void ParamsEdited::initFrom (const std::vector cacorrection.blue = cacorrection.blue && p.cacorrection.blue == other.cacorrection.blue; vignetting.amount = vignetting.amount && p.vignetting.amount == other.vignetting.amount; vignetting.radius = vignetting.radius && p.vignetting.radius == other.vignetting.radius; + vignetting.strength = vignetting.strength && p.vignetting.strength == other.vignetting.strength; + vignetting.centerX = vignetting.centerX && p.vignetting.centerX == other.vignetting.centerX; + vignetting.centerY = vignetting.centerY && p.vignetting.centerY == other.vignetting.centerY; chmixer.red[0] = chmixer.red[0] && p.chmixer.red[0] == other.chmixer.red[0]; chmixer.red[1] = chmixer.red[1] && p.chmixer.red[1] == other.chmixer.red[1]; chmixer.red[2] = chmixer.red[2] && p.chmixer.red[2] == other.chmixer.red[2]; @@ -352,6 +358,9 @@ void ParamsEdited::combine (rtengine::procparams::ProcParams& toEdit, const rten if (cacorrection.blue) toEdit.cacorrection.blue = options.baBehav[ADDSET_CA] ? toEdit.cacorrection.blue + mods.cacorrection.blue : mods.cacorrection.blue; if (vignetting.amount) toEdit.vignetting.amount = options.baBehav[ADDSET_VIGN_AMOUNT] ? toEdit.vignetting.amount + mods.vignetting.amount : mods.vignetting.amount; if (vignetting.radius) toEdit.vignetting.radius = mods.vignetting.radius; + if (vignetting.strength) toEdit.vignetting.strength = mods.vignetting.strength; + if (vignetting.centerX) toEdit.vignetting.centerX = mods.vignetting.centerX; + if (vignetting.centerY) toEdit.vignetting.centerY = mods.vignetting.centerY; if (chmixer.red[0]) toEdit.chmixer.red[0] = mods.chmixer.red[0]; if (chmixer.red[1]) toEdit.chmixer.red[1] = mods.chmixer.red[1]; if (chmixer.red[2]) toEdit.chmixer.red[2] = mods.chmixer.red[2]; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 11f060d0f..affa2166a 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -191,6 +191,9 @@ class VignettingParamsEdited { public: bool amount; bool radius; + bool strength; + bool centerX; + bool centerY; }; class ChannelMixerParamsEdited { diff --git a/rtgui/vignetting.cc b/rtgui/vignetting.cc index 622885f19..3839326c9 100644 --- a/rtgui/vignetting.cc +++ b/rtgui/vignetting.cc @@ -30,8 +30,20 @@ Vignetting::Vignetting () : vigAdd(false) { radius = Gtk::manage (new Adjuster (M("TP_VIGNETTING_RADIUS"), 0, 100, 1, 50)); radius->setAdjusterListener (this); + strength = Gtk::manage (new Adjuster (M("TP_VIGNETTING_STRENGTH"), 1, 100, 1, 1)); + strength->setAdjusterListener (this); + + centerX = Gtk::manage (new Adjuster (M("TP_VIGNETTING_CENTER_X"), -100, 100, 1, 0)); + centerX->setAdjusterListener (this); + + centerY = Gtk::manage (new Adjuster (M("TP_VIGNETTING_CENTER_Y"), -100, 100, 1, 0)); + centerY->setAdjusterListener (this); + pack_start (*amount); pack_start (*radius); + pack_start (*strength); + pack_start (*centerX); + pack_start (*centerY); show_all(); } @@ -45,6 +57,9 @@ void Vignetting::read (const ProcParams* pp, const ParamsEdited* pedited) { amount->setValue (pp->vignetting.amount); radius->setValue (pp->vignetting.radius); + strength->setValue (pp->vignetting.strength); + centerX->setValue (pp->vignetting.centerX); + centerY->setValue (pp->vignetting.centerY); enableListener (); } @@ -53,6 +68,9 @@ void Vignetting::write (ProcParams* pp, ParamsEdited* pedited) { pp->vignetting.amount = (int)amount->getValue (); pp->vignetting.radius = (int)radius->getValue (); + pp->vignetting.strength = (int)strength->getValue (); + pp->vignetting.centerX = (int)centerX->getValue (); + pp->vignetting.centerY = (int)centerY->getValue (); if (pedited) pedited->vignetting.amount = amount->getEditedState (); @@ -62,6 +80,9 @@ void Vignetting::setDefaults (const ProcParams* defParams, const ParamsEdited* p amount->setDefault (defParams->vignetting.amount); radius->setDefault (defParams->vignetting.radius); + strength->setDefault (defParams->vignetting.strength); + centerX->setDefault (defParams->vignetting.centerX); + centerY->setDefault (defParams->vignetting.centerY); if (pedited) amount->setDefaultEditedState (pedited->vignetting.amount ? Edited : UnEdited); @@ -72,7 +93,7 @@ void Vignetting::setDefaults (const ProcParams* defParams, const ParamsEdited* p void Vignetting::adjusterChanged (Adjuster* a, double newval) { if (listener) - listener->panelChanged (EvVignetting, Glib::ustring::compose ("%1=%3\n%2=%4", M("TP_VIGNETTING_AMOUNT"), M("TP_VIGNETTING_RADIUS"), (int)amount->getValue(), (int)radius->getValue())); + listener->panelChanged (EvVignetting, Glib::ustring::compose ("%1=%5\n%2=%6\n%3=%7\n%4=%8 %9", M("TP_VIGNETTING_AMOUNT"), M("TP_VIGNETTING_RADIUS"), M("TP_VIGNETTING_STRENGTH"), M("TP_VIGNETTING_CENTER"), (int)amount->getValue(), (int)radius->getValue(), (int)strength->getValue(), (int)centerX->getValue(), (int)centerY->getValue())); } void Vignetting::setAdjusterBehavior (bool bvadd) { diff --git a/rtgui/vignetting.h b/rtgui/vignetting.h index a4fc0dcd3..64d51c75d 100644 --- a/rtgui/vignetting.h +++ b/rtgui/vignetting.h @@ -28,6 +28,9 @@ class Vignetting : public Gtk::VBox, public AdjusterListener, public ToolPanel { protected: Adjuster* amount; Adjuster* radius; + Adjuster* strength; + Adjuster* centerX; + Adjuster* centerY; bool vigAdd; public: