|
LensSerious 0.1
Lens-correction mathematics as data, not as a library of callbacks
|
The closed forms, written once, compiled as C99 and as OpenCL C. More...
#include <math.h>
Include dependency graph for lensserious_eval.h:
This graph shows which files directly or indirectly include this file:Go to the source code of this file.
Data Structures | |
| struct | ls_eval_t |
| One lens resolved at one shooting configuration, as a flat block of scalars. More... | |
Typedefs | |
| typedef struct ls_eval_t | ls_eval_t |
| One lens resolved at one shooting configuration, as a flat block of scalars. | |
Functions | |
| static float | ls_eval_knot_lookup (const float *xs, const float *ys, const int n, const float x) |
| Piecewise-linear lookup over a knot table. | |
| static float | ls_eval_knot_factor (const ls_eval_t *p, const int c, const float x, const float y) |
| The per-channel radial scale a knot table gives at this point. | |
| static void | ls_eval_dist (const ls_eval_t *p, float *x, float *y) |
| Distortion, in place, in normalized coordinates. | |
| static void | ls_eval_tca (const ls_eval_t *p, float *xr, float *yr, float *xb, float *yb) |
| Transverse chromatic aberration: the red and blue coordinates diverge from green. | |
| static float | ls_eval_geom_angle (const int model, const float f, const float r) |
Field angle for a radius, under one projection. Negative if model has none. | |
| static float | ls_eval_geom_radius (const int model, const float f, const float theta) |
| Radius for a field angle, under one projection. The inverse of the above. | |
| static int | ls_eval_geometry (const ls_eval_t *p, float *x, float *y) |
| Reproject one point from the target geometry into the lens's own. | |
| static float | ls_eval_undist_factor (const ls_eval_t *p, const float rd) |
| Solve Rd = f(Ru) for Ru, given a radius Rd. The inverse of ls_eval_dist(). | |
| static void | ls_eval_undist (const ls_eval_t *p, float *x, float *y) |
| Undistort in place. The reverse of ls_eval_dist(). | |
| static void | ls_eval_untca (const ls_eval_t *p, float *xr, float *yr, float *xb, float *yb) |
| The reverse of ls_eval_tca(): recover each channel's undistorted radius. | |
| 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. | |
| 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. | |
| 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. | |
| static float | ls_eval_vignette_factor (const ls_eval_t *p, float xu, float yu) |
| The vignetting multiplier for ONE output pixel. Multiply the pixel by it. | |
The closed forms, written once, compiled as C99 and as OpenCL C.
This file is included by src/lensserious.c and by opencl/lensserious.cl, and it is the reason the two agree. The previous arrangement – the same six models typed out in both – had already drifted: the kernel computed its square roots with native_sqrt (implementation-defined precision, no accuracy guarantee) against the library's sqrtf, and never grew a vignetting evaluator at all. A drift like that is invisible to a parity harness that only ever tests the CPU side, which is exactly what tests/parity_lensfun.c does.
The rule for anything added here: it must compile unmodified under both toolchains. That means no float2/float4 (their host equivalents are not portable C), no address-space qualifiers on the arguments (ls_eval_t travels as a by-value kernel argument, so it lands in private memory on the device and is an ordinary local on the host), and arithmetic written so both sides fold it identically – see the note on argument form in ls_eval_map.
Definition in file lensserious_eval.h.
| #define LS_ASIN | ( | x | ) |
Definition at line 74 of file lensserious_eval.h.
Referenced by ls_eval_geom_angle().
| #define LS_ATAN | ( | x | ) |
Definition at line 73 of file lensserious_eval.h.
Referenced by ls_eval_geom_angle().
| #define LS_EVAL_DIST_KNOTS 4 |
Definition at line 88 of file lensserious_eval.h.
Referenced by ls_eval_coord_chain(), and ls_eval_map().
| #define LS_EVAL_DIST_NONE 0 |
Definition at line 99 of file lensserious_eval.h.
| #define LS_EVAL_DIST_POLY3 1 |
Definition at line 100 of file lensserious_eval.h.
Referenced by ls_eval_dist(), and ls_eval_undist_factor().
| #define LS_EVAL_DIST_POLY5 2 |
Definition at line 101 of file lensserious_eval.h.
Referenced by ls_eval_dist(), and ls_eval_undist_factor().
| #define LS_EVAL_DIST_PTLENS 3 |
Definition at line 102 of file lensserious_eval.h.
Referenced by ls_eval_dist(), and ls_eval_undist_factor().
| #define LS_EVAL_ENABLE_DISTORTION (1 << 0) |
Definition at line 126 of file lensserious_eval.h.
Referenced by ls_eval_coord_chain().
| #define LS_EVAL_ENABLE_GEOMETRY (1 << 4) |
Definition at line 130 of file lensserious_eval.h.
Referenced by ls_eval_coord_chain().
| #define LS_EVAL_ENABLE_SCALE (1 << 3) |
Definition at line 129 of file lensserious_eval.h.
Referenced by ls_eval_coord_chain().
| #define LS_EVAL_ENABLE_TCA (1 << 1) |
Definition at line 127 of file lensserious_eval.h.
Referenced by ls_eval_coord_chain(), and ls_eval_map().
| #define LS_EVAL_ENABLE_VIGNETTING (1 << 2) |
Definition at line 128 of file lensserious_eval.h.
Referenced by ls_eval_adopt_vignetting(), and ls_eval_vignette_factor().
| #define LS_EVAL_FULL_FRAME_HALF_DIAG_MM 21.633307f |
Half the diagonal of a 36x24 frame, in mm: sqrt(36^2+24^2)/2. The projection focal is expressed against it – see ls_modifier_init(), which is where the conversion lives.
Definition at line 113 of file lensserious_eval.h.
Referenced by ls_modifier_init(), and ls_modifier_set_projection().
| #define LS_EVAL_LENS_EQUIRECTANGULAR 4 |
Definition at line 120 of file lensserious_eval.h.
| #define LS_EVAL_LENS_FISHEYE 2 |
Definition at line 118 of file lensserious_eval.h.
Referenced by ls_eval_geom_angle(), and ls_eval_geom_radius().
| #define LS_EVAL_LENS_FISHEYE_EQUISOLID 7 |
Definition at line 123 of file lensserious_eval.h.
Referenced by ls_eval_geom_angle(), and ls_eval_geom_radius().
| #define LS_EVAL_LENS_FISHEYE_ORTHOGRAPHIC 5 |
Definition at line 121 of file lensserious_eval.h.
Referenced by ls_eval_geom_angle(), and ls_eval_geom_radius().
| #define LS_EVAL_LENS_FISHEYE_STEREOGRAPHIC 6 |
Definition at line 122 of file lensserious_eval.h.
Referenced by ls_eval_geom_angle(), and ls_eval_geom_radius().
| #define LS_EVAL_LENS_FISHEYE_THOBY 8 |
Definition at line 124 of file lensserious_eval.h.
Referenced by ls_eval_geom_angle(), and ls_eval_geom_radius().
| #define LS_EVAL_LENS_PANORAMIC 3 |
Definition at line 119 of file lensserious_eval.h.
| #define LS_EVAL_LENS_RECTILINEAR 1 |
Definition at line 117 of file lensserious_eval.h.
Referenced by ls_eval_geom_angle(), and ls_eval_geom_radius().
| #define LS_EVAL_LENS_UNKNOWN 0 |
Definition at line 116 of file lensserious_eval.h.
| #define LS_EVAL_TCA_LINEAR 1 |
Definition at line 105 of file lensserious_eval.h.
Referenced by ls_eval_from_modifier(), ls_eval_tca(), and ls_eval_untca().
| #define LS_EVAL_TCA_NONE 0 |
Definition at line 104 of file lensserious_eval.h.
| #define LS_EVAL_TCA_POLY3 2 |
Definition at line 106 of file lensserious_eval.h.
Referenced by ls_eval_tca(), and ls_eval_untca().
| #define LS_EVAL_VIG_KNOTS 2 |
Definition at line 89 of file lensserious_eval.h.
Referenced by ls_eval_vignette_from_r2().
| #define LS_EVAL_VIG_NONE 0 |
Definition at line 108 of file lensserious_eval.h.
| #define LS_EVAL_VIG_PA 1 |
Definition at line 109 of file lensserious_eval.h.
| #define LS_FABS | ( | x | ) |
Definition at line 77 of file lensserious_eval.h.
Referenced by _autoscale_distance(), ls_eval_undist_factor(), and ls_eval_untca().
| #define LS_MAX_KNOTS 16 |
Definition at line 97 of file lensserious_eval.h.
Referenced by _dng_populate(), _fuji_populate(), _olympus_populate(), _sony_has_data(), ls_eval_adopt_vignetting(), and ls_modifier_init_knots().
| #define LS_NEWTON_RTOL 1e-6f |
Definition at line 399 of file lensserious_eval.h.
Referenced by ls_eval_undist_factor(), and ls_eval_untca().
| #define LS_NEWTON_STEPS 6 |
Definition at line 398 of file lensserious_eval.h.
Referenced by ls_eval_undist_factor(), and ls_eval_untca().
| #define LS_SIN | ( | x | ) |
Definition at line 75 of file lensserious_eval.h.
Referenced by ls_eval_geom_radius().
| #define LS_SQRT | ( | x | ) |
Definition at line 72 of file lensserious_eval.h.
Referenced by ls_eval_dist(), ls_eval_geometry(), ls_eval_knot_factor(), ls_eval_tca(), ls_eval_undist(), ls_eval_untca(), and ls_eval_vignette_from_r2().
| #define LS_TAN | ( | x | ) |
Definition at line 76 of file lensserious_eval.h.
Referenced by ls_eval_geom_radius().
| typedef struct ls_eval_t ls_eval_t |
One lens resolved at one shooting configuration, as a flat block of scalars.
Scalars only, and no vector types: a struct of float and int has the same layout under every host C ABI and under OpenCL C, so this can be memcpy'd into a kernel argument. Anything richer (a float2 centre, say) would lay out differently and corrupt every field after it, silently. tests/parity_lensfun.c pins the size.
Produced by ls_eval_from_modifier(); consumed by ls_eval_map() and ls_eval_vignette_factor(), on either side.
|
inlinestatic |
The coordinate chain: scale, projection and distortion, in direction order.
| p | the lens resolved at one shooting configuration. |
| c | which channel's geometry to follow, 0 red / 1 green / 2 blue. Only a knot table distinguishes them – a vendor profile IS one radial curve per channel, distortion and TCA measured together rather than modelled as two stages. Every polynomial model puts all three on the green curve and expresses the difference as a separate TCA stage afterwards, so for those this argument is ignored. Pass 1 wherever a single geometry is meant. |
| x,y | a point in normalized coordinates, transformed in place. |
x and y are untouched and the caller decides what to write.Everything lensfun registers as a COORDINATE callback and nothing else – TCA is a subpixel callback and runs after, vignetting is a colour callback. It exists as its own function because autoscaling has to evaluate exactly this, and a second copy written for that purpose would be a second copy to drift.
The order is not symmetric between the directions: forward scale (100) -> projection (500) -> distortion (750) reverse undistortion (250) -> projection (500) -> scale (900) The projection sits in the middle either way; scale moves from first to last, and the resolver has already swapped the projection endpoints and un-reciprocated the scale.
A knot table occupies the distortion slot, and only that slot: the vendor measured the lens as shipped, so there is no projection change and no scale baked into its numbers, and a consumer that asks for either still gets it composed around the table in the order above. It sits in the FORWARD slot in both directions because the resolver builds the table for the direction asked for – inverting a piecewise-linear curve is exact at its own knots, which is why nothing here iterates the way ls_eval_undist() has to.
Definition at line 559 of file lensserious_eval.h.
References ls_eval_t::dist_model, ls_eval_t::enabled, ls_eval_t::knot_axes, ls_eval_dist(), LS_EVAL_DIST_KNOTS, LS_EVAL_ENABLE_DISTORTION, LS_EVAL_ENABLE_GEOMETRY, LS_EVAL_ENABLE_SCALE, LS_EVAL_ENABLE_TCA, ls_eval_geometry(), ls_eval_knot_factor(), ls_eval_undist(), ls_eval_t::reverse, and ls_eval_t::scale.
Referenced by _autoscale_distance(), and ls_eval_map().
|
inlinestatic |
Distortion, in place, in normalized coordinates.
Definition at line 255 of file lensserious_eval.h.
References ls_eval_t::dist_model, ls_eval_t::dist_terms, LS_EVAL_DIST_POLY3, LS_EVAL_DIST_POLY5, LS_EVAL_DIST_PTLENS, and LS_SQRT.
Referenced by ls_eval_coord_chain().
|
inlinestatic |
Field angle for a radius, under one projection. Negative if model has none.
The destination half of a projection change: the output image is in model's geometry, and this recovers the angle the ray came in at. Radii outside a projection's domain (a fisheye only maps so far) return -1 so the caller can leave the pixel black rather than fold the image back on itself.
Definition at line 316 of file lensserious_eval.h.
References LS_ASIN, LS_ATAN, LS_EVAL_LENS_FISHEYE, LS_EVAL_LENS_FISHEYE_EQUISOLID, LS_EVAL_LENS_FISHEYE_ORTHOGRAPHIC, LS_EVAL_LENS_FISHEYE_STEREOGRAPHIC, LS_EVAL_LENS_FISHEYE_THOBY, and LS_EVAL_LENS_RECTILINEAR.
Referenced by ls_eval_geometry().
|
inlinestatic |
Radius for a field angle, under one projection. The inverse of the above.
Definition at line 333 of file lensserious_eval.h.
References LS_EVAL_LENS_FISHEYE, LS_EVAL_LENS_FISHEYE_EQUISOLID, LS_EVAL_LENS_FISHEYE_ORTHOGRAPHIC, LS_EVAL_LENS_FISHEYE_STEREOGRAPHIC, LS_EVAL_LENS_FISHEYE_THOBY, LS_EVAL_LENS_RECTILINEAR, LS_SIN, and LS_TAN.
Referenced by ls_eval_geometry().
|
inlinestatic |
Reproject one point from the target geometry into the lens's own.
Radially symmetric, so it scales x and y by one factor rather than mapping them separately – which is exactly why panoramic and equirectangular are excluded: those two treat the axes differently and cannot be expressed this way.
Definition at line 360 of file lensserious_eval.h.
References ls_eval_t::geom_focal, ls_eval_t::geom_from, ls_eval_t::geom_to, ls_eval_geom_angle(), ls_eval_geom_radius(), and LS_SQRT.
Referenced by ls_eval_coord_chain().
|
inlinestatic |
The per-channel radial scale a knot table gives at this point.
| p | the lens resolved at one shooting configuration. |
| c | the channel, 0 red / 1 green / 2 blue. |
| x,y | a point in normalized coordinates. |
No conversion between radius conventions, because there is none to make: ls_modifier_init_knots() defines this modifier's normalized system to BE the one the vendors index their tables by – the distance from the image centre over half the image diagonal, so 1.0 at the corner. A knot table never shares a modifier with lens-database calibration data, so nothing has to reconcile the two.
Definition at line 247 of file lensserious_eval.h.
References ls_eval_t::knot_c, ls_eval_t::knot_n, ls_eval_t::knot_r, ls_eval_knot_lookup(), and LS_SQRT.
Referenced by ls_eval_coord_chain().
|
inlinestatic |
Piecewise-linear lookup over a knot table.
| xs | the knot positions, ascending, n of them. |
| ys | the value at each of them. |
| n | how many knots. |
| x | where to sample. Clamped to the ends rather than extrapolated. |
The vendors' own convention, and deliberately not something smoother: their profiles are DEFINED as the piecewise-linear interpolant of these points, so a spline through them would be a different correction, not a better one.
Definition at line 216 of file lensserious_eval.h.
Referenced by ls_eval_knot_factor(), and ls_eval_vignette_from_r2().
|
inlinestatic |
The map for ONE output pixel: six floats, source coordinates for R, G, B.
| p | the lens resolved at one shooting configuration. |
| xu | absolute output column, in pixels. |
| yu | absolute output row, in pixels. |
| out | six floats: xr yr xg yg xb yb, the layout of lfModifier::ApplySubpixelGeometryDistortion()'s buffer. |
xu and yu are ABSOLUTE, already summed by the caller – a row walker passes xu + col, a work-item passes xu + get_global_id(0). Both then evaluate the identical expression on the identical float, which is what makes the CPU row loop and the kernel agree bit for bit rather than merely closely. Do not "optimise" this into taking an origin plus an index: the two would then round differently.
Definition at line 613 of file lensserious_eval.h.
References ls_eval_t::center_x, ls_eval_t::center_y, ls_eval_t::dist_model, ls_eval_t::enabled, ls_eval_t::knot_axes, ls_eval_coord_chain(), LS_EVAL_DIST_KNOTS, LS_EVAL_ENABLE_TCA, ls_eval_tca(), ls_eval_untca(), ls_eval_t::norm_scale, ls_eval_t::norm_unscale, and ls_eval_t::reverse.
Referenced by ls_modifier_apply_subpixel_geometry(), and ls_subpixel_geometry().
|
inlinestatic |
Transverse chromatic aberration: the red and blue coordinates diverge from green.
Definition at line 282 of file lensserious_eval.h.
References LS_EVAL_TCA_LINEAR, LS_EVAL_TCA_POLY3, LS_SQRT, ls_eval_t::tca_model, and ls_eval_t::tca_terms.
Referenced by ls_eval_map().
|
inlinestatic |
Undistort in place. The reverse of ls_eval_dist().
Definition at line 468 of file lensserious_eval.h.
References ls_eval_undist_factor(), and LS_SQRT.
Referenced by ls_eval_coord_chain().
|
inlinestatic |
Solve Rd = f(Ru) for Ru, given a radius Rd. The inverse of ls_eval_dist().
| p | the lens resolved at one shooting configuration, reverse direction. |
| rd | the distorted radius, in normalized units. |
Definition at line 410 of file lensserious_eval.h.
References ls_eval_t::dist_model, ls_eval_t::dist_terms, LS_EVAL_DIST_POLY3, LS_EVAL_DIST_POLY5, LS_EVAL_DIST_PTLENS, LS_FABS, LS_NEWTON_RTOL, and LS_NEWTON_STEPS.
Referenced by ls_eval_undist().
|
inlinestatic |
The reverse of ls_eval_tca(): recover each channel's undistorted radius.
Linear is a reciprocal the resolver already took. Poly3 is the same Newton as above on Rd = b·Ru³ + c·Ru² + v·Ru, run once per channel, and – exactly as upstream – a channel that fails to converge keeps the coordinate it came in with while the other channel may still be corrected.
Definition at line 484 of file lensserious_eval.h.
References LS_EVAL_TCA_LINEAR, LS_EVAL_TCA_POLY3, LS_FABS, LS_NEWTON_RTOL, LS_NEWTON_STEPS, LS_SQRT, ls_eval_t::tca_model, and ls_eval_t::tca_terms.
Referenced by ls_eval_map().
|
inlinestatic |
The vignetting multiplier for ONE output pixel. Multiply the pixel by it.
Returns 1.0 when no vignetting is resolved, so a caller may apply it unconditionally. Absolute pixel coordinates, as in ls_eval_map().
Definition at line 752 of file lensserious_eval.h.
References ls_eval_t::enabled, LS_EVAL_ENABLE_VIGNETTING, ls_eval_vignette_from_r2(), ls_eval_t::vig_center_x, ls_eval_t::vig_center_y, and ls_eval_t::vig_scale.
Referenced by ls_vignette_map().
|
inlinestatic |
The vignetting multiplier for ONE output pixel. Multiply the pixel by it.
Returns 1.0 when no vignetting is resolved, so a caller may apply it unconditionally. Absolute pixel coordinates, as in ls_eval_map().
Two conventions that a reimplementation gets wrong and a harness catches late: "Damn! Hugin uses two different 'normalized' coordinate systems: for distortions it uses 1.0 = min(half width, half height) and for vignetting it uses 1.0 = half diagonal length" (mod-color.cpp) – hence the division by the aspect-ratio correction; and CORRECTING vignetting DIVIDES by the polynomial (ModifyColor_DeVignetting_PA applies 1/c), where multiplying by c is what applies it.
The vignetting multiplier for a squared radius already in the half-diagonal system.
Split out so a row walker can hoist everything that does not vary along a row – the y term and its square – while the polynomial itself, the pole handling and the clamp stay in ONE place for both the CPU and the kernel. Callers that have a pixel coordinate rather than a radius want ls_eval_vignette_factor().
Definition at line 697 of file lensserious_eval.h.
References ls_eval_t::knot_v, ls_eval_t::knot_vn, ls_eval_t::knot_vr, ls_eval_knot_lookup(), LS_EVAL_VIG_KNOTS, LS_SQRT, ls_eval_t::reverse, ls_eval_t::vig_model, and ls_eval_t::vig_terms.
Referenced by ls_eval_vignette_factor(), and ls_modifier_apply_vignetting().