19#if defined(__GNUC__) || defined(__clang__)
20 #define LS_RESTRICT __restrict__
36static float _interpolate(
float y1,
float y2,
float y3,
float y4,
float t)
38 const float t2 = t * t;
39 const float t3 = t2 * t;
40 const float tg2 = (y1 == FLT_MAX) ? y3 - y2 : (y3 - y1) * 0.5f;
41 const float tg3 = (y4 == FLT_MAX) ? y3 - y2 : (y4 - y2) * 0.5f;
42 return (2.f * t3 - 3.f * t2 + 1.f) * y2 + (t3 - 2.f * t2 + t) * tg2
43 + (-2.f * t3 + 3.f * t2) * y3 + (t3 - t2) * tg3;
53 memset(s->
v, 0,
sizeof(s->
v));
54 s->
d[0] = s->
d[1] = -FLT_MAX;
55 s->
d[2] = s->
d[3] = FLT_MAX;
62 if(dist > s->
d[1]) { s->
d[0] = s->
d[1]; s->
d[1] = dist; s->
v[0] = s->
v[1]; s->
v[1] = val; }
63 else if(dist > s->
d[0]) { s->
d[0] = dist; s->
v[0] = val; }
67 if(dist < s->d[2]) { s->
d[3] = s->
d[2]; s->
d[2] = dist; s->
v[3] = s->
v[2]; s->
v[2] = val; }
68 else if(dist < s->d[3]) { s->
d[3] = dist; s->
v[3] = val; }
91 const float df = focal - c->
focal;
92 if(df == 0.0f) { *res = c->
real_focal;
return 1; }
116 if(!have_dist)
return 1.f;
125 if(lens->
n_dist == 0)
return 0;
129 for(
int i = 0; i < lens->
n_dist; i++)
134 else if(model != c->
model)
continue;
135 const float df = focal - c->
focal;
136 if(df == 0.0f) { *res = *c;
return 1; }
143 if(lo) { *res = *lo;
return 1; }
144 if(hi) { *res = *hi;
return 1; }
156 for(
int i = 0; i < 3; i++)
159 fh ? fh->
terms[i] * fh->
focal : FLT_MAX, t) / focal;
165 if(lens->
n_tca == 0)
return 0;
169 for(
int i = 0; i < lens->
n_tca; i++)
174 else if(model != c->
model)
continue;
175 const float df = focal - c->
focal;
176 if(df == 0.0f) { *res = *c;
return 1; }
183 if(lo) { *res = *lo;
return 1; }
184 if(hi) { *res = *hi;
return 1; }
194 for(
int i = 0; i < 6; i++)
196 const float sl0 = (i < 2) ? 1.f : (fl ? fl->
focal : 1.f);
197 const float sl1 = (i < 2) ? 1.f : lo->
focal;
198 const float sl2 = (i < 2) ? 1.f : hi->
focal;
199 const float sl3 = (i < 2) ? 1.f : (fh ? fh->
focal : 1.f);
200 const float sl4 = (i < 2) ? 1.f : focal;
203 fh ? fh->
terms[i] * sl3 : FLT_MAX, t) / sl4;
216 float focal,
float aperture,
float distance)
221 if(df != 0.f) { f1 /= df; f2 /= df; }
222 const float a1 = 4.f / aperture;
224 const float d1 = 0.1f / distance;
225 const float d2 = 0.1f / c->
distance;
226 return sqrtf((f2 - f1) * (f2 - f1) + (a2 - a1) * (a2 - a1) + (d2 - d1) * (d2 - d1));
232 if(lens->
n_vig == 0)
return 0;
234 float total_weighting = 0.f;
235 float smallest = FLT_MAX;
236 float terms[3] = { 0.f, 0.f, 0.f };
238 for(
int i = 0; i < lens->
n_vig; i++)
243 else if(model != c->
model)
continue;
245 const float dist =
_vig_dist(lens, c, focal, aperture, distance);
246 if(dist < 0.0001f) { *res = *c;
return 1; }
247 if(dist < smallest) smallest = dist;
251 const float w = (float)fabs(1.0 / pow((
double)dist, 3.5));
252 for(
int k = 0; k < 3; k++) terms[k] += w * c->
terms[k];
253 total_weighting += w;
255 if(smallest > 1.f)
return 0;
256 if(total_weighting <= 0.f || smallest == FLT_MAX)
return 0;
260 for(
int k = 0; k < 3; k++) res->
terms[k] = terms[k] / total_weighting;
269 float crop,
int width,
int height,
270 float focal,
float aperture,
float distance,
271 float scale,
int target_type,
int flags,
int reverse)
273 memset(mod, 0,
sizeof(*mod));
274 if(!lens || crop <= 0.f)
return 0;
278 const float w = (width >= 2) ? (
float)(width - 1) : 1.f;
279 const float h = (height >= 2) ? (
float)(height - 1) : 1.f;
282 const float size = (w < h) ? w : h;
283 const float image_aspect_ratio = (w < h) ? h / w : w / h;
285 const float calibration_cropfactor = lens->
crop_factor;
287 const float aspect_ratio_correction = sqrtf(ar * ar + 1.f);
289 const float coordinate_correction =
290 1.f / sqrtf(image_aspect_ratio * image_aspect_ratio + 1.f)
291 * calibration_cropfactor / crop * aspect_ratio_correction;
293 mod->
norm_scale = 2.f / size * coordinate_correction;
294 mod->
norm_unscale = size * 0.5f / coordinate_correction;
302 const int from = (int)lens->
type;
338 float geom_focal_mm = focal;
345 const int have_dist =
_interp_dist(lens, focal, &hugin_dist);
346 float real_focal = 0.f;
361 mod->
reverse = reverse ? 1 : 0;
400 enabled &= ~LS_ENABLE_DISTORTION;
403 enabled &= ~LS_ENABLE_TCA;
444_Static_assert(
sizeof(
ls_eval_t) == 8 *
sizeof(float)
453 "ls_eval_t gained padding or a member: check it is still scalar-only");
460_Static_assert(
sizeof(
ls_eval_t) <= 1024 - 128,
461 "ls_eval_t no longer fits a guaranteed OpenCL kernel argument list");
462_Static_assert(_Alignof(
ls_eval_t) == _Alignof(
float),
"ls_eval_t alignment is no longer 4");
467 const float x,
const float y)
470 float t = -max_x - x;
if(t > r) r = t;
471 t = y - max_y;
if(t > r) r = t;
472 t = -max_y - y;
return (t > r) ? t : r;
486#define LS_GEOM_SENTINEL 1.6e16f
492 const float dist,
const float max_x,
const float max_y)
497 for(
int countdown = 50; ; countdown--)
499 float x = ca * ru, y = sa * ru;
504 if(rd > -1e-3f && rd < 1e-3f)
return ru;
505 if(!countdown)
return -1.f;
507 float x1 = ca * (ru + dx), y1 = sa * (ru + dx);
514 if(
LS_FABS(rd1 - rd) < 1e-5f) { dx *= 2.f;
continue; }
516 ru -= rd / ((rd1 - rd) / dx);
535 for(
int i = 1; i < n; i++)
536 if(!(xs[i] > xs[i - 1]))
return 0;
541 int width,
int height,
float scale,
int flags,
int reverse)
544 memset(mod, 0,
sizeof(*mod));
545 if(!knots || width < 1 || height < 1)
return 0;
556 const float w2 = (float)width * 0.5f;
557 const float h2 = (float)height * 0.5f;
558 const float rn = sqrtf(w2 * w2 + h2 * h2);
559 if(!(rn > 0.f))
return 0;
561 mod->
width = (float)width;
562 mod->
height = (float)height;
575 mod->
reverse = reverse ? 1 : 0;
579 if(scale != 1.f && scale > 0.f)
598 for(
int c = 0; c < 3 && usable; c++)
600 for(
int i = 0; i < n; i++)
602 const float r = knots->
radius[i];
603 const float f = knots->
cor_rgb[c][i];
604 if(!(f > 0.f)) { usable = 0;
break; }
618 mod->
knot_r[c][i] = r * f;
619 mod->
knot_c[c][i] = 1.f / f;
647 for(
int i = 0; i < vn; i++)
671 return subpixel_scale;
677 const float max_x = w * 0.5f * mod->
norm_scale;
678 const float max_y = h * 0.5f * mod->
norm_scale;
683 const float corner = atanf(h / w);
684 const float pi = 3.14159265f;
685 const float angles[8] = { 0.f, corner,
686 pi / 2.f, pi - corner,
688 3.f * pi / 2.f, 2.f * pi - corner };
689 const float diag = sqrtf(w * w + h * h) * 0.5f * mod->
norm_scale;
690 const float dists[8] = { max_x, diag, max_y, diag, max_x, diag, max_y, diag };
693 for(
int i = 0; i < 8; i++)
696 dists[i], max_x, max_y);
697 if(landed <= 0.f)
continue;
698 const float point_scale = dists[i] / landed;
699 if(point_scale > scale) scale = point_scale;
707 scale *= subpixel_scale;
709 return mod->
reverse ? 1.f / scale : scale;
713 const float focal_mm,
const float crop_factor)
725 if(!(from_type != to_type && radial && focal_mm > 0.f))
733 mod->
enabled &= ~LS_ENABLE_GEOMETRY;
747 if(!mod || !out)
return 0;
748 memset(out, 0,
sizeof(*out));
756 const float inv_arc = 1.f / arc;
781 for(
int c = 0; c < 3; c++)
782 for(
int i = 0; i < mod->
knot_n; i++)
788 for(
int i = 0; i < mod->
knot_vn; i++)
820 if(!dst || !src)
return 0;
845 float xu,
float yu,
int width,
int height,
848 if(!mod || !res || width <= 0 || height <= 0)
return 0;
861 for(
int row = 0; row < height; row++)
863 float *out = res + (size_t)row * width * 6;
864 const float y = yu + (float)row;
865 for(
int col = 0; col < width; col++, out += 6)
872 float xu,
float yu,
int width,
int height,
873 float *rgba,
int row_stride_bytes)
875 if(!mod || !rgba || width <= 0 || height <= 0)
return 0;
881 const size_t stride = row_stride_bytes ? (size_t)row_stride_bytes /
sizeof(
float)
899 enum { LS_VIG_BLOCK = 256 };
900 float mbuf[LS_VIG_BLOCK];
902 for(
int row = 0; row < height; row++)
904 float *
LS_RESTRICT px = rgba + (size_t)row * stride;
910 const float y = (yu + (float)row) * vs - p.
vig_center_y;
911 const float yy = y * y;
913 for(
int col0 = 0; col0 < width; col0 += LS_VIG_BLOCK)
915 const int n = (width - col0 < LS_VIG_BLOCK) ? (width - col0) : LS_VIG_BLOCK;
917 for(
int i = 0; i < n; i++)
919 const float x = (xu + (float)(col0 + i)) * vs - vcx;
923 for(
int i = 0; i < n; i++, px += 4)
925 const float m = mbuf[i];
941 const float a = px[3];
static int _interp_real_focal(const ls_lens_t *lens, float focal, float *res)
int ls_eval_from_modifier(const ls_modifier_t *mod, ls_eval_t *out)
Flatten a resolved modifier into the scalar block a kernel can take by value.
float ls_modifier_autoscale(const ls_modifier_t *mod)
The scale that just removes the black borders a correction leaves behind.
static float _hugin_focal_correction(const ls_calib_dist_t *dist, int have_dist)
static void _spline_init(spline_t *s)
static int _interp_tca(const ls_lens_t *lens, float focal, ls_calib_tca_t *res)
int ls_modifier_init_knots(ls_modifier_t *mod, const ls_knots_t *knots, int width, int height, float scale, int flags, int reverse)
Resolve a maker's embedded profile, in place of a database lens.
int ls_modifier_apply_vignetting(const ls_modifier_t *mod, float xu, float yu, int width, int height, float *rgba, int row_stride_bytes)
pa vignetting, multiplied in place over RGBA float rows. Contract of lfModifier::ApplyColorModificati...
static int _knot_axis_ascends(const float *xs, const int n)
static float _autoscale_residual(const ls_eval_t *p, const float max_x, const float max_y, const float x, const float y)
int ls_modifier_init(ls_modifier_t *mod, const ls_lens_t *lens, float crop, int width, int height, float focal, float aperture, float distance, float scale, int target_type, int flags, int reverse)
Resolve a lens at one (crop, geometry, focal, aperture, distance, scale).
static void _spline_insert(spline_t *s, float dist, const void *val)
static int _interp_dist(const ls_lens_t *lens, float focal, ls_calib_dist_t *res)
static float _interpolate(float y1, float y2, float y3, float y4, float t)
int ls_modifier_apply_subpixel_geometry(const ls_modifier_t *mod, float xu, float yu, int width, int height, float *res)
The geometry map: for count output pixels starting at (xu, yu), write 6 floats per pixel — source coo...
static float _vig_dist(const ls_lens_t *lens, const ls_calib_vig_t *c, float focal, float aperture, float distance)
static int _interp_vig(const ls_lens_t *lens, float focal, float aperture, float distance, ls_calib_vig_t *res)
static float _autoscale_distance(const ls_eval_t *p, const float ca, const float sa, const float dist, const float max_x, const float max_y)
int ls_modifier_set_projection(ls_modifier_t *mod, const int from_type, const int to_type, const float focal_mm, const float crop_factor)
Add a projection change to an already-resolved modifier.
int ls_eval_adopt_vignetting(ls_eval_t *dst, const ls_eval_t *src)
Move src's vignetting into dst, leaving dst's geometry untouched.
What this is, and what it deliberately is not.
#define LS_ENABLE_VIGNETTING
#define LS_ENABLE_DISTORTION
@ LS_LENS_EQUIRECTANGULAR
#define LS_ENABLE_GEOMETRY
The closed forms, written once, compiled as C99 and as OpenCL C.
#define LS_EVAL_DIST_POLY3
#define LS_EVAL_TCA_POLY3
static int ls_eval_coord_chain(const ls_eval_t *p, const int c, float *x, float *y)
The coordinate chain: scale, projection and distortion, in direction order.
#define LS_EVAL_ENABLE_DISTORTION
#define LS_EVAL_DIST_NONE
#define LS_EVAL_DIST_PTLENS
static float ls_eval_vignette_from_r2(const ls_eval_t *p, const float r2)
The vignetting multiplier for ONE output pixel. Multiply the pixel by it.
#define LS_EVAL_ENABLE_VIGNETTING
#define LS_EVAL_LENS_FISHEYE_THOBY
#define LS_EVAL_LENS_RECTILINEAR
#define LS_EVAL_ENABLE_SCALE
#define LS_EVAL_DIST_KNOTS
#define LS_EVAL_VIG_KNOTS
#define LS_EVAL_FULL_FRAME_HALF_DIAG_MM
#define LS_EVAL_DIST_POLY5
#define LS_EVAL_ENABLE_GEOMETRY
static void ls_eval_map(const ls_eval_t *p, float xu, float yu, float *out)
The map for ONE output pixel: six floats, source coordinates for R, G, B.
struct ls_eval_t ls_eval_t
One lens resolved at one shooting configuration, as a flat block of scalars.
#define LS_EVAL_ENABLE_TCA
#define LS_EVAL_TCA_LINEAR
One lens resolved at one shooting configuration, as a flat block of scalars.
A lens correction the camera maker measured and wrote into the file, as knots.
ls_calib_vig_t vig[LS_MAX_CALIB]
ls_calib_real_focal_t real_focal[LS_MAX_CALIB]
ls_calib_tca_t tca[LS_MAX_CALIB]
ls_calib_dist_t dist[LS_MAX_CALIB]
A modifier: the lens resolved at one shooting configuration.
float aspect_ratio_correction