43#define CURVE_RESOLUTION 0x10000
56#include "../../src/common/curve_tools.c"
63#define BASECURVE_PARAMS_VERSION 2
71#define DT_IOP_BASECURVE_MAXNODES 20
86#define TONECURVE_PARAMS_VERSION 4
94#define DT_IOP_TONECURVE_MAXNODES 20
112 static const char hex[] =
"0123456789abcdef";
113 for(
int i=0;
i<len;
i++)
115 out[2*
i ] = hex[in[
i] >> 4];
116 out[2*
i+1] = hex[in[
i] & 15];
130 r = fseek(
f, 0, SEEK_SET);
137 r = fread(buf, 1, 2,
f);
138 if (
r != 2 || buf[0] !=
'P' || buf[1] !=
'6')
145 r = fscanf(
f,
"%*[^0-9]%d %d\n%*[^\n]", wd, ht);
151 r = (
r != 2) ? -1 : 0;
163 f = fopen(filename,
"rb");
173 p = (uint16_t *)malloc(
sizeof(uint16_t)*3*(*wd)*(*ht));
174 int rd = fread(
p,
sizeof(uint16_t)*3, (*wd)*(*ht),
f);
175 if(rd != (*wd)*(*ht))
177 fprintf(stderr,
"[read_ppm] unexpected end of file! maybe you're loading an 8-bit ppm here instead of a 16-bit one? (%s)\n", filename);
197 f = fopen(filename,
"rb");
206 p = (uint8_t *)malloc(
sizeof(uint8_t)*3*(*wd)*(*ht));
207 int rd = fread(
p,
sizeof(uint8_t)*3, (*wd)*(*ht),
f);
208 if(rd != (*wd)*(*ht))
210 fprintf(stderr,
"[read_ppm] unexpected end of file! (%s)\n", filename);
228 const float max = 1.0f,
min = 0.0f;
237 if(
k < 655)
d *= 100;
246 for(
int k=1;
k<c->m_numAnchors-1;
k++)
248 float min = (c->m_anchors[
k-1].x + c->m_anchors[
k].x)/2.0f;
249 float max = (c->m_anchors[
k+1].x + c->m_anchors[
k].x)/2.0f;
256 t->m_anchors[
k].x =
x;
257 t->m_anchors[
k].y = basecurve[pos];
259 t->m_anchors[0].x = 0.0f;
260 t->m_anchors[0].y = 0.0f;
261 t->m_anchors[
t->m_numAnchors-1].x = 1.0f;
262 t->m_anchors[
t->m_numAnchors-1].y = 1.0f;
273 val = powf(((val + 0.055f)/1.055f), 2.4f);
278#define SQUARE(a) ((a)*(a))
279#define CUBIC(a) ((a)*SQUARE((a)))
281static inline float Lab(
float val)
286 val = powf(val, 1.f / 3.f);
290 val = 4.f / 29.f +
SQUARE(29.f) / (3.f *
SQUARE(6.f)) * val;
297RGB2Lab(
float*
L,
float* a,
float*b,
float R,
float G,
float B)
300 const float X = 0.4360747f*
R + 0.3850649f*G + 0.1430804f*
B;
301 const float Y = 0.2225045f*
R + 0.7168786f*G + 0.0606169f*
B;
302 const float Z = 0.0139322f*
R + 0.0971045f*G + 0.7141733f*
B;
305 const float fx =
Lab(X/0.9642f);
306 const float fy =
Lab(Y);
307 const float fz =
Lab(Z/0.8249f);
309 *
L = 116.f*fy - 16.f;
310 *a = 500.f*(
fx - fy);
311 *b = 200.f*(fy -
fz);
317 *a = (*a + 128.f) / 256.f;
318 *b = (*b + 128.f) / 256.f;
335#pragma omp parallel for
336 for (
int y=0; y<
height; y++) {
337 float*
d = _d + 3*
width*y;
338 uint8_t* s = _s + 3*
width*y;
355#pragma omp parallel for
356 for (
int y=0; y<
height; y++) {
357 float*
d = _d + 3*
width*y;
358 uint16_t* s = _s + 3*
width*y;
360 d[0] = (float)s[0]/65535.f;
361 d[1] = (float)s[1]/65535.f;
362 d[2] = (float)s[2]/65535.f;
371 int width_jpeg,
int height_jpeg,
float* buf_jpeg,
372 int offx_raw,
int offy_raw,
int width_raw,
float* buf_raw,
373 int ch,
float* curve, uint32_t* cnt)
375 for(
int j=0;j<height_jpeg;j++)
377 for(
int i=0;
i<width_jpeg;
i++)
380 const int ri = offx_raw +
i;
381 const int rj = offy_raw + j;
384 float jpegVal = buf_jpeg[3*(width_jpeg*j +
i) +
ch];
387 float rawVal = buf_raw[3*(width_raw*rj + ri) +
ch];
390 curve[raw] = (curve[raw]*cnt[raw] + jpegVal)/(cnt[raw] + 1.0f);
398 int width_jpeg,
int height_jpeg,
float* buf_jpeg,
399 int offx_raw,
int offy_raw,
int width_raw,
float* buf_raw,
400 float* curve, uint32_t* hist)
410 for(
int j=0;j<height_jpeg;j++)
412 for(
int i=0;
i<width_jpeg;
i++)
415 const int ri = offx_raw +
i;
416 const int rj = offy_raw + j;
419 float r = buf_jpeg[3*(width_jpeg*j +
i) + 0];
420 float g = buf_jpeg[3*(width_jpeg*j +
i) + 1];
421 float b = buf_jpeg[3*(width_jpeg*j +
i) + 2];
427 RGB2Lab(&L_jpeg, &a_jpeg, &b_jpeg,
r,
g, b);
431 r = buf_raw[3*(width_raw*rj + ri) + 0];
432 g = buf_raw[3*(width_raw*rj + ri) + 1];
433 b = buf_raw[3*(width_raw*rj + ri) + 2];
439 RGB2Lab(&L_raw, &a_raw, &b_raw,
r,
g, b);
445 cL[Li] = (cL[Li]*hL[Li] + L_jpeg)/(hL[Li] + 1.0f);
446 ca[ai] = (ca[ai]*ha[ai] + a_jpeg)/(ha[ai] + 1.0f);
447 cb[bi] = (cb[bi]*hb[bi] + b_jpeg)/(hb[bi] + 1.0f);
473 const float p_large = .0f;
474 float curr_m = FLT_MIN;
476 const int samples = 1000;
477 for(
int i=0;
i<samples;
i++)
479 if(
i == 0 || drand48() < p_large)
494 mutate(&curr, &tent, curve);
496 float m =
get_error(&tent, csample, curve, cnt);
505 const float a = curr_m/
m;
506 if(drand48() < a ||
i == 0)
518 static const union { uint8_t u8[4]; uint32_t u32;} byte_order
__attribute__((aligned(4))) = { .u8 = {1,2,3,4} };
519 return byte_order.u32 == 0x01020304;
542 "first pass, accumulate statistics (can be repeated to cover all tonal range):\n"
543 "%s [OPTIONS] <inputraw.ppm (16-bit)> <inputjpg.ppm (8-bit)>\n"
545 "second pass, compute the curves:\n"
549 " -n <integer> Number of nodes for the curve\n"
550 " -b <filename> Basecurve output filename\n"
551 " -c <filename> Basecurve Fit curve output filename\n"
552 " -t <filename> Tonecurve output filename\n"
553 " -u <filename> Tonecurve Fit curve output filename\n"
554 " -a Tonecurve Fit the a* and b* channels\n"
555 " -s <filename> Save state\n"
556 " -z Compute the fitting curve\n"
557 " -e <filename> Retrieve model and make from file's Exif metadata\n"
558 " -h Print this help message\n"
560 "convert the raw with `dcraw -6 -W -g 1 1 -w input.raw'\n"
561 "and the jpg with `convert input.jpg output.ppm'\n"
562 "plot the results with `gnuplot plot.(basecurve|tonecurve) depending on target module'\n"
564 "first do a pass over a few images to accumulate data in the save state file, and then\n"
565 "compute the fit curve using option -z\n",
573 static const char* default_filename_basecurve =
"basecurve.dat";
574 static const char* default_filename_basecurve_fit =
"basecurve.fit.dat";
575 static const char* default_filename_tonecurve =
"tonecurve.dat";
576 static const char* default_filename_tonecurve_fit =
"tonecurve.fit.dat";
577 static const char* default_state =
"dt-curve-tool.bin";
601 while ((c = getopt(argc, argv,
"hn:b:c:t:u:s:ze:a")) >= 0)
633 fprintf(stderr,
"missing argument for option -%c, ignored\n", optopt);
638 fprintf(stderr,
"unknown option -%c\n", optopt);
652 if (optind < argc - 1)
705 fprintf(stderr,
"error: failed writing curves to save state file\n");
712 fprintf(stderr,
"error: failed writing histograms to save state file\n");
740 uint16_t *raw_buff = NULL;
741 float* raw_buff_f = NULL;
745 int jpeg_height = -1;
746 uint8_t *jpeg_buff = NULL;
747 float* jpeg_buff_f = NULL;
754 float* curve_base = NULL;
755 float* curve_tone = NULL;
756 uint32_t* hist = NULL;
757 uint32_t* hist_base = NULL;
758 uint32_t* hist_tone = NULL;
779 fprintf(stderr,
"error: failed allocating curve\n");
788 fprintf(stderr,
"error: failed allocating histogram\n");
814 fprintf(stderr,
"error: failed reading the raw file data `%s'\n", opt.
filename_raw);
822 fprintf(stderr,
"error: failed reading JPEG file\n");
827 raw_offx = (raw_width - jpeg_width)/2;
828 raw_offy = (raw_height - jpeg_height)/2;
829 if(raw_offx < 0 || raw_offy < 0)
831 fprintf(stderr,
"error: jpeg has a higher resolution than the raw ? (%dx%d vs %dx%d)\n", jpeg_width, jpeg_height, raw_width, raw_height);
838 for (
int k=0;
k<3*raw_width*raw_height;
k++)
840 raw_buff[
k] = ((raw_buff[
k]&0xff) << 8) | (raw_buff[
k] >> 8);
844 raw_buff_f = calloc(1,
sizeof(
float)*3*raw_width*raw_height);
846 fprintf(stderr,
"error: failed allocating raw file float buffer\n");
857 jpeg_buff_f = calloc(1,
sizeof(
float)*3*jpeg_width*jpeg_height);
859 fprintf(stderr,
"error: failed allocating JPEG file float buffer\n");
876 uint32_t maxhist = 0;
878 for (
int i=0 ;
i<6;
i++)
889 if ((UINT32_MAX - maxhist) < (uint32_t)(jpeg_width*jpeg_height))
891 fprintf(stderr,
"error: analyzing this image could overflow internal counters. Refusing to process\n");
907 for (
int ch=0;
ch<3;
ch++)
922 fprintf(
f,
"# basecurve-red basecurve-green basecurve-blue basecurve-avg cnt-red cnt-green cnt-blue\n");
924 fprintf(
f,
"%f %f %f %f %" PRIu32
" %" PRIu32
" %" PRIu32
"\n", ch0[
k], ch1[
k], ch2[
k],
925 (ch0[
k] + ch1[
k] + ch2[
k]) / 3.0f, h0[
k], h1[
k], h2[
k]);
942 build_tonecurve(jpeg_width, jpeg_height, jpeg_buff_f, raw_offx, raw_offy, raw_width, raw_buff_f, curve_tone, hist_tone);
953 fprintf(
f,
"# tonecurve-L tonecurve-a tonecurve-b cnt-L cnt-a cnt-b\n");
955 fprintf(
f,
"%f %f %f %" PRIu32
" %" PRIu32
" %" PRIu32
"\n", ch0[
k], ch1[
k], ch2[
k], h0[
k], h1[
k], h2[
k]);
972 if (!
f && errno == ENOENT)
989 fprintf(stdout,
"failed opening save file errno=%d\n", errno);
1027 fprintf(
f,
"# err %f improved %d times\n", sqerr, accepts);
1028 fprintf(
f,
"# copy paste into iop/basecurve.c (be sure to insert name, maker, model, and set the last 0 to 1 if happy to filter it):\n");
1029 fprintf(
f,
"# { \"%s\", \"%s\", \"%s\", 0, FLT_MAX, {{{",
1048 uint8_t encoded[2048];
1051 memset(¶ms, 0,
sizeof(params));
1060 hexify(encoded, (uint8_t *)¶ms,
sizeof(params));
1062 fprintf(stdout,
"#!/bin/sh\n");
1063 fprintf(stdout,
"# to test your new basecurve, copy/paste the following line into your shell.\n");
1064 fprintf(stdout,
"# note that it is a smart idea to backup your database before messing with it on this level.\n");
1065 fprintf(stdout,
"# (you have been warned :) )\n\n");
1067 fprintf(stdout,
"echo \"INSERT INTO presets (name,description,operation,op_version,op_params,enabled,blendop_params,blendop_version,multi_priority,multi_name,model,maker,lens,iso_min,iso_max,exposure_min,exposure_max,aperture_min,aperture_max,focal_length_min,focal_length_max,writeprotect,autoapply,filter,def,format) VALUES('%s','','basecurve',%d,X'%s',1,X'00000000180000000000C842000000000000000000000000000000000000000000000000000000000000000000000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F',7,0,'','%%','%%','%%',0.0,340282346638528859812000000000000000000,0.0,10000000.0,0.0,100000000.0,0.0,1000.0,0,0,0,0,2);\" | sqlite3 ~/.config/ansel/data.db\n",
1071 fprintf(stdout,
"\n\n\n"
1072 "# if it pleases you, then in iop/basecurve.c append the following line to the array basecurve_presets and modify its name\n"
1073 "# {\"%s\", \"%s\", \"%s\", 0, FLT_MAX, {{{",
1079 fprintf(stdout,
"{%f, %f}%s", params.basecurve[0][
k].x, params.basecurve[0][
k].y,
k==fit.
m_numAnchors-1?
"":
", ");
1081 fprintf(stdout,
"}}, {%d}, {m}}, 0, 1},\n\n\n", fit.
m_numAnchors);
1097 memset(¶ms, 0,
sizeof(params));
1116 params.tonecurve_type[
i] = 2;
1124 params.tonecurve_autoscale_ab = 0;
1128 for (
int i=1;
i<3;
i++)
1132 params.tonecurve[
i][
k].x = (float)
k/(
float)opt.
num_nodes;
1133 params.tonecurve[
i][
k].y = (float)
k/(
float)opt.
num_nodes;
1136 params.tonecurve_type[
i] = 2;
1139 params.tonecurve_autoscale_ab = 1;
1141 params.tonecurve_unbound_ab = 0;
1143 uint8_t encoded[2048];
1144 hexify(encoded, (uint8_t*)¶ms,
sizeof(params));
1145 fprintf(stdout,
"#!/bin/sh\n");
1146 fprintf(stdout,
"# to test your new tonecurve, copy/paste the following line into your shell.\n");
1147 fprintf(stdout,
"# note that it is a smart idea to backup your database before messing with it on this level.\n\n");
1148 fprintf(stdout,
"echo \"INSERT INTO presets (name,description,operation,op_version,op_params,enabled,blendop_params,blendop_version,multi_priority,multi_name,model,maker,lens,iso_min,iso_max,exposure_min,exposure_max,aperture_min,aperture_max,focal_length_min,focal_length_max,writeprotect,autoapply,filter,def,format) VALUES('%s','','tonecurve',%d,X'%s',1,X'00000000180000000000C842000000000000000000000000000000000000000000000000000000000000000000000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F00000000000000000000803F0000803F',7,0,'','%%','%%','%%',0.0,340282346638528859812000000000000000000,0.0,10000000.0,0.0,100000000.0,0.0,1000.0,0,0,0,0,2);\" | sqlite3 ~/.config/ansel/data.db\n",
1151 fprintf(stdout,
"\n\n\n"
1152 "# if it pleases you, then in iop/tonecurve.c append the following line to the array preset_camera_curves and modify its name\n"
1153 "# {\"%s\", \"%s\", \"%s\", 0, FLT_MAX, {{",
1157 for(
int i = 0;
i < 3;
i++)
1159 fprintf(stdout,
"{");
1160 for(
int k = 0;
k < params.tonecurve_nodes[
i];
k++)
1161 fprintf(stdout,
"{%f, %f}%s", params.tonecurve[
i][
k].x, params.tonecurve[
i][
k].y,
1162 (
k + 1 < params.tonecurve_nodes[
i]) ?
", " :
"");
1163 fprintf(stdout, (
i + 1 < 3) ?
"}, " :
"}");
1165 fprintf(stdout,
"}, {%d, %d, %d}, {%d, %d, %d}, %d, 0, %d}},\n",
1166 params.tonecurve_nodes[0], params.tonecurve_nodes[1], params.tonecurve_nodes[2],
1167 params.tonecurve_type[0], params.tonecurve_type[1], params.tonecurve_type[2],
1168 params.tonecurve_autoscale_ab, params.tonecurve_unbound_ab);
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
const dt_aligned_pixel_t f
static const float const float const float min
static dt_aligned_pixel_t Lab
const dt_colormatrix_t dt_aligned_pixel_t out
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Enable aggressive floating-point arithmetic optimizations, in denormals handling. Set through user pr...
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
CurveAnchorPoint m_anchors[20]
unsigned char m_numAnchors
unsigned int m_spline_type
unsigned int m_samplingRes
unsigned short int * m_Samples
dt_iop_basecurve_node_t basecurve[3][20]
dt_iop_tonecurve_node_t tonecurve[3][20]
int tonecurve_autoscale_ab
const char * filename_exif
const char * filename_raw
const char * filename_basecurve
const char * filename_jpeg
const char * filename_basecurve_fit
const char * filename_tonecurve_fit
const char * filename_state
const char * filename_tonecurve