From f4c37598ee68db549170a3aa97a9b537fd9ef6e6 Mon Sep 17 00:00:00 2001 From: Lawrence Date: Wed, 18 Dec 2019 10:22:05 -0800 Subject: [PATCH] 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. --- rtdata/languages/default | 2 + rtengine/iptransform.cc | 118 +++++++++++++++++++++++++-------------- rtengine/procparams.cc | 12 +++- rtengine/procparams.h | 2 + rtgui/paramsedited.cc | 14 ++++- rtgui/paramsedited.h | 2 + rtgui/perspective.cc | 44 +++++++++++++-- rtgui/perspective.h | 2 + rtgui/preferences.cc | 2 +- 9 files changed, 145 insertions(+), 53 deletions(-) diff --git a/rtdata/languages/default b/rtdata/languages/default index da4d5c804..376eb6072 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1803,9 +1803,11 @@ TP_PCVIGNETTE_ROUNDNESS_TOOLTIP;Roundness:\n0 = rectangle,\n50 = fitted ellipse, TP_PCVIGNETTE_STRENGTH;Strength TP_PCVIGNETTE_STRENGTH_TOOLTIP;Filter strength in stops (reached in corners). TP_PDSHARPENING_LABEL;Capture Sharpening +TP_PERSPECTIVE_FOV;Field of view TP_PERSPECTIVE_HORIZONTAL;Horizontal TP_PERSPECTIVE_LABEL;Perspective TP_PERSPECTIVE_VERTICAL;Vertical +TP_PERSPECTIVE_VERTICAL_BIAS;Vertical bias TP_PFCURVE_CURVEEDITOR_CH;Hue TP_PFCURVE_CURVEEDITOR_CH_TOOLTIP;Controls defringe strength by color.\nHigher = more,\nLower = less. TP_PREPROCESS_DEADPIXFILT;Dead pixel filter diff --git a/rtengine/iptransform.cc b/rtengine/iptransform.cc index af513536e..7e509d584 100644 --- a/rtengine/iptransform.cc +++ b/rtengine/iptransform.cc @@ -236,20 +236,38 @@ bool ImProcFunctions::transCoord (int W, int H, const std::vector &src, 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.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); + // 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++) { 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 &src, y_d += ascale * (0 - 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); + x_d -= pxoffset; + y_d -= pyoffset; + 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; + y_d = p_yx * x_d + p_yy * y_d + pz_yz; + x_d = x_d_new / normalizer; + y_d /= normalizer; } // 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 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 bool darkening = (params->vignetting.amount <= 0.0); const double centerFactorx = cx - w2; 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 #ifdef _OPENMP #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 if (enablePerspective) { - // 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); + x_d -= pxoffset; + y_d -= pyoffset; + 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; + y_d = p_yx * x_d + p_yy * y_d + pz_yz; + x_d = x_d_new / normalizer; + y_d /= normalizer; } // rotate @@ -1150,7 +1182,7 @@ bool ImProcFunctions::needsRotation () 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 diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index ba6fc237b..16f06b71f 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -1851,7 +1851,9 @@ LensProfParams::LcMode LensProfParams::getMethodNumber(const Glib::ustring& mode PerspectiveParams::PerspectiveParams() : 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 horizontal == other.horizontal - && vertical == other.vertical; + && vertical == other.vertical + && vBias == other.vBias + && fov == other.fov; } 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 saveToKeyfile(!pedited || pedited->perspective.horizontal, "Perspective", "Horizontal", perspective.horizontal, 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 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")) { assignFromKeyfile(keyFile, "Perspective", "Horizontal", pedited, perspective.horizontal, pedited->perspective.horizontal); 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")) { diff --git a/rtengine/procparams.h b/rtengine/procparams.h index c41e55872..956a0ac0c 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -907,6 +907,8 @@ struct LensProfParams { struct PerspectiveParams { double horizontal; double vertical; + double vBias; + double fov; PerspectiveParams(); diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 82132008a..ce7f3400c 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -336,6 +336,8 @@ void ParamsEdited::set(bool v) lensProf.lfLens = v; perspective.horizontal = v; perspective.vertical = v; + perspective.vBias = v; + perspective.fov = v; gradient.enabled = v; gradient.degree = v; gradient.feather = v; @@ -919,6 +921,8 @@ void ParamsEdited::initFrom(const std::vector& 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; + 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.degree = gradient.degree && p.gradient.degree == other.gradient.degree; 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; } + 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) { toEdit.gradient.enabled = mods.gradient.enabled; } @@ -3308,4 +3320,4 @@ bool FilmNegativeParamsEdited::isUnchanged() const bool CaptureSharpeningParamsEdited::isUnchanged() const { return enabled && contrast && autoContrast && autoRadius && deconvradius && deconvradiusOffset && deconviter && deconvitercheck; -} \ No newline at end of file +} diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 01a3e4efe..aa1e10698 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -396,6 +396,8 @@ struct LensProfParamsEdited { struct PerspectiveParamsEdited { bool horizontal; bool vertical; + bool vBias; + bool fov; }; struct GradientParamsEdited { diff --git a/rtgui/perspective.cc b/rtgui/perspective.cc index b86da6a52..19bef6de6 100644 --- a/rtgui/perspective.cc +++ b/rtgui/perspective.cc @@ -32,18 +32,30 @@ PerspCorrection::PerspCorrection () : FoldableToolPanel(this, "perspective", M(" 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* 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)); - horiz->setAdjusterListener (this); - - vert = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_VERTICAL"), -100, 100, 0.1, 0, ipersVL, ipersVR)); + vert = Gtk::manage (new Adjuster (M("TP_PERSPECTIVE_VERTICAL"), -85, 85, 0.1, 0, ipersVL, ipersVR)); 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 (*horiz); + pack_start (*vBias); + pack_start (*fov); horiz->setLogScale(2, 0); vert->setLogScale(2, 0); + vBias->setLogScale(2, 0); + fov->setLogScale(2, 0); show_all(); } @@ -56,10 +68,14 @@ void PerspCorrection::read (const ProcParams* pp, const ParamsEdited* pedited) if (pedited) { horiz->setEditedState (pedited->perspective.horizontal ? 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); vert->setValue (pp->perspective.vertical); + vBias->setValue (pp->perspective.vBias); + fov->setValue (pp->perspective.fov); enableListener (); } @@ -69,10 +85,14 @@ void PerspCorrection::write (ProcParams* pp, ParamsEdited* pedited) pp->perspective.horizontal = horiz->getValue (); pp->perspective.vertical = vert->getValue (); + pp->perspective.vBias = vBias->getValue (); + pp->perspective.fov = fov->getValue (); if (pedited) { pedited->perspective.horizontal = horiz->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); vert->setDefault (defParams->perspective.vertical); + vBias->setDefault (defParams->perspective.vBias); + fov->setDefault (defParams->perspective.fov); if (pedited) { horiz->setDefaultEditedState (pedited->perspective.horizontal ? Edited : UnEdited); vert->setDefaultEditedState (pedited->perspective.vertical ? Edited : UnEdited); + vBias->setDefaultEditedState (pedited->perspective.vBias ? Edited : UnEdited); + fov->setDefaultEditedState (pedited->perspective.fov ? Edited : UnEdited); } else { horiz->setDefaultEditedState (Irrelevant); vert->setDefaultEditedState (Irrelevant); + vBias->setDefaultEditedState (Irrelevant); + fov->setDefaultEditedState (Irrelevant); } } void PerspCorrection::adjusterChanged(Adjuster* a, double newval) { 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); vert->setAddMode(badd); + vBias->setAddMode(badd); + fov->setAddMode(badd); } void PerspCorrection::trimValues (rtengine::procparams::ProcParams* pp) @@ -110,6 +138,8 @@ void PerspCorrection::trimValues (rtengine::procparams::ProcParams* pp) horiz->trimValue(pp->perspective.horizontal); vert->trimValue(pp->perspective.vertical); + vBias->trimValue(pp->perspective.vBias); + fov->trimValue(pp->perspective.fov); } void PerspCorrection::setBatchMode (bool batchMode) @@ -118,4 +148,6 @@ void PerspCorrection::setBatchMode (bool batchMode) ToolPanel::setBatchMode (batchMode); horiz->showEditedCB (); vert->showEditedCB (); + vBias->showEditedCB (); + fov->showEditedCB (); } diff --git a/rtgui/perspective.h b/rtgui/perspective.h index 0564479de..2b56f2727 100644 --- a/rtgui/perspective.h +++ b/rtgui/perspective.h @@ -32,6 +32,8 @@ class PerspCorrection final : protected: Adjuster* horiz; Adjuster* vert; + Adjuster* vBias; + Adjuster* fov; public: diff --git a/rtgui/preferences.cc b/rtgui/preferences.cc index 68ef3b9ce..4bbeb345d 100644 --- a/rtgui/preferences.cc +++ b/rtgui/preferences.cc @@ -343,7 +343,7 @@ Gtk::Widget* Preferences::getBatchProcPanel () mi = behModel->append (); 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->set_value (behavColumns.label, M ("TP_GRADIENT_LABEL"));