Adapt auto perspective for camera-based correction
Comment out parameters that darktable/ART use in case we decide to use them later. Add yaw and pitch parameters used by the camera-based perspective correction. Modify homography matrix calculation to use the camera-based perspective model.
This commit is contained in:
@@ -108,6 +108,7 @@ set(RTENGINESOURCEFILES
|
||||
myfile.cc
|
||||
panasonic_decoders.cc
|
||||
pdaflinesfilter.cc
|
||||
perspectivecorrection.cc
|
||||
PF_correct_RT.cc
|
||||
pipettebuffer.cc
|
||||
pixelshift.cc
|
||||
|
@@ -51,6 +51,7 @@ using namespace std;
|
||||
#define LENSSHIFT_RANGE_SOFT 1 // allowed min/max range for lensshift parameters with manual adjustment
|
||||
#define SHEAR_RANGE 0.2 // allowed min/max range for shear parameter
|
||||
#define SHEAR_RANGE_SOFT 0.5 // allowed min/max range for shear parameter with manual adjustment
|
||||
#define CAMERA_ANGLE_RANGE_SOFT 80
|
||||
#define MIN_LINE_LENGTH 5 // the minimum length of a line in pixels to be regarded as relevant
|
||||
#define MAX_TANGENTIAL_DEVIATION 30 // by how many degrees a line may deviate from the +/-180 and +/-90 to be regarded as relevant
|
||||
#define LSD_SCALE 0.99 // LSD: scaling factor for line detection
|
||||
@@ -97,6 +98,8 @@ using namespace std;
|
||||
// implemented by Michael F. Hutt.
|
||||
#include "ashift_nmsimplex.c"
|
||||
|
||||
#include "homogeneouscoordinates.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// RT: BEGIN COMMENT
|
||||
@@ -292,6 +295,8 @@ typedef struct dt_iop_ashift_params_t
|
||||
float cr;
|
||||
float ct;
|
||||
float cb;
|
||||
float camera_pitch;
|
||||
float camera_yaw;
|
||||
} dt_iop_ashift_params_t;
|
||||
|
||||
typedef struct dt_iop_ashift_line_t
|
||||
@@ -335,10 +340,14 @@ typedef struct dt_iop_ashift_fit_params_t
|
||||
float lensshift_v;
|
||||
float lensshift_h;
|
||||
float shear;
|
||||
float camera_pitch;
|
||||
float camera_yaw;
|
||||
float rotation_range;
|
||||
float lensshift_v_range;
|
||||
float lensshift_h_range;
|
||||
float shear_range;
|
||||
float camera_pitch_range;
|
||||
float camera_yaw_range;
|
||||
} dt_iop_ashift_fit_params_t;
|
||||
|
||||
typedef struct dt_iop_ashift_cropfit_params_t
|
||||
@@ -384,6 +393,8 @@ typedef struct dt_iop_ashift_gui_data_t
|
||||
float lensshift_v_range;
|
||||
float lensshift_h_range;
|
||||
float shear_range;
|
||||
float camera_pitch_range;
|
||||
float camera_yaw_range;
|
||||
dt_iop_ashift_line_t *lines;
|
||||
int lines_in_width;
|
||||
int lines_in_height;
|
||||
@@ -639,9 +650,16 @@ static void print_roi(const dt_iop_roi_t *roi, const char *label)
|
||||
|
||||
#define MAT3SWAP(a, b) { float (*tmp)[3] = (a); (a) = (b); (b) = tmp; }
|
||||
|
||||
/*
|
||||
static void homography(float *homograph, const float angle, const float shift_v, const float shift_h,
|
||||
const float shear, const float f_length_kb, const float orthocorr, const float aspect,
|
||||
const int width, const int height, dt_iop_ashift_homodir_t dir)
|
||||
*/
|
||||
static void homography(float *homograph, const float angle, const float shift_v,
|
||||
const float shift_h, const float shear, const float camera_pitch, const
|
||||
float camera_yaw, const float f_length_kb, const float orthocorr, const
|
||||
float aspect, const int width, const int height, dt_iop_ashift_homodir_t
|
||||
dir)
|
||||
{
|
||||
// calculate homograph that combines all translations, rotations
|
||||
// and warping into one single matrix operation.
|
||||
@@ -652,7 +670,11 @@ static void homography(float *homograph, const float angle, const float shift_v,
|
||||
|
||||
const float u = width;
|
||||
const float v = height;
|
||||
const float rot = M_PI * angle / 180.0f;
|
||||
const float pitch = M_PI * camera_pitch / 180.0f;
|
||||
const float yaw = M_PI * camera_yaw / 180.0f;
|
||||
|
||||
/*
|
||||
const float phi = M_PI * angle / 180.0f;
|
||||
const float cosi = cos(phi);
|
||||
const float sini = sin(phi);
|
||||
@@ -675,16 +697,19 @@ static void homography(float *homograph, const float angle, const float shift_v,
|
||||
const float alpha_h = CLAMP(atan(rad_h), -1.5f, 1.5f);
|
||||
const float rt_h = sin(0.5f * alpha_h);
|
||||
const float r_h = fmax(0.1f, 2.0f * (vertifac - 1.0f) * rt_h * rt_h + 1.0f);
|
||||
*/
|
||||
|
||||
const float f = f_length_kb * (sqrt(u*u + v*v) / sqrt(36.0*36.0 + 24.0*24.0));
|
||||
|
||||
// three intermediate buffers for matrix calculation ...
|
||||
float m1[3][3], m2[3][3], m3[3][3];
|
||||
float m1[3][3]/*, m2[3][3]*/, m3[3][3];
|
||||
|
||||
// ... and some pointers to handle them more intuitively
|
||||
float (*mwork)[3] = m1;
|
||||
float (*minput)[3] = m2;
|
||||
//float (*minput)[3] = m2;
|
||||
float (*moutput)[3] = m3;
|
||||
|
||||
/*
|
||||
// Step 1: flip x and y coordinates (see above)
|
||||
memset(minput, 0, 9 * sizeof(float));
|
||||
minput[0][1] = 1.0f;
|
||||
@@ -800,8 +825,43 @@ static void homography(float *homograph, const float angle, const float shift_v,
|
||||
MAT3SWAP(minput, moutput);
|
||||
// multiply mwork * minput -> moutput
|
||||
mat3mul((float *)moutput, (float *)mwork, (float *)minput);
|
||||
*/
|
||||
|
||||
rtengine::homogeneous::Vector<float> center;
|
||||
center[0] = 0.0f;
|
||||
center[1] = 0.0f;
|
||||
center[2] = f;
|
||||
center[3] = 1.0f;
|
||||
|
||||
using rtengine::operator*;
|
||||
|
||||
// Location of image center after rotations.
|
||||
const rtengine::homogeneous::Vector<float> camera_center_yaw_pitch =
|
||||
rtengine::homogeneous::rotationMatrix<float>(pitch, rtengine::homogeneous::Axis::X) *
|
||||
rtengine::homogeneous::rotationMatrix<float>(yaw, rtengine::homogeneous::Axis::Y) *
|
||||
center;
|
||||
|
||||
const rtengine::homogeneous::Matrix<float> matrix =
|
||||
// Perspective correction.
|
||||
rtengine::homogeneous::projectionMatrix<float>(camera_center_yaw_pitch[2], rtengine::homogeneous::Axis::Z) *
|
||||
rtengine::homogeneous::rotationMatrix<float>(yaw, rtengine::homogeneous::Axis::Y) *
|
||||
rtengine::homogeneous::rotationMatrix<float>(pitch, rtengine::homogeneous::Axis::X) *
|
||||
// Rotation.
|
||||
rtengine::homogeneous::rotationMatrix<float>(rot, rtengine::homogeneous::Axis::Z) *
|
||||
// Lens/sensor shift and move to z == camera_focal_length.
|
||||
rtengine::homogeneous::translationMatrix<float>((0.01f * shift_h - 0.5f) * u, (-0.01f * shift_v - 0.5f) * v, f);
|
||||
|
||||
m3[0][0] = matrix[0][0];
|
||||
m3[0][1] = matrix[0][1];
|
||||
m3[0][2] = matrix[0][3];
|
||||
m3[1][0] = matrix[1][0];
|
||||
m3[1][1] = matrix[1][1];
|
||||
m3[1][2] = matrix[1][3];
|
||||
m3[2][0] = matrix[3][0];
|
||||
m3[2][1] = matrix[3][1];
|
||||
m3[2][2] = matrix[3][3];
|
||||
|
||||
/*
|
||||
// Step 10: find x/y offsets and apply according correction so that
|
||||
// no negative coordinates occur in output vector
|
||||
float umin = FLT_MAX, vmin = FLT_MAX;
|
||||
@@ -830,6 +890,7 @@ static void homography(float *homograph, const float angle, const float shift_v,
|
||||
MAT3SWAP(minput, moutput);
|
||||
// multiply mwork * minput -> moutput
|
||||
mat3mul((float *)moutput, (float *)mwork, (float *)minput);
|
||||
*/
|
||||
|
||||
|
||||
// on request we either keep the final matrix for forward conversions
|
||||
@@ -1920,10 +1981,16 @@ static double model_fitness(double *params, void *data)
|
||||
float lensshift_v = fit->lensshift_v;
|
||||
float lensshift_h = fit->lensshift_h;
|
||||
float shear = fit->shear;
|
||||
float camera_pitch = fit->camera_pitch;
|
||||
float camera_yaw = fit->camera_yaw;
|
||||
float rotation_range = fit->rotation_range;
|
||||
/*
|
||||
float lensshift_v_range = fit->lensshift_v_range;
|
||||
float lensshift_h_range = fit->lensshift_h_range;
|
||||
float shear_range = fit->shear_range;
|
||||
*/
|
||||
float camera_pitch_range = fit->camera_pitch_range;
|
||||
float camera_yaw_range = fit->camera_yaw_range;
|
||||
|
||||
int pcount = 0;
|
||||
|
||||
@@ -1934,6 +2001,7 @@ static double model_fitness(double *params, void *data)
|
||||
pcount++;
|
||||
}
|
||||
|
||||
/*
|
||||
if(isnan(lensshift_v))
|
||||
{
|
||||
lensshift_v = ilogit(params[pcount], -lensshift_v_range, lensshift_v_range);
|
||||
@@ -1951,6 +2019,19 @@ static double model_fitness(double *params, void *data)
|
||||
shear = ilogit(params[pcount], -shear_range, shear_range);
|
||||
pcount++;
|
||||
}
|
||||
*/
|
||||
|
||||
if(isnan(camera_pitch))
|
||||
{
|
||||
camera_pitch = ilogit(params[pcount], -camera_pitch_range, camera_pitch_range);
|
||||
pcount++;
|
||||
}
|
||||
|
||||
if(isnan(camera_yaw))
|
||||
{
|
||||
camera_yaw = ilogit(params[pcount], -camera_yaw_range, camera_yaw_range);
|
||||
pcount++;
|
||||
}
|
||||
|
||||
assert(pcount == fit->params_count);
|
||||
|
||||
@@ -1960,7 +2041,7 @@ static double model_fitness(double *params, void *data)
|
||||
|
||||
// generate homograph out of the parameters
|
||||
float homograph[3][3];
|
||||
homography((float *)homograph, rotation, lensshift_v, lensshift_h, shear, f_length_kb,
|
||||
homography((float *)homograph, rotation, lensshift_v, lensshift_h, shear, camera_pitch, camera_yaw, f_length_kb,
|
||||
orthocorr, aspect, width, height, ASHIFT_HOMOGRAPH_FORWARD);
|
||||
|
||||
// accounting variables
|
||||
@@ -2018,8 +2099,12 @@ static double model_fitness(double *params, void *data)
|
||||
//double sum = sqrt(v + h) * 1.0e6;
|
||||
|
||||
#ifdef ASHIFT_DEBUG
|
||||
/*
|
||||
printf("fitness with rotation %f, lensshift_v %f, lensshift_h %f, shear %f -> lines %d, quality %10f\n",
|
||||
rotation, lensshift_v, lensshift_h, shear, count, sum);
|
||||
*/
|
||||
printf("fitness with rotation %f, camera_pitch %f, camera_yaw %f -> lines %d, quality %10f\n",
|
||||
rotation, camera_pitch, camera_yaw, count, sum);
|
||||
#endif
|
||||
|
||||
return sum;
|
||||
@@ -2050,10 +2135,14 @@ static dt_iop_ashift_nmsresult_t nmsfit(dt_iop_module_t *module, dt_iop_ashift_p
|
||||
fit.lensshift_v = p->lensshift_v;
|
||||
fit.lensshift_h = p->lensshift_h;
|
||||
fit.shear = p->shear;
|
||||
fit.camera_pitch = p->camera_pitch;
|
||||
fit.camera_yaw = p->camera_yaw;
|
||||
fit.rotation_range = g->rotation_range;
|
||||
fit.lensshift_v_range = g->lensshift_v_range;
|
||||
fit.lensshift_h_range = g->lensshift_h_range;
|
||||
fit.shear_range = g->shear_range;
|
||||
fit.camera_pitch_range = g->camera_pitch_range;
|
||||
fit.camera_yaw_range = g->camera_yaw_range;
|
||||
fit.linetype = ASHIFT_LINE_RELEVANT | ASHIFT_LINE_SELECTED;
|
||||
fit.linemask = ASHIFT_LINE_MASK;
|
||||
fit.params_count = 0;
|
||||
@@ -2086,6 +2175,7 @@ static dt_iop_ashift_nmsresult_t nmsfit(dt_iop_module_t *module, dt_iop_ashift_p
|
||||
fit.rotation = NAN;
|
||||
}
|
||||
|
||||
/*
|
||||
if(mdir & ASHIFT_FIT_LENS_VERT)
|
||||
{
|
||||
// we fit vertical lens shift
|
||||
@@ -2112,6 +2202,25 @@ static dt_iop_ashift_nmsresult_t nmsfit(dt_iop_module_t *module, dt_iop_ashift_p
|
||||
pcount++;
|
||||
fit.shear = NAN;
|
||||
}
|
||||
*/
|
||||
|
||||
if(mdir & ASHIFT_FIT_LENS_VERT)
|
||||
{
|
||||
// we fit pitch
|
||||
fit.params_count++;
|
||||
params[pcount] = logit(fit.camera_pitch, -fit.camera_pitch_range, fit.camera_pitch_range);
|
||||
pcount++;
|
||||
fit.camera_pitch = NAN;
|
||||
}
|
||||
|
||||
if(mdir & ASHIFT_FIT_LENS_HOR)
|
||||
{
|
||||
// we fit yaw
|
||||
fit.params_count++;
|
||||
params[pcount] = logit(fit.camera_yaw, -fit.camera_yaw_range, fit.camera_yaw_range);
|
||||
pcount++;
|
||||
fit.camera_yaw = NAN;
|
||||
}
|
||||
|
||||
if(mdir & ASHIFT_FIT_LINES_VERT)
|
||||
{
|
||||
@@ -2162,14 +2271,23 @@ static dt_iop_ashift_nmsresult_t nmsfit(dt_iop_module_t *module, dt_iop_ashift_p
|
||||
// fit was successful: now consolidate the results (order matters!!!)
|
||||
pcount = 0;
|
||||
fit.rotation = isnan(fit.rotation) ? ilogit(params[pcount++], -fit.rotation_range, fit.rotation_range) : fit.rotation;
|
||||
/*
|
||||
fit.lensshift_v = isnan(fit.lensshift_v) ? ilogit(params[pcount++], -fit.lensshift_v_range, fit.lensshift_v_range) : fit.lensshift_v;
|
||||
fit.lensshift_h = isnan(fit.lensshift_h) ? ilogit(params[pcount++], -fit.lensshift_h_range, fit.lensshift_h_range) : fit.lensshift_h;
|
||||
fit.shear = isnan(fit.shear) ? ilogit(params[pcount++], -fit.shear_range, fit.shear_range) : fit.shear;
|
||||
*/
|
||||
fit.camera_pitch = isnan(fit.camera_pitch) ? ilogit(params[pcount++], -fit.camera_pitch_range, fit.camera_pitch_range) : fit.camera_pitch;
|
||||
fit.camera_yaw = isnan(fit.camera_yaw) ? ilogit(params[pcount++], -fit.camera_yaw_range, fit.camera_yaw_range) : fit.camera_yaw;
|
||||
#ifdef ASHIFT_DEBUG
|
||||
/*
|
||||
printf("params after optimization (%d iterations): rotation %f, lensshift_v %f, lensshift_h %f, shear %f\n",
|
||||
iter, fit.rotation, fit.lensshift_v, fit.lensshift_h, fit.shear);
|
||||
*/
|
||||
printf("params after optimization (%d iterations): rotation %f, camera_pitch %f, camera_yaw %f\n",
|
||||
iter, fit.rotation, fit.camera_pitch, fit.camera_yaw);
|
||||
#endif
|
||||
|
||||
/*
|
||||
// sanity check: in case of extreme values the image gets distorted so strongly that it spans an insanely huge area. we check that
|
||||
// case and assume values that increase the image area by more than a factor of 4 as being insane.
|
||||
float homograph[3][3];
|
||||
@@ -2202,12 +2320,17 @@ static dt_iop_ashift_nmsresult_t nmsfit(dt_iop_module_t *module, dt_iop_ashift_p
|
||||
#endif
|
||||
return NMS_INSANE;
|
||||
}
|
||||
*/
|
||||
|
||||
// now write the results into structure p
|
||||
p->rotation = fit.rotation;
|
||||
/*
|
||||
p->lensshift_v = fit.lensshift_v;
|
||||
p->lensshift_h = fit.lensshift_h;
|
||||
p->shear = fit.shear;
|
||||
*/
|
||||
p->camera_pitch = fit.camera_pitch;
|
||||
p->camera_yaw = fit.camera_yaw;
|
||||
return NMS_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -2291,6 +2414,10 @@ static void model_probe(dt_iop_module_t *module, dt_iop_ashift_params_t *p, dt_i
|
||||
#endif // if 0
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// RT: BEGIN COMMENT (no crop support yet)
|
||||
//-----------------------------------------------------------------------------
|
||||
#if 0
|
||||
// function to keep crop fitting parameters within constraints
|
||||
static void crop_constraint(double *params, int pcount)
|
||||
{
|
||||
@@ -2383,7 +2510,12 @@ static double crop_fitness(double *params, void *data)
|
||||
// and return -A to allow Nelder-Mead simplex to search for the minimum
|
||||
return -A;
|
||||
}
|
||||
#endif // if 0
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// RT: BEGIN COMMENT
|
||||
#if 0
|
||||
// strategy: for a given center of the crop area and a specific aspect angle
|
||||
// we calculate the largest crop area that still lies within the output image;
|
||||
// now we allow a Nelder-Mead simplex to search for the center coordinates
|
||||
@@ -2561,9 +2693,11 @@ failed:
|
||||
dt_control_log(_("automatic cropping failed"));
|
||||
return;
|
||||
}
|
||||
#endif // if 0
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// RT: BEGIN COMMENT
|
||||
// RT: BEGIN COMMENT (no crop support yet)
|
||||
//-----------------------------------------------------------------------------
|
||||
#if 0
|
||||
// manually adjust crop area by shifting its center
|
||||
@@ -2804,8 +2938,10 @@ static int do_fit(dt_iop_module_t *module, dt_iop_ashift_params_t *p, dt_iop_ash
|
||||
|
||||
g->fitting = 0;
|
||||
|
||||
/*
|
||||
// finally apply cropping
|
||||
do_crop(module, p);
|
||||
*/
|
||||
|
||||
return TRUE;
|
||||
|
||||
@@ -3042,7 +3178,7 @@ int process_cl(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, cl_m
|
||||
}
|
||||
|
||||
float ihomograph[3][3];
|
||||
homography((float *)ihomograph, d->rotation, d->lensshift_v, d->lensshift_h, d->shear, d->f_length_kb,
|
||||
homography((float *)ihomograph, d->rotation, d->lensshift_v, d->lensshift_h, d->shear, d->f_length_kb, d->camera_pitch, d->camera_yaw,
|
||||
d->orthocorr, d->aspect, piece->buf_in.width, piece->buf_in.height, ASHIFT_HOMOGRAPH_INVERTED);
|
||||
|
||||
// clipping offset
|
||||
|
@@ -55,6 +55,8 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "../rtgui/threadutils.h"
|
||||
#include "colortemp.h"
|
||||
#include "imagefloat.h"
|
||||
#include "settings.h"
|
||||
|
||||
namespace rtengine { extern const Settings *settings; }
|
||||
@@ -97,76 +99,12 @@ inline int mat3inv(float *const dst, const float *const src)
|
||||
#include "ashift_dt.c"
|
||||
|
||||
|
||||
procparams::PerspectiveParams import_meta(const procparams::PerspectiveParams &pp, const FramesMetaData *metadata)
|
||||
{
|
||||
procparams::PerspectiveParams ret(pp);
|
||||
if (metadata && ret.flength == 0) {
|
||||
double f = metadata->getFocalLen();
|
||||
double f35 = metadata->getFocalLen35mm();
|
||||
if (f > 0 && f35 > 0) {
|
||||
ret.flength = f;
|
||||
ret.cropfactor = f35 / f;
|
||||
} else if (f > 0) {
|
||||
ret.flength = f;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
PerspectiveCorrection::PerspectiveCorrection():
|
||||
ok_(false),
|
||||
scale_(1.0),
|
||||
offx_(0.0),
|
||||
offy_(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void PerspectiveCorrection::init(int width, int height, const procparams::PerspectiveParams ¶ms, bool fill, const FramesMetaData *metadata)
|
||||
{
|
||||
if (params.enabled) {
|
||||
auto pp = import_meta(params, metadata);
|
||||
homography((float *)ihomograph_, params.angle, params.vertical / 100.0, -params.horizontal / 100.0, params.shear / 100.0, params.flength * params.cropfactor, 100.f, params.aspect, width, height, ASHIFT_HOMOGRAPH_INVERTED);
|
||||
|
||||
ok_ = true;
|
||||
calc_scale(width, height, pp, fill);
|
||||
} else {
|
||||
ok_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
inline void PerspectiveCorrection::correct(double &x, double &y, double scale, double offx, double offy)
|
||||
{
|
||||
if (ok_) {
|
||||
float pin[3], pout[3];
|
||||
pout[0] = x;
|
||||
pout[1] = y;
|
||||
pout[0] *= scale;
|
||||
pout[1] *= scale;
|
||||
pout[0] += offx;
|
||||
pout[1] += offy;
|
||||
pout[2] = 1.f;
|
||||
mat3mulv(pin, (float *)ihomograph_, pout);
|
||||
pin[0] /= pin[2];
|
||||
pin[1] /= pin[2];
|
||||
x = pin[0];
|
||||
y = pin[1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PerspectiveCorrection::operator()(double &x, double &y)
|
||||
{
|
||||
correct(x, y, scale_, offx_, offy_);
|
||||
}
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
/*
|
||||
std::vector<Coord2D> get_corners(int w, int h)
|
||||
{
|
||||
int x1 = 0, y1 = 0;
|
||||
@@ -180,9 +118,10 @@ std::vector<Coord2D> get_corners(int w, int h)
|
||||
};
|
||||
return corners;
|
||||
}
|
||||
*/
|
||||
|
||||
void init_dt_structures(dt_iop_ashift_params_t *p, dt_iop_ashift_gui_data_t *g,
|
||||
const procparams::PerspectiveParams *params)
|
||||
const procparams::ProcParams *params)
|
||||
{
|
||||
dt_iop_ashift_params_t dp = {
|
||||
0.0f,
|
||||
@@ -199,7 +138,9 @@ void init_dt_structures(dt_iop_ashift_params_t *p, dt_iop_ashift_gui_data_t *g,
|
||||
0.0f,
|
||||
1.0f,
|
||||
0.0f,
|
||||
1.0f
|
||||
1.0f,
|
||||
0.0f,
|
||||
0.0f
|
||||
};
|
||||
*p = dp;
|
||||
|
||||
@@ -223,6 +164,8 @@ void init_dt_structures(dt_iop_ashift_params_t *p, dt_iop_ashift_gui_data_t *g,
|
||||
g->lensshift_v_range = LENSSHIFT_RANGE_SOFT;
|
||||
g->lensshift_h_range = LENSSHIFT_RANGE_SOFT;
|
||||
g->shear_range = SHEAR_RANGE_SOFT;
|
||||
g->camera_pitch_range = CAMERA_ANGLE_RANGE_SOFT;
|
||||
g->camera_yaw_range = CAMERA_ANGLE_RANGE_SOFT;
|
||||
g->lines_suppressed = 0;
|
||||
g->lines_version = 0;
|
||||
g->show_guides = 0;
|
||||
@@ -242,17 +185,18 @@ void init_dt_structures(dt_iop_ashift_params_t *p, dt_iop_ashift_gui_data_t *g,
|
||||
g->crop_cx = g->crop_cy = 1.0f;
|
||||
|
||||
if (params) {
|
||||
p->rotation = params->angle;
|
||||
p->lensshift_v = params->vertical / 100.0;
|
||||
p->lensshift_h = -params->horizontal / 100.0;
|
||||
p->shear = params->shear / 100.0;
|
||||
p->f_length = params->flength;
|
||||
p->crop_factor = params->cropfactor;
|
||||
p->aspect = params->aspect;
|
||||
p->rotation = params->rotate.degree;
|
||||
p->lensshift_v = params->perspective.camera_shift_vert;
|
||||
p->lensshift_h = params->perspective.camera_shift_horiz;
|
||||
p->f_length = params->perspective.camera_focal_length;
|
||||
p->crop_factor = params->perspective.camera_crop_factor;
|
||||
p->camera_pitch = params->perspective.camera_pitch;
|
||||
p->camera_yaw = params->perspective.camera_yaw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
void get_view_size(int w, int h, const procparams::PerspectiveParams ¶ms, double &cw, double &ch)
|
||||
{
|
||||
double min_x = RT_INFINITY, max_x = -RT_INFINITY;
|
||||
@@ -278,47 +222,27 @@ void get_view_size(int w, int h, const procparams::PerspectiveParams ¶ms, do
|
||||
cw = max_x - min_x;
|
||||
ch = max_y - min_y;
|
||||
}
|
||||
*/
|
||||
|
||||
} // namespace
|
||||
|
||||
|
||||
void PerspectiveCorrection::calc_scale(int w, int h, const procparams::PerspectiveParams ¶ms, bool fill)
|
||||
PerspectiveCorrection::Params PerspectiveCorrection::autocompute(ImageSource *src, bool corr_pitch, bool corr_yaw, const procparams::ProcParams *pparams, const FramesMetaData *metadata)
|
||||
{
|
||||
double cw, ch;
|
||||
get_view_size(w, h, params, cw, ch);
|
||||
|
||||
if (!fill) {
|
||||
scale_ = max(cw / double(w), ch / double(h));
|
||||
offx_ = (cw - w * scale_) * 0.5;
|
||||
offy_ = (ch - h * scale_) * 0.5;
|
||||
} else {
|
||||
dt_iop_ashift_params_t p;
|
||||
dt_iop_ashift_gui_data_t g;
|
||||
init_dt_structures(&p, &g, ¶ms);
|
||||
dt_iop_module_t module = { &g, false };
|
||||
g.buf_width = w;
|
||||
g.buf_height = h;
|
||||
p.cropmode = ASHIFT_CROP_ASPECT;
|
||||
do_crop(&module, &p);
|
||||
offx_ = p.cl * cw;
|
||||
offy_ = p.ct * ch;
|
||||
scale_ = (p.cr - p.cl) * cw/double(w);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
procparams::PerspectiveParams PerspectiveCorrection::autocompute(ImageSource *src, Direction dir, const procparams::ProcParams *pparams, const FramesMetaData *metadata)
|
||||
{
|
||||
auto pcp = import_meta(pparams->perspective, metadata);
|
||||
auto pcp = procparams::PerspectiveParams(pparams->perspective);
|
||||
procparams::PerspectiveParams dflt;
|
||||
/*
|
||||
pcp.horizontal = dflt.horizontal;
|
||||
pcp.vertical = dflt.vertical;
|
||||
pcp.angle = dflt.angle;
|
||||
pcp.shear = dflt.shear;
|
||||
*/
|
||||
pcp.camera_pitch = dflt.camera_pitch;
|
||||
pcp.camera_yaw = dflt.camera_yaw;
|
||||
|
||||
dt_iop_ashift_params_t p;
|
||||
dt_iop_ashift_gui_data_t g;
|
||||
init_dt_structures(&p, &g, &pcp);
|
||||
init_dt_structures(&p, &g, pparams);
|
||||
dt_iop_module_t module;
|
||||
module.gui_data = &g;
|
||||
module.is_raw = src->isRAW();
|
||||
@@ -336,9 +260,11 @@ procparams::PerspectiveParams PerspectiveCorrection::autocompute(ImageSource *sr
|
||||
neutral.raw.bayersensor.method = RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::FAST);
|
||||
neutral.raw.xtranssensor.method = RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FAST);
|
||||
neutral.icm.outputProfile = ColorManagementParams::NoICMString;
|
||||
src->getImage(src->getWB(), tr, img.get(), pp, neutral.exposure, neutral.raw);
|
||||
src->getImage(src->getWB(), tr, img.get(), pp, neutral.toneCurve, neutral.raw);
|
||||
src->convertColorSpace(img.get(), pparams->icm, src->getWB());
|
||||
|
||||
neutral.commonTrans.autofill = false; // Ensures crop factor is correct.
|
||||
// TODO: Ensure image borders of rotated image do not get detected as lines.
|
||||
neutral.rotate = pparams->rotate;
|
||||
neutral.distortion = pparams->distortion;
|
||||
neutral.lensProf = pparams->lensProf;
|
||||
@@ -371,16 +297,12 @@ procparams::PerspectiveParams PerspectiveCorrection::autocompute(ImageSource *sr
|
||||
}
|
||||
|
||||
dt_iop_ashift_fitaxis_t fitaxis = ASHIFT_FIT_NONE;
|
||||
switch (dir) {
|
||||
case HORIZONTAL:
|
||||
fitaxis = ASHIFT_FIT_HORIZONTALLY;
|
||||
break;
|
||||
case VERTICAL:
|
||||
fitaxis = ASHIFT_FIT_VERTICALLY;
|
||||
break;
|
||||
default:
|
||||
if (corr_pitch && corr_yaw) {
|
||||
fitaxis = ASHIFT_FIT_BOTH_SHEAR;
|
||||
break;
|
||||
} else if (corr_pitch) {
|
||||
fitaxis = ASHIFT_FIT_VERTICALLY;
|
||||
} else if (corr_yaw) {
|
||||
fitaxis = ASHIFT_FIT_HORIZONTALLY;
|
||||
}
|
||||
|
||||
// reset the pseudo-random seed for repeatability -- ashift_dt uses rand()
|
||||
@@ -388,7 +310,11 @@ procparams::PerspectiveParams PerspectiveCorrection::autocompute(ImageSource *sr
|
||||
srand(1);
|
||||
|
||||
auto res = do_get_structure(&module, &p, ASHIFT_ENHANCE_EDGES) && do_fit(&module, &p, fitaxis);
|
||||
procparams::PerspectiveParams retval = pparams->perspective;
|
||||
Params retval = {
|
||||
.angle = p.rotation,
|
||||
.pitch = p.camera_pitch,
|
||||
.yaw = p.camera_yaw
|
||||
};
|
||||
|
||||
// cleanup the gui
|
||||
if (g.lines) free(g.lines);
|
||||
@@ -396,16 +322,16 @@ procparams::PerspectiveParams PerspectiveCorrection::autocompute(ImageSource *sr
|
||||
if (g.points_idx) free(g.points_idx);
|
||||
free(g.buf);
|
||||
|
||||
if (res) {
|
||||
retval.horizontal = -p.lensshift_h * 100;
|
||||
retval.vertical = p.lensshift_v * 100;
|
||||
retval.angle = p.rotation;
|
||||
retval.shear = p.shear * 100;
|
||||
if (!res) {
|
||||
retval.angle = pparams->rotate.degree;
|
||||
retval.pitch = pparams->perspective.camera_pitch;
|
||||
retval.yaw = pparams->perspective.camera_yaw;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
void PerspectiveCorrection::autocrop(int width, int height, bool fixratio, const procparams::PerspectiveParams ¶ms, const FramesMetaData *metadata, int &x, int &y, int &w, int &h)
|
||||
{
|
||||
auto pp = import_meta(params, metadata);
|
||||
@@ -429,5 +355,6 @@ void PerspectiveCorrection::autocrop(int width, int height, bool fixratio, const
|
||||
w = (p.cr - p.cl) * cw;
|
||||
h = (p.cb - p.ct) * ch;
|
||||
}
|
||||
*/
|
||||
|
||||
} // namespace rtengine
|
||||
|
@@ -28,28 +28,16 @@ namespace rtengine {
|
||||
|
||||
class PerspectiveCorrection {
|
||||
public:
|
||||
PerspectiveCorrection();
|
||||
void init(int width, int height, const procparams::PerspectiveParams ¶ms, bool fill, const FramesMetaData *meta);
|
||||
void operator()(double &x, double &y);
|
||||
|
||||
enum Direction {
|
||||
HORIZONTAL,
|
||||
VERTICAL,
|
||||
BOTH
|
||||
struct Params
|
||||
{
|
||||
double angle;
|
||||
double pitch;
|
||||
double yaw;
|
||||
};
|
||||
static procparams::PerspectiveParams autocompute(ImageSource *src, Direction dir, const procparams::ProcParams *pparams, const FramesMetaData *metadata);
|
||||
|
||||
static void autocrop(int width, int height, bool fixratio, const procparams::PerspectiveParams ¶ms, const FramesMetaData *metadata, int &x, int &y, int &w, int &h);
|
||||
static Params autocompute(ImageSource *src, bool corr_pitch, bool corr_yaw, const procparams::ProcParams *pparams, const FramesMetaData *metadata);
|
||||
|
||||
private:
|
||||
void correct(double &x, double &y, double scale, double offx, double offy);
|
||||
void calc_scale(int w, int h, const procparams::PerspectiveParams ¶ms, bool fill);
|
||||
|
||||
bool ok_;
|
||||
double scale_;
|
||||
double offx_;
|
||||
double offy_;
|
||||
float ihomograph_[3][3];
|
||||
//static void autocrop(int width, int height, bool fixratio, const procparams::PerspectiveParams ¶ms, const FramesMetaData *metadata, int &x, int &y, int &w, int &h);
|
||||
};
|
||||
|
||||
} // namespace rtengine
|
||||
|
Reference in New Issue
Block a user