63#define DEBUG_DUMP_PFM 0
77#define MAX_NUM_SCALES 10
115 GtkWidget *
iterations, *
fourth, *
third, *
second, *
radius, *
radius_center, *
sharpness, *
threshold, *
regularization, *
first,
157 if(anisotropy == 0.f)
159 else if(anisotropy > 0.f)
168 return _(
"diffuse or _sharpen");
173 return _(
"diffusion|deconvolution|blur|sharpening");
179 _(
"simulate directional diffusion of light with heat transfer model\n"
180 "to apply an iterative edge-oriented blur,\n"
181 "inpaint damaged parts of the image,"
182 "or to remove blur with blind deconvolution."),
183 _(
"corrective and creative"),
184 _(
"linear, RGB, scene-referred"),
186 _(
"linear, RGB, scene-referred"));
205 const int new_version)
207 if(old_version == 1 && new_version == 2)
209 typedef struct dt_iop_diffuse_params_v1_t
215 float regularization;
216 float variance_threshold;
218 float anisotropy_first;
219 float anisotropy_second;
220 float anisotropy_third;
221 float anisotropy_fourth;
229 } dt_iop_diffuse_params_v1_t;
231 dt_iop_diffuse_params_v1_t *o = (dt_iop_diffuse_params_v1_t *)old_params;
238 memcpy(
n, o,
sizeof(dt_iop_diffuse_params_v1_t));
241 n->radius_center = 0;
251 if(old_version == 2 && new_version == 3)
253 typedef struct dt_iop_diffuse_params_v2_t
259 float regularization;
260 float variance_threshold;
262 float anisotropy_first;
263 float anisotropy_second;
264 float anisotropy_third;
265 float anisotropy_fourth;
277 } dt_iop_diffuse_params_v2_t;
279 dt_iop_diffuse_params_v2_t *o = (dt_iop_diffuse_params_v2_t *)old_params;
286 memcpy(
n, o,
sizeof(dt_iop_diffuse_params_v2_t));
289 n->normalize_band_energy = 1;
301 memset(&
p, 0,
sizeof(
p));
307 p.variance_threshold = +0.f;
308 p.regularization = 1.f;
310 p.anisotropy_first = +2.f;
311 p.anisotropy_second = 0.f;
312 p.anisotropy_third = +2.f;
313 p.anisotropy_fourth = 0.f;
338 p.variance_threshold = 0.f;
339 p.regularization = 2.5f;
346 p.anisotropy_first = 2.f;
347 p.anisotropy_second = 0.f;
348 p.anisotropy_third = 2.f;
349 p.anisotropy_fourth = 0.f;
357 p.variance_threshold = -0.f;
358 p.regularization = 4.f;
360 p.anisotropy_first = +2.f;
361 p.anisotropy_second = 0.f;
362 p.anisotropy_third = +2.f;
363 p.anisotropy_fourth = 0.f;
398 p.variance_threshold = 0.f;
399 p.regularization = 4.f;
401 p.anisotropy_first = +4.f;
402 p.anisotropy_second = +4.f;
403 p.anisotropy_third = +4.f;
404 p.anisotropy_fourth = +4.f;
416 p.variance_threshold = 0.f;
417 p.regularization = 0.f;
419 p.anisotropy_first = 0.f;
420 p.anisotropy_second = 0.f;
421 p.anisotropy_third = 0.f;
422 p.anisotropy_fourth = 0.f;
434 p.variance_threshold = 0.f;
435 p.regularization = 1.f;
437 p.anisotropy_first = +1.f;
438 p.anisotropy_second = +1.f;
439 p.anisotropy_third = +1.f;
440 p.anisotropy_fourth = +1.f;
457 p.variance_threshold = 0.f;
458 p.regularization = 2.f;
460 p.anisotropy_first = 0.f;
461 p.anisotropy_second = 0.f;
462 p.anisotropy_third = +4.f;
463 p.anisotropy_fourth = +4.f;
475 p.variance_threshold = 0.f;
476 p.regularization = 4.f;
478 p.anisotropy_first = -5.f;
479 p.anisotropy_second = -5.f;
480 p.anisotropy_third = -5.f;
481 p.anisotropy_fourth = -5.f;
492 p.variance_threshold = 0.f;
494 p.anisotropy_first = -2.5f;
495 p.anisotropy_second = 0.f;
496 p.anisotropy_third = 0.f;
497 p.anisotropy_fourth = -2.5f;
506 p.radius_center = 512;
507 p.regularization = 0.1f;
516 p.variance_threshold = 0.f;
517 p.regularization = 0.f;
519 p.anisotropy_first = +0.f;
520 p.anisotropy_second = +0.f;
521 p.anisotropy_third = +0.f;
522 p.anisotropy_fourth = +2.f;
535 p.variance_threshold = 0.f;
536 p.regularization = 0.f;
538 p.anisotropy_first = 0.f;
539 p.anisotropy_second = 0.f;
540 p.anisotropy_third = 5.f;
541 p.anisotropy_fourth = 0.f;
552 p.radius_center = 512;
556 p.variance_threshold = 0.f;
557 p.regularization = 0.f;
560 p.anisotropy_first = 0.f;
561 p.anisotropy_second = 0.f;
562 p.anisotropy_third = 5.f;
563 p.anisotropy_fourth = 0.f;
584 const int max_filter_radius = (1 << scales);
589 tiling->factor = 6.0625f + scales;
590 tiling->factor_cl = 6.0625f + scales;
595 tiling->overlap = max_filter_radius;
617static inline __attribute__((always_inline))
void find_gradients(
const dt_aligned_pixel_simd_t pixels[9],
618 dt_aligned_pixel_simd_t xy[2])
622 const dt_aligned_pixel_simd_t half =
dt_simd_set1(0.5f);
623 xy[0] = (pixels[7] - pixels[1]) * half;
624 xy[1] = (pixels[5] - pixels[3]) * half;
627static inline __attribute__((always_inline))
void find_laplacians(
const dt_aligned_pixel_simd_t pixels[9],
628 dt_aligned_pixel_simd_t xy[2])
633 xy[0] = (pixels[7] + pixels[1]) - two * pixels[4];
634 xy[1] = (pixels[5] + pixels[3]) - two * pixels[4];
638static inline __attribute__((always_inline))
void rotation_matrix_isophote(
639 const dt_aligned_pixel_simd_t
c2,
const dt_aligned_pixel_simd_t cos_theta_sin_theta,
640 const dt_aligned_pixel_simd_t cos_theta2,
const dt_aligned_pixel_simd_t sin_theta2,
641 dt_aligned_pixel_simd_t a[2][2])
648 a[0][0] = cos_theta2 +
c2 * sin_theta2;
649 a[1][1] =
c2 * cos_theta2 + sin_theta2;
650 a[0][1] = a[1][0] = (
c2 -
dt_simd_set1(1.f)) * cos_theta_sin_theta;
653static inline __attribute__((always_inline))
void rotation_matrix_gradient(
654 const dt_aligned_pixel_simd_t
c2,
const dt_aligned_pixel_simd_t cos_theta_sin_theta,
655 const dt_aligned_pixel_simd_t cos_theta2,
const dt_aligned_pixel_simd_t sin_theta2,
656 dt_aligned_pixel_simd_t a[2][2])
663 a[0][0] =
c2 * cos_theta2 + sin_theta2;
664 a[1][1] = cos_theta2 +
c2 * sin_theta2;
665 a[0][1] = a[1][0] = (
dt_simd_set1(1.f) -
c2) * cos_theta_sin_theta;
669static inline __attribute__((always_inline))
void build_matrix(
const dt_aligned_pixel_simd_t a[2][2],
670 dt_aligned_pixel_simd_t
kernel[9])
672 const dt_aligned_pixel_simd_t half =
dt_simd_set1(0.5f);
673 const dt_aligned_pixel_simd_t minus_two =
dt_simd_set1(-2.f);
674 const dt_aligned_pixel_simd_t b11 = a[0][1] * half;
675 const dt_aligned_pixel_simd_t b13 = -b11;
676 const dt_aligned_pixel_simd_t b22 = minus_two * (a[0][0] + a[1][1]);
699static inline __attribute__((always_inline))
void isotrope_laplacian(dt_aligned_pixel_simd_t
kernel[9])
703 const dt_aligned_pixel_simd_t corner =
dt_simd_set1(0.25f);
704 const dt_aligned_pixel_simd_t edge =
dt_simd_set1(0.5f);
705 const dt_aligned_pixel_simd_t center =
dt_simd_set1(-3.f);
717static inline __attribute__((always_inline))
void compute_kernel(
718 const dt_aligned_pixel_simd_t
c2,
const dt_aligned_pixel_simd_t cos_theta_sin_theta,
719 const dt_aligned_pixel_simd_t cos_theta2,
const dt_aligned_pixel_simd_t sin_theta2,
724 switch(isotropy_type)
729 isotrope_laplacian(
kernel);
734 dt_aligned_pixel_simd_t a[2][2] = { {
dt_simd_set1(0.f) } };
735 rotation_matrix_isophote(
c2, cos_theta_sin_theta, cos_theta2, sin_theta2, a);
741 dt_aligned_pixel_simd_t a[2][2] = { {
dt_simd_set1(0.f) } };
742 rotation_matrix_gradient(
c2, cos_theta_sin_theta, cos_theta2, sin_theta2, a);
750static inline void heat_PDE_diffusion(
const float *
const restrict high_freq,
const float *
const restrict low_freq,
751 const uint8_t *
const restrict mask,
const int has_mask,
752 float *
const restrict output,
const size_t width,
753 const size_t height,
const dt_aligned_pixel_simd_t anisotropy,
755 const float variance_threshold,
const int mult,
756 const float normalized_regularization,
757 const dt_aligned_pixel_simd_t
ABCD,
const float strength,
758 const int use_nontemporal)
773 const dt_aligned_pixel_simd_t flt_min =
dt_simd_set1(1e-8f);
774 const dt_aligned_pixel_simd_t variance_threshold_v =
dt_simd_set1(variance_threshold);
775 const dt_aligned_pixel_simd_t normalized_regularization_v =
dt_simd_set1(normalized_regularization);
784 const size_t i_neighbours[3]
788 for(
size_t j = 0; j <
width; ++j)
790 const size_t idx = (
i *
width + j);
791 const size_t index = idx * 4;
792 const uint8_t opacity = (has_mask) ? mask[idx] : 1;
797 const size_t j_neighbours[3]
798 = {
MAX((
int)(j - mult *
H), (
int)0),
800 MIN((
int)(j + mult *
H), (
int)
width - 1) };
803 dt_aligned_pixel_simd_t neighbour_pixel_HF[9];
804 dt_aligned_pixel_simd_t neighbour_pixel_LF[9];
805 dt_aligned_pixel_simd_t energy = zero;
807 for(
size_t ii = 0; ii < 3; ii++)
808 for(
size_t jj = 0; jj < 3; jj++)
810 const size_t neighbor = 4 * (i_neighbours[ii] + j_neighbours[jj]);
811 const dt_aligned_pixel_simd_t hf_value = dt_load_simd_aligned(HF + neighbor);
812 const dt_aligned_pixel_simd_t lf_value = dt_load_simd_aligned(LF + neighbor);
813 neighbour_pixel_HF[3 * ii + jj] = hf_value;
814 neighbour_pixel_LF[3 * ii + jj] = lf_value;
817 const dt_aligned_pixel_simd_t safe_lf = dt_simd_max_zero(lf_value - flt_min) + flt_min;
818 const dt_aligned_pixel_simd_t ratio = hf_value / safe_lf;
819 energy += ratio * ratio;
825 energy = dt_simd_max_zero(variance_threshold_v + energy * normalized_regularization_v - flt_min) + flt_min;
828 dt_aligned_pixel_simd_t lf_gradient[2], hf_gradient[2];
829 find_gradients(neighbour_pixel_LF, lf_gradient);
830 find_gradients(neighbour_pixel_HF, hf_gradient);
833 dt_aligned_pixel_simd_t
c2[4];
834 dt_aligned_pixel_simd_t grad_x = lf_gradient[0];
835 dt_aligned_pixel_simd_t grad_y = lf_gradient[1];
836 dt_aligned_pixel_simd_t c2_first = zero;
837 dt_aligned_pixel_simd_t c2_third = zero;
838 dt_aligned_pixel_simd_t cos_theta_grad_sq = zero;
839 dt_aligned_pixel_simd_t sin_theta_grad_sq = zero;
840 dt_aligned_pixel_simd_t cos_theta_sin_theta_grad = zero;
843 const float magnitude_grad = dt_fast_hypotf(grad_x[c], grad_y[c]);
844 c2_first[c] = -magnitude_grad * anisotropy[0];
845 c2_third[c] = -magnitude_grad * anisotropy[2];
848 const float nonzero = (magnitude_grad != 0.f);
849 const float inv_mag = 1.f / (magnitude_grad + (1.f - nonzero));
850 grad_x[c] = grad_x[c] * inv_mag + (1.f - nonzero);
851 grad_y[c] = grad_y[c] * inv_mag;
853 cos_theta_grad_sq[c] = sqf(grad_x[c]);
854 sin_theta_grad_sq[c] = sqf(grad_y[c]);
855 cos_theta_sin_theta_grad[c] = grad_x[c] * grad_y[c];
860 dt_aligned_pixel_simd_t lapl_x = hf_gradient[0];
861 dt_aligned_pixel_simd_t lapl_y = hf_gradient[1];
862 dt_aligned_pixel_simd_t c2_second = zero;
863 dt_aligned_pixel_simd_t c2_fourth = zero;
864 dt_aligned_pixel_simd_t cos_theta_lapl_sq = zero;
865 dt_aligned_pixel_simd_t sin_theta_lapl_sq = zero;
866 dt_aligned_pixel_simd_t cos_theta_sin_theta_lapl = zero;
869 const float magnitude_lapl = dt_fast_hypotf(lapl_x[c], lapl_y[c]);
870 c2_second[c] = -magnitude_lapl * anisotropy[1];
871 c2_fourth[c] = -magnitude_lapl * anisotropy[3];
874 const float nonzero = (magnitude_lapl != 0.f);
875 const float inv_mag = 1.f / (magnitude_lapl + (1.f - nonzero));
876 lapl_x[c] = lapl_x[c] * inv_mag + (1.f - nonzero);
877 lapl_y[c] = lapl_y[c] * inv_mag;
879 cos_theta_lapl_sq[c] = sqf(lapl_x[c]);
880 sin_theta_lapl_sq[c] = sqf(lapl_y[c]);
881 cos_theta_sin_theta_lapl[c] = lapl_x[c] * lapl_y[c];
887 for(
size_t k = 0;
k < 4;
k++)
890 dt_aligned_pixel_simd_t kern_first[9], kern_second[9], kern_third[9], kern_fourth[9];
891 compute_kernel(
c2[0], cos_theta_sin_theta_grad, cos_theta_grad_sq, sin_theta_grad_sq, isotropy_type[0],
893 compute_kernel(
c2[1], cos_theta_sin_theta_lapl, cos_theta_lapl_sq, sin_theta_lapl_sq, isotropy_type[1],
895 compute_kernel(
c2[2], cos_theta_sin_theta_grad, cos_theta_grad_sq, sin_theta_grad_sq, isotropy_type[2],
897 compute_kernel(
c2[3], cos_theta_sin_theta_lapl, cos_theta_lapl_sq, sin_theta_lapl_sq, isotropy_type[3],
900 dt_aligned_pixel_simd_t derivatives[4] = { zero, zero, zero, zero };
907 for(
size_t k = 0;
k < 9;
k++)
909 derivatives[0] = kern_first[
k] * neighbour_pixel_LF[
k] + derivatives[0];
910 derivatives[1] = kern_second[
k] * neighbour_pixel_LF[
k] + derivatives[1];
911 derivatives[2] = kern_third[
k] * neighbour_pixel_HF[
k] + derivatives[2];
912 derivatives[3] = kern_fourth[
k] * neighbour_pixel_HF[
k] + derivatives[3];
916 dt_aligned_pixel_simd_t update = derivatives[0] *
ABCD[0];
917 update = derivatives[1] *
ABCD[1] + update;
918 update = derivatives[2] *
ABCD[2] + update;
919 update = derivatives[3] *
ABCD[3] + update;
920 const dt_aligned_pixel_simd_t acc = neighbour_pixel_HF[4] * strength_v + update / energy;
923 dt_store_simd_nontemporal(
out + index, dt_simd_max_zero(acc + neighbour_pixel_LF[4]));
931 dt_store_simd_nontemporal(
out + index, dt_simd_max_zero(dt_load_simd_aligned(HF + index)
932 + dt_load_simd_aligned(LF + index)));
935 + dt_load_simd_aligned(LF + index)));
950 return sqf(user_param);
955static void dump_PFM(
const char *filename,
const float*
out,
const uint32_t w,
const uint32_t h)
957 FILE *
f = g_fopen(filename,
"wb");
958 fprintf(
f,
"PF\n%d %d\n-1.0\n", w, h);
959 for(
int j = h - 1 ; j >= 0 ; j--)
960 for(
int i = 0 ;
i < w ;
i++)
961 for(
int c = 0 ;
c < 3 ;
c++)
962 fwrite(
out + (j * w +
i) * 4 + c, 1,
sizeof(
float),
f);
968static inline int wavelets_process(
const float *
const restrict in,
float *
const restrict reconstructed,
969 const uint8_t *
const restrict mask,
const size_t width,
971 const float zoom,
const int scales,
974 float *
const restrict LF_odd,
975 float *
const restrict LF_even)
977 const dt_aligned_pixel_simd_t anisotropy
989 const float regularization = powf(10.f, data->
regularization) - 1.f;
995 float *restrict residual;
1001 for(
int s = 0; s < scales; ++s)
1003 const int mult = 1 << s;
1005 const float *restrict buffer_in;
1006 float *restrict buffer_out;
1011 buffer_out = LF_odd;
1016 buffer_out = LF_even;
1020 buffer_in = LF_even;
1021 buffer_out = LF_odd;
1026 residual = buffer_out;
1030 sprintf(
name,
"/tmp/scale-input-%i.pfm", s);
1033 sprintf(
name,
"/tmp/scale-blur-%i.pfm", s);
1040 float *restrict temp = (residual == LF_even) ? LF_odd : LF_even;
1043 for(
int s = scales - 1; s > -1; --s)
1045 const int mult = 1 << s;
1047 const float real_radius = current_radius * zoom;
1050 const float normalized_regularization =
1051 (data->normalize_band_energy)
1052 ? regularization * sqf(real_radius) / 9.f
1053 : regularization / 9.f;
1055 const float normalized_regularization = regularization / 9.f * sqf(real_radius);
1058 const float norm = expf(-sqf(real_radius - (
float)data->
radius_center) / sqf(data->
radius));
1060 const dt_aligned_pixel_simd_t
ABCD = { data->
first *
KAPPA * norm,
1066 const float *restrict buffer_in;
1067 float *restrict buffer_out;
1071 buffer_in = residual;
1074 else if(count % 2 != 0)
1077 buffer_out = residual;
1081 buffer_in = residual;
1085 if(s == 0) buffer_out = reconstructed;
1088 anisotropy, isotropy_type, variance_threshold, mult,
1099static inline void build_mask(
const float *
const restrict input, uint8_t *
const restrict mask,
1112static inline void inpaint_mask(
float *
const restrict inpainted,
const float *
const restrict original,
1113 const uint8_t *
const restrict mask,
const size_t width,
1123 const uint32_t j =
k -
i;
1133 inpainted[
k + c] = fabsf(gaussian_noise(original[
k + c], original[
k + c],
i % 2 || j % 2,
state));
1138 inpainted[
k + c] = original[
k + c];
1146 const void *
const restrict ivoid,
void *
const restrict
ovoid)
1152 float *restrict in =
DT_IS_ALIGNED((
float *
const restrict)ivoid);
1158 float *restrict temp_in = NULL;
1159 float *restrict temp_out = NULL;
1163 sizeof(uint8_t) * roi_out->
width * roi_out->
height,
1172 const int iterations =
MAX((
int)ceilf((
float)data->
iterations), 1);
1179 for(
int s = 0; s < scales; s++)
1182 if(!HF[s]) out_of_memory =
TRUE;
1197 const int has_mask = (data->
threshold > 0.f);
1210 for(
int it = 0; it < iterations; it++)
1217 else if(it % 2 == 0)
1228 if(it == (
int)iterations - 1)
1232 data, zoom, scales, has_mask, HF, LF_odd, LF_even))
1245 for(
int s = 0; s < scales; s++)
1252 const size_t sizes[3],
const int width,
const int height,
1255 const float zoom,
const int scales,
1263 const dt_aligned_pixel_simd_t anisotropy
1285 const float regularization = powf(10.f, data->
regularization) - 1.f;
1290 for(
int s = 0; s < scales; ++s)
1292 const int mult = 1 << s;
1300 buffer_out = LF_odd;
1305 buffer_out = LF_even;
1309 buffer_in = LF_even;
1310 buffer_out = LF_odd;
1314 const int clamp_lf = 1;
1317 .yoffset = 0, .yfactor = 1,
1318 .cellsize = 4 *
sizeof(float), .overhead = 0,
1319 .sizex = 1 << 16, .sizey = 1 };
1321 hblocksize = hlocopt.
sizex;
1329 .yoffset = 2 * mult, .yfactor = 1,
1330 .cellsize = 4 *
sizeof(float), .overhead = 0,
1331 .sizex = 1, .sizey = 1 << 16 };
1333 vblocksize = vlocopt.
sizey;
1340 const size_t vertical_local[3] = { 1, vblocksize, 1 };
1348 (vblocksize + 4 * mult) * 4 *
sizeof(
float), NULL);
1350 vertical_sizes, vertical_local);
1362 if(err != CL_SUCCESS)
return err;
1367 const size_t horizontal_local[3] = { hblocksize, 1, 1 };
1375 (hblocksize + 4 * mult) * 4 *
sizeof(
float), NULL);
1377 horizontal_sizes, horizontal_local);
1389 if(err != CL_SUCCESS)
return err;
1399 if(err != CL_SUCCESS)
return err;
1401 residual = buffer_out;
1405 cl_mem temp = (residual == LF_even) ? LF_odd : LF_even;
1408 for(
int s = scales - 1; s > -1; --s)
1410 const int mult = 1 << s;
1412 const float real_radius = current_radius * zoom;
1415 const float normalized_regularization =
1416 (data->normalize_band_energy)
1417 ? regularization * sqf(real_radius) / 9.f
1418 : regularization / 9.f;
1420 const float normalized_regularization = regularization / 9.f * sqf(real_radius);
1423 const float norm = expf(-sqf(real_radius - (
float)data->
radius_center) / sqf(data->
radius));
1425 const dt_aligned_pixel_simd_t
ABCD = { data->
first *
KAPPA * norm,
1436 buffer_in = residual;
1439 else if(count % 2 != 0)
1442 buffer_out = residual;
1446 buffer_in = residual;
1450 if(s == 0) buffer_out = reconstructed;
1468 if(err != CL_SUCCESS)
return err;
1483 int out_of_memory =
FALSE;
1487 const int devid = pipe->
devid;
1498 cl_mem temp_in = NULL;
1499 cl_mem temp_out = NULL;
1508 const int iterations =
MAX((
int)ceilf((
float)data->
iterations), 1);
1513 for(
int s = 0; s < scales; s++)
1516 if(!HF[s]) out_of_memory =
TRUE;
1527 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
1531 const int has_mask = (data->
threshold > 0.f);
1542 if(err != CL_SUCCESS)
goto error;
1551 if(err != CL_SUCCESS)
goto error;
1556 for(
int it = 0; it < iterations; it++)
1563 else if(it % 2 == 0)
1574 if(it == (
int)iterations - 1) temp_out = dev_out;
1576 data, gd, zoom, scales, has_mask, HF, LF_odd, LF_even);
1577 if(err != CL_SUCCESS)
goto error;
1603 const int program = 33;
1611 const int wavelets = 35;
1646 gtk_widget_set_tooltip_text(
g->iterations,
1647 _(
"more iterations make the effect stronger but the module slower.\n"
1648 "this is analogous to giving more time to the diffusion reaction.\n"
1649 "if you plan on sharpening or inpainting, \n"
1650 "more iterations help reconstruction."));
1655 gtk_widget_set_tooltip_text(
1656 g->radius_center, _(
"main scale of the diffusion.\n"
1657 "zero makes diffusion act on the finest details more heavily.\n"
1658 "non-zero defines the size of the details to diffuse heavily.\n"
1659 "for deblurring and denoising, set to zero.\n"
1660 "increase to act on local contrast instead."));
1665 gtk_widget_set_tooltip_text(
1666 g->radius, _(
"width of the diffusion around the central radius.\n"
1667 "high values diffuse on a large band of radii.\n"
1668 "low values diffuse closer to the central radius.\n"
1669 "if you plan on deblurring, \n"
1670 "the radius should be around the width of your lens blur."));
1678 gtk_widget_set_tooltip_text(
g->first, _(
"diffusion speed of low-frequency wavelet layers\n"
1679 "in the direction of 1st order anisotropy (set below).\n\n"
1680 "negative values sharpen, \n"
1681 "positive values diffuse and blur, \n"
1682 "zero does nothing."));
1687 gtk_widget_set_tooltip_text(
g->second, _(
"diffusion speed of low-frequency wavelet layers\n"
1688 "in the direction of 2nd order anisotropy (set below).\n\n"
1689 "negative values sharpen, \n"
1690 "positive values diffuse and blur, \n"
1691 "zero does nothing."));
1696 gtk_widget_set_tooltip_text(
g->third, _(
"diffusion speed of high-frequency wavelet layers\n"
1697 "in the direction of 3rd order anisotropy (set below).\n\n"
1698 "negative values sharpen, \n"
1699 "positive values diffuse and blur, \n"
1700 "zero does nothing."));
1705 gtk_widget_set_tooltip_text(
g->fourth, _(
"diffusion speed of high-frequency wavelet layers\n"
1706 "in the direction of 4th order anisotropy (set below).\n\n"
1707 "negative values sharpen, \n"
1708 "positive values diffuse and blur, \n"
1709 "zero does nothing."));
1712 gtk_box_pack_start(GTK_BOX(self->
widget), label_direction,
FALSE,
FALSE, 0);
1717 gtk_widget_set_tooltip_text(
g->anisotropy_first, _(
"direction of 1st order speed (set above).\n\n"
1718 "negative values follow gradients more closely, \n"
1719 "positive values rather avoid edges (isophotes), \n"
1720 "zero affects both equally (isotropic)."));
1725 gtk_widget_set_tooltip_text(
g->anisotropy_second,_(
"direction of 2nd order speed (set above).\n\n"
1726 "negative values follow gradients more closely, \n"
1727 "positive values rather avoid edges (isophotes), \n"
1728 "zero affects both equally (isotropic)."));
1733 gtk_widget_set_tooltip_text(
g->anisotropy_third,_(
"direction of 3rd order speed (set above).\n\n"
1734 "negative values follow gradients more closely, \n"
1735 "positive values rather avoid edges (isophotes), \n"
1736 "zero affects both equally (isotropic)."));
1741 gtk_widget_set_tooltip_text(
g->anisotropy_fourth,_(
"direction of 4th order speed (set above).\n\n"
1742 "negative values follow gradients more closely, \n"
1743 "positive values rather avoid edges (isophotes), \n"
1744 "zero affects both equally (isotropic)."));
1750 gtk_widget_set_tooltip_text(
g->sharpness,
1751 _(
"increase or decrease the sharpness of the highest frequencies.\n"
1752 "can be used to keep details after blooming,\n"
1753 "for standalone sharpening set speed to negative values."));
1756 gtk_widget_set_tooltip_text(
g->regularization,
1757 _(
"define the sensitivity of the variance penalty for edges.\n"
1758 "increase to exclude more edges from diffusion,\n"
1759 "if fringes or halos appear."));
1762 gtk_widget_set_tooltip_text(
g->variance_threshold,
1763 _(
"define the variance threshold between edge amplification and penalty.\n"
1764 "decrease if you want pixels on smooth surfaces get a boost,\n"
1765 "increase if you see noise appear on smooth surfaces or\n"
1766 "if dark areas seem oversharpened compared to bright areas."));
1774 gtk_widget_set_tooltip_text(
g->threshold,
1775 _(
"luminance threshold for the mask.\n"
1776 "0. disables the luminance masking and applies the module on the whole image.\n"
1777 "any higher value excludes pixels with luminance lower than the threshold.\n"
1778 "this can be used to inpaint highlights."));
static void error(char *msg)
void dt_bauhaus_slider_set_soft_range(GtkWidget *widget, float soft_min, float soft_max)
void dt_bauhaus_slider_set_digits(GtkWidget *widget, int val)
void dt_bauhaus_slider_set_format(GtkWidget *widget, const char *format)
@ DEVELOP_BLEND_CS_RGB_SCENE
static unsigned int num_steps_to_reach_equivalent_sigma(const float sigma_filter, const float sigma_final)
static float equivalent_sigma_at_step(const float sigma, const unsigned int s)
static void decompose_2D_Bspline(const float *const restrict in, float *const restrict HF, float *const restrict LF, const size_t width, const size_t height, const int mult, float *const tempbuf, size_t padded_size)
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
return vector dt_simd_set1(valid ?(scaling+NORM_MIN) :NORM_MIN)
const dt_aligned_pixel_t f
const dt_colormatrix_t dt_aligned_pixel_t out
dt_store_simd_aligned(out, dt_mat3x4_mul_vec4(vin, dt_colormatrix_row_to_simd(matrix, 0), dt_colormatrix_row_to_simd(matrix, 1), dt_colormatrix_row_to_simd(matrix, 2)))
static float strength(float value, float strength)
void dt_print(dt_debug_thread_t thread, const char *msg,...)
#define for_each_channel(_var,...)
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...
#define dt_pixelpipe_cache_alloc_align(size, pipe)
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
#define __OMP_DECLARE_SIMD__(...)
#define dt_pixelpipe_cache_free_align(mem)
#define dt_pixelpipe_cache_alloc_align_float(pixels, pipe)
#define __DT_CLONE_TARGETS__
#define for_four_channels(_var,...)
#define __OMP_PARALLEL_FOR__(...)
#define __OMP_PARALLEL_FOR_SIMD__(...)
#define dt_pixelpipe_cache_alloc_perthread_float(n, padded_size)
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
static unsigned int splitmix32(const unsigned long seed)
static float xoshiro128plus(uint state[4])
const char ** description(struct dt_iop_module_t *self)
static __DT_CLONE_TARGETS__ int wavelets_process(const float *const restrict in, float *const restrict reconstructed, const uint8_t *const restrict mask, const size_t width, const size_t height, const dt_iop_diffuse_data_t *const data, const float zoom, const int scales, const int has_mask, float *const restrict HF[10], float *const restrict LF_odd, float *const restrict LF_even)
__DT_CLONE_TARGETS__ int process(dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const restrict ivoid, void *const restrict ovoid)
void commit_params(struct dt_iop_module_t *self, dt_iop_params_t *params, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece)
static float compute_anisotropy_factor(const float user_param)
static __DT_CLONE_TARGETS__ void build_mask(const float *const restrict input, uint8_t *const restrict mask, const float threshold, const size_t width, const size_t height)
static __DT_CLONE_TARGETS__ void heat_PDE_diffusion(const float *const restrict high_freq, const float *const restrict low_freq, const uint8_t *const restrict mask, const int has_mask, float *const restrict output, const size_t width, const size_t height, const dt_aligned_pixel_simd_t anisotropy, const dt_isotropy_t isotropy_type[4], const float variance_threshold, const int mult, const float normalized_regularization, const dt_aligned_pixel_simd_t ABCD, const float strength, const int use_nontemporal)
void gui_init(struct dt_iop_module_t *self)
void tiling_callback(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
void cleanup_global(dt_iop_module_so_t *module)
static cl_int wavelets_process_cl(const int devid, cl_mem in, cl_mem reconstructed, cl_mem mask, const size_t sizes[3], const int width, const int height, const dt_iop_diffuse_data_t *const data, dt_iop_diffuse_global_data_t *const gd, const float zoom, const int scales, const int has_mask, cl_mem HF[10], cl_mem LF_odd, cl_mem LF_even)
int default_colorspace(dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
void init_presets(dt_iop_module_so_t *self)
static __DT_CLONE_TARGETS__ void init_reconstruct(float *const restrict reconstructed, const size_t width, const size_t height)
static dt_isotropy_t check_isotropy_mode(const float anisotropy)
void init_global(dt_iop_module_so_t *module)
int process_cl(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, cl_mem dev_in, cl_mem dev_out)
int legacy_params(dt_iop_module_t *self, const void *const old_params, const int old_version, void *new_params, const int new_version)
static __DT_CLONE_TARGETS__ void inpaint_mask(float *const restrict inpainted, const float *const restrict original, const uint8_t *const restrict mask, const size_t width, const size_t height)
static int dwt_interleave_rows(const int rowid, const int height, const int stride)
static GtkWidget * dt_ui_section_label_new(const gchar *str)
#define DT_GUI_BOX_SPACING
void dt_gui_presets_add_generic(const char *name, dt_dev_operation_t op, const int32_t version, const void *params, const int32_t params_size, const int32_t enabled, const dt_develop_blend_colorspace_t blend_cst)
const char ** dt_iop_set_description(dt_iop_module_t *module, const char *main_text, const char *purpose, const char *input, const char *process, const char *output)
float dt_dev_get_module_scale(const dt_dev_pixelpipe_t *const pipe, const dt_iop_roi_t *const roi_in)
#define dt_omploop_sfence()
@ IOP_FLAGS_INCLUDE_IN_STYLES
@ IOP_FLAGS_SUPPORTS_BLENDING
#define IOP_GUI_ALLOC(module)
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
static float kernel(const float *x, const float *y)
float *const restrict const size_t k
int dt_opencl_local_buffer_opt(const int devid, const int kernel, dt_opencl_local_buffer_t *factors)
int dt_opencl_enqueue_kernel_2d(const int dev, const int kernel, const size_t *sizes)
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
int dt_opencl_create_kernel(const int prog, const char *name)
void dt_opencl_free_kernel(const int kernel)
int dt_opencl_set_kernel_arg(const int dev, const int kernel, const int num, const size_t size, const void *arg)
int dt_opencl_enqueue_kernel_2d_with_local(const int dev, const int kernel, const size_t *sizes, const size_t *local)
void dt_opencl_release_mem_object(cl_mem mem)
struct _GtkWidget GtkWidget
const float uint32_t state[4]
unsigned __int64 uint64_t
struct dt_iop_module_t *void * data
gboolean cache_output_on_ram
int kernel_filmic_wavelets_detail
int kernel_diffuse_build_mask
int kernel_diffuse_inpaint_mask
int kernel_filmic_bspline_vertical
int kernel_filmic_bspline_horizontal_local
int kernel_filmic_bspline_horizontal
int kernel_filmic_bspline_vertical_local
GtkWidget * anisotropy_third
GtkWidget * anisotropy_first
GtkWidget * regularization
GtkWidget * regularization_first
GtkWidget * anisotropy_second
GtkWidget * radius_center
GtkWidget * variance_threshold
GtkWidget * anisotropy_fourth
GModule *dt_dev_operation_t op
dt_iop_global_data_t * data
dt_iop_params_t * default_params
dt_iop_global_data_t * global_data
Region of interest passed through the pixelpipe.