90#define ROTATION_RANGE 10
91#define ROTATION_RANGE_SOFT 180
92#define LENSSHIFT_RANGE 1.0
93#define LENSSHIFT_RANGE_SOFT 2.0
94#define SHEAR_RANGE 0.2
95#define SHEAR_RANGE_SOFT 0.5
96#define MIN_LINE_LENGTH 5
97#define MAX_TANGENTIAL_DEVIATION 30
99#define LSD_SIGMA_SCALE 0.6
101#define LSD_ANG_TH 22.5
102#define LSD_LOG_EPS 0.0
103#define LSD_DENSITY_TH 0.7
104#define LSD_N_BINS 1024
105#define LSD_GAMMA 0.45
106#define RANSAC_RUNS 400
107#define RANSAC_EPSILON 2
108#define RANSAC_EPSILON_STEP 1
109#define RANSAC_ELIMINATION_RATIO 60
110#define RANSAC_OPTIMIZATION_STEPS 5
111#define RANSAC_OPTIMIZATION_DRY_RUNS 50
112#define RANSAC_HURDLE 5
113#define MINIMUM_FITLINES 2
114#define NMS_EPSILON 1e-3
116#define NMS_ITERATIONS 400
117#define NMS_CROP_EPSILON 100.0
118#define NMS_CROP_SCALE 0.5
119#define NMS_CROP_ITERATIONS 100
123#define DEFAULT_F_LENGTH 28.0
128#define SQR(a) ((a) * (a))
132#define MAX_SAVED_LINES 50
152 return _(
"Horizon and _perspective");
157 return _(
"rotation|keystone|distortion|crop|reframe|horizon");
163 _(
"corrective or creative"),
164 _(
"linear, RGB, scene-referred"),
166 _(
"linear, RGB, scene-referred"));
557 void *new_params,
const int new_version)
559 if(old_version == 1 && new_version == 5)
568 new->crop_factor = 1.0f;
569 new->orthocorr = 100.0f;
578 for(
int i = 0;
i < 8;
i++) new->last_quad_lines[
i] = 0.0f;
579 new->last_drawn_lines_count = 0;
582 if(old_version == 2 && new_version == 5)
593 new->aspect = old->
aspect;
594 new->mode = old->
mode;
601 for(
int i = 0;
i < 8;
i++) new->last_quad_lines[
i] = 0.0f;
602 new->last_drawn_lines_count = 0;
605 if(old_version == 3 && new_version == 5)
616 new->aspect = old->
aspect;
617 new->mode = old->
mode;
624 for(
int i = 0;
i < 8;
i++) new->last_quad_lines[
i] = 0.0f;
625 new->last_drawn_lines_count = 0;
628 if(old_version == 4 && new_version == 5)
635 new->shear = old->
shear;
639 new->aspect = old->
aspect;
640 new->mode = old->
mode;
647 for(
int i = 0;
i < 8;
i++) new->last_quad_lines[
i] = 0.0f;
648 new->last_drawn_lines_count = 0;
662 return &
g->new_params;
670static inline void vec3prodn(
float *dst,
const float *
const v1,
const float *
const v2)
672 const float l1 = v1[1] * v2[2] - v1[2] * v2[1];
673 const float l2 = v1[2] * v2[0] - v1[0] * v2[2];
674 const float l3 = v1[0] * v2[1] - v1[1] * v2[0];
677 const float sq = sqrtf(
l1 *
l1 +
l2 *
l2 + l3 * l3);
679 const float f = sq > 0.0f ? 1.0f / sq : 1.0f;
688static inline void vec3norm(
float *dst,
const float *
const v)
690 const float sq = sqrtf(
v[0] *
v[0] +
v[1] *
v[1] +
v[2] *
v[2]);
693 const float f = sq > 0.0f ? 1.0f / sq : 1.0f;
703static inline void vec3lnorm(
float *dst,
const float *
const v)
705 const float sq = sqrtf(
v[0] *
v[0] +
v[1] *
v[1]);
708 const float f = sq > 0.0f ? 1.0f / sq : 1.0f;
717static inline float vec3scalar(
const float *
const v1,
const float *
const v2)
719 return (v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]);
725 const float eps = 1e-10f;
726 return (fabsf(
v[0]) <
eps && fabsf(
v[1]) <
eps && fabsf(
v[2]) <
eps);
730static void print_roi(
const dt_iop_roi_t *roi,
const char *label)
732 printf(
"{ %5d %5d %5d %5d %.6f } %s\n", roi->
x, roi->
y, roi->
width, roi->
height, roi->
scale, label);
752#define MAT3SWAP(a, b) { float (*tmp)[3] = (a); (a) = (b); (b) = tmp; }
755static void homography(
float *homograph,
const float angle,
const float shift_v,
const float shift_h,
756 const float shear,
const float f_length_kb,
const float orthocorr,
const float aspect,
766 const float u =
width;
769 const float phi =
M_PI * angle / 180.0f;
770 const float cosi = cosf(phi);
771 const float sini = sinf(phi);
772 const float ascale = sqrtf(aspect);
775 const float f_global = f_length_kb;
776 const float horifac = 1.0f - orthocorr / 100.0f;
777 const float exppa_v = expf(shift_v);
778 const float fdb_v = f_global / (14.4f + (
v / u - 1) * 7.2f);
779 const float rad_v = fdb_v * (exppa_v - 1.0f) / (exppa_v + 1.0f);
780 const float alpha_v = CLAMP(atanf(rad_v), -1.5f, 1.5f);
781 const float rt_v = sinf(0.5f * alpha_v);
782 const float r_v = fmaxf(0.1f, 2.0f * (horifac - 1.0f) * rt_v * rt_v + 1.0f);
784 const float vertifac = 1.0f - orthocorr / 100.0f;
785 const float exppa_h = expf(shift_h);
786 const float fdb_h = f_global / (14.4f + (u /
v - 1) * 7.2f);
787 const float rad_h = fdb_h * (exppa_h - 1.0f) / (exppa_h + 1.0f);
788 const float alpha_h = CLAMP(atanf(rad_h), -1.5f, 1.5f);
789 const float rt_h = sinf(0.5f * alpha_h);
790 const float r_h = fmaxf(0.1f, 2.0f * (vertifac - 1.0f) * rt_h * rt_h + 1.0f);
794 float m1[3][3], m2[3][3], m3[3][3];
797 float (*mwork)[3] = m1;
798 float (*minput)[3] = m2;
799 float (*moutput)[3] = m3;
802 memset(minput, 0,
sizeof(
float) * 9);
809 memset(mwork, 0,
sizeof(
float) * 9);
814 mwork[0][2] = -0.5f *
v * cosi + 0.5f * u * sini + 0.5f *
v;
815 mwork[1][2] = -0.5f *
v * sini - 0.5f * u * cosi + 0.5f * u;
819 mat3mul((
float *)moutput, (
float *)mwork, (
float *)minput);
823 memset(mwork, 0,
sizeof(
float) * 9);
833 mat3mul((
float *)moutput, (
float *)mwork, (
float *)minput);
837 memset(mwork, 0,
sizeof(
float) * 9);
838 mwork[0][0] = exppa_v;
839 mwork[1][0] = 0.5f * ((exppa_v - 1.0f) * u) /
v;
840 mwork[1][1] = 2.0f * exppa_v / (exppa_v + 1.0f);
841 mwork[1][2] = -0.5f * ((exppa_v - 1.0f) * u) / (exppa_v + 1.0f);
842 mwork[2][0] = (exppa_v - 1.0f) /
v;
848 mat3mul((
float *)moutput, (
float *)mwork, (
float *)minput);
852 memset(mwork, 0,
sizeof(
float) * 9);
855 mwork[1][2] = 0.5f * u * (1.0f - r_v);
861 mat3mul((
float *)moutput, (
float *)mwork, (
float *)minput);
865 memset(mwork, 0,
sizeof(
float) * 9);
873 mat3mul((
float *)moutput, (
float *)mwork, (
float *)minput);
879 memset(mwork, 0,
sizeof(
float) * 9);
880 mwork[0][0] = exppa_h;
881 mwork[1][0] = 0.5f * ((exppa_h - 1.0f) *
v) / u;
882 mwork[1][1] = 2.0f * exppa_h / (exppa_h + 1.0f);
883 mwork[1][2] = -0.5f * ((exppa_h - 1.0f) *
v) / (exppa_h + 1.0f);
884 mwork[2][0] = (exppa_h - 1.0f) / u;
890 mat3mul((
float *)moutput, (
float *)mwork, (
float *)minput);
894 memset(mwork, 0,
sizeof(
float) * 9);
897 mwork[1][2] = 0.5f *
v * (1.0f - r_h);
903 mat3mul((
float *)moutput, (
float *)mwork, (
float *)minput);
907 memset(mwork, 0,
sizeof(
float) * 9);
908 mwork[0][0] = 1.0f * ascale;
909 mwork[1][1] = 1.0f / ascale;
915 mat3mul((
float *)moutput, (
float *)mwork, (
float *)minput);
920 float umin = FLT_MAX, vmin = FLT_MAX;
931 umin = fmin(umin, po[0] / po[2]);
932 vmin = fmin(vmin, po[1] / po[2]);
935 memset(mwork, 0,
sizeof(
float) * 9);
945 mat3mul((
float *)moutput, (
float *)mwork, (
float *)minput);
953 memcpy(homograph, moutput,
sizeof(
float) * 9);
958 if(
mat3inv((
float *)homograph, (
float *)moutput))
961 memset(mwork, 0,
sizeof(
float) * 9);
965 memcpy(homograph, mwork,
sizeof(
float) * 9);
977 const float eps = 1.0e-4f;
985 1.0f - data->
cr <
eps &&
987 1.0f - data->
cb <
eps);
992 float *
const restrict points,
size_t points_count)
1004 const float fullwidth = (float)piece->
buf_out.
width / (data->
cr - data->
cl);
1006 const float cx = fullwidth * data->
cl;
1007 const float cy = fullheight * data->
ct;
1009 for(
size_t i = 0;
i < points_count * 2;
i += 2)
1013 mat3mulv(po, (
float *)homograph, pi);
1014 points[
i] = po[0] / po[2] - cx;
1015 points[
i + 1] = po[1] / po[2] - cy;
1023 float *points,
size_t points_count)
1035 const float fullwidth = (float)piece->
buf_out.
width / (data->
cr - data->
cl);
1037 const float cx = fullwidth * data->
cl;
1038 const float cy = fullheight * data->
ct;
1040 for(
size_t i = 0;
i < points_count * 2;
i += 2)
1044 mat3mulv(po, (
float *)ihomograph, pi);
1045 points[
i] = po[0] / po[2];
1046 points[
i + 1] = po[1] / po[2];
1053 const float *
const in,
float *
const out,
const dt_iop_roi_t *
const roi_in,
1068 float ihomograph[3][3];
1073 const float fullwidth = (float)piece->
buf_out.
width / (data->
cr - data->
cl);
1075 const float cx = roi_out->
scale * fullwidth * data->
cl;
1076 const float cy = roi_out->
scale * fullheight * data->
ct;
1079 for(
int j = 0; j < roi_out->
height; j++)
1081 float *
const restrict _out =
out + (size_t)j * roi_out->
width;
1082 for(
int i = 0;
i < roi_out->
width;
i++)
1084 float pin[4], pout[4];
1087 pout[0] = roi_out->
x +
i + cx;
1088 pout[1] = roi_out->
y + j + cy;
1089 pout[0] /= roi_out->
scale;
1090 pout[1] /= roi_out->
scale;
1094 mat3mulv(pin, (
float *)ihomograph, pout);
1099 pin[0] *= roi_in->
scale;
1100 pin[1] *= roi_in->
scale;
1101 pin[0] -= roi_in->
x;
1102 pin[1] -= roi_in->
y;
1121 float homograph[3][3];
1125 float xm = FLT_MAX, xM = -FLT_MAX, ym = FLT_MAX, yM = -FLT_MAX;
1128 for(
int y = 0; y < roi_in->
height; y += roi_in->
height - 1)
1132 float pin[3], pout[3];
1135 pin[0] = roi_in->
x +
x;
1136 pin[1] = roi_in->
y + y;
1137 pin[0] /= roi_in->
scale;
1138 pin[1] /= roi_in->
scale;
1142 mat3mulv(pout, (
float *)homograph, pin);
1147 pout[0] *= roi_out->
scale;
1148 pout[1] *= roi_out->
scale;
1149 xm =
MIN(xm, pout[0]);
1150 xM =
MAX(xM, pout[0]);
1151 ym =
MIN(ym, pout[1]);
1152 yM =
MAX(yM, pout[1]);
1156 float width = xM - xm + 1;
1157 float height = yM - ym + 1;
1167 print_roi(roi_in,
"roi_in (going into modify_roi_out)");
1168 print_roi(roi_out,
"roi_out (after modify_roi_out)");
1187 float ihomograph[3][3];
1195 const float fullwidth = (float)piece->
buf_out.
width / (data->
cr - data->
cl);
1197 const float cx = roi_out->
scale * fullwidth * data->
cl;
1198 const float cy = roi_out->
scale * fullheight * data->
ct;
1200 float xm = FLT_MAX, xM = -FLT_MAX, ym = FLT_MAX, yM = -FLT_MAX;
1203 for(
int y = 0; y < roi_out->
height; y += roi_out->
height - 1)
1207 float pin[3], pout[3];
1210 pout[0] = roi_out->
x +
x + cx;
1211 pout[1] = roi_out->
y + y + cy;
1212 pout[0] /= roi_out->
scale;
1213 pout[1] /= roi_out->
scale;
1217 mat3mulv(pin, (
float *)ihomograph, pout);
1222 pin[0] *= roi_in->
scale;
1223 pin[1] *= roi_in->
scale;
1224 xm =
MIN(xm, pin[0]);
1225 xM =
MAX(xM, pin[0]);
1226 ym =
MIN(ym, pin[1]);
1227 yM =
MAX(yM, pin[1]);
1232 roi_in->
x = fmaxf(0.0f, xm - interpolation->
width);
1233 roi_in->
y = fmaxf(0.0f, ym - interpolation->
width);
1234 roi_in->
width = fminf(ceilf(orig_w) - roi_in->
x, xM - roi_in->
x + 1 + interpolation->
width);
1235 roi_in->
height = fminf(ceilf(orig_h) - roi_in->
y, yM - roi_in->
y + 1 + interpolation->
width);
1238 roi_in->
x = CLAMP(roi_in->
x, 0, (
int)floorf(orig_w));
1239 roi_in->
y = CLAMP(roi_in->
y, 0, (
int)floorf(orig_h));
1240 roi_in->
width = CLAMP(roi_in->
width, 1, (
int)floorf(orig_w) - roi_in->
x);
1241 roi_in->
height = CLAMP(roi_in->
height, 1, (
int)floorf(orig_h) - roi_in->
y);
1243 print_roi(roi_out,
"roi_out (going into modify_roi_in)");
1244 print_roi(roi_in,
"roi_in (after modify_roi_in)");
1254 for(
int index = 0; index < npixels; index++)
1256 out[index] = (0.3f * in[4*index+0] + 0.59f * in[4*index+1] + 0.11f * in[4*index+2]) * 256.0;
1265 const double hkernel[3][3] = { { 1.0, 0.0, -1.0 }, { 2.0, 0.0, -2.0 }, { 1.0, 0.0, -1.0 } };
1266 const double vkernel[3][3] = { { 1.0, 2.0, 1.0 }, { 0.0, 0.0, 0.0 }, { -1.0, -2.0, -1.0 } };
1267 const int kwidth = 3;
1268 const int khwidth = kwidth / 2;
1274 for(
int j = khwidth; j <
height - khwidth; j++)
1276 const double *inp = in + (size_t)j *
width + khwidth;
1277 double *outp =
out + (size_t)j *
width + khwidth;
1278 for(
int i = khwidth;
i <
width - khwidth;
i++, inp++, outp++)
1281 for(
int jj = 0; jj < kwidth; jj++)
1283 const int k = jj * kwidth;
1284 const int l = (jj - khwidth) *
width;
1285 for(
int ii = 0; ii < kwidth; ii++)
1287 sum += inp[l + ii - khwidth] *
kernel[
k + ii];
1295 for(
int j = 0; j <
height; j++)
1302 else if(j >=
height - khwidth)
1304 else if(
i < khwidth)
1306 else if(
i >=
width - khwidth)
1312 if(
i == khwidth && j >= khwidth && j <
height - khwidth)
i =
width - khwidth;
1336 out[
k] = sqrt(Gx[
k] * Gx[
k] + Gy[
k] * Gy[
k]);
1352 sRGB[0] = 3.1338561f *
XYZ[0] - 1.6168667f *
XYZ[1] - 0.4906146f *
XYZ[2];
1353 sRGB[1] = -0.9787684f *
XYZ[0] + 1.9161415f *
XYZ[1] + 0.0334540f *
XYZ[2];
1354 sRGB[2] = 0.0719453f *
XYZ[0] - 0.2289914f *
XYZ[1] + 1.4052427f *
XYZ[2];
1360 XYZ[0] = 0.4360747f *
sRGB[0] + 0.3850649f *
sRGB[1] + 0.1430804f *
sRGB[2];
1361 XYZ[1] = 0.2225045f *
sRGB[0] + 0.7168786f *
sRGB[1] + 0.0606169f *
sRGB[2];
1362 XYZ[2] = 0.0139322f *
sRGB[0] + 0.0971045f *
sRGB[1] + 0.7141733f *
sRGB[2];
1370 const float detail = 10.0f;
1379 for(
size_t index = 0; index < 4*npixels; index += 4)
1401 for(
size_t index = 0; index < 4*npixels; index += 4)
1416 for(
int index = 0; index < 4*npixels; index += 4)
1418 for(
int c = 0; c < 3; c++)
1429 double *greyscale = NULL;
1430 double *lsd_lines = NULL;
1433 int vertical_count = 0;
1434 int horizontal_count = 0;
1435 float vertical_weight = 0.0f;
1436 float horizontal_weight = 0.0f;
1451 greyscale = malloc(
sizeof(
double) *
width *
height);
1481 for(
int n = 0;
n < lines_count;
n++)
1483 const float x1 = lsd_lines[
n * 7 + 0];
1484 const float y1 = lsd_lines[
n * 7 + 1];
1485 const float x2 = lsd_lines[
n * 7 + 2];
1486 const float y2 = lsd_lines[
n * 7 + 3];
1491 if((fabsf(x1 - x2) < 1 && fmaxf(x1, x2) < 2)
1492 || (fabsf(x1 - x2) < 1 && fminf(x1, x2) >
width - 3)
1493 || (fabsf(y1 - y2) < 1 && fmaxf(y1, y2) < 2)
1494 || (fabsf(y1 - y2) < 1 && fminf(y1, y2) >
height - 3))
1498 float px1 = x_off + x1;
1499 float py1 = y_off + y1;
1500 float px2 = x_off + x2;
1501 float py2 = y_off + y2;
1510 ashift_lines[lct].
p1[0] = px1;
1511 ashift_lines[lct].
p1[1] = py1;
1512 ashift_lines[lct].
p1[2] = 1.0f;
1513 ashift_lines[lct].
p2[0] = px2;
1514 ashift_lines[lct].
p2[1] = py2;
1515 ashift_lines[lct].
p2[2] = 1.0f;
1518 vec3prodn(ashift_lines[lct].
L, ashift_lines[lct].p1, ashift_lines[lct].p2);
1522 vec3lnorm(ashift_lines[lct].
L, ashift_lines[lct].
L);
1525 ashift_lines[lct].
length = sqrt((px2 - px1) * (px2 - px1) + (py2 - py1) * (py2 - py1));
1526 ashift_lines[lct].
width = lsd_lines[
n * 7 + 4] / scale;
1529 const float weight = ashift_lines[lct].
length * ashift_lines[lct].
width * lsd_lines[
n * 7 + 5];
1533 const float angle = atan2f(py2 - py1, px2 - px1) /
M_PI * 180.0f;
1541 if(vertical && relevant)
1545 vertical_weight +=
weight;
1547 else if(horizontal && relevant)
1551 horizontal_weight +=
weight;
1560 printf(
"%d lines (vertical %d, horizontal %d, not relevant %d)\n", lines_count, vertical_count,
1561 horizontal_count, lct - vertical_count - horizontal_count);
1562 float xmin = FLT_MAX, xmax = FLT_MIN, ymin = FLT_MAX, ymax = FLT_MIN;
1563 for(
int n = 0;
n < lct;
n++)
1565 xmin = fmin(xmin, fmin(ashift_lines[
n].p1[0], ashift_lines[
n].p2[0]));
1566 xmax = fmax(xmax, fmax(ashift_lines[
n].p1[0], ashift_lines[
n].p2[0]));
1567 ymin = fmin(ymin, fmin(ashift_lines[
n].p1[1], ashift_lines[
n].p2[1]));
1568 ymax = fmax(ymax, fmax(ashift_lines[
n].p1[1], ashift_lines[
n].p2[1]));
1569 printf(
"x1 %.0f, y1 %.0f, x2 %.0f, y2 %.0f, length %.0f, width %f, X %f, Y %f, Z %f, type %d, scalars %f %f\n",
1570 ashift_lines[
n].p1[0], ashift_lines[
n].p1[1], ashift_lines[
n].p2[0], ashift_lines[
n].p2[1],
1571 ashift_lines[
n].length, ashift_lines[
n].
width,
1572 ashift_lines[
n].
L[0], ashift_lines[
n].
L[1], ashift_lines[
n].
L[2], ashift_lines[
n].
type,
1576 printf(
"xmin %.0f, xmax %.0f, ymin %.0f, ymax %.0f\n", xmin, xmax, ymin, ymax);
1581 *vcount = vertical_count;
1582 *vweight = vertical_weight;
1583 *hcount = horizontal_count;
1584 *hweight = horizontal_weight;
1585 *alines = ashift_lines;
1603 float *buffer = NULL;
1616 x_off =
g->buf_x_off;
1617 y_off =
g->buf_y_off;
1618 scale =
g->buf_scale;
1621 buffer = malloc(
sizeof(
float) * 4 * (
size_t)
width *
height);
1631 g->vertical_count = 0;
1632 g->horizontal_count = 0;
1638 int horizontal_count;
1639 float vertical_weight;
1640 float horizontal_weight;
1646 dt_iop_fmt_log(module,
"structure: class=%s raw_origin=%d enhance=%d",
1648 raw_origin, enhance);
1650 &vertical_count, &horizontal_count, &vertical_weight, &horizontal_weight,
1651 enhance, raw_origin))
1657 const float inv_scale = (scale > 0.f) ? (1.f / scale) : 1.f;
1658 g->lines_in_width = (int)roundf(
width * inv_scale);
1659 g->lines_in_height = (int)roundf(
height * inv_scale);
1660 g->lines_x_off = (int)roundf(x_off * inv_scale);
1661 g->lines_y_off = (int)roundf(y_off * inv_scale);
1662 g->lines_count = lines_count;
1663 g->vertical_count = vertical_count;
1664 g->horizontal_count = horizontal_count;
1665 g->vertical_weight = vertical_weight;
1666 g->horizontal_weight = horizontal_weight;
1680static inline void swap(
int *a,
int *b)
1693 int j = (*
i % 2 == 1) ?
p[*
i] : 0;
1694 swap(&a[j], &a[*
i]);
1707 for(
int i = 0;
i <
N;
i++)
1709 int j =
i + rand() % (
N -
i);
1717 return (
n == 1 ? 1 :
n *
fact(
n - 1));
1737 const int set_count,
const float total_weight,
const int xmin,
const int xmax,
1738 const int ymin,
const int ymax)
1740 if(set_count < 3)
return;
1742 const size_t set_size = set_count *
sizeof(int);
1743 int *best_set = malloc(set_size);
1744 memcpy(best_set, index_set, set_size);
1745 int *best_inout = calloc(1, set_size);
1747 float best_quality = 0.0f;
1754 int lines_eliminated = 0;
1763 int *
perm = malloc(
sizeof(
int) * (set_count + 1));
1764 for(
int n = 0;
n < set_count + 1;
n++)
perm[
n] =
n;
1768 int *inout = malloc(set_size);
1770 for(
int r = 0;
r < optiruns + riter;
r++)
1774 shuffle(index_set, set_count);
1779 float quality = 0.0f;
1782 const float *L1 = lines[index_set[0]].
L;
1783 const float *L2 = lines[index_set[1]].
L;
1793 (fabsf(
V[2]) > 0.0f &&
1794 V[0]/
V[2] >= xmin &&
1795 V[1]/
V[2] >= ymin &&
1796 V[0]/
V[2] <= xmax &&
1816 for(
int n = 2;
n < set_count;
n++)
1819 const float *L3 = lines[index_set[
n]].
L;
1828 inout[
n] = (
d < epsilon) ? 1 : 0;
1836 q = 0.33f / (float)set_count
1837 + 0.33f * lines[index_set[
n]].
weight / total_weight
1838 + 0.33f * (1.0f -
d / epsilon) * (float)set_count * lines[index_set[
n]].
weight / total_weight;
1857 printf(
"ransac self-tuning (run %d): epsilon %f",
r, epsilon);
1860 float ratio = 100.0f * (float)lines_eliminated / ((
float)set_count * valid_runs);
1863 epsilon = powf(10.0f, log10(epsilon) - epsilon_step);
1865 epsilon = powf(10.0f, log10(epsilon) + epsilon_step);
1867 printf(
" (elimination ratio %f) -> %f\n", ratio, epsilon);
1870 epsilon_step /= 2.0f;
1871 lines_eliminated = 0;
1878 if(quality > best_quality)
1880 memcpy(best_set, index_set, set_size);
1881 memcpy(best_inout, inout, set_size);
1882 best_quality = quality;
1888 int count = 0, lastcount = 0;
1889 for(
int n = 0;
n < set_count;
n++) count += best_inout[
n];
1890 for(
int n = 0;
n < set_count;
n++) lastcount += inout[
n];
1891 printf(
"ransac run %d: best qual %.6f, eps %.6f, line count %d of %d (this run: qual %.5f, count %d (%2f%%))\n",
r,
1892 best_quality, epsilon, count, set_count, quality, lastcount, 100.0f * lastcount / (
float)set_count);
1897 memcpy(index_set, best_set, set_size);
1898 memcpy(inout_set, best_inout, set_size);
1913 const int width =
g->lines_in_width;
1914 const int height =
g->lines_in_height;
1915 const int xmin =
g->lines_x_off;
1916 const int ymin =
g->lines_y_off;
1917 const int xmax = xmin +
width;
1918 const int ymax = ymin +
height;
1921 int *lines_set = malloc(
sizeof(
int) *
g->lines_count);
1923 int *inout_set = malloc(
sizeof(
int) *
g->lines_count);
1926 int vnb = 0, vcount = 0;
1927 int hnb = 0, hcount = 0;
1933 for(
int n = 0;
n <
g->lines_count;
n++)
1946 ransac(
g->lines, lines_set, inout_set, vnb,
g->vertical_weight,
1947 xmin, xmax, ymin, ymax);
1950 for(
int n = 0;
n < vnb;
n++)
1952 const int m = lines_set[
n];
1953 if(inout_set[
n] == 1)
1959 g->lines[
m].type &= ~ASHIFT_LINE_SELECTED;
1962 g->vertical_count = vcount;
1966 for(
int n = 0;
n <
g->lines_count;
n++)
1979 ransac(
g->lines, lines_set, inout_set, hnb,
g->horizontal_weight,
1980 xmin, xmax, ymin, ymax);
1983 for(
int n = 0;
n < hnb;
n++)
1985 const int m = lines_set[
n];
1986 if(inout_set[
n] == 1)
1992 g->lines[
m].type &= ~ASHIFT_LINE_SELECTED;
1995 g->horizontal_count = hcount;
2012 const double eps = 1.0e-6;
2017 return (2.0 * atanh(2.0 *
p - 1.0));
2023 double p = 0.5 * (1.0 + tanh(0.5 *
L));
2046 const float aspect = fit->
aspect;
2051 float shear = fit->
shear;
2062 rotation =
ilogit(params[pcount], -rotation_range, rotation_range);
2066 if(isnan(lensshift_v))
2068 lensshift_v =
ilogit(params[pcount], -lensshift_v_range, lensshift_v_range);
2072 if(isnan(lensshift_h))
2074 lensshift_h =
ilogit(params[pcount], -lensshift_h_range, lensshift_h_range);
2080 shear =
ilogit(params[pcount], -shear_range, shear_range);
2087 const float Av[3] = { 1.0f, 0.0f, 0.0f };
2088 const float Ah[3] = { 0.0f, 1.0f, 0.0f };
2091 float homograph[3][3];
2092 homography((
float *)homograph, rotation, lensshift_v, lensshift_h, shear, f_length_kb,
2096 double sumsq_v = 0.0;
2097 double sumsq_h = 0.0;
2098 double weight_v = 0.0;
2099 double weight_h = 0.0;
2105 for(
int n = 0;
n < lines_count;
n++)
2115 const float *
A = isvertical ? Ah : Av;
2119 mat3mulv(P1, (
float *)homograph, lines[
n].p1);
2120 mat3mulv(P2, (
float *)homograph, lines[
n].p2);
2134 sumsq_v += isvertical ? s * s * lines[
n].
weight : 0.0;
2135 weight_v += isvertical ? lines[
n].
weight : 0.0;
2136 count_v += isvertical ? 1 : 0;
2137 sumsq_h += !isvertical ? s * s * lines[
n].
weight : 0.0;
2138 weight_h += !isvertical ? lines[
n].
weight : 0.0;
2139 count_h += !isvertical ? 1 : 0;
2143 const double v = weight_v > 0.0f && count > 0 ? sumsq_v / weight_v * (float)count_v / count : 0.0;
2144 const double h = weight_h > 0.0f && count > 0 ? sumsq_h / weight_h * (float)count_h / count : 0.0;
2146 double sum = sqrt(1.0 - (1.0 -
v) * (1.0 - h)) * 1.0e6;
2150 printf(
"fitness with rotation %f, lensshift_v %f, lensshift_h %f, shear %f -> lines %d, quality %10f\n",
2151 rotation, lensshift_v, lensshift_h, shear, count, sum);
2167 int enough_lines =
TRUE;
2173 fit.
width =
g->lines_in_width;
2174 fit.
height =
g->lines_in_height;
2249 fit.
weight +=
g->vertical_weight;
2257 fit.
weight +=
g->horizontal_weight;
2274 printf(
"optimization not possible: insufficient number of lines\n");
2286 printf(
"optimization not successful: maximum number of iterations reached (%d)\n", iter);
2298 printf(
"params after optimization (%d iterations): rotation %f, lensshift_v %f, lensshift_h %f, shear %f\n",
2304 float homograph[3][3];
2309 float xm = FLT_MAX, xM = -FLT_MAX, ym = FLT_MAX, yM = -FLT_MAX;
2317 mat3mulv(po, (
float *)homograph, pi);
2320 xm = fmin(xm, po[0]);
2321 ym = fmin(ym, po[1]);
2322 xM = fmax(xM, po[0]);
2323 yM = fmax(yM, po[1]);
2326 if((xM - xm) * (yM - ym) > 4.0f * fit.
width * fit.
height)
2329 printf(
"optimization not successful: degenerate case with area growth factor (%f) exceeding limits\n",
2330 (xM - xm) * (yM - ym) / (fit.
width * fit.
height));
2354 int enough_lines =
TRUE;
2360 fit.
width =
g->lines_in_width;
2361 fit.
height =
g->lines_in_height;
2390 fit.
weight +=
g->vertical_weight;
2398 fit.
weight +=
g->horizontal_weight;
2413 printf(
"model fitness: %.8f (rotation %f, lensshift_v %f, lensshift_h %f, shear %f)\n",
2414 quality,
p->rotation,
p->lensshift_v,
p->lensshift_h,
p->shear);
2421 if(pcount > 0) params[0] = fabs(params[0]);
2422 if(pcount > 1) params[1] = fabs(params[1]);
2423 if(pcount > 2) params[2] = fabs(params[2]);
2425 if(pcount > 0 && params[0] > 1.0) params[0] = 1.0 - params[0];
2426 if(pcount > 1 && params[1] > 1.0) params[1] = 1.0 - params[1];
2427 if(pcount > 2 && params[2] > 0.5*
M_PI) params[2] = 0.5*
M_PI - params[2];
2440 const float wd = cropfit->
width;
2441 const float ht = cropfit->
height;
2444 const float x = isnan(cropfit->
x) ? params[0] : cropfit->
x;
2445 const float y = isnan(cropfit->
y) ? params[1] : cropfit->
y;
2446 const float alpha = isnan(cropfit->
alpha) ? params[2] : cropfit->
alpha;
2449 const float Pc[3] = {
x * wd, y * ht, 1.0f };
2459 const float Pa[2][3] = { {
P[0] + 10.0f * cosf(alpha),
P[1] + 10.0f * sinf(alpha), 1.0f },
2460 {
P[0] + 10.0f * cosf(alpha),
P[1] - 10.0f * sinf(alpha), 1.0f } };
2470 float d2min = FLT_MAX;
2471 for(
int k = 0;
k < 4;
k++)
2472 for(
int l = 0; l < 2; l++)
2494 const float d2 =
SQR(
P[0] - I[0]) +
SQR(
P[1] - I[1]);
2497 d2min =
MIN(d2min, d2);
2501 const float A = 2.0f * d2min * sinf(2.0f * alpha);
2504 printf(
"crop fitness with x %f, y %f, angle %f -> distance %f, area %f\n",
2505 x, y, alpha, d2min,
A);
2539 int crop_width = 0, crop_height = 0;
2549 crop_width =
g->buf_width;
2550 crop_height =
g->buf_height;
2554 if(crop_width == 0 || crop_height == 0)
return;
2557 if(
g->fitting)
return;
2573 const float rotation =
p->rotation;
2574 const float lensshift_v =
p->lensshift_v;
2575 const float lensshift_h =
p->lensshift_h;
2576 const float shear =
p->shear;
2580 cropfit.
width = crop_width;
2581 cropfit.
height = crop_height;
2582 homography((
float *)cropfit.
homograph, rotation, lensshift_v, lensshift_h, shear, f_length_kb,
2585 const float wd = cropfit.
width;
2586 const float ht = cropfit.
height;
2590 const float crop_alpha = atan2f(ht, wd);
2593 const float Vc[4][3] = { { 0.0f, 0.0f, 1.0f },
2596 { wd, 0.0f, 1.0f } };
2600 for(
int n = 0;
n < 4;
n++)
2604 float xmin = FLT_MAX, ymin = FLT_MAX, xmax = FLT_MIN, ymax = FLT_MIN;
2605 for(
int n = 0;
n < 4;
n++)
2611 xmin =
MIN(xmin,
V[
n][0]);
2612 xmax =
MAX(xmax,
V[
n][0]);
2613 ymin =
MIN(ymin,
V[
n][1]);
2614 ymax =
MAX(ymax,
V[
n][1]);
2616 const float owd = xmax - xmin;
2617 const float oht = ymax - ymin;
2620 for(
int n = 0;
n < 4;
n++)
2629 params[2] = crop_alpha;
2632 cropfit.
alpha = NAN;
2641 cropfit.
alpha = crop_alpha;
2652 cropfit.
x = isnan(cropfit.
x) ? params[0] : cropfit.
x;
2653 cropfit.
y = isnan(cropfit.
y) ? params[1] : cropfit.
y;
2657 const float A = fabs(
crop_fitness(params, (
void*)&cropfit));
2660 if(
A == 0.0f)
goto failed;
2664 const float d = sqrtf(
A / (2.0f * sinf(2.0f * cropfit.
alpha)));
2667 const float Pc[3] = { cropfit.
x * wd, cropfit.
y * ht, 1.0f };
2676 p->cl = CLAMP((
P[0] -
d * cosf(cropfit.
alpha)) / owd, 0.0f, 1.0f);
2677 p->cr = CLAMP((
P[0] +
d * cosf(cropfit.
alpha)) / owd, 0.0f, 1.0f);
2678 p->ct = CLAMP((
P[1] -
d * sinf(cropfit.
alpha)) / oht, 0.0f, 1.0f);
2679 p->cb = CLAMP((
P[1] +
d * sinf(cropfit.
alpha)) / oht, 0.0f, 1.0f);
2682 if(
p->cr -
p->cl <= 0.0f ||
p->cb -
p->ct <= 0.0f)
goto failed;
2687 printf(
"margins after crop fitting: iter %d, x %f, y %f, angle %f, crop area (%f %f %f %f), width %f, height %f\n",
2688 iter, cropfit.
x, cropfit.
y, cropfit.
alpha,
p->cl,
p->cr,
p->ct,
p->cb, wd, ht);
2723 if(fabsf(line->
p1[0] - line->
p2[0]) > fabsf(line->
p1[1] - line->
p2[1]))
2725 line->
type = linetype;
2748 line->
length = sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
2759 gtk_widget_set_sensitive(
g->fit_v,
enable);
2760 gtk_widget_set_sensitive(
g->fit_h,
enable);
2761 gtk_widget_set_sensitive(
g->fit_both,
enable);
2776 float pts[8] = {
g->lines[0].p1[0],
g->lines[0].p1[1],
g->lines[0].p2[0],
2777 g->lines[0].p2[1],
g->lines[1].p1[0],
g->lines[1].p1[1],
2778 g->lines[1].p2[0],
g->lines[1].p2[1] };
2782 for(
int i = 0;
i < 8;
i++)
p->last_quad_lines[
i] = pts[
i];
2788 p->last_drawn_lines_count = 0;
2790 for(
int i = 0;
i <
g->lines_count;
i++)
2796 p->last_drawn_lines[
p->last_drawn_lines_count * 4 ] =
g->lines[
i].p1[0];
2797 p->last_drawn_lines[
p->last_drawn_lines_count * 4 + 1] =
g->lines[
i].p1[1];
2798 p->last_drawn_lines[
p->last_drawn_lines_count * 4 + 2] =
g->lines[
i].p2[0];
2799 p->last_drawn_lines[
p->last_drawn_lines_count * 4 + 3] =
g->lines[
i].p2[1];
2800 p->last_drawn_lines_count++;
2806 p->last_drawn_lines_count * 2);
2823 &&
p->last_quad_lines[0] > 0.0f &&
p->last_quad_lines[1] > 0.0f
2824 &&
p->last_quad_lines[2] > 0.0f &&
p->last_quad_lines[3] > 0.0f)
2826 float pts[8] = {
p->last_quad_lines[0],
p->last_quad_lines[1],
2827 p->last_quad_lines[2],
p->last_quad_lines[3],
2828 p->last_quad_lines[4],
p->last_quad_lines[5],
2829 p->last_quad_lines[6],
p->last_quad_lines[7] };
2851 g->vertical_count = 2;
2852 g->horizontal_count = 2;
2853 g->vertical_weight = 2.0;
2854 g->horizontal_weight = 2.0;
2855 g->lines_in_width = piece->
iwidth;
2856 g->lines_in_height = piece->
iheight;
2857 g->current_structure_method = method;
2866 for(
int i = 0;
i <
p->last_drawn_lines_count * 4;
i++)
2867 pts[
i] =
p->last_drawn_lines[
i];
2880 for(
int i = 0;
i <
p->last_drawn_lines_count;
i++)
2884 if(fabsf(pts[
i * 4] - pts[
i * 4 + 2]) > fabsf(pts[
i * 4 + 1] - pts[
i * 4 + 3]))
2894 g->lines_count =
p->last_drawn_lines_count;
2895 g->vertical_count = vnb;
2896 g->horizontal_count = hnb;
2897 g->vertical_weight = (float)vnb;
2898 g->horizontal_weight = (float)hnb;
2899 g->lines_in_width = piece->
iwidth;
2900 g->lines_in_height = piece->
iheight;
2901 g->current_structure_method = method;
2913 if(
g->fitting)
return FALSE;
2920 g->vertical_count = 0;
2921 g->horizontal_count = 0;
2939 if(
g->fitting)
return FALSE;
2956 g->jobparams = enhance;
2965 printf(
"do_get_structure: buf %p, buf_hash %" PRIu64
", buf_width %d, buf_height %d, lines %p, lines_count %d\n",
2966 g->buf,
g->buf_hash,
g->buf_width,
g->buf_height,
g->lines,
g->lines_count);
2976 printf(
"_remove_outliers: buf %p, buf_hash %" PRIu64
", buf_width %d, buf_height %d, lines %p, lines_count %d\n",
2977 g->buf,
g->buf_hash,
g->buf_width,
g->buf_height,
g->lines,
g->lines_count);
3007 g->lines_in_width = piece->
iwidth;
3008 g->lines_in_height = piece->
iheight;
3042 float pts[8] = { wd * 0.2, ht * 0.2, wd * 0.2, ht * 0.8, wd * 0.8, ht * 0.2, wd * 0.8, ht * 0.8 };
3062 g->lines_in_width = piece->
iwidth;
3063 g->lines_in_height = piece->
iheight;
3066 g->vertical_count = 2;
3067 g->horizontal_count = 2;
3068 g->vertical_weight = 2.0;
3069 g->horizontal_weight = 2.0;
3083 if(
g->fitting)
return;
3089 if(
g->lines_in_width > 0 &&
g->lines_in_height > 0)
3095 float homograph[3][3];
3096 homography((
float *)homograph,
p->rotation,
p->lensshift_v,
p->lensshift_h,
p->shear, f_length_kb,
3099 const float ivec[2] = { (float)
g->lines_in_width, (
float)
g->lines_in_height };
3100 const float ivecl = sqrtf(ivec[0] * ivec[0] + ivec[1] * ivec[1]);
3102 const float pin0[3] = { 0.0f, 0.0f, 1.0f };
3103 const float pin1[3] = { (float)
g->lines_in_width, (
float)
g->lines_in_height, 1.0f };
3106 mat3mulv(pout0, (
float *)homograph, pin0);
3107 mat3mulv(pout1, (
float *)homograph, pin1);
3108 pout0[0] /= pout0[2];
3109 pout0[1] /= pout0[2];
3110 pout1[0] /= pout1[2];
3111 pout1[1] /= pout1[2];
3113 const float ovec[2] = { pout1[0] - pout0[0], pout1[1] - pout0[1] };
3114 const float ovecl = sqrtf(ovec[0] * ovec[0] + ovec[1] * ovec[1]);
3115 const float alpha = acos(CLAMP((ivec[0] * ovec[0] + ivec[1] * ovec[1]) / (ivecl * ovecl), -1.0f, 1.0f));
3116 g->isflipped = fabs(fmod(alpha +
M_PI,
M_PI) -
M_PI / 2.0f) <
M_PI / 4.0f ? 1 : 0;
3129 _(
"not enough structure for automatic correction\nminimum %d lines in each relevant direction"),
3134 dt_control_log(_(
"automatic correction failed, please correct manually"));
3162 const int ch_width =
ch * roi_in->
width;
3173 const int x_off = roi_in->
x;
3174 const int y_off = roi_in->
y;
3179 const float scale = 0.5f * (scale_x + scale_y);
3183 float ivec[2] = { points[2] - points[0], points[3] - points[1] };
3184 float ivecl = sqrtf(ivec[0] * ivec[0] + ivec[1] * ivec[1]);
3190 float ovec[2] = { points[2] - points[0], points[3] - points[1] };
3191 float ovecl = sqrtf(ovec[0] * ovec[0] + ovec[1] * ovec[1]);
3194 float alpha = acos(CLAMP((ivec[0] * ovec[0] + ivec[1] * ovec[1]) / (ivecl * ovecl), -1.0f, 1.0f));
3197 const int isflipped = fabs(fmod(alpha +
M_PI,
M_PI) -
M_PI / 2.0f) <
M_PI / 4.0f ? 1 : 0;
3203 g->isflipped = isflipped;
3226 g->buf_x_off = x_off;
3227 g->buf_y_off = y_off;
3228 g->buf_scale = scale;
3244 float ihomograph[3][3];
3249 const float fullwidth = (float)piece->
buf_out.
width / (data->
cr - data->
cl);
3251 const float cx = roi_out->
scale * fullwidth * data->
cl;
3252 const float cy = roi_out->
scale * fullheight * data->
ct;
3255 for(
int j = 0; j < roi_out->
height; j++)
3257 float *
const restrict
out = ((
float *)
ovoid) + (size_t)
ch * j * roi_out->
width;
3258 for(
int i = 0;
i < roi_out->
width;
i++)
3260 float pin[3], pout[3];
3263 pout[0] = roi_out->
x +
i + cx;
3264 pout[1] = roi_out->
y + j + cy;
3265 pout[0] /= roi_out->
scale;
3266 pout[1] /= roi_out->
scale;
3270 mat3mulv(pin, (
float *)ihomograph, pout);
3275 pin[0] *= roi_in->
scale;
3276 pin[1] *= roi_in->
scale;
3277 pin[0] -= roi_in->
x;
3278 pin[1] -= roi_in->
y;
3282 roi_in->
height, ch_width);
3297 const int devid = pipe->
devid;
3298 const int iwidth = roi_in->
width;
3299 const int iheight = roi_in->
height;
3304 cl_mem dev_homo = NULL;
3313 const int x_off = roi_in->
x;
3314 const int y_off = roi_in->
y;
3319 const float scale = 0.5f * (scale_x + scale_y);
3323 const float ivec[2] = { points[2] - points[0], points[3] - points[1] };
3324 const float ivecl = sqrtf(ivec[0] * ivec[0] + ivec[1] * ivec[1]);
3330 const float ovec[2] = { points[2] - points[0], points[3] - points[1] };
3331 const float ovecl = sqrtf(ovec[0] * ovec[0] + ovec[1] * ovec[1]);
3334 const float alpha = acos(CLAMP((ivec[0] * ovec[0] + ivec[1] * ovec[1]) / (ivecl * ovecl), -1.0f, 1.0f));
3337 const int isflipped = fabs(fmod(alpha +
M_PI,
M_PI) -
M_PI / 2.0f) <
M_PI / 4.0f ? 1 : 0;
3343 g->isflipped = isflipped;
3346 if(
IS_NULL_PTR(
g->buf) || (
size_t)
g->buf_width *
g->buf_height < (
size_t)iwidth * iheight)
3351 g->buf = malloc(
sizeof(
float) * 4 * iwidth * iheight);
3359 g->buf_width = iwidth;
3360 g->buf_height = iheight;
3361 g->buf_x_off = x_off;
3362 g->buf_y_off = y_off;
3363 g->buf_scale = scale;
3367 if(err != CL_SUCCESS)
goto error;
3373 size_t origin[] = { 0, 0, 0 };
3376 if(err != CL_SUCCESS)
goto error;
3380 float ihomograph[3][3];
3381 homography((
float *)ihomograph,
d->rotation,
d->lensshift_v,
d->lensshift_h,
d->shear,
d->f_length_kb,
3385 const float fullwidth = (float)piece->
buf_out.
width / (
d->cr -
d->cl);
3386 const float fullheight = (float)piece->
buf_out.
height / (
d->cb -
d->ct);
3387 const float cx = roi_out->
scale * fullwidth *
d->cl;
3388 const float cy = roi_out->
scale * fullheight *
d->ct;
3393 const int iroi[2] = { roi_in->
x, roi_in->
y };
3394 const int oroi[2] = { roi_out->
x, roi_out->
y };
3395 const float in_scale = roi_in->
scale;
3396 const float out_scale = roi_out->
scale;
3397 const float clip[2] = { cx, cy };
3405 switch(interpolation->
id)
3433 if(err != CL_SUCCESS)
goto error;
3447 float pzy,
float delta, gboolean multiple)
3451 for(
int n = 0;
n < lines_count;
n++)
3453 points_idx[
n].
near = 0;
3460 if(pzx < points_idx[
n].bbx -
delta &&
3461 pzx > points_idx[
n].bbX +
delta &&
3462 pzy < points_idx[
n].bby -
delta &&
3463 pzy > points_idx[
n].bbY +
delta)
3467 size_t offset = points_idx[
n].
offset;
3468 const int length = points_idx[
n].
length;
3471 if(length < 2)
continue;
3474 for(
int l = 0; l < length; l++, offset++)
3476 float dx = pzx - points[offset * 2];
3477 float dy = pzy - points[offset * 2 + 1];
3479 if(dx * dx + dy * dy < delta2)
3481 points_idx[
n].
near = 1;
3486 if(!multiple && points_idx[
n].near)
break;
3492 const int points_lines_count,
float pzx,
float pzy,
3515 for(
int n = 0;
n < points_lines_count;
n++)
3518 points_idx[
n].
near = 0;
3526 if(points_idx[
n].bbx >= ax && points_idx[
n].bbx <= bx && points_idx[
n].bbX >= ax
3527 && points_idx[
n].bbX <= bx && points_idx[
n].bby >= ay && points_idx[
n].bby <= by
3528 && points_idx[
n].bbY >= ay && points_idx[
n].bbY <= by)
3541 for(
int n = 0;
n < lines_count;
n++)
3552 int points_lines_count)
3557 const int isflipped =
g->isflipped;
3560 for(
int n = 0;
n < points_lines_count;
n++)
3584 const int lines_version,
float **points,
float **extremas,
3591 float *my_points = NULL;
3592 float *my_extremas = NULL;
3595 const int isflipped =
g->isflipped;
3602 size_t total_points = 0;
3605 for(
int n = 0;
n < lines_count;
n++)
3607 const int length =
MAX(lines[
n].length, 2);
3609 total_points += length;
3611 my_points_idx[
n].
length = length;
3612 my_points_idx[
n].
near = 0;
3634 my_points = (
float *)malloc(
sizeof(
float) * 2 * total_points);
3635 my_extremas = (
float *)malloc(
sizeof(
float) * 2 * 2 * lines_count);
3639 for(
int n = 0, offset = 0;
n < lines_count;
n++)
3641 my_extremas[4 *
n] = lines[
n].
p1[0];
3642 my_extremas[4 *
n + 1] = lines[
n].
p1[1];
3643 my_extremas[4 *
n + 2] = lines[
n].
p2[0];
3644 my_extremas[4 *
n + 3] = lines[
n].
p2[1];
3646 my_points_idx[
n].
offset = offset;
3648 float x = lines[
n].
p1[0];
3649 float y = lines[
n].
p1[1];
3650 const int length = lines[
n].
length;
3652 const float dx = (lines[
n].
p2[0] -
x) / (
float)(length - 1);
3653 const float dy = (lines[
n].
p2[1] - y) / (
float)(length - 1);
3658 my_points[2 * offset] =
x;
3659 my_points[2 * offset + 1] = y;
3661 my_points[2 * offset] = lines[
n].
p2[0];
3662 my_points[2 * offset + 1] = lines[
n].
p2[1];
3667 for(
int l = 0; l < length && offset < total_points; l++, offset++)
3669 my_points[2 * offset] =
x;
3670 my_points[2 * offset + 1] = y;
3682 my_extremas, 2 * lines_count))
3686 const float gui_scale = (scale > 0.f) ? scale : 1.f;
3687 if(gui_scale != 1.f)
3689 for(
size_t i = 0;
i < total_points * 2;
i++)
3690 my_points[
i] *= gui_scale;
3691 for(
int i = 0;
i < 4 * lines_count;
i++)
3692 my_extremas[
i] *= gui_scale;
3696 for(
int n = 0;
n < lines_count;
n++)
3698 float xmin = FLT_MAX, xmax = FLT_MIN, ymin = FLT_MAX, ymax = FLT_MIN;
3700 const size_t offset = my_points_idx[
n].
offset;
3701 const int length = my_points_idx[
n].
length;
3705 for(
int l = 0; l < length; l++)
3707 const size_t point = offset + l;
3708 xmin = fmin(xmin, my_points[2 *
point]);
3709 xmax = fmax(xmax, my_points[2 *
point]);
3710 ymin = fmin(ymin, my_points[2 *
point + 1]);
3711 ymax = fmax(ymax, my_points[2 *
point + 1]);
3714 my_points_idx[
n].
bbx = xmin;
3715 my_points_idx[
n].
bbX = xmax;
3716 my_points_idx[
n].
bby = ymin;
3717 my_points_idx[
n].
bbY = ymax;
3721 if(
g->lines_version > lines_version)
3724 *points = my_points;
3725 *points_idx = my_points_idx;
3726 *points_lines_count = lines_count;
3727 *extremas = my_extremas;
3743 float *points,
size_t points_count)
3748 if(piece->module == self &&
3751 if(piece->module->distort_transform)
3752 ret = piece->module->distort_transform(piece->module, pipe, piece, points, points_count);
3762 int32_t pointerx, int32_t pointery)
3772 if(wd < 1.0 || ht < 1.0)
return;
3788 if(
g->straightening && !
g->editing)
3796 float pzxpy[2] = { (float)pointerx, (
float)pointery };
3798 const float pzx = pzxpy[0];
3799 const float pzy = pzxpy[1];
3802 PangoLayout *layout;
3805 pango_font_description_set_weight(desc, PANGO_WEIGHT_BOLD);
3806 pango_font_description_set_absolute_size(desc, fontsize * PANGO_SCALE / zoom_scale);
3807 layout = pango_cairo_create_layout(cr);
3808 pango_layout_set_font_description(layout, desc);
3809 const float bzx =
g->straighten_x;
3810 const float bzy =
g->straighten_y;
3815 cairo_move_to(cr, bzx * wd, bzy * ht);
3816 cairo_line_to(cr, pzx * wd, pzy * ht);
3820 float dx = pzx * wd - bzx * wd;
3821 float dy = pzy * ht - bzy * ht;
3827 float angle = atan2f(dy, dx);
3828 angle = angle * 180 /
M_PI;
3829 if(angle > 45.0) angle -= 90;
3830 if(angle < -45.0) angle += 90;
3832 gchar *view_angle = NULL;
3833 view_angle = g_strdup_printf(
"%.2f\302\260", angle);
3834 pango_layout_set_text(layout, view_angle ? view_angle :
"-1\302\260", -1);
3837 PangoRectangle logic;
3838 pango_layout_get_pixel_extents(layout, &ink, &logic);
3839 const float text_w = logic.width;
3840 const float text_h = logic.height;
3842 cairo_set_source_rgba(cr, .5, .5, .5, .9);
3844 const float yp = pzy * ht - logic.height;
3846 const double rectangle_x = xp - margin;
3847 const double rectangle_y = yp - margin;
3848 const double rectangle_w = text_w + 2 * margin;
3849 const double rectangle_h = text_h + 2 * margin;
3852 cairo_set_source_rgba(cr, .7, .7, .7, .7);
3853 cairo_move_to(cr, xp, yp);
3854 pango_cairo_show_layout(cr, layout);
3855 pango_font_description_free(desc);
3856 g_object_unref(layout);
3861 if(!
g->editing)
return;
3876 const float ixo = piece->
buf_in.
x;
3877 const float iyo = piece->
buf_in.
y;
3880 float V[4][2] = { { ixo, iyo },
3882 { ixo + iwd, iyo + iht },
3883 { ixo + iwd, iyo } };
3890 float xmin = FLT_MAX, ymin = FLT_MAX, xmax = FLT_MIN, ymax = FLT_MIN;
3891 for(
int n = 0;
n < 4;
n++)
3893 xmin =
MIN(xmin,
V[
n][0]);
3894 xmax =
MAX(xmax,
V[
n][0]);
3895 ymin =
MIN(ymin,
V[
n][1]);
3896 ymax =
MAX(ymax,
V[
n][1]);
3927 const float owd = xmax - xmin;
3928 const float oht = ymax - ymin;
3931 float C[4][2] = { { xmin +
p->cl * owd, ymin +
p->ct * oht },
3932 { xmin +
p->cl * owd, ymin +
p->cb * oht },
3933 { xmin +
p->cr * owd, ymin +
p->cb * oht },
3934 { xmin +
p->cr * owd, ymin +
p->ct * oht } };
3945 cairo_set_dash(cr, &dashes, 0, 0);
3949 for(
size_t i = 0;
i < 4;
i++)
3951 V[
i][0] *= scale_factor;
3952 V[
i][1] *= scale_factor;
3953 C[
i][0] *= scale_factor;
3954 C[
i][1] *= scale_factor;
3958 cairo_set_source_rgba(cr, .2, .2, .2, .8);
3959 cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
3960 cairo_rectangle(cr, 0.0, 0.0, wd, ht);
3961 cairo_move_to(cr,
C[0][0],
C[0][1]);
3962 cairo_line_to(cr,
C[1][0],
C[1][1]);
3963 cairo_line_to(cr,
C[2][0],
C[2][1]);
3964 cairo_line_to(cr,
C[3][0],
C[3][1]);
3965 cairo_close_path(cr);
3969 cairo_set_source_rgb(cr, 0.0, 0.0, 0.0);
3970 cairo_rectangle(cr, 0.0, 0.0, wd, ht);
3971 cairo_move_to(cr,
V[0][0],
V[0][1]);
3972 cairo_line_to(cr,
V[1][0],
V[1][1]);
3973 cairo_line_to(cr,
V[2][0],
V[2][1]);
3974 cairo_line_to(cr,
V[3][0],
V[3][1]);
3975 cairo_close_path(cr);
3976 cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
3979 cairo_move_to(cr,
C[0][0],
C[0][1]);
3980 cairo_line_to(cr,
C[1][0],
C[1][1]);
3981 cairo_line_to(cr,
C[2][0],
C[2][1]);
3982 cairo_line_to(cr,
C[3][0],
C[3][1]);
3983 cairo_close_path(cr);
3989 const float cx = fminf(
C[0][0], fminf(
C[1][0], fminf(
C[2][0],
C[3][0])));
3990 const float cy = fminf(
C[0][1], fminf(
C[1][1], fminf(
C[2][1],
C[3][1])));
3991 const float cw = fmaxf(
C[0][0], fmaxf(
C[1][0], fmaxf(
C[2][0],
C[3][0]))) - cx;
3992 const float ch = fmaxf(
C[0][1], fmaxf(
C[1][1], fmaxf(
C[2][1],
C[3][1]))) - cy;
4013 ||
g->points_lines_count !=
g->lines_count
4014 || (
g->lines_version >
g->points_version
4015 &&
g->lines_hash != lines_hash))
4021 g->points_lines_count = 0;
4025 if(!
get_points(self,
g->lines,
g->lines_count,
g->lines_version, &
g->points, &
g->draw_points, &
g->points_idx,
4026 &
g->points_lines_count, scale))
4029 g->points_version =
g->lines_version;
4030 g->grid_hash = hash;
4031 g->lines_hash = lines_hash;
4033 else if(
g->lines_hash == lines_hash)
4036 for(
int n = 0;
n <
g->points_lines_count;
n++)
4037 g->points_idx[
n].type =
g->lines[
n].type;
4043 g->points_version =
g->lines_version;
4053 const float line_colors[5][4] =
4054 { { 0.3f, 0.3f, 0.3f, 0.8f },
4055 { 0.0f, 1.0f, 0.0f, 0.8f },
4056 { 0.8f, 0.0f, 0.0f, 0.8f },
4057 { 0.0f, 0.0f, 1.0f, 0.8f },
4058 { 0.8f, 0.8f, 0.0f, 0.8f } };
4060 cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
4063 for(
int n = 0;
n <
g->points_lines_count;
n++)
4071 if(
g->points_idx[
n].near)
4077 const float *color = line_colors[
g->points_idx[
n].color];
4078 cairo_set_source_rgba(cr, color[0], color[1], color[2], color[3]);
4080 size_t offset =
g->points_idx[
n].offset;
4081 const int length =
g->points_idx[
n].length;
4084 if(length < 2)
continue;
4087 cairo_move_to(cr,
g->points[offset * 2],
g->points[offset * 2 + 1]);
4091 for(
int l = 1; l < length; l++, offset++)
4093 cairo_line_to(cr,
g->points[offset * 2],
g->points[offset * 2 + 1]);
4106 for(
int i = 0;
i < nb;
i++)
4112 if(
g->draw_near_point ==
i)
4125 float pzxpy[2] = { (float)pointerx, (
float)pointery };
4127 const float pzx = pzxpy[0];
4128 const float pzy = pzxpy[1];
4131 dashed[0] /= zoom_scale;
4132 dashed[1] /= zoom_scale;
4133 const int len =
sizeof(dashed) /
sizeof(dashed[0]);
4135 cairo_rectangle(cr,
g->lastx * wd,
g->lasty * ht, (pzx -
g->lastx) * wd,
4136 (pzy -
g->lasty) * ht);
4137 cairo_set_source_rgba(cr, .3, .3, .3, .8);
4138 cairo_set_line_width(cr, 1.0 / zoom_scale);
4139 cairo_set_dash(cr, dashed, len, 0);
4140 cairo_stroke_preserve(cr);
4141 cairo_set_source_rgba(cr, .8, .8, .8, .8);
4142 cairo_set_dash(cr, dashed, len, 4);
4147 if(
g->near_delta > 0)
4149 float pzxpy[2] = { (float)pointerx, (
float)pointery };
4151 const float pzx = pzxpy[0];
4152 const float pzy = pzxpy[1];
4155 dashed[0] /= zoom_scale;
4156 dashed[1] /= zoom_scale;
4157 const int len =
sizeof(dashed) /
sizeof(dashed[0]);
4159 cairo_arc(cr, pzx * wd, pzy * ht,
g->near_delta, 0, 2.0 *
M_PI);
4161 cairo_set_source_rgba(cr, .3, .3, .3, .8);
4162 cairo_set_line_width(cr, 1.0 / zoom_scale);
4163 cairo_set_dash(cr, dashed, len, 0);
4164 cairo_stroke_preserve(cr);
4165 cairo_set_source_rgba(cr, .8, .8, .8, .8);
4166 cairo_set_dash(cr, dashed, len, 4);
4175 int *vertical_count,
int *horizontal_count)
4180 for(
int n = 0;
n < lines_count;
n++)
4188 *vertical_count = vlines;
4189 *horizontal_count = hlines;
4198 for(
int i = 0;
i < limit;
i++)
4201 && y - points[
i * 2 + 1] > -
delta)
4209 line->
length = sqrt((line->
p2[0] - line->
p1[0]) * (line->
p2[0] - line->
p1[0])
4210 + (line->
p2[1] - line->
p1[1]) * (line->
p2[1] - line->
p1[1]));
4218 if(
g->straightening)
4224 gboolean handled =
FALSE;
4228 if(wd < 1.0 || ht < 1.0)
return 1;
4230 float pzxpy[2] = { (float)
x, (
float)y };
4232 float pzx = pzxpy[0];
4233 float pzy = pzxpy[1];
4243 ?
MIN(
g->points_lines_count,
g->lines_count)
4247 if(
g->draw_point_move)
4249 const int line =
g->draw_near_point / 2;
4250 if(
g->draw_near_point < 0 || line >=
g->lines_count)
4252 g->draw_point_move =
FALSE;
4253 g->draw_near_point = -1;
4259 float pts[2] = { pzx * pd_w, pzy * pd_h };
4264 if(
g->draw_near_point >= 0)
4266 if(
g->draw_near_point % 2 == 0)
4268 g->lines[line].p1[0] = pts[0];
4269 g->lines[line].p1[1] = pts[1];
4273 g->lines[line].p2[0] = pts[0];
4274 g->lines[line].p2[1] = pts[1];
4282 if(
g->draw_near_point == 0)
4284 g->lines[2].p1[0] = pts[0];
4285 g->lines[2].p1[1] = pts[1];
4288 else if(
g->draw_near_point == 1)
4290 g->lines[3].p1[0] = pts[0];
4291 g->lines[3].p1[1] = pts[1];
4294 else if(
g->draw_near_point == 2)
4296 g->lines[2].p2[0] = pts[0];
4297 g->lines[2].p2[1] = pts[1];
4300 else if(
g->draw_near_point == 3)
4302 g->lines[3].p2[0] = pts[0];
4303 g->lines[3].p2[1] = pts[1];
4315 if(
g->draw_line_move >= 0)
4317 if(
g->draw_line_move >=
g->lines_count)
4319 g->draw_line_move = -1;
4325 float pts[2] = { pzx * pd_w, pzy * pd_h };
4329 const float dx = (pts[0] -
g->draw_pointmove_x);
4330 const float dy = (pts[1] -
g->draw_pointmove_y);
4331 const int n =
g->draw_line_move;
4332 g->draw_pointmove_x = pts[0];
4333 g->draw_pointmove_y = pts[1];
4336 g->lines[
n].p1[0] += dx;
4337 g->lines[
n].p1[1] += dy;
4338 g->lines[
n].p2[0] += dx;
4339 g->lines[
n].p2[1] += dy;
4341 g->lines[
n].p1[0] =
CLAMPF(
g->lines[
n].p1[0], 0.0f,
g->lines_in_width);
4342 g->lines[
n].p1[1] =
CLAMPF(
g->lines[
n].p1[1], 0.0f,
g->lines_in_height);
4343 g->lines[
n].p2[0] =
CLAMPF(
g->lines[
n].p2[0], 0.0f,
g->lines_in_width);
4344 g->lines[
n].p2[1] =
CLAMPF(
g->lines[
n].p2[1], 0.0f,
g->lines_in_height);
4353 g->lines[2].p1[0] =
g->lines[
n].p1[0];
4354 g->lines[2].p1[1] =
g->lines[
n].p1[1];
4355 g->lines[3].p1[0] =
g->lines[
n].p2[0];
4356 g->lines[3].p1[1] =
g->lines[
n].p2[1];
4362 g->lines[2].p2[0] =
g->lines[
n].p1[0];
4363 g->lines[2].p2[1] =
g->lines[
n].p1[1];
4364 g->lines[3].p2[0] =
g->lines[
n].p2[0];
4365 g->lines[3].p2[1] =
g->lines[
n].p2[1];
4371 g->lines[0].p1[0] =
g->lines[
n].p1[0];
4372 g->lines[0].p1[1] =
g->lines[
n].p1[1];
4373 g->lines[1].p1[0] =
g->lines[
n].p2[0];
4374 g->lines[1].p1[1] =
g->lines[
n].p2[1];
4380 g->lines[0].p2[0] =
g->lines[
n].p1[0];
4381 g->lines[0].p2[1] =
g->lines[
n].p1[1];
4382 g->lines[1].p2[0] =
g->lines[
n].p2[0];
4383 g->lines[1].p2[1] =
g->lines[
n].p2[1];
4408 if(wd >= 1.0 && ht >= 1.0 && selectable_lines_count > 0)
4412 g->lasty * ht,
g->isbounding);
4420 if(selectable_lines_count > 0)
4422 g->points,
g->points_idx, selectable_lines_count, pzx * wd, pzy * ht,
g->near_delta,
4426 if(
g->isdeselecting ||
g->isselecting)
4429 for(
int n = 0;
g->selecting_lines_version ==
g->lines_version &&
n < selectable_lines_count;
n++)
4431 if(
g->points_idx[
n].near == 0)
4434 if(
g->isdeselecting)
4436 g->lines[
n].type &= ~ASHIFT_LINE_SELECTED;
4451 g->selecting_lines_version++;
4457 return (
g->isdeselecting ||
g->isselecting);
4465 gboolean handled =
FALSE;
4468 if(
type == GDK_2BUTTON_PRESS && which == 1)
4471 float pzxpy[2] = { (float)
x, (
float)y };
4473 float pzx = pzxpy[0];
4474 float pzy = pzxpy[1];
4478 if(wd < 1.0 || ht < 1.0)
return 1;
4484 g->straightening =
TRUE;
4487 g->straighten_x = pzx;
4488 g->straighten_y = pzy;
4495 &&
g->draw_near_point >= 0)
4497 const int line =
g->draw_near_point / 2;
4500 g->draw_point_move =
TRUE;
4508 g->selecting_lines_version =
g->lines_version;
4532 const int selectable_lines_count = (!
IS_NULL_PTR(
g->lines)
4535 ?
MIN(
g->points_lines_count,
g->lines_count)
4539 const int take_control = (cur_scale == min_scale) && (selectable_lines_count > 0);
4547 if(selectable_lines_count > 0)
4548 _get_near(
g->points,
g->points_idx, selectable_lines_count,
4549 pzx * wd, pzy * ht,
g->near_delta,
4557 for(
int n = 0;
n < selectable_lines_count;
n++)
4559 if(
g->points_idx[
n].near)
4563 float pts[2] = { pzx * pd_w, pzy * pd_h };
4566 g->draw_line_move =
n;
4567 g->draw_pointmove_x = pts[0];
4568 g->draw_pointmove_y = pts[1];
4579 for(
int n = 0;
g->selecting_lines_version ==
g->lines_version &&
n < selectable_lines_count;
n++)
4581 if(
g->points_idx[
n].near == 0)
continue;
4586 g->lines[
n].type &= ~ASHIFT_LINE_SELECTED;
4592 g->horizontal_count--;
4593 g->horizontal_weight -= 1.0f;
4597 g->vertical_count--;
4598 g->vertical_weight -= 1.0f;
4601 const int count =
g->lines_count - 1;
4610 g->horizontal_count++;
4611 g->horizontal_weight += 1.0f;
4615 g->vertical_count++;
4616 g->vertical_weight += 1.0f;
4622 for(
int i = 0;
i <
g->lines_count;
i++)
4626 lines[pos] =
g->lines[
i];
4635 g->lines_count = count;
4653 g->draw_point_move =
TRUE;
4661 float pts[2] = { pzx * pd_w, pzy * pd_h };
4664 const int count =
g->lines_count + 1;
4670 for(
int i = 0;
i <
g->lines_count;
i++)
4672 lines[
i] =
g->lines[
i];
4679 g->lines_count = count;
4682 g->vertical_count++;
4683 g->vertical_weight += 1.0f;
4684 g->draw_near_point =
g->lines_count * 2 - 1;
4691 if((take_control || handled) && which == 3)
4694 g->isdeselecting = 1;
4696 else if(take_control || handled)
4706 g->selecting_lines_version++;
4709 return (take_control || handled);
4722 if(
g->straightening && !
g->editing)
4724 g->straightening =
FALSE;
4726 float pzxpy[2] = { (float)
x, (
float)y };
4728 const float pzx = pzxpy[0];
4729 const float pzy = pzxpy[1];
4732 float pts[4] = { pzx * pd_w, pzy * pd_h,
g->lastx * pd_w,
g->lasty * pd_h };
4737 float dx = pts[0] - pts[2];
4738 float dy = pts[1] - pts[3];
4745 float angle = atan2f(dy, dx);
4746 if(!(angle >= -
M_PI / 2.0 && angle <=
M_PI / 2.0)) angle = 0.0f;
4747 float close = angle;
4748 if(close >
M_PI / 4.0)
4749 close =
M_PI / 2.0 - close;
4750 else if(close < -
M_PI / 4.0)
4751 close = -
M_PI / 2.0 - close;
4755 float a = 180.0 /
M_PI * close;
4756 if(a < -180.0) a += 360.0;
4757 if(a > 180.0) a -= 360.0;
4772 if(
g->draw_line_move >= 0)
4774 g->draw_line_move = -1;
4781 if(
g->draw_point_move)
4785 g->draw_point_move =
FALSE;
4786 g->draw_near_point = -1;
4793 for(
int l = 0; l <
g->lines_count; l++)
4800 g->vertical_count++;
4801 g->vertical_weight += 1.0f;
4802 g->horizontal_count--;
4803 g->horizontal_weight -= 1.0f;
4805 else if(
g->lines[l].type != old_linetype)
4807 g->horizontal_count++;
4808 g->horizontal_weight += 1.0f;
4809 g->vertical_count--;
4810 g->vertical_weight -= 1.0f;
4815 g->draw_point_move =
FALSE;
4816 g->draw_near_point = -1;
4829 gboolean handled =
FALSE;
4832 float pzxpy[2] = { (float)
x, (
float)y };
4834 const float pzx = pzxpy[0];
4835 const float pzy = pzxpy[1];
4837 if(wd >= 1.0 && ht >= 1.0)
4839 const int selectable_lines_count = (!
IS_NULL_PTR(
g->lines)
4842 ?
MIN(
g->points_lines_count,
g->lines_count)
4846 if(selectable_lines_count > 0)
4848 g->lasty * ht,
g->isbounding);
4851 for(
int n = 0;
g->selecting_lines_version ==
g->lines_version &&
n < selectable_lines_count;
n++)
4853 if(
g->points_idx[
n].bounded == 0)
continue;
4857 g->lines[
n].type &= ~ASHIFT_LINE_SELECTED;
4871 g->selecting_lines_version++;
4879 g->isselecting =
g->isdeselecting = 0;
4882 g->lastx =
g->lasty = -1.0f;
4883 g->crop_cx =
g->crop_cy = -1.0f;
4903 if(
g->near_delta > 0 && (
g->isdeselecting ||
g->isselecting))
4905 gboolean handled =
FALSE;
4907 float pzxpy[2] = { (float)
x, (
float)y };
4909 const float pzx = pzxpy[0];
4910 const float pzy = pzxpy[1];
4914 float near_delta = 5.0f;
4919 const float amount = up ? 0.8f : 1.25f;
4920 near_delta =
MAX(4.0f,
MIN(near_delta * amount, 100.0f));
4925 g->near_delta = near_delta;
4933 ?
MIN(
g->points_lines_count,
g->lines_count)
4935 if(selectable_lines_count > 0)
4936 _get_near(
g->points,
g->points_idx, selectable_lines_count, pzx * wd, pzy * ht,
g->near_delta,
TRUE);
4939 for(
int n = 0;
g->selecting_lines_version ==
g->lines_version &&
n < selectable_lines_count;
n++)
4941 if(
g->points_idx[
n].near == 0)
4944 if(
g->isdeselecting)
4946 g->lines[
n].type &= ~ASHIFT_LINE_SELECTED;
4962 g->selecting_lines_version++;
4976 gtk_widget_set_sensitive(
g->structure_auto, sensitive);
4977 gtk_widget_set_sensitive(
g->structure_lines, sensitive);
4978 gtk_widget_set_sensitive(
g->structure_quad, sensitive);
4989 model_probe(self,
p,
g->lastfit);
4992 if(w ==
g->rotation)
4994 else if(w ==
g->lensshift_h)
4996 else if(w ==
g->lensshift_v)
4998 else if(w ==
g->shear)
5000 else if(w ==
g->mode)
5005 else if(w ==
g->f_length)
5007 else if(w ==
g->crop_factor)
5009 else if(w ==
g->orthocorr)
5011 else if(w ==
g->aspect)
5032 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->edit_button),
FALSE);
5033 gtk_button_set_label(GTK_BUTTON(
g->edit_button), _(
"Edit"));
5034 gtk_widget_set_sensitive(
g->commit_button,
FALSE);
5060 p->cropmode = crop_mode;
5080 if(event->button == 1)
5086 switch(
g->fitting_mode)
5114 g->jobparams =
g->lastfit = fitaxis;
5127 if(event->button == 1)
5133 switch(
g->fitting_mode)
5161 g->jobparams =
g->lastfit = fitaxis;
5174 if(event->button == 1)
5180 switch(
g->fitting_mode)
5210 g->jobparams =
g->lastfit = fitaxis;
5223 if(event->button == 1)
5239 if(enhance ==
ASHIFT_ENHANCE_NONE && gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget)))
5247 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(widget),
FALSE);
5264 g->jobparams = enhance;
5278 if(!
g->editing)
return FALSE;
5303 if(!
g->editing)
return FALSE;
5329 g->editing = gtk_toggle_button_get_active(button);
5344 gtk_button_set_label(GTK_BUTTON(button), _(
"Cancel"));
5345 gtk_widget_set_sensitive(
g->commit_button,
TRUE);
5363 gtk_button_set_label(GTK_BUTTON(button), _(
"Edit"));
5364 gtk_widget_set_sensitive(
g->commit_button,
FALSE);
5384 gtk_widget_set_sensitive(
g->commit_button,
FALSE);
5400 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(
g->edit_button),
FALSE);
5401 gtk_button_set_label(GTK_BUTTON(
g->edit_button), _(
"Edit"));
5411 int jobparams =
g->jobparams;
5502 d->lensshift_v =
p->lensshift_v;
5503 d->lensshift_h =
p->lensshift_h;
5504 d->shear =
p->shear;
5543 piece->
data = (
void *)
d;
5568 module->default_enabled = 0;
5572 float crop_factor = 1.0f;
5577 const dt_image_t *img = &
module->dev->image_storage;
5604 snprintf(string_v,
sizeof(string_v), _(
"lens shift (%s)"), isflipped ? _(
"horizontal") : _(
"vertical"));
5605 snprintf(string_h,
sizeof(string_h), _(
"lens shift (%s)"), isflipped ? _(
"vertical") : _(
"horizontal"));
5621 g->buf_scale = 1.0f;
5631 g->horizontal_count = 0;
5632 g->vertical_count = 0;
5639 g->lines_version = 0;
5641 g->isdeselecting = 0;
5644 g->selecting_lines_version = 0;
5648 g->points_lines_count = 0;
5649 g->points_version = 0;
5653 g->lastx =
g->lasty = -1.0f;
5654 g->crop_cx =
g->crop_cy = 1.0f;
5657 g->draw_line_move = -1;
5658 g->draw_near_point = -1;
5659 g->draw_point_move =
FALSE;
5674 const int program = 2;
5696 const int isflipped =
g->isflipped;
5699 if(isflipped == -1)
return FALSE;
5704 snprintf(string_v,
sizeof(string_v), _(
"lens shift (%s)"), isflipped ? _(
"horizontal") : _(
"vertical"));
5705 snprintf(string_h,
sizeof(string_h), _(
"lens shift (%s)"), isflipped ? _(
"vertical") : _(
"horizontal"));
5725 g->buf_scale = 1.0f;
5736 g->vertical_count = 0;
5737 g->horizontal_count = 0;
5738 g->lines_version = 0;
5740 g->points_idx = NULL;
5741 g->points_lines_count = 0;
5742 g->points_version = 0;
5750 g->isdeselecting = 0;
5753 g->selecting_lines_version = 0;
5757 g->lastx =
g->lasty = -1.0f;
5758 g->crop_cx =
g->crop_cy = 1.0f;
5762 g->draw_near_point = -1;
5763 g->draw_line_move = -1;
5769 g->edit_button = gtk_toggle_button_new_with_label(_(
"Edit"));
5770 g_signal_connect(GTK_TOGGLE_BUTTON(
g->edit_button),
"toggled", G_CALLBACK(
_enter_edit_mode), self);
5771 gtk_box_pack_start(GTK_BOX(box),
g->edit_button,
TRUE,
TRUE, 0);
5774 gtk_box_pack_start(GTK_BOX(box),
g->commit_button,
TRUE,
TRUE, 0);
5775 gtk_widget_set_sensitive(
g->commit_button,
FALSE);
5777 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(box),
TRUE,
TRUE, 0);
5783 "plugins/darkroom/ashift/expand_values",
5784 _(
"Manual settings"),
5785 GTK_BOX(main_box), GTK_PACK_END);
5787 self->
widget = GTK_WIDGET(
g->cs.container);
5820 gtk_widget_set_no_show_all(
g->orthocorr,
TRUE);
5821 gtk_widget_set_visible(
g->orthocorr,
FALSE);
5825 gtk_box_pack_start(GTK_BOX(
g->cs.container),
g->specifics,
TRUE,
TRUE, 0);
5829 GtkGrid *auto_grid = GTK_GRID(gtk_grid_new());
5833 gtk_grid_attach(auto_grid,
dt_ui_label_new(_(
"Mark reference lines")), 0, 0, 1, 1);
5836 gtk_widget_set_hexpand(GTK_WIDGET(
g->structure_lines),
TRUE);
5837 gtk_grid_attach(auto_grid,
g->structure_lines, 1, 0, 1, 1);
5840 gtk_widget_set_hexpand(GTK_WIDGET(
g->structure_quad),
TRUE);
5841 gtk_grid_attach(auto_grid,
g->structure_quad, 2, 0, 1, 1);
5844 gtk_widget_set_hexpand(GTK_WIDGET(
g->structure_auto),
TRUE);
5845 gtk_grid_attach(auto_grid,
g->structure_auto, 3, 0, 1, 1);
5847 gtk_grid_attach(auto_grid,
dt_ui_label_new(_(
"Fit perspective transform")), 0, 1, 1, 1);
5850 gtk_widget_set_hexpand(GTK_WIDGET(
g->fit_v),
TRUE);
5851 gtk_grid_attach(auto_grid,
g->fit_v, 1, 1, 1, 1);
5854 gtk_widget_set_hexpand(GTK_WIDGET(
g->fit_h),
TRUE);
5855 gtk_grid_attach(auto_grid,
g->fit_h, 2, 1, 1, 1);
5858 gtk_widget_set_hexpand(GTK_WIDGET(
g->fit_both),
TRUE);
5859 gtk_grid_attach(auto_grid,
g->fit_both, 3, 1, 1, 1);
5861 gtk_widget_show_all(GTK_WIDGET(auto_grid));
5862 gtk_box_pack_start(GTK_BOX(self->
widget), GTK_WIDGET(auto_grid),
TRUE,
TRUE, 0);
5865 gtk_box_pack_start(GTK_BOX(self->
widget), helpers,
TRUE,
TRUE, 0);
5867 const gchar *option_labels[] = { _(
"rotation, lens shift, shear"),
5868 _(
"rotation, lens shift"),
5870 _(
"lens shift only"), NULL };
5874 gtk_box_pack_start(GTK_BOX(self->
widget),
g->fitting_option,
TRUE,
TRUE, 0);
5876 const gchar *crop_labels[] = { _(
"off"), _(
"largest area"), _(
"original format"), NULL };
5887 gtk_widget_set_tooltip_text(
g->rotation, _(
"rotate image\nright-click and drag to define a horizontal or vertical line by drawing on the image"));
5888 gtk_widget_set_tooltip_text(
g->lensshift_v, _(
"apply lens shift correction in one direction"));
5889 gtk_widget_set_tooltip_text(
g->lensshift_h, _(
"apply lens shift correction in one direction"));
5890 gtk_widget_set_tooltip_text(
g->shear, _(
"shear the image along one diagonal"));
5891 gtk_widget_set_tooltip_text(
g->cropmode, _(
"automatically crop to avoid black edges"));
5892 gtk_widget_set_tooltip_text(
g->mode, _(
"lens model of the perspective correction: "
5893 "generic or according to the focal length"));
5894 gtk_widget_set_tooltip_text(
g->f_length, _(
"focal length of the lens, "
5895 "default value set from EXIF data if available"));
5896 gtk_widget_set_tooltip_text(
g->crop_factor, _(
"crop factor of the camera sensor, "
5897 "default value set from EXIF data if available, "
5898 "manual setting is often required"));
5899 gtk_widget_set_tooltip_text(
g->orthocorr, _(
"the level of lens dependent correction, set to maximum for full lens dependency, "
5900 "set to zero for the generic case"));
5901 gtk_widget_set_tooltip_text(
g->aspect, _(
"adjust aspect ratio of image by horizontal and vertical scaling"));
5902 gtk_widget_set_tooltip_text(
g->fit_v, _(
"automatically correct for vertical perspective distortion\n"
5903 "ctrl+click to only fit rotation\n"
5904 "shift+click to only fit lens shift"));
5905 gtk_widget_set_tooltip_text(
g->fit_h, _(
"automatically correct for horizontal perspective distortion\n"
5906 "ctrl+click to only fit rotation\n"
5907 "shift+click to only fit lens shift"));
5908 gtk_widget_set_tooltip_text(
g->fit_both, _(
"automatically correct for vertical and "
5909 "horizontal perspective distortions; fitting rotation,"
5910 "lens shift in both directions, and shear\n"
5911 "ctrl+click to only fit rotation\n"
5912 "shift+click to only fit lens shift\n"
5913 "ctrl+shift+click to only fit rotation and lens shift"));
5914 gtk_widget_set_tooltip_text(
g->structure_auto, _(
"automatically analyse line structure in image\n"
5915 "ctrl+click for an additional edge enhancement\n"
5916 "shift+click for an additional detail enhancement\n"
5917 "ctrl+shift+click for a combination of both methods"));
5918 gtk_widget_set_tooltip_text(
g->structure_quad, _(
"manually define perspective rectangle"));
5919 gtk_widget_set_tooltip_text(
g->structure_lines, _(
"manually draw structure lines"));
5933 g_signal_connect(G_OBJECT(self->
widget),
"draw", G_CALLBACK(
_event_draw), self);
int operation_tags_filter()
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static double logit(double x, double min, double max)
void distort_mask(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece, const float *const in, float *const out, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out)
static void vec3norm(float *dst, const float *const v)
const char ** description(struct dt_iop_module_t *self)
static int _remove_outliers(dt_iop_module_t *module)
static void sRGB_to_XYZ(const dt_aligned_pixel_t sRGB, dt_aligned_pixel_t XYZ)
static float vec3scalar(const float *const v1, const float *const v2)
int scrolled(struct dt_iop_module_t *self, double x, double y, int up, uint32_t state)
__DT_CLONE_TARGETS__ int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid)
#define RANSAC_OPTIMIZATION_STEPS
static void _gui_update_structure_states(dt_iop_module_t *self, gboolean enable)
static int update_colors(struct dt_iop_module_t *self, dt_iop_ashift_points_idx_t *points_idx, int points_lines_count)
static double ilogit(double L, double min, double max)
@ ASHIFT_BOUNDING_DESELECT
static void _update_lines_count(const dt_iop_ashift_line_t *lines, const int lines_count, int *vertical_count, int *horizontal_count)
void reload_defaults(dt_iop_module_t *module)
static dt_iop_ashift_nmsresult_t nmsfit(dt_iop_module_t *module, dt_iop_ashift_params_t *p, dt_iop_ashift_fitaxis_t dir)
static void vec3prodn(float *dst, const float *const v1, const float *const v2)
int distort_transform(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, float *const restrict points, size_t points_count)
static void _event_process_after_preview_callback(gpointer instance, gpointer user_data)
static void vec3lnorm(float *dst, const float *const v)
static int fact(const int n)
static gboolean _draw_retrieve_lines_from_params(dt_iop_module_t *self, dt_iop_ashift_method_t method)
static void _get_near(const float *points, dt_iop_ashift_points_idx_t *points_idx, const int lines_count, float pzx, float pzy, float delta, gboolean multiple)
static int _event_structure_auto_clicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
static int _get_structure(dt_iop_module_t *module, dt_iop_ashift_enhance_t enhance)
dt_iop_ashift_params_t * _get_ashift_params(dt_iop_module_t *self)
dt_iop_ashift_linecolor_t
@ ASHIFT_LINECOLOR_YELLOW
static int _event_structure_lines_clicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
static void XYZ_to_sRGB(const dt_aligned_pixel_t XYZ, dt_aligned_pixel_t sRGB)
@ ASHIFT_FIT_BOTH_NO_ROTATION
@ ASHIFT_FIT_HORIZONTALLY_NO_ROTATION
@ ASHIFT_FIT_ROTATION_HORIZONTAL_LINES
@ ASHIFT_FIT_ROTATION_VERTICAL_LINES
@ ASHIFT_FIT_HORIZONTALLY
@ ASHIFT_FIT_ROTATION_BOTH_LINES
@ ASHIFT_FIT_VERTICALLY_NO_ROTATION
void init_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static void _clear_crop_box(dt_iop_ashift_params_t *p)
Reset the active crop rectangle to the complete transformed image.
static void shuffle(int *a, const int N)
static double model_fitness(double *params, void *data)
static int _event_fit_h_button_clicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
dt_iop_ashift_nmsresult_t
static void _event_process_after_ui_callback(gpointer instance, gpointer user_data)
Refresh ashift overlay geometry once the displayed pipe published its new output.
void gui_reset(struct dt_iop_module_t *self)
void gui_update(struct dt_iop_module_t *self)
static int quickperm(int *a, int *p, const int N, int *i)
int distort_backtransform(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, float *points, size_t points_count)
void gui_init(struct dt_iop_module_t *self)
int button_pressed(struct dt_iop_module_t *self, double x, double y, double pressure, int which, int type, uint32_t state)
static int _do_clean_structure(dt_iop_module_t *module, dt_iop_ashift_params_t *p, gboolean save_drawn)
static int _do_get_structure_auto(dt_iop_module_t *self, dt_iop_ashift_params_t *p, dt_iop_ashift_enhance_t enhance)
void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous)
static double crop_fitness(double *params, void *data)
int button_released(struct dt_iop_module_t *self, double x, double y, int which, uint32_t state)
static void _run_pending_preview_job(dt_iop_module_t *self)
static void gamma_correct(const float *const in, float *const out, const int width, const int height)
static int _event_fit_v_button_clicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
static int isneutral(const dt_iop_ashift_data_t *data)
static int edge_enhance(const double *in, double *out, const int width, const int height)
void _make_controls_sensitive(dt_iop_module_t *self, const gboolean sensitive)
#define RANSAC_EPSILON_STEP
void cleanup_global(dt_iop_module_so_t *module)
@ ASHIFT_JOBCODE_GET_STRUCTURE
@ ASHIFT_JOBCODE_GET_STRUCTURE_LINES
@ ASHIFT_JOBCODE_GET_STRUCTURE_QUAD
static uint64_t _get_lines_hash(const dt_iop_ashift_line_t *lines, const int lines_count)
static __DT_CLONE_TARGETS__ 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 _get_bounded_inside(const float *points, dt_iop_ashift_points_idx_t *points_idx, const int points_lines_count, float pzx, float pzy, float pzx2, float pzy2, dt_iop_ashift_bounding_t mode)
static void _enter_edit_mode(GtkToggleButton *button, struct dt_iop_module_t *self)
static void crop_constraint(double *params, int pcount)
static gboolean _event_draw(GtkWidget *widget, cairo_t *cr, dt_iop_module_t *self)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
#define LENSSHIFT_RANGE_SOFT
void gui_post_expose(struct dt_iop_module_t *self, cairo_t *cr, int32_t width, int32_t height, int32_t pointerx, int32_t pointery)
@ ASHIFT_FITTING_LENS_ROTATION
@ ASHIFT_FITTING_ROTATION
static int _draw_near_point(const float x, const float y, const float *points, const int limit)
#define MAX_TANGENTIAL_DEVIATION
void modify_roi_in(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *const roi_out, dt_iop_roi_t *roi_in)
void gui_cleanup(struct dt_iop_module_t *self)
static void _draw_recompute_line_length(dt_iop_ashift_line_t *line)
static void _draw_retrieve_line_type(dt_iop_ashift_line_t *line)
static int call_distort_transform(dt_dev_pixelpipe_t *pipe, struct dt_iop_module_t *self, float *points, size_t points_count)
#define ROTATION_RANGE_SOFT
#define RANSAC_ELIMINATION_RATIO
static void edge_enhance_1d(const double *in, double *out, const int width, const int height, dt_iop_ashift_enhance_t dir)
static int detail_enhance(const float *const in, float *const out, const int width, const int height)
static void ransac(const dt_iop_ashift_line_t *lines, int *index_set, int *inout_set, const int set_count, const float total_weight, const int xmin, const int xmax, const int ymin, const int ymax)
#define RANSAC_OPTIMIZATION_DRY_RUNS
static int vec3isnull(const float *const v)
void cleanup_pipe(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static int _event_structure_quad_clicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
@ ASHIFT_ENHANCE_HORIZONTAL
@ ASHIFT_ENHANCE_VERTICAL
@ ASHIFT_LINE_VERTICAL_NOT_SELECTED
@ ASHIFT_LINE_HORIZONTAL_NOT_SELECTED
@ ASHIFT_LINE_HORIZONTAL_SELECTED
@ ASHIFT_LINE_VERTICAL_SELECTED
static void _do_get_structure_lines(dt_iop_module_t *self)
static void _draw_save_lines_to_params(dt_iop_module_t *self)
static void do_fit(dt_iop_module_t *module, dt_iop_ashift_params_t *p, dt_iop_ashift_fitaxis_t dir)
void init_global(dt_iop_module_so_t *module)
static int line_detect(float *in, const int width, const int height, const int x_off, const int y_off, const float scale, dt_iop_ashift_line_t **alines, int *lcount, int *vcount, int *hcount, float *vweight, float *hweight, dt_iop_ashift_enhance_t enhance, const int is_raw)
int process_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
static void rgb2grey256(const float *const in, double *const out, const int width, const int height)
int mouse_moved(struct dt_iop_module_t *self, double x, double y, double pressure, int which)
static void _do_get_structure_quad(dt_iop_module_t *self)
@ ASHIFT_HOMOGRAPH_FORWARD
@ ASHIFT_HOMOGRAPH_INVERTED
static void fitting_option_changed(GtkWidget *widget, gpointer user_data)
static void _event_commit_clicked(GtkButton *button, dt_iop_module_t *self)
static int _event_fit_both_button_clicked(GtkWidget *widget, GdkEventButton *event, gpointer user_data)
static int get_points(struct dt_iop_module_t *self, const dt_iop_ashift_line_t *lines, const int lines_count, const int lines_version, float **points, float **extremas, dt_iop_ashift_points_idx_t **points_idx, int *points_lines_count, float scale)
static void cropmode_callback(GtkWidget *widget, gpointer user_data)
static void do_crop(dt_iop_module_t *self, dt_iop_ashift_params_t *p)
static void swap(int *a, int *b)
void modify_roi_out(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, struct dt_dev_pixelpipe_iop_t *piece, dt_iop_roi_t *roi_out, const dt_iop_roi_t *roi_in)
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
gboolean runtime_data_hash(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
static void _draw_basic_line(dt_iop_ashift_line_t *line, float x1, float y1, float x2, float y2, dt_iop_ashift_linetype_t type)
#define NMS_CROP_ITERATIONS
static double * LineSegmentDetection(int *n_out, double *img, int X, int Y, double scale, double sigma_scale, double quant, double ang_th, double log_eps, double density_th, int n_bins, int **reg_img, int *reg_x, int *reg_y)
static void error(char *msg)
static int simplex(double(*objfunc)(double[], void *params), double start[], int n, double EPSILON, double scale, int maxiter, void(*constrain)(double[], int n), void *params)
GtkWidget * dt_bauhaus_combobox_new_full(dt_bauhaus_t *bh, dt_gui_module_t *self, const char *label, const char *tip, int pos, GtkCallback callback, gpointer data, const char **texts)
void dt_bauhaus_slider_set_soft_range(GtkWidget *widget, float soft_min, float soft_max)
void dt_bauhaus_slider_set_digits(GtkWidget *widget, int val)
void dt_bauhaus_slider_set_default(GtkWidget *widget, float def)
float dt_bauhaus_slider_get(GtkWidget *widget)
int dt_bauhaus_combobox_get(GtkWidget *widget)
void dt_bauhaus_combobox_set_default(GtkWidget *widget, int def)
void dt_bauhaus_slider_set(GtkWidget *widget, float pos)
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
void dt_bauhaus_widget_set_label(GtkWidget *widget, const char *label)
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
void dt_bilateral_free(dt_bilateral_t *b)
__DT_CLONE_TARGETS__ void dt_bilateral_splat(const dt_bilateral_t *b, const float *const in)
dt_bilateral_t * dt_bilateral_init(const int width, const int height, const float sigma_s, const float sigma_r)
__DT_CLONE_TARGETS__ void dt_bilateral_slice_to_output(const dt_bilateral_t *const b, const float *const in, float *out, const float detail)
void dt_bilateral_blur(const dt_bilateral_t *b)
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
int mat3inv(float *const dst, const float *const src)
const dt_aligned_pixel_t f
static const float const float const float min
static dt_aligned_pixel_t XYZ
static dt_aligned_pixel_t sRGB
const dt_colormatrix_t dt_aligned_pixel_t out
static const float const float C
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
dt_image_pipe_class_t dt_image_pipe_class(const dt_image_t *img)
const char * dt_image_pipe_class_name(const dt_image_pipe_class_t klass)
gboolean dt_image_needs_rawprepare(const dt_image_t *img)
void dt_conf_set_float(const char *name, float val)
float dt_conf_get_float(const char *name)
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
void dt_control_log(const char *msg,...)
void dt_control_queue_redraw_center()
request redraw of center window. This redraws the center view within a gdk critical section to preven...
void dt_control_queue_redraw()
request redraw of the workspace. This redraws the whole workspace within a gdk critical section to pr...
#define dt_control_change_cursor(cursor)
void dt_print(dt_debug_thread_t thread, const char *msg,...)
#define dt_free_align(ptr)
static void * dt_calloc_align(size_t size)
static gboolean dt_modifiers_include(const GdkModifierType state, const GdkModifierType desired_modifier_mask)
float dt_boundingbox_t[4]
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
static uint64_t dt_hash(uint64_t hash, const char *str, size_t size)
#define __DT_CLONE_TARGETS__
#define __OMP_PARALLEL_FOR__(...)
#define __OMP_PARALLEL_FOR_SIMD__(...)
static gboolean dt_modifier_is(const GdkModifierType state, const GdkModifierType desired_modifier_mask)
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
#define dt_dev_add_history_item(dev, module, enable, redraw)
void dt_dev_pixelpipe_sync_virtual(dt_develop_t *dev, dt_dev_pixelpipe_change_t flag)
gboolean dt_dev_pixelpipe_activemodule_disables_currentmodule(struct dt_develop_t *dev, struct dt_iop_module_t *current_module)
#define dt_dev_pixelpipe_resync_history_all(dev)
#define dt_dev_pixelpipe_update_zoom_preview(dev)
#define dt_dev_pixelpipe_update_zoom_main(dev)
#define dt_dev_pixelpipe_update_history_preview(dev)
float dt_dev_get_natural_scale(dt_develop_t *dev)
dt_dev_pixelpipe_iop_t * dt_dev_distort_get_iop_pipe(struct dt_dev_pixelpipe_t *pipe, struct dt_iop_module_t *module)
int dt_dev_get_thumbnail_size(dt_develop_t *dev)
int dt_dev_distort_transform_plus(const dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction, float *points, size_t points_count)
float dt_dev_get_overlay_scale(dt_develop_t *dev)
Get the overlay scale factor in GUI logical coordinates.
float dt_dev_get_zoom_scale(const dt_develop_t *dev, const gboolean preview)
gboolean dt_dev_clip_roi(dt_develop_t *dev, cairo_t *cr, int32_t width, int32_t height)
Clip the view to the ROI. WARNING: this must be done before any translation.
gboolean dt_dev_rescale_roi(dt_develop_t *dev, cairo_t *cr, int32_t width, int32_t height)
Scale the ROI to fit within given width/height, centered.
gboolean dt_dev_pixelpipe_has_preview_output(const dt_develop_t *dev, const dt_dev_pixelpipe_t *pipe, const dt_iop_roi_t *roi)
void dt_dev_coordinates_widget_to_image_norm(dt_develop_t *dev, float *points, size_t num_points)
Coordinate conversion helpers between widget, normalized image, and absolute image spaces.
int dt_dev_distort_backtransform_plus(const dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction, float *points, size_t points_count)
static uint64_t dt_dev_get_history_hash(const dt_develop_t *dev)
@ DT_DEV_TRANSFORM_DIR_BACK_EXCL
@ DT_DEV_TRANSFORM_DIR_FORW_INCL
@ DT_DEV_TRANSFORM_DIR_FORW_EXCL
static void dt_draw_set_color_overlay(cairo_t *cr, gboolean bright, double alpha)
void dtgtk_cairo_paint_structure(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_draw_structure(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_masks_drawn(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
void dtgtk_cairo_paint_perspective(cairo_t *cr, gint x, gint y, gint w, gint h, gint flags, void *data)
static void weight(const float *c1, const float *c2, const float sharpen, dt_aligned_pixel_t weight)
void dt_gui_new_collapsible_section(dt_gui_collapsible_section_t *cs, const char *confname, const char *label, GtkBox *parent, GtkPackType pack)
Create a collapsible section and pack it into the parent box.
void dt_gui_draw_rounded_rectangle(cairo_t *cr, float width, float height, float x, float y)
void dt_gui_update_collapsible_section(dt_gui_collapsible_section_t *cs)
static GtkWidget * dt_ui_section_label_new(const gchar *str)
#define DT_GUI_BOX_SPACING
#define DT_PIXEL_APPLY_DPI(value)
static GtkWidget * dt_ui_label_new(const gchar *str)
void dt_guides_draw(cairo_t *cr, const float left, const float top, const float width, const float height, const float zoom_scale)
static gboolean enable(dt_image_t *image)
@ ORIENTATION_ROTATE_CCW_90_DEG
@ ORIENTATION_ROTATE_CW_90_DEG
static void dt_iop_image_copy_by_size(float *const __restrict__ out, const float *const __restrict__ in, const size_t width, const size_t height, const size_t ch)
void dt_iop_request_focus(dt_iop_module_t *module)
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
void dt_iop_set_cache_bypass(dt_iop_module_t *module, gboolean state)
static void dt_iop_gui_enter_critical_section(dt_iop_module_t *const module) ACQUIRE(&module -> gui_lock)
#define dt_iop_fmt_log(module, fmt,...)
Debug helper to trace a module's input-format-driven decisions on the -d pipe channel (DT_DEBUG_PIPE)...
@ IOP_FLAGS_GUIDES_SPECIAL_DRAW
@ IOP_FLAGS_TILING_FULL_ROI
static void dt_iop_gui_leave_critical_section(dt_iop_module_t *const module) RELEASE(&module -> gui_lock)
#define IOP_GUI_ALLOC(module)
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
GtkWidget * dt_bauhaus_combobox_from_params(dt_iop_module_t *self, const char *param)
const struct dt_interpolation * dt_interpolation_new(enum dt_interpolation_type type)
__DT_CLONE_TARGETS__ void dt_interpolation_compute_pixel4c(const struct dt_interpolation *itor, const float *in, float *out, const float x, const float y, const int width, const int height, const int linestride)
@ DT_INTERPOLATION_BICUBIC
@ DT_INTERPOLATION_BILINEAR
@ DT_INTERPOLATION_MITCHELL
@ DT_INTERPOLATION_USERPREF_WARP
static float kernel(const float *x, const float *y)
GtkWidget * dt_action_button_new(dt_lib_module_t *self, const gchar *label, gpointer callback, gpointer data, const gchar *tooltip, guint accel_key, GdkModifierType mods)
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
static void mat3mul(float *const __restrict__ dest, const float *const __restrict__ m1, const float *const __restrict__ m2)
#define CLAMPF(a, mn, mx)
static void mat3mulv(float *const __restrict__ dest, const float *const mat, const float *const __restrict__ v)
float dt_aligned_pixel_t[4]
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
int dt_opencl_copy_device_to_host(const int devid, void *host, void *device, const int width, const int height, const int bpp)
int dt_opencl_create_kernel(const int prog, const char *name)
void * dt_opencl_copy_host_to_device_constant(const int devid, const size_t size, void *host)
int dt_opencl_enqueue_copy_image(const int devid, cl_mem src, cl_mem dst, size_t *orig_src, size_t *orig_dst, size_t *region)
void dt_opencl_free_kernel(const int kernel)
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
void dt_opencl_release_mem_object(cl_mem mem)
#define DT_PIXELPIPE_CACHE_HASH_INVALID
static uint64_t dt_dev_pixelpipe_get_hash(const dt_dev_pixelpipe_t *pipe)
@ DT_DEV_PIPE_TOP_CHANGED
static uint64_t dt_dev_pixelpipe_get_history_hash(const dt_dev_pixelpipe_t *pipe)
#define DT_DEBUG_CONTROL_SIGNAL_DISCONNECT(ctlsig, cb, user_data)
@ DT_SIGNAL_DEVELOP_PREVIEW_PIPE_FINISHED
This signal is raised when develop preview pipe process is finished no param, no returned value.
@ DT_SIGNAL_DEVELOP_UI_PIPE_FINISHED
This signal is raised when pipe is finished and the gui is attached no param, no returned value.
#define DT_DEBUG_CONTROL_SIGNAL_CONNECT(ctlsig, signal, cb, user_data)
struct _GtkWidget GtkWidget
const float uint32_t state[4]
unsigned __int64 uint64_t
struct dt_gui_gtk_t * gui
struct dt_control_signal_t * signals
struct dt_bauhaus_t * bauhaus
struct dt_develop_t * develop
PangoFontDescription * pango_font_desc
dt_iop_buffer_dsc_t dsc_in
struct dt_iop_module_t *void * data
struct dt_develop_t * dev
struct dt_dev_pixelpipe_t * preview_pipe
struct dt_dev_pixelpipe_t * virtual_pipe
struct dt_develop_t::@17 roi
dt_image_orientation_t orientation
enum dt_interpolation_type id
dt_iop_ashift_linetype_t linemask
dt_iop_ashift_line_t * lines
dt_iop_ashift_linetype_t linetype
int kernel_ashift_bilinear
int kernel_ashift_bicubic
int kernel_ashift_mitchell
GtkWidget * commit_button
dt_iop_ashift_jobcode_t jobcode
GtkWidget * structure_auto
dt_iop_ashift_fitting_t fitting_mode
GtkWidget * structure_quad
dt_iop_ashift_points_idx_t * points_idx
int selecting_lines_version
GtkWidget * structure_lines
dt_iop_ashift_line_t * lines
dt_gui_collapsible_section_t cs
dt_iop_ashift_bounding_t isbounding
dt_iop_ashift_fitaxis_t lastfit
dt_iop_ashift_params_t previous_params
GtkWidget * fitting_option
dt_iop_ashift_params_t new_params
dt_iop_ashift_method_t current_structure_method
dt_iop_ashift_linetype_t type
dt_iop_ashift_mode_t mode
dt_iop_ashift_mode_t mode
dt_iop_ashift_crop_t cropmode
dt_iop_ashift_mode_t mode
dt_iop_ashift_crop_t cropmode
int last_drawn_lines_count
float last_drawn_lines[50 *4]
dt_iop_ashift_crop_t cropmode
dt_iop_ashift_mode_t mode
dt_iop_ashift_linecolor_t color
dt_iop_ashift_linetype_t type
dt_iop_global_data_t * data
dt_iop_params_t * default_params
struct dt_develop_t * dev
dt_iop_gui_data_t * gui_data
dt_iop_global_data_t * global_data
Region of interest passed through the pixelpipe.