34static float _linear_spline(
const float *xi,
const float *yi,
const int ni,
const float x)
36 if(ni <= 0)
return 1.0f;
37 if(x < xi[0])
return yi[0];
39 for(
int i = 1; i < ni; i++)
41 if(x >= xi[i - 1] && x <= xi[i])
43 const float denom = xi[i] - xi[i - 1];
44 if(denom == 0.0f)
return yi[i - 1];
45 const float dydx = (yi[i] - yi[i - 1]) / denom;
46 return yi[i - 1] + (x - xi[i - 1]) * dydx;
70 for(
int i = 0; i < sony->
nc; i++)
82 static const float SONY_DIST_SCALE = 1.0f / 16384.0f;
83 static const float SONY_CA_SCALE = 1.0f / 2097152.0f;
84 static const float SONY_VIG_SCALE = 1.0f / 8192.0f;
87 const int nc = sony->
nc;
89 for(
int i = 0; i < nc; i++)
91 const float frac = (float)(i + 0.5) / (float)(nc - 1);
96 knots->
cor_rgb[0][i] = dist_cor;
97 knots->
cor_rgb[1][i] = dist_cor;
98 knots->
cor_rgb[2][i] = dist_cor;
100 knots->
cor_rgb[0][i] *= ft->
ca_red * ((float)sony->
ca_r[i] * SONY_CA_SCALE) + 1.0f;
104 knots->
vig[i] = powf(2.0f, 0.5f - powf(2.0f, val - 1.0f));
125 for(
int i = 0; i < fuji->
nc; i++)
143 const int ncsrc = fuji->
nc;
151 if(fuji->
knots[0] > 0.0f)
154 cor_rgb_in[j] = 1.0f;
155 cor_ca_r_in[j] = 0.0f;
156 cor_ca_b_in[j] = 0.0f;
158 knots->
vig[j] = 1.0f;
162 for(
int i = 0; i < ncsrc; i++, j++)
173 if(ncin <= 0)
return 0;
178 knots->
vig[k] = knots->
vig[ncin - 1];
182 for(
int i = 0; i < nc; i++)
184 const float rin = (float)i / (
float)(nc - 1);
186 const float r = (fabsf(m) > 1e-6f) ? rin / m : rin;
193 const float mcar =
_linear_spline(knots_in, cor_ca_r_in, ncin, rin);
194 const float mcab =
_linear_spline(knots_in, cor_ca_b_in, ncin, rin);
195 knots->
cor_rgb[0][i] *= mcar + 1.0f;
196 knots->
cor_rgb[2][i] *= mcab + 1.0f;
219 return coeffs[0] + r2 * (coeffs[1] + r2 * (coeffs[2] + r2 * coeffs[3]));
227 const uint32_t three = 3;
229 const int canonical_plane = (dng->
warp_planes > 1) ? 1 : 0;
232 for(
int i = 0; i < nc; i++)
234 const float r = (float)i / (
float)(nc - 1);
237 const double r2 = (double)r * (
double)r;
241 for(
int c = 0; c < 3; c++)
243 const int plane = apply_tca ? (c < nplanes - 1 ? c : nplanes - 1) : canonical_plane;
257 const double dvig = r2
261 knots->
vig[i] = (float)(1.0 / (1.0 + ft->
vignette * dvig));
265 knots->
vig[i] = 1.0f;
319 for(
int i = 0; i < nc; i++)
321 const float r = (float)i / (
float)(nc - 1);
324 knots->
vig[i] = 1.0f;
329 const float rs2 = (r * drs) * (r * drs);
330 const float r_cor = drs * (1.0f + rs2 * (dk2 + rs2 * (dk4 + rs2 * dk6)));
331 base = ft->
distortion * (r_cor - 1.0f) + 1.0f;
337 if(oly->
has_ca && r > 0.0f)
339 const float rd = base * r;
340 const float rd2 = rd * rd;
341 knots->
cor_rgb[0][i] += ft->
ca_red * (rd * (car0 + rd2 * (car2 + rd2 * car4))) / r;
342 knots->
cor_rgb[2][i] += ft->
ca_blue * (rd * (cab0 + rd2 * (cab2 + rd2 * cab4))) / r;
369 int w,
int h,
ls_knots_t *knots,
float *autoscale)
371 if(autoscale) *autoscale = 1.0f;
373 memset(knots, 0,
sizeof(*knots));
385 if(axes == 0)
return 0;
398 memset(knots, 0,
sizeof(*knots));
406 const float iwd2 = 0.5f * (float)w;
407 const float iht2 = 0.5f * (float)h;
408 const float diag = hypotf(iwd2, iht2);
409 const float sr = fminf(iwd2, iht2);
410 const float srr = (diag > 1e-6f) ? sr / diag : 0.0f;
412 const int tested = 200;
414 for(
int i = 0; i < tested; i++)
416 const float x = srr + (1.0f - srr) * (
float)i / (float)(tested - 1);
417 for(
int c = 0; c < 3; c++)
420 if(scale <= 1e-6f) scale = 1.0f;
422 for(
int i = 0; i < nc; i++)
424 knots->
radius[i] *= scale;
425 for(
int c = 0; c < 3; c++) knots->
cor_rgb[c][i] /= scale;
431 if(autoscale) *autoscale = scale;
442#define DNG_OPCODE_ID_WARP_RECTILINEAR 1u
443#define DNG_OPCODE_ID_VIGNETTE_RADIAL 3u
445#define DNG_WARP_PLANES_MIN 1u
446#define DNG_WARP_PLANES_MAX 3u
447#define DNG_WARP_HEADER_SIZE 4u
448#define DNG_WARP_PLANE_SIZE (6u * 8u)
449#define DNG_WARP_CENTER_SIZE (2u * 8u)
450#define DNG_VIGNETTE_COEFFS_SIZE (5u * 8u)
451#define DNG_VIGNETTE_CENTER_SIZE (2u * 8u)
456 for(
int i = 0; i < 8; i++) v = (v << 8) | p[i];
458 memcpy(&out, &v,
sizeof(out));
464 return ((uint32_t)p[0] << 24) | ((uint32_t)p[1] << 16) | ((uint32_t)p[2] << 8) | (uint32_t)p[3];
475 const uint64_t min_size
477 if(param_size < min_size)
return;
480 for(uint32_t p = 0; p < planes; p++)
482 for(
int c = 0; c < 6; c++)
508 memset(out, 0,
sizeof(*out));
522 if(offset + 16 > len) { broke = 1;
break; }
525 const uint32_t param_size =
_get_be_long(&blob[offset + 12]);
526 const uint8_t *param = &blob[offset + 16];
528 if(offset + 16 + (uint64_t)param_size > len) { broke = 1;
break; }
535 offset += 16 + (uint64_t)param_size;
#define LS_ENABLE_VIGNETTING
#define LS_ENABLE_DISTORTION
static int _dng_axes(const ls_vendor_data_t *d)
static int _sony_axes(const ls_vendor_data_t *d)
#define DNG_OPCODE_ID_WARP_RECTILINEAR
static void _parse_vignette_radial(const uint8_t *param, uint32_t param_size, ls_vendor_dng_t *out)
static int _fuji_axes(const ls_vendor_data_t *d)
static int _sony_populate(const ls_vendor_data_t *d, const ls_vendor_finetune_t *ft, ls_knots_t *knots)
static double _get_be_double(const uint8_t *p)
static int _fuji_has_data(const ls_vendor_data_t *d)
static float _linear_spline(const float *xi, const float *yi, const int ni, const float x)
#define DNG_VIGNETTE_CENTER_SIZE
#define DNG_VIGNETTE_COEFFS_SIZE
static int _olympus_populate(const ls_vendor_data_t *d, const ls_vendor_finetune_t *ft, ls_knots_t *knots)
static void _parse_warp_rectilinear(const uint8_t *param, uint32_t param_size, ls_vendor_dng_t *out)
static uint32_t _get_be_long(const uint8_t *p)
static const ls_vendor_finetune_t _ft_identity
#define DNG_OPCODE_ID_VIGNETTE_RADIAL
static int _fuji_populate(const ls_vendor_data_t *d, const ls_vendor_finetune_t *ft, ls_knots_t *knots)
static int _dng_populate(const ls_vendor_data_t *d, const ls_vendor_finetune_t *ft, ls_knots_t *knots)
static int _olympus_axes(const ls_vendor_data_t *d)
#define DNG_WARP_CENTER_SIZE
#define DNG_WARP_PLANE_SIZE
#define DNG_WARP_HEADER_SIZE
int ls_vendor_parse_dng_opcodelist3(const uint8_t *blob, size_t len, ls_vendor_dng_t *out)
Parse a DNG OpcodeList3 payload: WarpRectilinear (1) and VignetteRadial (3).
int ls_vendor_axes(const ls_vendor_data_t *d)
Which correction axes this data carries.
int ls_vendor_resolve(const ls_vendor_data_t *d, const ls_vendor_finetune_t *ft, int w, int h, ls_knots_t *knots, float *autoscale)
The conversion: vendor tables in, generic knots out.
static double _dng_warp_radial(const double coeffs[6], const double r2)
#define DNG_WARP_PLANES_MAX
static int _sony_has_data(const ls_vendor_data_t *d)
Turn a camera maker's embedded lens-correction tables into ls_knots_t.
#define LS_VENDOR_EBADDATA
Resolve/parse result: the data is structurally malformed. Distinct from 0 ("carries nothing") so the ...
A lens correction the camera maker measured and wrote into the file, as knots.
One image's embedded correction data: the type tag and the matching member. A plain value — embed it ...
ls_vendor_olympus_t olympus
union ls_vendor_data_t::@1 u
A DNG's OpcodeList3 corrections, parsed. Fill it with ls_vendor_parse_dng_opcodelist3() — or by hand,...
Per-axis strength blend, 1.0 = exactly as the maker measured. The vendors' own GUIs expose these as "...
Fujifilm maker-note tables, verbatim: explicit knot radii shared by the three corrections,...
Olympus maker-note polynomials, verbatim. No vignetting: Olympus does not publish one,...
Sony maker-note tables, verbatim: fixed-point int16 over nc evenly spaced radii, which the file leave...