Generalize perspective correction

Revise perspective transformation to remove hard-coded angular field of
view and horizontal perspective axis of rotation. Add vertical bias
parameter to retain ability to perform vertical perspective
transformation independent of the horizontal perspective axis of
rotation. Add field of view parameter as a tentative method for
specifying angular field of view.

The current implementation of perspective transformation applies
horizontal perspective transformation in such a way that preserves the
orientation of a horizontal line going through the center of the image.
In common use cases, horizontal lines such as the horizon do not go
through the center of the image. In such cases, the horizontal
perspective axis of rotation should not be parallel to the image's
y-axis. This commit makes the axis of rotation dependent on the vertical
parameter.

The two axes of rotation should be placed at the appropriate distance
from the image in order to prevent stretched or compressed proportions.
In the current implementation, the axes are at a fixed relative distance
from the image. This commit adds the ability to specify the distance in
the form of the diagonal angular field of view.
This commit is contained in:
Lawrence
2019-12-18 10:22:05 -08:00
parent 3a207dace7
commit f4c37598ee
9 changed files with 145 additions and 53 deletions

View File

@@ -1803,9 +1803,11 @@ TP_PCVIGNETTE_ROUNDNESS_TOOLTIP;Roundness:\n0 = rectangle,\n50 = fitted ellipse,
TP_PCVIGNETTE_STRENGTH;Strength TP_PCVIGNETTE_STRENGTH;Strength
TP_PCVIGNETTE_STRENGTH_TOOLTIP;Filter strength in stops (reached in corners). TP_PCVIGNETTE_STRENGTH_TOOLTIP;Filter strength in stops (reached in corners).
TP_PDSHARPENING_LABEL;Capture Sharpening TP_PDSHARPENING_LABEL;Capture Sharpening
TP_PERSPECTIVE_FOV;Field of view
TP_PERSPECTIVE_HORIZONTAL;Horizontal TP_PERSPECTIVE_HORIZONTAL;Horizontal
TP_PERSPECTIVE_LABEL;Perspective TP_PERSPECTIVE_LABEL;Perspective
TP_PERSPECTIVE_VERTICAL;Vertical TP_PERSPECTIVE_VERTICAL;Vertical
TP_PERSPECTIVE_VERTICAL_BIAS;Vertical bias
TP_PFCURVE_CURVEEDITOR_CH;Hue TP_PFCURVE_CURVEEDITOR_CH;Hue
TP_PFCURVE_CURVEEDITOR_CH_TOOLTIP;Controls defringe strength by color.\nHigher = more,\nLower = less. TP_PFCURVE_CURVEEDITOR_CH_TOOLTIP;Controls defringe strength by color.\nHigher = more,\nLower = less.
TP_PREPROCESS_DEADPIXFILT;Dead pixel filter TP_PREPROCESS_DEADPIXFILT;Dead pixel filter

View File

@@ -236,20 +236,38 @@ bool ImProcFunctions::transCoord (int W, int H, const std::vector<Coord2D> &src,
double cost = cos (params->rotate.degree * rtengine::RT_PI / 180.0); double cost = cos (params->rotate.degree * rtengine::RT_PI / 180.0);
double sint = sin (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.0 - 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.0 - 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 = ascaleDef > 0 ? ascaleDef : (params->commonTrans.autofill ? getTransformAutoFill (oW, oH, pLCPMap) : 1.0); double ascale = ascaleDef > 0 ? ascaleDef : (params->commonTrans.autofill ? getTransformAutoFill (oW, oH, pLCPMap) : 1.0);
// auxiliary variables for perspective correction
const double f = maxRadius / tan(params->perspective.fov / 360.0 * rtengine::RT_PI);
const double phtheta = params->perspective.horizontal / -180.0 * rtengine::RT_PI;
const double pvtheta = params->perspective.vertical / -180.0 * rtengine::RT_PI;
const double pbtheta = params->perspective.vBias / -180.0 * rtengine::RT_PI;
const double phcos = cos(phtheta);
const double pvcos = cos(pvtheta);
const double pbcos = cos(pbtheta);
const double phsin = sin(phtheta);
const double pvsin = sin(pvtheta);
const double pbsin = sin(pbtheta);
// Coordinates of distorted image center.
const double pxoffset = f * phsin * pvcos;
const double pyoffset = -f * (phcos * pvcos * pbsin + pvsin * pbcos);
const double pz = f * (phcos * pvcos * pbcos - pvsin * pbsin);
// Inverse transformation matrix.
const double p_xx = f * phcos;
const double p_xy = f * phsin * pbsin;
const double p_xz = f * phsin * pbcos;
const double p_yx = f * phsin * pvsin;
const double p_yy = f * (pvcos * pbcos - phcos * pvsin * pbsin);
const double p_yz = f * (-pvcos * pbsin - phcos * pvsin * pbcos);
const double p_zx = -phsin * pvcos;
const double p_zy = phcos * pvcos * pbsin + pvsin * pbcos;
const double p_zz = phcos * pvcos * pbcos - pvsin * pbsin;
// z is known, can calculate these in advance.
const double pz_xz = pz * p_xz;
const double pz_yz = pz * p_yz;
const double pz_zz = pz * p_zz;
for (size_t i = 0; i < src.size(); i++) { for (size_t i = 0; i < src.size(); i++) {
double x_d = src[i].x, y_d = src[i].y; double x_d = src[i].x, y_d = src[i].y;
@@ -264,13 +282,13 @@ bool ImProcFunctions::transCoord (int W, int H, const std::vector<Coord2D> &src,
y_d += ascale * (0 - h2); // centering y coord & scale y_d += ascale * (0 - h2); // centering y coord & scale
if (needsPerspective()) { if (needsPerspective()) {
// horizontal perspective transformation x_d -= pxoffset;
y_d *= maxRadius / (maxRadius + x_d * hptanpt); y_d -= pyoffset;
x_d *= maxRadius * hpcospt / (maxRadius + x_d * hptanpt); const double normalizer = p_zx * x_d + p_zy * y_d + pz_zz;
const double x_d_new = p_xx * x_d + p_xy * y_d + pz_xz;
// vertical perspective transformation y_d = p_yx * x_d + p_yy * y_d + pz_yz;
x_d *= maxRadius / (maxRadius - y_d * vptanpt); x_d = x_d_new / normalizer;
y_d *= maxRadius * vpcospt / (maxRadius - y_d * vptanpt); y_d /= normalizer;
} }
// rotate // rotate
@@ -903,28 +921,42 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I
const double cost = cos(params->rotate.degree * rtengine::RT_PI / 180.0); const double cost = cos(params->rotate.degree * rtengine::RT_PI / 180.0);
const double sint = sin(params->rotate.degree * rtengine::RT_PI / 180.0); const double sint = sin(params->rotate.degree * rtengine::RT_PI / 180.0);
// auxiliary variables for vertical perspective correction
const double vpdeg = params->perspective.vertical / 100.0 * 45.0;
const double vpalpha = (90.0 - vpdeg) / 180.0 * rtengine::RT_PI;
const double vpteta = fabs(vpalpha - rtengine::RT_PI / 2) < 3e-4 ? 0.0 : acos((vpdeg > 0 ? 1.0 : -1.0) * sqrt((-SQR(oW * tan(vpalpha)) + (vpdeg > 0 ? 1.0 : -1.0) *
oW * tan(vpalpha) * sqrt(SQR(4 * maxRadius) + SQR(oW * tan(vpalpha)))) / (SQR(maxRadius) * 8)));
const double vpcospt = (vpdeg >= 0 ? 1.0 : -1.0) * cos(vpteta);
const double vptanpt = tan(vpteta);
// auxiliary variables for horizontal perspective correction
const double hpdeg = params->perspective.horizontal / 100.0 * 45.0;
const double hpalpha = (90.0 - hpdeg) / 180.0 * rtengine::RT_PI;
const double hpteta = fabs(hpalpha - rtengine::RT_PI / 2) < 3e-4 ? 0.0 : acos((hpdeg > 0 ? 1.0 : -1.0) * sqrt((-SQR(oH * tan(hpalpha)) + (hpdeg > 0 ? 1.0 : -1.0) *
oH * tan(hpalpha) * sqrt(SQR(4 * maxRadius) + SQR(oH * tan(hpalpha)))) / (SQR(maxRadius) * 8)));
const double hpcospt = (hpdeg >= 0 ? 1.0 : -1.0) * cos(hpteta);
const double hptanpt = tan(hpteta);
const double ascale = params->commonTrans.autofill ? getTransformAutoFill(oW, oH, pLCPMap) : 1.0; const double ascale = params->commonTrans.autofill ? getTransformAutoFill(oW, oH, pLCPMap) : 1.0;
const bool darkening = (params->vignetting.amount <= 0.0); const bool darkening = (params->vignetting.amount <= 0.0);
const double centerFactorx = cx - w2; const double centerFactorx = cx - w2;
const double centerFactory = cy - h2; const double centerFactory = cy - h2;
// auxiliary variables for perspective correction
const double f = maxRadius / tan(params->perspective.fov / 360.0 * rtengine::RT_PI);
const double phtheta = params->perspective.horizontal / -180.0 * rtengine::RT_PI;
const double pvtheta = params->perspective.vertical / -180.0 * rtengine::RT_PI;
const double pbtheta = params->perspective.vBias / -180.0 * rtengine::RT_PI;
const double phcos = cos(phtheta);
const double pvcos = cos(pvtheta);
const double pbcos = cos(pbtheta);
const double phsin = sin(phtheta);
const double pvsin = sin(pvtheta);
const double pbsin = sin(pbtheta);
// Coordinates of distorted image center.
const double pxoffset = f * phsin * pvcos;
const double pyoffset = -f * (phcos * pvcos * pbsin + pvsin * pbcos);
const double pz = f * (phcos * pvcos * pbcos - pvsin * pbsin);
// Inverse transformation matrix.
const double p_xx = f * phcos;
const double p_xy = f * phsin * pbsin;
const double p_xz = f * phsin * pbcos;
const double p_yx = f * phsin * pvsin;
const double p_yy = f * (pvcos * pbcos - phcos * pvsin * pbsin);
const double p_yz = f * (-pvcos * pbsin - phcos * pvsin * pbcos);
const double p_zx = -phsin * pvcos;
const double p_zy = phcos * pvcos * pbsin + pvsin * pbcos;
const double p_zz = phcos * pvcos * pbcos - pvsin * pbsin;
// z is known, can calculate these in advance.
const double pz_xz = pz * p_xz;
const double pz_yz = pz * p_yz;
const double pz_zz = pz * p_zz;
// main cycle // main cycle
#ifdef _OPENMP #ifdef _OPENMP
#pragma omp parallel for schedule(dynamic, 16) if(multiThread) #pragma omp parallel for schedule(dynamic, 16) if(multiThread)
@@ -946,13 +978,13 @@ void ImProcFunctions::transformGeneral(bool highQuality, Imagefloat *original, I
y_d += ascale * centerFactory; // centering y coord & scale y_d += ascale * centerFactory; // centering y coord & scale
if (enablePerspective) { if (enablePerspective) {
// horizontal perspective transformation x_d -= pxoffset;
y_d *= maxRadius / (maxRadius + x_d * hptanpt); y_d -= pyoffset;
x_d *= maxRadius * hpcospt / (maxRadius + x_d * hptanpt); const double normalizer = p_zx * x_d + p_zy * y_d + pz_zz;
const double x_d_new = p_xx * x_d + p_xy * y_d + pz_xz;
// vertical perspective transformation y_d = p_yx * x_d + p_yy * y_d + pz_yz;
x_d *= maxRadius / (maxRadius - y_d * vptanpt); x_d = x_d_new / normalizer;
y_d *= maxRadius * vpcospt / (maxRadius - y_d * vptanpt); y_d /= normalizer;
} }
// rotate // rotate
@@ -1150,7 +1182,7 @@ bool ImProcFunctions::needsRotation () const
bool ImProcFunctions::needsPerspective () const bool ImProcFunctions::needsPerspective () const
{ {
return params->perspective.horizontal || params->perspective.vertical; return params->perspective.horizontal || params->perspective.vertical || params->perspective.vBias;
} }
bool ImProcFunctions::needsGradient () const bool ImProcFunctions::needsGradient () const

View File

@@ -1851,7 +1851,9 @@ LensProfParams::LcMode LensProfParams::getMethodNumber(const Glib::ustring& mode
PerspectiveParams::PerspectiveParams() : PerspectiveParams::PerspectiveParams() :
horizontal(0.0), horizontal(0.0),
vertical(0.0) vertical(0.0),
vBias(0.0),
fov(65.0)
{ {
} }
@@ -1859,7 +1861,9 @@ bool PerspectiveParams::operator ==(const PerspectiveParams& other) const
{ {
return return
horizontal == other.horizontal horizontal == other.horizontal
&& vertical == other.vertical; && vertical == other.vertical
&& vBias == other.vBias
&& fov == other.fov;
} }
bool PerspectiveParams::operator !=(const PerspectiveParams& other) const bool PerspectiveParams::operator !=(const PerspectiveParams& other) const
@@ -3343,6 +3347,8 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo
// Perspective correction // Perspective correction
saveToKeyfile(!pedited || pedited->perspective.horizontal, "Perspective", "Horizontal", perspective.horizontal, keyFile); saveToKeyfile(!pedited || pedited->perspective.horizontal, "Perspective", "Horizontal", perspective.horizontal, keyFile);
saveToKeyfile(!pedited || pedited->perspective.vertical, "Perspective", "Vertical", perspective.vertical, keyFile); saveToKeyfile(!pedited || pedited->perspective.vertical, "Perspective", "Vertical", perspective.vertical, keyFile);
saveToKeyfile(!pedited || pedited->perspective.vBias, "Perspective", "VerticalBias", perspective.vBias, keyFile);
saveToKeyfile(!pedited || pedited->perspective.fov, "Perspective", "FOV", perspective.fov, keyFile);
// Gradient // Gradient
saveToKeyfile(!pedited || pedited->gradient.enabled, "Gradient", "Enabled", gradient.enabled, keyFile); saveToKeyfile(!pedited || pedited->gradient.enabled, "Gradient", "Enabled", gradient.enabled, keyFile);
@@ -4420,6 +4426,8 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited)
if (keyFile.has_group("Perspective")) { if (keyFile.has_group("Perspective")) {
assignFromKeyfile(keyFile, "Perspective", "Horizontal", pedited, perspective.horizontal, pedited->perspective.horizontal); assignFromKeyfile(keyFile, "Perspective", "Horizontal", pedited, perspective.horizontal, pedited->perspective.horizontal);
assignFromKeyfile(keyFile, "Perspective", "Vertical", pedited, perspective.vertical, pedited->perspective.vertical); assignFromKeyfile(keyFile, "Perspective", "Vertical", pedited, perspective.vertical, pedited->perspective.vertical);
assignFromKeyfile(keyFile, "Perspective", "VerticalBias", pedited, perspective.vBias, pedited->perspective.vBias);
assignFromKeyfile(keyFile, "Perspective", "FOV", pedited, perspective.fov, pedited->perspective.fov);
} }
if (keyFile.has_group("Gradient")) { if (keyFile.has_group("Gradient")) {

View File

@@ -907,6 +907,8 @@ struct LensProfParams {
struct PerspectiveParams { struct PerspectiveParams {
double horizontal; double horizontal;
double vertical; double vertical;
double vBias;
double fov;
PerspectiveParams(); PerspectiveParams();

View File

@@ -336,6 +336,8 @@ void ParamsEdited::set(bool v)
lensProf.lfLens = v; lensProf.lfLens = v;
perspective.horizontal = v; perspective.horizontal = v;
perspective.vertical = v; perspective.vertical = v;
perspective.vBias = v;
perspective.fov = v;
gradient.enabled = v; gradient.enabled = v;
gradient.degree = v; gradient.degree = v;
gradient.feather = v; gradient.feather = v;
@@ -919,6 +921,8 @@ void ParamsEdited::initFrom(const std::vector<rtengine::procparams::ProcParams>&
lensProf.lfLens = lensProf.lfLens && p.lensProf.lfLens == other.lensProf.lfLens; lensProf.lfLens = lensProf.lfLens && p.lensProf.lfLens == other.lensProf.lfLens;
perspective.horizontal = perspective.horizontal && p.perspective.horizontal == other.perspective.horizontal; perspective.horizontal = perspective.horizontal && p.perspective.horizontal == other.perspective.horizontal;
perspective.vertical = perspective.vertical && p.perspective.vertical == other.perspective.vertical; perspective.vertical = perspective.vertical && p.perspective.vertical == other.perspective.vertical;
perspective.vBias = perspective.vBias && p.perspective.vBias == other.perspective.vBias;
perspective.fov = perspective.fov && p.perspective.fov == other.perspective.fov;
gradient.enabled = gradient.enabled && p.gradient.enabled == other.gradient.enabled; gradient.enabled = gradient.enabled && p.gradient.enabled == other.gradient.enabled;
gradient.degree = gradient.degree && p.gradient.degree == other.gradient.degree; gradient.degree = gradient.degree && p.gradient.degree == other.gradient.degree;
gradient.feather = gradient.feather && p.gradient.feather == other.gradient.feather; gradient.feather = gradient.feather && p.gradient.feather == other.gradient.feather;
@@ -2317,6 +2321,14 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng
toEdit.perspective.vertical = dontforceSet && options.baBehav[ADDSET_PERSPECTIVE] ? toEdit.perspective.vertical + mods.perspective.vertical : mods.perspective.vertical; toEdit.perspective.vertical = dontforceSet && options.baBehav[ADDSET_PERSPECTIVE] ? toEdit.perspective.vertical + mods.perspective.vertical : mods.perspective.vertical;
} }
if (perspective.vBias) {
toEdit.perspective.vBias = dontforceSet && options.baBehav[ADDSET_PERSPECTIVE] ? toEdit.perspective.vBias + mods.perspective.vBias : mods.perspective.vBias;
}
if (perspective.fov) {
toEdit.perspective.fov = dontforceSet && options.baBehav[ADDSET_PERSPECTIVE] ? toEdit.perspective.fov + mods.perspective.fov : mods.perspective.fov;
}
if (gradient.enabled) { if (gradient.enabled) {
toEdit.gradient.enabled = mods.gradient.enabled; toEdit.gradient.enabled = mods.gradient.enabled;
} }
@@ -3308,4 +3320,4 @@ bool FilmNegativeParamsEdited::isUnchanged() const
bool CaptureSharpeningParamsEdited::isUnchanged() const bool CaptureSharpeningParamsEdited::isUnchanged() const
{ {
return enabled && contrast && autoContrast && autoRadius && deconvradius && deconvradiusOffset && deconviter && deconvitercheck; return enabled && contrast && autoContrast && autoRadius && deconvradius && deconvradiusOffset && deconviter && deconvitercheck;
} }

View File

@@ -396,6 +396,8 @@ struct LensProfParamsEdited {
struct PerspectiveParamsEdited { struct PerspectiveParamsEdited {
bool horizontal; bool horizontal;
bool vertical; bool vertical;
bool vBias;
bool fov;
}; };
struct GradientParamsEdited { struct GradientParamsEdited {

View File

@@ -32,18 +32,30 @@ PerspCorrection::PerspCorrection () : FoldableToolPanel(this, "perspective", M("
Gtk::Image* ipersHR = Gtk::manage (new RTImage ("perspective-horizontal-right-small.png")); Gtk::Image* ipersHR = Gtk::manage (new RTImage ("perspective-horizontal-right-small.png"));
Gtk::Image* ipersVL = Gtk::manage (new RTImage ("perspective-vertical-bottom-small.png")); Gtk::Image* ipersVL = Gtk::manage (new RTImage ("perspective-vertical-bottom-small.png"));
Gtk::Image* ipersVR = Gtk::manage (new RTImage ("perspective-vertical-top-small.png")); Gtk::Image* ipersVR = Gtk::manage (new RTImage ("perspective-vertical-top-small.png"));
Gtk::Image* ipersBL = Gtk::manage (new RTImage ("perspective-vertical-bottom-small.png"));
Gtk::Image* ipersBR = Gtk::manage (new RTImage ("perspective-vertical-top-small.png"));
horiz = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_HORIZONTAL"), -100, 100, 0.1, 0, ipersHL, ipersHR)); vert = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_VERTICAL"), -85, 85, 0.1, 0, ipersVL, ipersVR));
horiz->setAdjusterListener (this);
vert = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_VERTICAL"), -100, 100, 0.1, 0, ipersVL, ipersVR));
vert->setAdjusterListener (this); vert->setAdjusterListener (this);
pack_start (*horiz); horiz = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_HORIZONTAL"), -85, 85, 0.1, 0, ipersHL, ipersHR));
horiz->setAdjusterListener (this);
vBias = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_VERTICAL_BIAS"), -85, 85, 0.1, 0, ipersBL, ipersBR));
vBias->setAdjusterListener (this);
fov = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_FOV"), 0.1, 150, 0.1, 65));
fov->setAdjusterListener (this);
pack_start (*vert); pack_start (*vert);
pack_start (*horiz);
pack_start (*vBias);
pack_start (*fov);
horiz->setLogScale(2, 0); horiz->setLogScale(2, 0);
vert->setLogScale(2, 0); vert->setLogScale(2, 0);
vBias->setLogScale(2, 0);
fov->setLogScale(2, 0);
show_all(); show_all();
} }
@@ -56,10 +68,14 @@ void PerspCorrection::read (const ProcParams* pp, const ParamsEdited* pedited)
if (pedited) { if (pedited) {
horiz->setEditedState (pedited->perspective.horizontal ? Edited : UnEdited); horiz->setEditedState (pedited->perspective.horizontal ? Edited : UnEdited);
vert->setEditedState (pedited->perspective.vertical ? Edited : UnEdited); vert->setEditedState (pedited->perspective.vertical ? Edited : UnEdited);
vBias->setEditedState (pedited->perspective.vBias ? Edited : UnEdited);
fov->setEditedState (pedited->perspective.fov ? Edited : UnEdited);
} }
horiz->setValue (pp->perspective.horizontal); horiz->setValue (pp->perspective.horizontal);
vert->setValue (pp->perspective.vertical); vert->setValue (pp->perspective.vertical);
vBias->setValue (pp->perspective.vBias);
fov->setValue (pp->perspective.fov);
enableListener (); enableListener ();
} }
@@ -69,10 +85,14 @@ void PerspCorrection::write (ProcParams* pp, ParamsEdited* pedited)
pp->perspective.horizontal = horiz->getValue (); pp->perspective.horizontal = horiz->getValue ();
pp->perspective.vertical = vert->getValue (); pp->perspective.vertical = vert->getValue ();
pp->perspective.vBias = vBias->getValue ();
pp->perspective.fov = fov->getValue ();
if (pedited) { if (pedited) {
pedited->perspective.horizontal = horiz->getEditedState (); pedited->perspective.horizontal = horiz->getEditedState ();
pedited->perspective.vertical = vert->getEditedState (); pedited->perspective.vertical = vert->getEditedState ();
pedited->perspective.vBias = vBias->getEditedState ();
pedited->perspective.fov = fov->getEditedState ();
} }
} }
@@ -81,20 +101,26 @@ void PerspCorrection::setDefaults (const ProcParams* defParams, const ParamsEdit
horiz->setDefault (defParams->perspective.horizontal); horiz->setDefault (defParams->perspective.horizontal);
vert->setDefault (defParams->perspective.vertical); vert->setDefault (defParams->perspective.vertical);
vBias->setDefault (defParams->perspective.vBias);
fov->setDefault (defParams->perspective.fov);
if (pedited) { if (pedited) {
horiz->setDefaultEditedState (pedited->perspective.horizontal ? Edited : UnEdited); horiz->setDefaultEditedState (pedited->perspective.horizontal ? Edited : UnEdited);
vert->setDefaultEditedState (pedited->perspective.vertical ? Edited : UnEdited); vert->setDefaultEditedState (pedited->perspective.vertical ? Edited : UnEdited);
vBias->setDefaultEditedState (pedited->perspective.vBias ? Edited : UnEdited);
fov->setDefaultEditedState (pedited->perspective.fov ? Edited : UnEdited);
} else { } else {
horiz->setDefaultEditedState (Irrelevant); horiz->setDefaultEditedState (Irrelevant);
vert->setDefaultEditedState (Irrelevant); vert->setDefaultEditedState (Irrelevant);
vBias->setDefaultEditedState (Irrelevant);
fov->setDefaultEditedState (Irrelevant);
} }
} }
void PerspCorrection::adjusterChanged(Adjuster* a, double newval) void PerspCorrection::adjusterChanged(Adjuster* a, double newval)
{ {
if (listener) { if (listener) {
listener->panelChanged (EvPerspCorr, Glib::ustring::compose ("%1=%3\n%2=%4", M("TP_PERSPECTIVE_HORIZONTAL"), M("TP_PERSPECTIVE_VERTICAL"), horiz->getValue(), vert->getValue())); listener->panelChanged (EvPerspCorr, Glib::ustring::compose ("%1=%5\n%2=%6\n%3=%7\n%4=%8", M("TP_PERSPECTIVE_HORIZONTAL"), M("TP_PERSPECTIVE_VERTICAL"), M("TP_PERSPECTIVE_VERTICAL_BIAS"), M("TP_PERSPECTIVE_FOV"), horiz->getValue(), vert->getValue(), vBias->getValue(), fov->getValue()));
} }
} }
@@ -103,6 +129,8 @@ void PerspCorrection::setAdjusterBehavior (bool badd)
horiz->setAddMode(badd); horiz->setAddMode(badd);
vert->setAddMode(badd); vert->setAddMode(badd);
vBias->setAddMode(badd);
fov->setAddMode(badd);
} }
void PerspCorrection::trimValues (rtengine::procparams::ProcParams* pp) void PerspCorrection::trimValues (rtengine::procparams::ProcParams* pp)
@@ -110,6 +138,8 @@ void PerspCorrection::trimValues (rtengine::procparams::ProcParams* pp)
horiz->trimValue(pp->perspective.horizontal); horiz->trimValue(pp->perspective.horizontal);
vert->trimValue(pp->perspective.vertical); vert->trimValue(pp->perspective.vertical);
vBias->trimValue(pp->perspective.vBias);
fov->trimValue(pp->perspective.fov);
} }
void PerspCorrection::setBatchMode (bool batchMode) void PerspCorrection::setBatchMode (bool batchMode)
@@ -118,4 +148,6 @@ void PerspCorrection::setBatchMode (bool batchMode)
ToolPanel::setBatchMode (batchMode); ToolPanel::setBatchMode (batchMode);
horiz->showEditedCB (); horiz->showEditedCB ();
vert->showEditedCB (); vert->showEditedCB ();
vBias->showEditedCB ();
fov->showEditedCB ();
} }

View File

@@ -32,6 +32,8 @@ class PerspCorrection final :
protected: protected:
Adjuster* horiz; Adjuster* horiz;
Adjuster* vert; Adjuster* vert;
Adjuster* vBias;
Adjuster* fov;
public: public:

View File

@@ -343,7 +343,7 @@ Gtk::Widget* Preferences::getBatchProcPanel ()
mi = behModel->append (); mi = behModel->append ();
mi->set_value (behavColumns.label, M ("TP_PERSPECTIVE_LABEL")); mi->set_value (behavColumns.label, M ("TP_PERSPECTIVE_LABEL"));
appendBehavList (mi, M ("TP_PERSPECTIVE_HORIZONTAL") + ", " + M ("TP_PERSPECTIVE_VERTICAL"), ADDSET_PERSPECTIVE, false); appendBehavList (mi, M ("TP_PERSPECTIVE_HORIZONTAL") + ", " + M ("TP_PERSPECTIVE_VERTICAL") + ", " + M ("TP_PERSPECTIVE_VERTICAL_BIAS") + ", " + M ("TP_PERSPECTIVE_FOV"), ADDSET_PERSPECTIVE, false);
mi = behModel->append (); mi = behModel->append ();
mi->set_value (behavColumns.label, M ("TP_GRADIENT_LABEL")); mi->set_value (behavColumns.label, M ("TP_GRADIENT_LABEL"));