109 const uint32_t filters,
const dt_iop_roi_t *
const roi_in,
const uint8_t (*
const xtrans)[6],
114 for(
int c = 0; c < 3; c++)
117 memset(curves[c].lift, 0,
sizeof(curves[c].lift));
123 const int base = xtrans ? 6 : 2;
125 while((
width / ((
size_t)base * downsample)) * (
height / ((
size_t)base * downsample)) > 1500000) downsample++;
127 const int quad_size = base * downsample;
128 const size_t bin_w =
width / quad_size;
129 const size_t bin_h =
height / quad_size;
130 const size_t bin_pixels = bin_w * bin_h;
131 if(bin_w < 16 || bin_h < 16)
return 0;
133 float *
const restrict binned
137 float *
const restrict joint_moments
139 float *
const restrict pair_moments
142 float *
const restrict pk_in
145 uint8_t *
const restrict done = calloc(bin_pixels * 3,
sizeof(uint8_t));
155 for(
size_t i = 0;
i < bin_h;
i++)
156 for(
size_t j = 0; j < bin_w; j++)
161 for(
int y = 0; y < quad_size; y++)
162 for(
int cell_x = 0; cell_x < quad_size; cell_x++)
164 const size_t row =
i * quad_size + y;
165 const size_t col = j * quad_size + cell_x;
166 const size_t c = xtrans ? (size_t)
FCxtrans((
int)
row, (int)col, roi_in, xtrans) :
FC(
row, col, filters);
170 accum[c] += input[
row *
width + col];
177 for(
int c = 0; c < 3; c++)
178 binned[c * bin_pixels +
i * bin_w + j] = (counts[c] > 0.f) ? accum[c] / (counts[c] * clipval_raw[c]) : 0.f;
183 size_t nband[3] = { 0, 0, 0 };
184 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
185 for(
int c = 0; c < 3; c++)
189 if(nband[0] < 200 && nband[1] < 200 && nband[2] < 200)
goto cleanup;
206 const float sigma = sigmas[sigma_index];
213 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
215 const float x_red = binned[0 * bin_pixels + pixel];
216 const float x_green = binned[1 * bin_pixels + pixel];
217 const float x_blue = binned[2 * bin_pixels + pixel];
221 joint_moments[0 * bin_pixels + pixel] =
weight;
222 joint_moments[1 * bin_pixels + pixel] =
weight * x_red;
223 joint_moments[2 * bin_pixels + pixel] =
weight * x_green;
224 joint_moments[3 * bin_pixels + pixel] =
weight * x_blue;
225 joint_moments[4 * bin_pixels + pixel] =
weight * x_red * x_red;
226 joint_moments[5 * bin_pixels + pixel] =
weight * x_red * x_green;
227 joint_moments[6 * bin_pixels + pixel] =
weight * x_red * x_blue;
228 joint_moments[7 * bin_pixels + pixel] =
weight * x_green * x_green;
229 joint_moments[8 * bin_pixels + pixel] =
weight * x_green * x_blue;
230 joint_moments[9 * bin_pixels + pixel] =
weight * x_blue * x_blue;
233 for(
int plane_base = 0; plane_base < 10; plane_base += 4)
235 const int n_planes =
MIN(4, 10 - plane_base);
236 const float *plane_in[4] = { 0 };
237 float *plane_out[4] = { 0 };
238 for(
int k = 0;
k < n_planes;
k++)
239 plane_in[
k] = plane_out[
k] = joint_moments + (
size_t)(plane_base +
k) * bin_pixels;
240 _knee_blur4(plane_in, plane_out, n_planes, bin_w, bin_h,
sigma, pk_in, pk_out);
246 for(
int c = 0; c < 3; c++)
248 if(nband[c] < 200)
continue;
250 const int guide1 = (c == 0) ? 1 : 0;
251 const int guide2 = (c == 2) ? 1 : 2;
254 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
256 if(done[c * bin_pixels + pixel])
continue;
258 const float x_val = binned[c * bin_pixels + pixel];
259 const float x_guide1 = binned[guide1 * bin_pixels + pixel];
260 const float x_guide2 = binned[guide2 * bin_pixels + pixel];
261 const float weight_sum = joint_moments[pixel];
267 const float inv_weight = 1.f / weight_sum;
269 const float mean_target = joint_moments[(size_t)(1 + c) * bin_pixels + pixel] * inv_weight;
270 const float mean_guide1 = joint_moments[(size_t)(1 + guide1) * bin_pixels + pixel] * inv_weight;
271 const float mean_guide2 = joint_moments[(size_t)(1 + guide2) * bin_pixels + pixel] * inv_weight;
275 = fmaxf(joint_moments[(
size_t)
_knee_p2(guide1, guide1) * bin_pixels + pixel] * inv_weight
276 - mean_guide1 * mean_guide1,
279 = fmaxf(joint_moments[(
size_t)
_knee_p2(guide2, guide2) * bin_pixels + pixel] * inv_weight
280 - mean_guide2 * mean_guide2,
282 const float var_12 = joint_moments[(size_t)
_knee_p2(guide1, guide2) * bin_pixels + pixel] * inv_weight
283 - mean_guide1 * mean_guide2;
284 const float cov_1 = joint_moments[(size_t)
_knee_p2(c, guide1) * bin_pixels + pixel] * inv_weight
285 - mean_target * mean_guide1;
286 const float cov_2 = joint_moments[(size_t)
_knee_p2(c, guide2) * bin_pixels + pixel] * inv_weight
287 - mean_target * mean_guide2;
288 const float var_target = fmaxf(joint_moments[(
size_t)
_knee_p2(c, c) * bin_pixels + pixel] * inv_weight
289 - mean_target * mean_target,
294 const float lambda = 1e-3f * 0.5f * (var_11 + var_22) + 1e-12f;
295 const float diag_11 = var_11 + lambda;
296 const float diag_22 = var_22 + lambda;
297 const float determinant = fmaxf(diag_11 * diag_22 - var_12 * var_12, 1e-18f);
298 const float slope_1 = (diag_22 * cov_1 - var_12 * cov_2) / determinant;
299 const float slope_2 = (diag_11 * cov_2 - var_12 * cov_1) / determinant;
302 pred[c * bin_pixels + pixel]
303 = mean_target + slope_1 * (x_guide1 - mean_guide1) + slope_2 * (x_guide2 - mean_guide2);
305 r2_scores[c * bin_pixels + pixel]
306 = CLAMP((slope_1 * cov_1 + slope_2 * cov_2) / (var_target + 1e-12f), 0.f, 1.f);
307 done[c * bin_pixels + pixel] = 1;
314 for(
int chan_a = 0; chan_a < 3; chan_a++)
315 for(
int chan_b = chan_a + 1; chan_b < 3; chan_b++)
317 if(nband[chan_a] < 200 && nband[chan_b] < 200)
continue;
322 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
324 const float val_a = binned[chan_a * bin_pixels + pixel];
325 const float val_b = binned[chan_b * bin_pixels + pixel];
327 pair_moments[0 * bin_pixels + pixel] =
weight;
328 pair_moments[1 * bin_pixels + pixel] =
weight * val_a;
329 pair_moments[2 * bin_pixels + pixel] =
weight * val_b;
330 pair_moments[3 * bin_pixels + pixel] =
weight * val_a * val_a;
331 pair_moments[4 * bin_pixels + pixel] =
weight * val_b * val_b;
332 pair_moments[5 * bin_pixels + pixel] =
weight * val_a * val_b;
335 for(
int plane_base = 0; plane_base < 6; plane_base += 4)
337 const int n_planes =
MIN(4, 6 - plane_base);
338 const float *plane_in[4] = { 0 };
339 float *plane_out[4] = { 0 };
340 for(
int k = 0;
k < n_planes;
k++)
341 plane_in[
k] = plane_out[
k] = pair_moments + (
size_t)(plane_base +
k) * bin_pixels;
342 _knee_blur4(plane_in, plane_out, n_planes, bin_w, bin_h,
sigma, pk_in, pk_out);
347 for(
int orient = 0; orient < 2; orient++)
349 const int target_ch = orient ? chan_b : chan_a;
350 const int guide_ch = orient ? chan_a : chan_b;
351 const int target_mean_plane = orient ? 2 : 1;
352 const int guide_mean_plane = orient ? 1 : 2;
353 const int target_sq_plane = orient ? 4 : 3;
354 const int guide_sq_plane = orient ? 3 : 4;
356 if(nband[target_ch] < 200)
continue;
359 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
361 if(done[target_ch * bin_pixels + pixel])
continue;
363 const float x_val = binned[target_ch * bin_pixels + pixel];
364 const float x_guide = binned[guide_ch * bin_pixels + pixel];
365 const float weight_sum = pair_moments[pixel];
371 const float inv_weight = 1.f / weight_sum;
372 const float mean_target
373 = pair_moments[(size_t)target_mean_plane * bin_pixels + pixel] * inv_weight;
374 const float mean_guide
375 = pair_moments[(size_t)guide_mean_plane * bin_pixels + pixel] * inv_weight;
376 const float covariance
377 = pair_moments[(size_t)5 * bin_pixels + pixel] * inv_weight - mean_target * mean_guide;
378 const float var_guide = fmaxf(pair_moments[(
size_t)guide_sq_plane * bin_pixels + pixel] * inv_weight
379 - mean_guide * mean_guide,
381 const float var_target = fmaxf(pair_moments[(
size_t)target_sq_plane * bin_pixels + pixel] * inv_weight
382 - mean_target * mean_target,
384 const float slope = covariance / (var_guide * (1.f + 1e-3f) + 1e-12f);
386 pred[target_ch * bin_pixels + pixel]
387 = mean_target + slope * (x_guide - mean_guide);
388 r2_scores[target_ch * bin_pixels + pixel]
389 = CLAMP(covariance * covariance / (var_guide * var_target + 1e-18f), 0.f, 1.f);
390 done[target_ch * bin_pixels + pixel] = 1;
399 for(
int c = 0; c < 3; c++)
401 if(nband[c] < 200)
continue;
411 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
413 if(!done[c * bin_pixels + pixel] || r2_scores[c * bin_pixels + pixel] <=
DT_HL_KNEE_R2MIN)
continue;
420 offset[
i + 1] = offset[
i] + count[
i];
423 memcpy(fill, offset,
sizeof(fill));
426 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
428 if(!done[c * bin_pixels + pixel] || r2_scores[c * bin_pixels + pixel] <=
DT_HL_KNEE_R2MIN)
continue;
429 const float x_val = binned[c * bin_pixels + pixel];
431 votes[fill[bin_index]++] = pred[c * bin_pixels + pixel] - x_val;
446 float *
const bin_votes = votes + offset[
i];
451 for(
size_t k = 0;
k < count[
i];
k++) bin_votes[
k] = fabsf(bin_votes[
k] - median_lift);
452 const float median_abs_dev =
_knee_median(bin_votes, count[
i]);
454 const float std_err = 1.858f * median_abs_dev / sqrtf((
float)count[
i]);
463 if(nseen < 3)
continue;
485 if(prev < 0 && next < 0)
488 lift[
i] = lift[next];
490 lift[
i] = lift[prev];
492 lift[
i] = lift[prev] + (lift[next] - lift[prev]) * (
float)(
i - prev) / (
float)(next - prev);
497 float running_max = 0.f;
498 float lift_max = 0.f;
502 running_max = fmaxf(running_max, fmaxf(lift[
i], 0.f));
503 curves[c].
lift[
i] = running_max;
504 lift_max = fmaxf(lift_max, running_max);
510 if(!curves[c].engaged) memset(curves[c].lift, 0,
sizeof(curves[c].lift));
597 const uint32_t filters,
const dt_iop_roi_t *
const roi_in, cl_mem dev_xtrans,
605 for(
int c = 0; c < 3; c++)
608 memset(curves[c].lift, 0,
sizeof(curves[c].lift));
611 const int base = is_xtrans ? 6 : 2;
613 while((
width / ((
size_t)base * downsample)) * (
height / ((
size_t)base * downsample)) > 1500000) downsample++;
615 const int quad_size = base * downsample;
616 const size_t bin_w =
width / quad_size;
617 const size_t bin_h =
height / quad_size;
618 const size_t bin_pixels = bin_w * bin_h;
619 if(bin_w < 16 || bin_h < 16)
return CL_SUCCESS;
621 const int bin_w_int = (int)bin_w, bin_h_int = (
int)bin_h;
638 uint8_t *done = calloc(bin_pixels * 3,
sizeof(uint8_t));
639 if(!dev_binned || !dev_pred || !dev_r2 || !dev_done || !moment_a || !moment_b || !moment_c || !blur_a || !blur_b
640 || !blur_c || !binned || !pred || !r2_scores || !votes || !done)
644 if(cl_err != CL_SUCCESS)
goto cleanup;
649 const int width_int = (int)
width;
650 const int height_int = (int)
height;
651 const int quad_size_int = quad_size;
652 const int roi_x = roi_in ? roi_in->
x : 0;
653 const int roi_y = roi_in ? roi_in->
y : 0;
654 const cl_float4 clip4 = { { clipval_raw[0], clipval_raw[1], clipval_raw[2], 1.f } };
669 if(cl_err != CL_SUCCESS)
goto cleanup;
675 if(cl_err != CL_SUCCESS)
goto cleanup;
679 size_t nband[3] = { 0, 0, 0 };
680 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
681 for(
int c = 0; c < 3; c++)
685 if(nband[0] < 200 && nband[1] < 200 && nband[2] < 200)
700 const float sigma = sigmas[sigma_index];
716 if(cl_err != CL_SUCCESS)
goto cleanup;
727 if(cl_err != CL_SUCCESS)
goto cleanup;
731 for(
int c = 0; c < 3; c++)
733 if(nband[c] < 200)
continue;
734 const int guide1 = (c == 0) ? 1 : 0;
735 const int guide2 = (c == 2) ? 1 : 2;
753 if(cl_err != CL_SUCCESS)
goto cleanup;
758 for(
int chan_a = 0; chan_a < 3; chan_a++)
759 for(
int chan_b = chan_a + 1; chan_b < 3; chan_b++)
761 if(nband[chan_a] < 200 && nband[chan_b] < 200)
continue;
773 if(cl_err != CL_SUCCESS)
goto cleanup;
777 if(cl_err != CL_SUCCESS)
goto cleanup;
779 for(
int orient = 0; orient < 2; orient++)
781 const int target_ch = orient ? chan_b : chan_a;
782 const int guide_ch = orient ? chan_a : chan_b;
783 const int is_first_orient = (orient == 0);
784 if(nband[target_ch] < 200)
continue;
801 if(cl_err != CL_SUCCESS)
goto cleanup;
808 if(cl_err == CL_SUCCESS)
811 if(cl_err == CL_SUCCESS)
813 if(cl_err != CL_SUCCESS)
goto cleanup;
818 for(
int c = 0; c < 3; c++)
820 if(nband[c] < 200)
continue;
827 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
829 if(!done[c * bin_pixels + pixel] || r2_scores[c * bin_pixels + pixel] <=
DT_HL_KNEE_R2MIN)
continue;
837 memcpy(fill, offset,
sizeof(fill));
839 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
841 if(!done[c * bin_pixels + pixel] || r2_scores[c * bin_pixels + pixel] <=
DT_HL_KNEE_R2MIN)
continue;
842 const float x_val = binned[c * bin_pixels + pixel];
844 votes[fill[bin_index]++] = pred[c * bin_pixels + pixel] - x_val;
855 float *
const bin_votes = votes + offset[
i];
857 for(
size_t k = 0;
k < count[
i];
k++) bin_votes[
k] = fabsf(bin_votes[
k] - median_lift);
858 const float median_abs_dev =
_knee_median(bin_votes, count[
i]);
860 const float std_err = 1.858f * median_abs_dev / sqrtf((
float)count[
i]);
864 lift[
i] = median_lift;
866 if(nseen < 3)
continue;
884 if(prev < 0 && next < 0)
887 lift[
i] = lift[next];
889 lift[
i] = lift[prev];
891 lift[
i] = lift[prev] + (lift[next] - lift[prev]) * (
float)(
i - prev) / (
float)(next - prev);
895 float running_max = 0.f;
896 float lift_max = 0.f;
899 running_max = fmaxf(running_max, fmaxf(lift[
i], 0.f));
900 curves[c].
lift[
i] = running_max;
901 lift_max = fmaxf(lift_max, running_max);
905 if(!curves[c].engaged) memset(curves[c].lift, 0,
sizeof(curves[c].lift));