106 const uint32_t filters,
const dt_iop_roi_t *
const roi_in,
const uint8_t (*
const xtrans)[6],
110 for(
int c = 0; c < 3; c++)
113 memset(curves[c].lift, 0,
sizeof(curves[c].lift));
119 const int base = xtrans ? 6 : 2;
121 while((
width / ((
size_t)base * downsample)) * (
height / ((
size_t)base * downsample)) > 1500000) downsample++;
123 const int quad_size = base * downsample;
124 const size_t bin_w =
width / quad_size;
125 const size_t bin_h =
height / quad_size;
126 const size_t bin_pixels = bin_w * bin_h;
127 if(bin_w < 16 || bin_h < 16)
return;
129 float *
const restrict binned
133 float *
const restrict joint_moments
135 float *
const restrict pair_moments
138 float *
const restrict pk_in
141 uint8_t *
const restrict done = calloc(bin_pixels * 3,
sizeof(uint8_t));
151 for(
size_t i = 0;
i < bin_h;
i++)
152 for(
size_t j = 0; j < bin_w; j++)
157 for(
int y = 0; y < quad_size; y++)
158 for(
int cell_x = 0; cell_x < quad_size; cell_x++)
160 const size_t row =
i * quad_size + y;
161 const size_t col = j * quad_size + cell_x;
162 const size_t c = xtrans ? (size_t)
FCxtrans((
int)
row, (int)col, roi_in, xtrans) :
FC(
row, col, filters);
166 accum[c] += input[
row *
width + col];
173 for(
int c = 0; c < 3; c++)
174 binned[c * bin_pixels +
i * bin_w + j] = (counts[c] > 0.f) ? accum[c] / (counts[c] * clipval_raw[c]) : 0.f;
179 size_t nband[3] = { 0, 0, 0 };
180 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
181 for(
int c = 0; c < 3; c++)
185 if(nband[0] < 200 && nband[1] < 200 && nband[2] < 200)
goto cleanup;
195 const float sigma = sigmas[sigma_index];
202 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
204 const float x_red = binned[0 * bin_pixels + pixel];
205 const float x_green = binned[1 * bin_pixels + pixel];
206 const float x_blue = binned[2 * bin_pixels + pixel];
210 joint_moments[0 * bin_pixels + pixel] =
weight;
211 joint_moments[1 * bin_pixels + pixel] =
weight * x_red;
212 joint_moments[2 * bin_pixels + pixel] =
weight * x_green;
213 joint_moments[3 * bin_pixels + pixel] =
weight * x_blue;
214 joint_moments[4 * bin_pixels + pixel] =
weight * x_red * x_red;
215 joint_moments[5 * bin_pixels + pixel] =
weight * x_red * x_green;
216 joint_moments[6 * bin_pixels + pixel] =
weight * x_red * x_blue;
217 joint_moments[7 * bin_pixels + pixel] =
weight * x_green * x_green;
218 joint_moments[8 * bin_pixels + pixel] =
weight * x_green * x_blue;
219 joint_moments[9 * bin_pixels + pixel] =
weight * x_blue * x_blue;
222 for(
int plane_base = 0; plane_base < 10; plane_base += 4)
224 const int n_planes =
MIN(4, 10 - plane_base);
225 const float *plane_in[4] = { 0 };
226 float *plane_out[4] = { 0 };
227 for(
int k = 0;
k < n_planes;
k++)
228 plane_in[
k] = plane_out[
k] = joint_moments + (
size_t)(plane_base +
k) * bin_pixels;
229 _knee_blur4(plane_in, plane_out, n_planes, bin_w, bin_h,
sigma, pk_in, pk_out);
235 for(
int c = 0; c < 3; c++)
237 if(nband[c] < 200)
continue;
239 const int guide1 = (c == 0) ? 1 : 0;
240 const int guide2 = (c == 2) ? 1 : 2;
243 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
245 if(done[c * bin_pixels + pixel])
continue;
247 const float x_val = binned[c * bin_pixels + pixel];
248 const float x_guide1 = binned[guide1 * bin_pixels + pixel];
249 const float x_guide2 = binned[guide2 * bin_pixels + pixel];
250 const float weight_sum = joint_moments[pixel];
256 const float inv_weight = 1.f / weight_sum;
258 const float mean_target = joint_moments[(size_t)(1 + c) * bin_pixels + pixel] * inv_weight;
259 const float mean_guide1 = joint_moments[(size_t)(1 + guide1) * bin_pixels + pixel] * inv_weight;
260 const float mean_guide2 = joint_moments[(size_t)(1 + guide2) * bin_pixels + pixel] * inv_weight;
264 = fmaxf(joint_moments[(
size_t)
_knee_p2(guide1, guide1) * bin_pixels + pixel] * inv_weight
265 - mean_guide1 * mean_guide1,
268 = fmaxf(joint_moments[(
size_t)
_knee_p2(guide2, guide2) * bin_pixels + pixel] * inv_weight
269 - mean_guide2 * mean_guide2,
271 const float var_12 = joint_moments[(size_t)
_knee_p2(guide1, guide2) * bin_pixels + pixel] * inv_weight
272 - mean_guide1 * mean_guide2;
273 const float cov_1 = joint_moments[(size_t)
_knee_p2(c, guide1) * bin_pixels + pixel] * inv_weight
274 - mean_target * mean_guide1;
275 const float cov_2 = joint_moments[(size_t)
_knee_p2(c, guide2) * bin_pixels + pixel] * inv_weight
276 - mean_target * mean_guide2;
277 const float var_target = fmaxf(joint_moments[(
size_t)
_knee_p2(c, c) * bin_pixels + pixel] * inv_weight
278 - mean_target * mean_target,
283 const float lambda = 1e-3f * 0.5f * (var_11 + var_22) + 1e-12f;
284 const float diag_11 = var_11 + lambda;
285 const float diag_22 = var_22 + lambda;
286 const float determinant = fmaxf(diag_11 * diag_22 - var_12 * var_12, 1e-18f);
287 const float slope_1 = (diag_22 * cov_1 - var_12 * cov_2) / determinant;
288 const float slope_2 = (diag_11 * cov_2 - var_12 * cov_1) / determinant;
291 pred[c * bin_pixels + pixel]
292 = mean_target + slope_1 * (x_guide1 - mean_guide1) + slope_2 * (x_guide2 - mean_guide2);
294 r2_scores[c * bin_pixels + pixel]
295 = CLAMP((slope_1 * cov_1 + slope_2 * cov_2) / (var_target + 1e-12f), 0.f, 1.f);
296 done[c * bin_pixels + pixel] = 1;
303 for(
int chan_a = 0; chan_a < 3; chan_a++)
304 for(
int chan_b = chan_a + 1; chan_b < 3; chan_b++)
306 if(nband[chan_a] < 200 && nband[chan_b] < 200)
continue;
311 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
313 const float val_a = binned[chan_a * bin_pixels + pixel];
314 const float val_b = binned[chan_b * bin_pixels + pixel];
316 pair_moments[0 * bin_pixels + pixel] =
weight;
317 pair_moments[1 * bin_pixels + pixel] =
weight * val_a;
318 pair_moments[2 * bin_pixels + pixel] =
weight * val_b;
319 pair_moments[3 * bin_pixels + pixel] =
weight * val_a * val_a;
320 pair_moments[4 * bin_pixels + pixel] =
weight * val_b * val_b;
321 pair_moments[5 * bin_pixels + pixel] =
weight * val_a * val_b;
324 for(
int plane_base = 0; plane_base < 6; plane_base += 4)
326 const int n_planes =
MIN(4, 6 - plane_base);
327 const float *plane_in[4] = { 0 };
328 float *plane_out[4] = { 0 };
329 for(
int k = 0;
k < n_planes;
k++)
330 plane_in[
k] = plane_out[
k] = pair_moments + (
size_t)(plane_base +
k) * bin_pixels;
331 _knee_blur4(plane_in, plane_out, n_planes, bin_w, bin_h,
sigma, pk_in, pk_out);
336 for(
int orient = 0; orient < 2; orient++)
338 const int target_ch = orient ? chan_b : chan_a;
339 const int guide_ch = orient ? chan_a : chan_b;
340 const int target_mean_plane = orient ? 2 : 1;
341 const int guide_mean_plane = orient ? 1 : 2;
342 const int target_sq_plane = orient ? 4 : 3;
343 const int guide_sq_plane = orient ? 3 : 4;
345 if(nband[target_ch] < 200)
continue;
348 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
350 if(done[target_ch * bin_pixels + pixel])
continue;
352 const float x_val = binned[target_ch * bin_pixels + pixel];
353 const float x_guide = binned[guide_ch * bin_pixels + pixel];
354 const float weight_sum = pair_moments[pixel];
360 const float inv_weight = 1.f / weight_sum;
361 const float mean_target
362 = pair_moments[(size_t)target_mean_plane * bin_pixels + pixel] * inv_weight;
363 const float mean_guide
364 = pair_moments[(size_t)guide_mean_plane * bin_pixels + pixel] * inv_weight;
365 const float covariance
366 = pair_moments[(size_t)5 * bin_pixels + pixel] * inv_weight - mean_target * mean_guide;
367 const float var_guide = fmaxf(pair_moments[(
size_t)guide_sq_plane * bin_pixels + pixel] * inv_weight
368 - mean_guide * mean_guide,
370 const float var_target = fmaxf(pair_moments[(
size_t)target_sq_plane * bin_pixels + pixel] * inv_weight
371 - mean_target * mean_target,
373 const float slope = covariance / (var_guide * (1.f + 1e-3f) + 1e-12f);
375 pred[target_ch * bin_pixels + pixel]
376 = mean_target + slope * (x_guide - mean_guide);
377 r2_scores[target_ch * bin_pixels + pixel]
378 = CLAMP(covariance * covariance / (var_guide * var_target + 1e-18f), 0.f, 1.f);
379 done[target_ch * bin_pixels + pixel] = 1;
388 for(
int c = 0; c < 3; c++)
390 if(nband[c] < 200)
continue;
400 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
402 if(!done[c * bin_pixels + pixel] || r2_scores[c * bin_pixels + pixel] <=
DT_HL_KNEE_R2MIN)
continue;
409 offset[
i + 1] = offset[
i] + count[
i];
412 memcpy(fill, offset,
sizeof(fill));
415 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
417 if(!done[c * bin_pixels + pixel] || r2_scores[c * bin_pixels + pixel] <=
DT_HL_KNEE_R2MIN)
continue;
418 const float x_val = binned[c * bin_pixels + pixel];
420 votes[fill[bin_index]++] = pred[c * bin_pixels + pixel] - x_val;
435 float *
const bin_votes = votes + offset[
i];
440 for(
size_t k = 0;
k < count[
i];
k++) bin_votes[
k] = fabsf(bin_votes[
k] - median_lift);
441 const float median_abs_dev =
_knee_median(bin_votes, count[
i]);
443 const float std_err = 1.858f * median_abs_dev / sqrtf((
float)count[
i]);
452 if(nseen < 3)
continue;
474 if(prev < 0 && next < 0)
477 lift[
i] = lift[next];
479 lift[
i] = lift[prev];
481 lift[
i] = lift[prev] + (lift[next] - lift[prev]) * (
float)(
i - prev) / (
float)(next - prev);
486 float running_max = 0.f;
487 float lift_max = 0.f;
491 running_max = fmaxf(running_max, fmaxf(lift[
i], 0.f));
492 curves[c].
lift[
i] = running_max;
493 lift_max = fmaxf(lift_max, running_max);
499 if(!curves[c].engaged) memset(curves[c].lift, 0,
sizeof(curves[c].lift));
585 const uint32_t filters,
const dt_iop_roi_t *
const roi_in, cl_mem dev_xtrans,
593 for(
int c = 0; c < 3; c++)
596 memset(curves[c].lift, 0,
sizeof(curves[c].lift));
599 const int base = is_xtrans ? 6 : 2;
601 while((
width / ((
size_t)base * downsample)) * (
height / ((
size_t)base * downsample)) > 1500000) downsample++;
603 const int quad_size = base * downsample;
604 const size_t bin_w =
width / quad_size;
605 const size_t bin_h =
height / quad_size;
606 const size_t bin_pixels = bin_w * bin_h;
607 if(bin_w < 16 || bin_h < 16)
return CL_SUCCESS;
609 const int bin_w_int = (int)bin_w, bin_h_int = (
int)bin_h;
626 uint8_t *done = calloc(bin_pixels * 3,
sizeof(uint8_t));
627 if(!dev_binned || !dev_pred || !dev_r2 || !dev_done || !moment_a || !moment_b || !moment_c || !blur_a || !blur_b
628 || !blur_c || !binned || !pred || !r2_scores || !votes || !done)
632 if(cl_err != CL_SUCCESS)
goto cleanup;
637 const int width_int = (int)
width;
638 const int height_int = (int)
height;
639 const int quad_size_int = quad_size;
640 const int roi_x = roi_in ? roi_in->
x : 0;
641 const int roi_y = roi_in ? roi_in->
y : 0;
642 const cl_float4 clip4 = { { clipval_raw[0], clipval_raw[1], clipval_raw[2], 1.f } };
657 if(cl_err != CL_SUCCESS)
goto cleanup;
663 if(cl_err != CL_SUCCESS)
goto cleanup;
667 size_t nband[3] = { 0, 0, 0 };
668 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
669 for(
int c = 0; c < 3; c++)
673 if(nband[0] < 200 && nband[1] < 200 && nband[2] < 200)
688 const float sigma = sigmas[sigma_index];
704 if(cl_err != CL_SUCCESS)
goto cleanup;
715 if(cl_err != CL_SUCCESS)
goto cleanup;
719 for(
int c = 0; c < 3; c++)
721 if(nband[c] < 200)
continue;
722 const int guide1 = (c == 0) ? 1 : 0;
723 const int guide2 = (c == 2) ? 1 : 2;
741 if(cl_err != CL_SUCCESS)
goto cleanup;
746 for(
int chan_a = 0; chan_a < 3; chan_a++)
747 for(
int chan_b = chan_a + 1; chan_b < 3; chan_b++)
749 if(nband[chan_a] < 200 && nband[chan_b] < 200)
continue;
761 if(cl_err != CL_SUCCESS)
goto cleanup;
765 if(cl_err != CL_SUCCESS)
goto cleanup;
767 for(
int orient = 0; orient < 2; orient++)
769 const int target_ch = orient ? chan_b : chan_a;
770 const int guide_ch = orient ? chan_a : chan_b;
771 const int is_first_orient = (orient == 0);
772 if(nband[target_ch] < 200)
continue;
789 if(cl_err != CL_SUCCESS)
goto cleanup;
796 if(cl_err == CL_SUCCESS)
799 if(cl_err == CL_SUCCESS)
801 if(cl_err != CL_SUCCESS)
goto cleanup;
806 for(
int c = 0; c < 3; c++)
808 if(nband[c] < 200)
continue;
815 for(
size_t pixel = 0; pixel < bin_pixels; pixel++)
817 if(!done[c * bin_pixels + pixel] || r2_scores[c * bin_pixels + pixel] <=
DT_HL_KNEE_R2MIN)
continue;
825 memcpy(fill, offset,
sizeof(fill));
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;
830 const float x_val = binned[c * bin_pixels + pixel];
832 votes[fill[bin_index]++] = pred[c * bin_pixels + pixel] - x_val;
843 float *
const bin_votes = votes + offset[
i];
845 for(
size_t k = 0;
k < count[
i];
k++) bin_votes[
k] = fabsf(bin_votes[
k] - median_lift);
846 const float median_abs_dev =
_knee_median(bin_votes, count[
i]);
848 const float std_err = 1.858f * median_abs_dev / sqrtf((
float)count[
i]);
852 lift[
i] = median_lift;
854 if(nseen < 3)
continue;
872 if(prev < 0 && next < 0)
875 lift[
i] = lift[next];
877 lift[
i] = lift[prev];
879 lift[
i] = lift[prev] + (lift[next] - lift[prev]) * (
float)(
i - prev) / (
float)(next - prev);
883 float running_max = 0.f;
884 float lift_max = 0.f;
887 running_max = fmaxf(running_max, fmaxf(lift[
i], 0.f));
888 curves[c].
lift[
i] = running_max;
889 lift_max = fmaxf(lift_max, running_max);
893 if(!curves[c].engaged) memset(curves[c].lift, 0,
sizeof(curves[c].lift));