108 const uint32_t filters,
const dt_iop_roi_t *
const roi_in,
const uint8_t (*
const xtrans)[6],
112 for(
int c = 0; c < 3; c++)
115 memset(curves[c].lift, 0,
sizeof(curves[c].lift));
121 const int base = xtrans ? 6 : 2;
123 while((
width / ((
size_t)base * downsample)) * (
height / ((
size_t)base * downsample)) > 1500000) downsample++;
125 const int quad_size = base * downsample;
126 const size_t bin_w =
width / quad_size;
127 const size_t bin_h =
height / quad_size;
128 const size_t bin_pixels = bin_w * bin_h;
129 if(bin_w < 16 || bin_h < 16)
return;
131 float *
const restrict binned
135 float *
const restrict joint_moments
137 float *
const restrict pair_moments
140 float *
const restrict pk_in
143 uint8_t *
const restrict done = calloc(bin_pixels * 3,
sizeof(uint8_t));
153 for(
size_t i = 0;
i < bin_h;
i++)
154 for(
size_t j = 0; j < bin_w; j++)
159 for(
int y = 0; y < quad_size; y++)
160 for(
int cell_x = 0; cell_x < quad_size; cell_x++)
162 const size_t row =
i * quad_size + y;
163 const size_t col = j * quad_size + cell_x;
164 const size_t c = xtrans ? (size_t)
FCxtrans((
int)
row, (int)col, roi_in, xtrans) :
FC(
row, col, filters);
168 accum[c] += input[
row *
width + col];
175 for(
int c = 0; c < 3; c++)
176 binned[c * bin_pixels +
i * bin_w + j] = (counts[c] > 0.f) ? accum[c] / (counts[c] * clipval_raw[c]) : 0.f;
181 size_t nband[3] = { 0, 0, 0 };
182 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
183 for(
int c = 0; c < 3; c++)
187 if(nband[0] < 200 && nband[1] < 200 && nband[2] < 200)
goto cleanup;
197 const float sigma = sigmas[sigma_index];
204 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
206 const float x_red = binned[0 * bin_pixels + pixel];
207 const float x_green = binned[1 * bin_pixels + pixel];
208 const float x_blue = binned[2 * bin_pixels + pixel];
212 joint_moments[0 * bin_pixels + pixel] =
weight;
213 joint_moments[1 * bin_pixels + pixel] =
weight * x_red;
214 joint_moments[2 * bin_pixels + pixel] =
weight * x_green;
215 joint_moments[3 * bin_pixels + pixel] =
weight * x_blue;
216 joint_moments[4 * bin_pixels + pixel] =
weight * x_red * x_red;
217 joint_moments[5 * bin_pixels + pixel] =
weight * x_red * x_green;
218 joint_moments[6 * bin_pixels + pixel] =
weight * x_red * x_blue;
219 joint_moments[7 * bin_pixels + pixel] =
weight * x_green * x_green;
220 joint_moments[8 * bin_pixels + pixel] =
weight * x_green * x_blue;
221 joint_moments[9 * bin_pixels + pixel] =
weight * x_blue * x_blue;
224 for(
int plane_base = 0; plane_base < 10; plane_base += 4)
226 const int n_planes =
MIN(4, 10 - plane_base);
227 const float *plane_in[4] = { 0 };
228 float *plane_out[4] = { 0 };
229 for(
int k = 0;
k < n_planes;
k++)
230 plane_in[
k] = plane_out[
k] = joint_moments + (
size_t)(plane_base +
k) * bin_pixels;
231 _knee_blur4(plane_in, plane_out, n_planes, bin_w, bin_h,
sigma, pk_in, pk_out);
237 for(
int c = 0; c < 3; c++)
239 if(nband[c] < 200)
continue;
241 const int guide1 = (c == 0) ? 1 : 0;
242 const int guide2 = (c == 2) ? 1 : 2;
245 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
247 if(done[c * bin_pixels + pixel])
continue;
249 const float x_val = binned[c * bin_pixels + pixel];
250 const float x_guide1 = binned[guide1 * bin_pixels + pixel];
251 const float x_guide2 = binned[guide2 * bin_pixels + pixel];
252 const float weight_sum = joint_moments[pixel];
258 const float inv_weight = 1.f / weight_sum;
260 const float mean_target = joint_moments[(size_t)(1 + c) * bin_pixels + pixel] * inv_weight;
261 const float mean_guide1 = joint_moments[(size_t)(1 + guide1) * bin_pixels + pixel] * inv_weight;
262 const float mean_guide2 = joint_moments[(size_t)(1 + guide2) * bin_pixels + pixel] * inv_weight;
266 = fmaxf(joint_moments[(
size_t)
_knee_p2(guide1, guide1) * bin_pixels + pixel] * inv_weight
267 - mean_guide1 * mean_guide1,
270 = fmaxf(joint_moments[(
size_t)
_knee_p2(guide2, guide2) * bin_pixels + pixel] * inv_weight
271 - mean_guide2 * mean_guide2,
273 const float var_12 = joint_moments[(size_t)
_knee_p2(guide1, guide2) * bin_pixels + pixel] * inv_weight
274 - mean_guide1 * mean_guide2;
275 const float cov_1 = joint_moments[(size_t)
_knee_p2(c, guide1) * bin_pixels + pixel] * inv_weight
276 - mean_target * mean_guide1;
277 const float cov_2 = joint_moments[(size_t)
_knee_p2(c, guide2) * bin_pixels + pixel] * inv_weight
278 - mean_target * mean_guide2;
279 const float var_target = fmaxf(joint_moments[(
size_t)
_knee_p2(c, c) * bin_pixels + pixel] * inv_weight
280 - mean_target * mean_target,
285 const float lambda = 1e-3f * 0.5f * (var_11 + var_22) + 1e-12f;
286 const float diag_11 = var_11 + lambda;
287 const float diag_22 = var_22 + lambda;
288 const float determinant = fmaxf(diag_11 * diag_22 - var_12 * var_12, 1e-18f);
289 const float slope_1 = (diag_22 * cov_1 - var_12 * cov_2) / determinant;
290 const float slope_2 = (diag_11 * cov_2 - var_12 * cov_1) / determinant;
293 pred[c * bin_pixels + pixel]
294 = mean_target + slope_1 * (x_guide1 - mean_guide1) + slope_2 * (x_guide2 - mean_guide2);
296 r2_scores[c * bin_pixels + pixel]
297 = CLAMP((slope_1 * cov_1 + slope_2 * cov_2) / (var_target + 1e-12f), 0.f, 1.f);
298 done[c * bin_pixels + pixel] = 1;
305 for(
int chan_a = 0; chan_a < 3; chan_a++)
306 for(
int chan_b = chan_a + 1; chan_b < 3; chan_b++)
308 if(nband[chan_a] < 200 && nband[chan_b] < 200)
continue;
313 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
315 const float val_a = binned[chan_a * bin_pixels + pixel];
316 const float val_b = binned[chan_b * bin_pixels + pixel];
318 pair_moments[0 * bin_pixels + pixel] =
weight;
319 pair_moments[1 * bin_pixels + pixel] =
weight * val_a;
320 pair_moments[2 * bin_pixels + pixel] =
weight * val_b;
321 pair_moments[3 * bin_pixels + pixel] =
weight * val_a * val_a;
322 pair_moments[4 * bin_pixels + pixel] =
weight * val_b * val_b;
323 pair_moments[5 * bin_pixels + pixel] =
weight * val_a * val_b;
326 for(
int plane_base = 0; plane_base < 6; plane_base += 4)
328 const int n_planes =
MIN(4, 6 - plane_base);
329 const float *plane_in[4] = { 0 };
330 float *plane_out[4] = { 0 };
331 for(
int k = 0;
k < n_planes;
k++)
332 plane_in[
k] = plane_out[
k] = pair_moments + (
size_t)(plane_base +
k) * bin_pixels;
333 _knee_blur4(plane_in, plane_out, n_planes, bin_w, bin_h,
sigma, pk_in, pk_out);
338 for(
int orient = 0; orient < 2; orient++)
340 const int target_ch = orient ? chan_b : chan_a;
341 const int guide_ch = orient ? chan_a : chan_b;
342 const int target_mean_plane = orient ? 2 : 1;
343 const int guide_mean_plane = orient ? 1 : 2;
344 const int target_sq_plane = orient ? 4 : 3;
345 const int guide_sq_plane = orient ? 3 : 4;
347 if(nband[target_ch] < 200)
continue;
350 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
352 if(done[target_ch * bin_pixels + pixel])
continue;
354 const float x_val = binned[target_ch * bin_pixels + pixel];
355 const float x_guide = binned[guide_ch * bin_pixels + pixel];
356 const float weight_sum = pair_moments[pixel];
362 const float inv_weight = 1.f / weight_sum;
363 const float mean_target
364 = pair_moments[(size_t)target_mean_plane * bin_pixels + pixel] * inv_weight;
365 const float mean_guide
366 = pair_moments[(size_t)guide_mean_plane * bin_pixels + pixel] * inv_weight;
367 const float covariance
368 = pair_moments[(size_t)5 * bin_pixels + pixel] * inv_weight - mean_target * mean_guide;
369 const float var_guide = fmaxf(pair_moments[(
size_t)guide_sq_plane * bin_pixels + pixel] * inv_weight
370 - mean_guide * mean_guide,
372 const float var_target = fmaxf(pair_moments[(
size_t)target_sq_plane * bin_pixels + pixel] * inv_weight
373 - mean_target * mean_target,
375 const float slope = covariance / (var_guide * (1.f + 1e-3f) + 1e-12f);
377 pred[target_ch * bin_pixels + pixel]
378 = mean_target + slope * (x_guide - mean_guide);
379 r2_scores[target_ch * bin_pixels + pixel]
380 = CLAMP(covariance * covariance / (var_guide * var_target + 1e-18f), 0.f, 1.f);
381 done[target_ch * bin_pixels + pixel] = 1;
390 for(
int c = 0; c < 3; c++)
392 if(nband[c] < 200)
continue;
402 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
404 if(!done[c * bin_pixels + pixel] || r2_scores[c * bin_pixels + pixel] <=
DT_HL_KNEE_R2MIN)
continue;
411 offset[
i + 1] = offset[
i] + count[
i];
414 memcpy(fill, offset,
sizeof(fill));
417 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
419 if(!done[c * bin_pixels + pixel] || r2_scores[c * bin_pixels + pixel] <=
DT_HL_KNEE_R2MIN)
continue;
420 const float x_val = binned[c * bin_pixels + pixel];
422 votes[fill[bin_index]++] = pred[c * bin_pixels + pixel] - x_val;
437 float *
const bin_votes = votes + offset[
i];
442 for(
size_t k = 0;
k < count[
i];
k++) bin_votes[
k] = fabsf(bin_votes[
k] - median_lift);
443 const float median_abs_dev =
_knee_median(bin_votes, count[
i]);
445 const float std_err = 1.858f * median_abs_dev / sqrtf((
float)count[
i]);
454 if(nseen < 3)
continue;
476 if(prev < 0 && next < 0)
479 lift[
i] = lift[next];
481 lift[
i] = lift[prev];
483 lift[
i] = lift[prev] + (lift[next] - lift[prev]) * (
float)(
i - prev) / (
float)(next - prev);
488 float running_max = 0.f;
489 float lift_max = 0.f;
493 running_max = fmaxf(running_max, fmaxf(lift[
i], 0.f));
494 curves[c].
lift[
i] = running_max;
495 lift_max = fmaxf(lift_max, running_max);
501 if(!curves[c].engaged) memset(curves[c].lift, 0,
sizeof(curves[c].lift));
587 const uint32_t filters,
const dt_iop_roi_t *
const roi_in, cl_mem dev_xtrans,
595 for(
int c = 0; c < 3; c++)
598 memset(curves[c].lift, 0,
sizeof(curves[c].lift));
601 const int base = is_xtrans ? 6 : 2;
603 while((
width / ((
size_t)base * downsample)) * (
height / ((
size_t)base * downsample)) > 1500000) downsample++;
605 const int quad_size = base * downsample;
606 const size_t bin_w =
width / quad_size;
607 const size_t bin_h =
height / quad_size;
608 const size_t bin_pixels = bin_w * bin_h;
609 if(bin_w < 16 || bin_h < 16)
return CL_SUCCESS;
611 const int bin_w_int = (int)bin_w, bin_h_int = (
int)bin_h;
628 uint8_t *done = calloc(bin_pixels * 3,
sizeof(uint8_t));
629 if(!dev_binned || !dev_pred || !dev_r2 || !dev_done || !moment_a || !moment_b || !moment_c || !blur_a || !blur_b
630 || !blur_c || !binned || !pred || !r2_scores || !votes || !done)
634 if(cl_err != CL_SUCCESS)
goto cleanup;
639 const int width_int = (int)
width;
640 const int height_int = (int)
height;
641 const int quad_size_int = quad_size;
642 const int roi_x = roi_in ? roi_in->
x : 0;
643 const int roi_y = roi_in ? roi_in->
y : 0;
644 const cl_float4 clip4 = { { clipval_raw[0], clipval_raw[1], clipval_raw[2], 1.f } };
659 if(cl_err != CL_SUCCESS)
goto cleanup;
665 if(cl_err != CL_SUCCESS)
goto cleanup;
669 size_t nband[3] = { 0, 0, 0 };
670 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
671 for(
int c = 0; c < 3; c++)
675 if(nband[0] < 200 && nband[1] < 200 && nband[2] < 200)
690 const float sigma = sigmas[sigma_index];
706 if(cl_err != CL_SUCCESS)
goto cleanup;
717 if(cl_err != CL_SUCCESS)
goto cleanup;
721 for(
int c = 0; c < 3; c++)
723 if(nband[c] < 200)
continue;
724 const int guide1 = (c == 0) ? 1 : 0;
725 const int guide2 = (c == 2) ? 1 : 2;
743 if(cl_err != CL_SUCCESS)
goto cleanup;
748 for(
int chan_a = 0; chan_a < 3; chan_a++)
749 for(
int chan_b = chan_a + 1; chan_b < 3; chan_b++)
751 if(nband[chan_a] < 200 && nband[chan_b] < 200)
continue;
763 if(cl_err != CL_SUCCESS)
goto cleanup;
767 if(cl_err != CL_SUCCESS)
goto cleanup;
769 for(
int orient = 0; orient < 2; orient++)
771 const int target_ch = orient ? chan_b : chan_a;
772 const int guide_ch = orient ? chan_a : chan_b;
773 const int is_first_orient = (orient == 0);
774 if(nband[target_ch] < 200)
continue;
791 if(cl_err != CL_SUCCESS)
goto cleanup;
798 if(cl_err == CL_SUCCESS)
801 if(cl_err == CL_SUCCESS)
803 if(cl_err != CL_SUCCESS)
goto cleanup;
808 for(
int c = 0; c < 3; c++)
810 if(nband[c] < 200)
continue;
817 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
819 if(!done[c * bin_pixels + pixel] || r2_scores[c * bin_pixels + pixel] <=
DT_HL_KNEE_R2MIN)
continue;
827 memcpy(fill, offset,
sizeof(fill));
829 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
831 if(!done[c * bin_pixels + pixel] || r2_scores[c * bin_pixels + pixel] <=
DT_HL_KNEE_R2MIN)
continue;
832 const float x_val = binned[c * bin_pixels + pixel];
834 votes[fill[bin_index]++] = pred[c * bin_pixels + pixel] - x_val;
845 float *
const bin_votes = votes + offset[
i];
847 for(
size_t k = 0;
k < count[
i];
k++) bin_votes[
k] = fabsf(bin_votes[
k] - median_lift);
848 const float median_abs_dev =
_knee_median(bin_votes, count[
i]);
850 const float std_err = 1.858f * median_abs_dev / sqrtf((
float)count[
i]);
854 lift[
i] = median_lift;
856 if(nseen < 3)
continue;
874 if(prev < 0 && next < 0)
877 lift[
i] = lift[next];
879 lift[
i] = lift[prev];
881 lift[
i] = lift[prev] + (lift[next] - lift[prev]) * (
float)(
i - prev) / (
float)(next - prev);
885 float running_max = 0.f;
886 float lift_max = 0.f;
889 running_max = fmaxf(running_max, fmaxf(lift[
i], 0.f));
890 curves[c].
lift[
i] = running_max;
891 lift_max = fmaxf(lift_max, running_max);
895 if(!curves[c].engaged) memset(curves[c].lift, 0,
sizeof(curves[c].lift));