61#define DEBUG_DUMP_PFM 0
75#define MAX_NUM_SCALES 10
113 GtkWidget *
iterations, *
fourth, *
third, *
second, *
radius, *
radius_center, *
sharpness, *
threshold, *
regularization, *
first,
155 if(anisotropy == 0.f)
157 else if(anisotropy > 0.f)
166 return _(
"diffuse or _sharpen");
171 return _(
"diffusion|deconvolution|blur|sharpening");
177 _(
"simulate directional diffusion of light with heat transfer model\n"
178 "to apply an iterative edge-oriented blur,\n"
179 "inpaint damaged parts of the image,"
180 "or to remove blur with blind deconvolution."),
181 _(
"corrective and creative"),
182 _(
"linear, RGB, scene-referred"),
184 _(
"linear, RGB, scene-referred"));
203 const int new_version)
205 if(old_version == 1 && new_version == 2)
207 typedef struct dt_iop_diffuse_params_v1_t
213 float regularization;
214 float variance_threshold;
216 float anisotropy_first;
217 float anisotropy_second;
218 float anisotropy_third;
219 float anisotropy_fourth;
227 } dt_iop_diffuse_params_v1_t;
229 dt_iop_diffuse_params_v1_t *o = (dt_iop_diffuse_params_v1_t *)old_params;
236 memcpy(
n, o,
sizeof(dt_iop_diffuse_params_v1_t));
239 n->radius_center = 0;
249 if(old_version == 2 && new_version == 3)
251 typedef struct dt_iop_diffuse_params_v2_t
257 float regularization;
258 float variance_threshold;
260 float anisotropy_first;
261 float anisotropy_second;
262 float anisotropy_third;
263 float anisotropy_fourth;
275 } dt_iop_diffuse_params_v2_t;
277 dt_iop_diffuse_params_v2_t *o = (dt_iop_diffuse_params_v2_t *)old_params;
284 memcpy(
n, o,
sizeof(dt_iop_diffuse_params_v2_t));
287 n->normalize_band_energy = 1;
299 memset(&
p, 0,
sizeof(
p));
305 p.variance_threshold = +0.f;
306 p.regularization = 1.f;
308 p.anisotropy_first = +2.f;
309 p.anisotropy_second = 0.f;
310 p.anisotropy_third = +2.f;
311 p.anisotropy_fourth = 0.f;
336 p.variance_threshold = 0.f;
337 p.regularization = 2.5f;
344 p.anisotropy_first = 2.f;
345 p.anisotropy_second = 0.f;
346 p.anisotropy_third = 2.f;
347 p.anisotropy_fourth = 0.f;
367 p.variance_threshold = -0.f;
368 p.regularization = 2.5f;
370 p.anisotropy_first = +2.f;
371 p.anisotropy_second = 0.f;
372 p.anisotropy_third = +2.f;
373 p.anisotropy_fourth = 0.f;
408 p.variance_threshold = 0.f;
409 p.regularization = 4.f;
411 p.anisotropy_first = +4.f;
412 p.anisotropy_second = +4.f;
413 p.anisotropy_third = +4.f;
414 p.anisotropy_fourth = +4.f;
426 p.variance_threshold = 0.f;
427 p.regularization = 0.f;
429 p.anisotropy_first = 0.f;
430 p.anisotropy_second = 0.f;
431 p.anisotropy_third = 0.f;
432 p.anisotropy_fourth = 0.f;
444 p.variance_threshold = 0.f;
445 p.regularization = 1.f;
447 p.anisotropy_first = +1.f;
448 p.anisotropy_second = +1.f;
449 p.anisotropy_third = +1.f;
450 p.anisotropy_fourth = +1.f;
467 p.variance_threshold = 0.f;
468 p.regularization = 2.f;
470 p.anisotropy_first = 0.f;
471 p.anisotropy_second = 0.f;
472 p.anisotropy_third = +4.f;
473 p.anisotropy_fourth = +4.f;
485 p.variance_threshold = 0.f;
486 p.regularization = 4.f;
488 p.anisotropy_first = -5.f;
489 p.anisotropy_second = -5.f;
490 p.anisotropy_third = -5.f;
491 p.anisotropy_fourth = -5.f;
502 p.variance_threshold = 0.f;
504 p.anisotropy_first = -2.5f;
505 p.anisotropy_second = 0.f;
506 p.anisotropy_third = 0.f;
507 p.anisotropy_fourth = -2.5f;
516 p.radius_center = 512;
517 p.regularization = 0.1f;
526 p.variance_threshold = 0.f;
527 p.regularization = 0.f;
529 p.anisotropy_first = +0.f;
530 p.anisotropy_second = +0.f;
531 p.anisotropy_third = +0.f;
532 p.anisotropy_fourth = +2.f;
545 p.variance_threshold = 0.f;
546 p.regularization = 0.f;
548 p.anisotropy_first = 0.f;
549 p.anisotropy_second = 0.f;
550 p.anisotropy_third = 5.f;
551 p.anisotropy_fourth = 0.f;
562 p.radius_center = 512;
566 p.variance_threshold = 0.f;
567 p.regularization = 0.f;
570 p.anisotropy_first = 0.f;
571 p.anisotropy_second = 0.f;
572 p.anisotropy_third = 5.f;
573 p.anisotropy_fourth = 0.f;
594 const int max_filter_radius = (1 << scales);
599 tiling->factor = 6.0625f + scales;
600 tiling->factor_cl = 6.0625f + scales;
605 tiling->overlap = max_filter_radius;
627static inline __attribute__((always_inline))
void find_gradients(
const dt_aligned_pixel_simd_t pixels[9],
628 dt_aligned_pixel_simd_t xy[2])
632 const dt_aligned_pixel_simd_t half =
dt_simd_set1(0.5f);
633 xy[0] = (pixels[7] - pixels[1]) * half;
634 xy[1] = (pixels[5] - pixels[3]) * half;
637static inline __attribute__((always_inline))
void find_laplacians(
const dt_aligned_pixel_simd_t pixels[9],
638 dt_aligned_pixel_simd_t xy[2])
643 xy[0] = (pixels[7] + pixels[1]) - two * pixels[4];
644 xy[1] = (pixels[5] + pixels[3]) - two * pixels[4];
648static inline __attribute__((always_inline))
void rotation_matrix_isophote(
649 const dt_aligned_pixel_simd_t
c2,
const dt_aligned_pixel_simd_t cos_theta_sin_theta,
650 const dt_aligned_pixel_simd_t cos_theta2,
const dt_aligned_pixel_simd_t sin_theta2,
651 dt_aligned_pixel_simd_t a[2][2])
658 a[0][0] = cos_theta2 +
c2 * sin_theta2;
659 a[1][1] =
c2 * cos_theta2 + sin_theta2;
663static inline __attribute__((always_inline))
void rotation_matrix_gradient(
664 const dt_aligned_pixel_simd_t
c2,
const dt_aligned_pixel_simd_t cos_theta_sin_theta,
665 const dt_aligned_pixel_simd_t cos_theta2,
const dt_aligned_pixel_simd_t sin_theta2,
666 dt_aligned_pixel_simd_t a[2][2])
673 a[0][0] =
c2 * cos_theta2 + sin_theta2;
674 a[1][1] = cos_theta2 +
c2 * sin_theta2;
679static inline __attribute__((always_inline))
void build_matrix(
const dt_aligned_pixel_simd_t a[2][2],
680 dt_aligned_pixel_simd_t
kernel[9])
682 const dt_aligned_pixel_simd_t half =
dt_simd_set1(0.5f);
683 const dt_aligned_pixel_simd_t minus_two =
dt_simd_set1(-2.f);
684 const dt_aligned_pixel_simd_t b11 =
a[0][1] * half;
685 const dt_aligned_pixel_simd_t b13 = -b11;
686 const dt_aligned_pixel_simd_t b22 = minus_two * (
a[0][0] +
a[1][1]);
709static inline __attribute__((always_inline))
void isotrope_laplacian(dt_aligned_pixel_simd_t
kernel[9])
713 const dt_aligned_pixel_simd_t corner =
dt_simd_set1(0.25f);
714 const dt_aligned_pixel_simd_t edge =
dt_simd_set1(0.5f);
715 const dt_aligned_pixel_simd_t center =
dt_simd_set1(-3.f);
727static inline __attribute__((always_inline))
void compute_kernel(
728 const dt_aligned_pixel_simd_t
c2,
const dt_aligned_pixel_simd_t cos_theta_sin_theta,
729 const dt_aligned_pixel_simd_t cos_theta2,
const dt_aligned_pixel_simd_t sin_theta2,
734 switch(isotropy_type)
739 isotrope_laplacian(
kernel);
745 rotation_matrix_isophote(
c2, cos_theta_sin_theta, cos_theta2, sin_theta2, a);
752 rotation_matrix_gradient(
c2, cos_theta_sin_theta, cos_theta2, sin_theta2, a);
760static inline void heat_PDE_diffusion(
const float *
const restrict high_freq,
const float *
const restrict low_freq,
761 const uint8_t *
const restrict mask,
const int has_mask,
762 float *
const restrict output,
const size_t width,
763 const size_t height,
const dt_aligned_pixel_simd_t anisotropy,
765 const float variance_threshold,
const int mult,
766 const float normalized_regularization,
767 const dt_aligned_pixel_simd_t
ABCD,
const float strength,
768 const int use_nontemporal)
783 const dt_aligned_pixel_simd_t flt_min =
dt_simd_set1(1e-8f);
784 const dt_aligned_pixel_simd_t variance_threshold_v =
dt_simd_set1(variance_threshold);
785 const dt_aligned_pixel_simd_t normalized_regularization_v =
dt_simd_set1(normalized_regularization);
794 const size_t i_neighbours[3]
798 for(
size_t j = 0; j <
width; ++j)
800 const size_t idx = (
i *
width + j);
801 const size_t index = idx * 4;
802 const uint8_t opacity = (has_mask) ? mask[idx] : 1;
807 const size_t j_neighbours[3]
808 = {
MAX((
int)(j - mult *
H), (
int)0),
810 MIN((
int)(j + mult *
H), (
int)
width - 1) };
813 dt_aligned_pixel_simd_t neighbour_pixel_HF[9];
814 dt_aligned_pixel_simd_t neighbour_pixel_LF[9];
815 dt_aligned_pixel_simd_t energy = zero;
817 for(
size_t ii = 0; ii < 3; ii++)
818 for(
size_t jj = 0; jj < 3; jj++)
820 const size_t neighbor = 4 * (i_neighbours[ii] + j_neighbours[jj]);
821 const dt_aligned_pixel_simd_t hf_value = dt_load_simd_aligned(HF + neighbor);
822 const dt_aligned_pixel_simd_t lf_value = dt_load_simd_aligned(LF + neighbor);
823 neighbour_pixel_HF[3 * ii + jj] = hf_value;
824 neighbour_pixel_LF[3 * ii + jj] = lf_value;
827 const dt_aligned_pixel_simd_t safe_lf = dt_simd_max_zero(lf_value - flt_min) + flt_min;
828 const dt_aligned_pixel_simd_t ratio = hf_value / safe_lf;
829 energy += ratio * ratio;
835 energy = dt_simd_max_zero(variance_threshold_v + energy * normalized_regularization_v - flt_min) + flt_min;
838 dt_aligned_pixel_simd_t lf_gradient[2], hf_gradient[2];
839 find_gradients(neighbour_pixel_LF, lf_gradient);
840 find_gradients(neighbour_pixel_HF, hf_gradient);
843 dt_aligned_pixel_simd_t
c2[4];
844 dt_aligned_pixel_simd_t grad_x = lf_gradient[0];
845 dt_aligned_pixel_simd_t grad_y = lf_gradient[1];
846 dt_aligned_pixel_simd_t c2_first = zero;
847 dt_aligned_pixel_simd_t c2_third = zero;
848 dt_aligned_pixel_simd_t cos_theta_grad_sq = zero;
849 dt_aligned_pixel_simd_t sin_theta_grad_sq = zero;
850 dt_aligned_pixel_simd_t cos_theta_sin_theta_grad = zero;
853 const float magnitude_grad = dt_fast_hypotf(grad_x[c], grad_y[c]);
854 c2_first[c] = -magnitude_grad * anisotropy[0];
855 c2_third[c] = -magnitude_grad * anisotropy[2];
858 const float nonzero = (magnitude_grad != 0.f);
859 const float inv_mag = 1.f / (magnitude_grad + (1.f - nonzero));
860 grad_x[c] = grad_x[c] * inv_mag + (1.f - nonzero);
861 grad_y[c] = grad_y[c] * inv_mag;
863 cos_theta_grad_sq[c] = sqf(grad_x[c]);
864 sin_theta_grad_sq[c] = sqf(grad_y[c]);
865 cos_theta_sin_theta_grad[c] = grad_x[c] * grad_y[c];
870 dt_aligned_pixel_simd_t lapl_x = hf_gradient[0];
871 dt_aligned_pixel_simd_t lapl_y = hf_gradient[1];
872 dt_aligned_pixel_simd_t c2_second = zero;
873 dt_aligned_pixel_simd_t c2_fourth = zero;
874 dt_aligned_pixel_simd_t cos_theta_lapl_sq = zero;
875 dt_aligned_pixel_simd_t sin_theta_lapl_sq = zero;
876 dt_aligned_pixel_simd_t cos_theta_sin_theta_lapl = zero;
879 const float magnitude_lapl = dt_fast_hypotf(lapl_x[c], lapl_y[c]);
880 c2_second[c] = -magnitude_lapl * anisotropy[1];
881 c2_fourth[c] = -magnitude_lapl * anisotropy[3];
884 const float nonzero = (magnitude_lapl != 0.f);
885 const float inv_mag = 1.f / (magnitude_lapl + (1.f - nonzero));
886 lapl_x[c] = lapl_x[c] * inv_mag + (1.f - nonzero);
887 lapl_y[c] = lapl_y[c] * inv_mag;
889 cos_theta_lapl_sq[c] = sqf(lapl_x[c]);
890 sin_theta_lapl_sq[c] = sqf(lapl_y[c]);
891 cos_theta_sin_theta_lapl[c] = lapl_x[c] * lapl_y[c];
897 for(
size_t k = 0;
k < 4;
k++)
900 dt_aligned_pixel_simd_t kern_first[9], kern_second[9], kern_third[9], kern_fourth[9];
901 compute_kernel(
c2[0], cos_theta_sin_theta_grad, cos_theta_grad_sq, sin_theta_grad_sq, isotropy_type[0],
903 compute_kernel(
c2[1], cos_theta_sin_theta_lapl, cos_theta_lapl_sq, sin_theta_lapl_sq, isotropy_type[1],
905 compute_kernel(
c2[2], cos_theta_sin_theta_grad, cos_theta_grad_sq, sin_theta_grad_sq, isotropy_type[2],
907 compute_kernel(
c2[3], cos_theta_sin_theta_lapl, cos_theta_lapl_sq, sin_theta_lapl_sq, isotropy_type[3],
910 dt_aligned_pixel_simd_t derivatives[4] = { zero, zero, zero, zero };
917 for(
size_t k = 0;
k < 9;
k++)
919 derivatives[0] = kern_first[
k] * neighbour_pixel_LF[
k] + derivatives[0];
920 derivatives[1] = kern_second[
k] * neighbour_pixel_LF[
k] + derivatives[1];
921 derivatives[2] = kern_third[
k] * neighbour_pixel_HF[
k] + derivatives[2];
922 derivatives[3] = kern_fourth[
k] * neighbour_pixel_HF[
k] + derivatives[3];
926 dt_aligned_pixel_simd_t update = derivatives[0] *
ABCD[0];
927 update = derivatives[1] *
ABCD[1] + update;
928 update = derivatives[2] *
ABCD[2] + update;
929 update = derivatives[3] *
ABCD[3] + update;
930 const dt_aligned_pixel_simd_t acc = neighbour_pixel_HF[4] * strength_v + update / energy;
933 dt_store_simd_nontemporal(
out + index, dt_simd_max_zero(acc + neighbour_pixel_LF[4]));
941 dt_store_simd_nontemporal(
out + index, dt_simd_max_zero(dt_load_simd_aligned(HF + index)
942 + dt_load_simd_aligned(LF + index)));
945 + dt_load_simd_aligned(LF + index)));
960 return sqf(user_param);
965static void dump_PFM(
const char *filename,
const float*
out,
const uint32_t w,
const uint32_t h)
967 FILE *
f = g_fopen(filename,
"wb");
968 fprintf(
f,
"PF\n%d %d\n-1.0\n", w, h);
969 for(
int j = h - 1 ; j >= 0 ; j--)
970 for(
int i = 0 ;
i < w ;
i++)
971 for(
int c = 0 ;
c < 3 ;
c++)
972 fwrite(
out + (j * w +
i) * 4 + c, 1,
sizeof(
float),
f);
978static inline int wavelets_process(
const float *
const restrict in,
float *
const restrict reconstructed,
979 const uint8_t *
const restrict mask,
const size_t width,
981 const float zoom,
const int scales,
984 float *
const restrict LF_odd,
985 float *
const restrict LF_even)
987 const dt_aligned_pixel_simd_t anisotropy
999 const float regularization = powf(10.f, data->
regularization) - 1.f;
1005 float *restrict residual;
1011 for(
int s = 0; s < scales; ++s)
1013 const int mult = 1 << s;
1015 const float *restrict buffer_in;
1016 float *restrict buffer_out;
1021 buffer_out = LF_odd;
1026 buffer_out = LF_even;
1030 buffer_in = LF_even;
1031 buffer_out = LF_odd;
1036 residual = buffer_out;
1040 sprintf(
name,
"/tmp/scale-input-%i.pfm", s);
1043 sprintf(
name,
"/tmp/scale-blur-%i.pfm", s);
1050 float *restrict temp = (residual == LF_even) ? LF_odd : LF_even;
1053 for(
int s = scales - 1; s > -1; --s)
1055 const int mult = 1 << s;
1057 const float real_radius = current_radius * zoom;
1060 const float normalized_regularization =
1061 (data->normalize_band_energy)
1062 ? regularization * sqf(real_radius) / 9.f
1063 : regularization / 9.f;
1065 const float normalized_regularization = regularization / 9.f * sqf(real_radius);
1068 const float norm = expf(-sqf(real_radius - (
float)data->
radius_center) / sqf(data->
radius));
1070 const dt_aligned_pixel_simd_t
ABCD = { data->
first *
KAPPA * norm,
1076 const float *restrict buffer_in;
1077 float *restrict buffer_out;
1081 buffer_in = residual;
1084 else if(count % 2 != 0)
1087 buffer_out = residual;
1091 buffer_in = residual;
1095 if(s == 0) buffer_out = reconstructed;
1098 anisotropy, isotropy_type, variance_threshold, mult,
1109static inline void build_mask(
const float *
const restrict input, uint8_t *
const restrict mask,
1122static inline void inpaint_mask(
float *
const restrict inpainted,
const float *
const restrict original,
1123 const uint8_t *
const restrict mask,
const size_t width,
1133 const uint32_t j =
k -
i;
1143 inpainted[
k + c] = fabsf(gaussian_noise(original[
k + c], original[
k + c],
i % 2 || j % 2,
state));
1148 inpainted[
k + c] = original[
k + c];
1156 const void *
const restrict ivoid,
void *
const restrict
ovoid)
1162 float *restrict in =
DT_IS_ALIGNED((
float *
const restrict)ivoid);
1168 float *restrict temp_in = NULL;
1169 float *restrict temp_out = NULL;
1173 sizeof(uint8_t) * roi_out->
width * roi_out->
height,
1182 const int iterations =
MAX((
int)ceilf((
float)data->
iterations), 1);
1189 for(
int s = 0; s < scales; s++)
1192 if(!HF[s]) out_of_memory =
TRUE;
1207 const int has_mask = (data->
threshold > 0.f);
1220 for(
int it = 0; it < iterations; it++)
1227 else if(it % 2 == 0)
1238 if(it == (
int)iterations - 1)
1242 data, zoom, scales, has_mask, HF, LF_odd, LF_even))
1255 for(
int s = 0; s < scales; s++)
1262 const size_t sizes[3],
const int width,
const int height,
1265 const float zoom,
const int scales,
1273 const dt_aligned_pixel_simd_t anisotropy
1295 const float regularization = powf(10.f, data->
regularization) - 1.f;
1300 for(
int s = 0; s < scales; ++s)
1302 const int mult = 1 << s;
1310 buffer_out = LF_odd;
1315 buffer_out = LF_even;
1319 buffer_in = LF_even;
1320 buffer_out = LF_odd;
1324 const int clamp_lf = 1;
1327 .yoffset = 0, .yfactor = 1,
1328 .cellsize = 4 *
sizeof(float), .overhead = 0,
1329 .sizex = 1 << 16, .sizey = 1 };
1331 hblocksize = hlocopt.
sizex;
1339 .yoffset = 2 * mult, .yfactor = 1,
1340 .cellsize = 4 *
sizeof(float), .overhead = 0,
1341 .sizex = 1, .sizey = 1 << 16 };
1343 vblocksize = vlocopt.
sizey;
1350 const size_t vertical_local[3] = { 1, vblocksize, 1 };
1358 (vblocksize + 4 * mult) * 4 *
sizeof(
float), NULL);
1360 vertical_sizes, vertical_local);
1372 if(err != CL_SUCCESS)
return err;
1377 const size_t horizontal_local[3] = { hblocksize, 1, 1 };
1385 (hblocksize + 4 * mult) * 4 *
sizeof(
float), NULL);
1387 horizontal_sizes, horizontal_local);
1399 if(err != CL_SUCCESS)
return err;
1409 if(err != CL_SUCCESS)
return err;
1411 residual = buffer_out;
1415 cl_mem temp = (residual == LF_even) ? LF_odd : LF_even;
1418 for(
int s = scales - 1; s > -1; --s)
1420 const int mult = 1 << s;
1422 const float real_radius = current_radius * zoom;
1425 const float normalized_regularization =
1426 (data->normalize_band_energy)
1427 ? regularization * sqf(real_radius) / 9.f
1428 : regularization / 9.f;
1430 const float normalized_regularization = regularization / 9.f * sqf(real_radius);
1433 const float norm = expf(-sqf(real_radius - (
float)data->
radius_center) / sqf(data->
radius));
1435 const dt_aligned_pixel_simd_t
ABCD = { data->
first *
KAPPA * norm,
1446 buffer_in = residual;
1449 else if(count % 2 != 0)
1452 buffer_out = residual;
1456 buffer_in = residual;
1460 if(s == 0) buffer_out = reconstructed;
1478 if(err != CL_SUCCESS)
return err;
1493 int out_of_memory =
FALSE;
1497 const int devid = pipe->
devid;
1508 cl_mem temp_in = NULL;
1509 cl_mem temp_out = NULL;
1518 const int iterations =
MAX((
int)ceilf((
float)data->
iterations), 1);
1523 for(
int s = 0; s < scales; s++)
1526 if(!HF[s]) out_of_memory =
TRUE;
1537 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
1541 const int has_mask = (data->
threshold > 0.f);
1552 if(err != CL_SUCCESS)
goto error;
1561 if(err != CL_SUCCESS)
goto error;
1566 for(
int it = 0; it < iterations; it++)
1573 else if(it % 2 == 0)
1584 if(it == (
int)iterations - 1) temp_out = dev_out;
1586 data, gd, zoom, scales, has_mask, HF, LF_odd, LF_even);
1587 if(err != CL_SUCCESS)
goto error;
1613 const int program = 33;
1621 const int wavelets = 35;
1656 gtk_widget_set_tooltip_text(
g->iterations,
1657 _(
"more iterations make the effect stronger but the module slower.\n"
1658 "this is analogous to giving more time to the diffusion reaction.\n"
1659 "if you plan on sharpening or inpainting, \n"
1660 "more iterations help reconstruction."));
1665 gtk_widget_set_tooltip_text(
1666 g->radius_center, _(
"main scale of the diffusion.\n"
1667 "zero makes diffusion act on the finest details more heavily.\n"
1668 "non-zero defines the size of the details to diffuse heavily.\n"
1669 "for deblurring and denoising, set to zero.\n"
1670 "increase to act on local contrast instead."));
1675 gtk_widget_set_tooltip_text(
1676 g->radius, _(
"width of the diffusion around the central radius.\n"
1677 "high values diffuse on a large band of radii.\n"
1678 "low values diffuse closer to the central radius.\n"
1679 "if you plan on deblurring, \n"
1680 "the radius should be around the width of your lens blur."));
1688 gtk_widget_set_tooltip_text(
g->first, _(
"diffusion speed of low-frequency wavelet layers\n"
1689 "in the direction of 1st order anisotropy (set below).\n\n"
1690 "negative values sharpen, \n"
1691 "positive values diffuse and blur, \n"
1692 "zero does nothing."));
1697 gtk_widget_set_tooltip_text(
g->second, _(
"diffusion speed of low-frequency wavelet layers\n"
1698 "in the direction of 2nd order anisotropy (set below).\n\n"
1699 "negative values sharpen, \n"
1700 "positive values diffuse and blur, \n"
1701 "zero does nothing."));
1706 gtk_widget_set_tooltip_text(
g->third, _(
"diffusion speed of high-frequency wavelet layers\n"
1707 "in the direction of 3rd order anisotropy (set below).\n\n"
1708 "negative values sharpen, \n"
1709 "positive values diffuse and blur, \n"
1710 "zero does nothing."));
1715 gtk_widget_set_tooltip_text(
g->fourth, _(
"diffusion speed of high-frequency wavelet layers\n"
1716 "in the direction of 4th order anisotropy (set below).\n\n"
1717 "negative values sharpen, \n"
1718 "positive values diffuse and blur, \n"
1719 "zero does nothing."));
1727 gtk_widget_set_tooltip_text(
g->anisotropy_first, _(
"direction of 1st order speed (set above).\n\n"
1728 "negative values follow gradients more closely, \n"
1729 "positive values rather avoid edges (isophotes), \n"
1730 "zero affects both equally (isotropic)."));
1735 gtk_widget_set_tooltip_text(
g->anisotropy_second,_(
"direction of 2nd order speed (set above).\n\n"
1736 "negative values follow gradients more closely, \n"
1737 "positive values rather avoid edges (isophotes), \n"
1738 "zero affects both equally (isotropic)."));
1743 gtk_widget_set_tooltip_text(
g->anisotropy_third,_(
"direction of 3rd order speed (set above).\n\n"
1744 "negative values follow gradients more closely, \n"
1745 "positive values rather avoid edges (isophotes), \n"
1746 "zero affects both equally (isotropic)."));
1751 gtk_widget_set_tooltip_text(
g->anisotropy_fourth,_(
"direction of 4th order speed (set above).\n\n"
1752 "negative values follow gradients more closely, \n"
1753 "positive values rather avoid edges (isophotes), \n"
1754 "zero affects both equally (isotropic)."));
1760 gtk_widget_set_tooltip_text(
g->sharpness,
1761 _(
"increase or decrease the sharpness of the highest frequencies.\n"
1762 "can be used to keep details after blooming,\n"
1763 "for standalone sharpening set speed to negative values."));
1766 gtk_widget_set_tooltip_text(
g->regularization,
1767 _(
"define the sensitivity of the variance penalty for edges.\n"
1768 "increase to exclude more edges from diffusion,\n"
1769 "if fringes or halos appear."));
1772 gtk_widget_set_tooltip_text(
g->variance_threshold,
1773 _(
"define the variance threshold between edge amplification and penalty.\n"
1774 "decrease if you want pixels on smooth surfaces get a boost,\n"
1775 "increase if you see noise appear on smooth surfaces or\n"
1776 "if dark areas seem oversharpened compared to bright areas."));
1784 gtk_widget_set_tooltip_text(
g->threshold,
1785 _(
"luminance threshold for the mask.\n"
1786 "0. disables the luminance masking and applies the module on the whole image.\n"
1787 "any higher value excludes pixels with luminance lower than the threshold.\n"
1788 "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)
return vector dt_simd_set1(valid ?(scaling+NORM_MIN) :NORM_MIN)
struct _GtkWidget GtkWidget
GtkWidget, opaque, spelled exactly as GTK spells it.
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)
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)
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)
@ IOP_FLAGS_INCLUDE_IN_STYLES
@ IOP_FLAGS_SUPPORTS_BLENDING
GtkWidget * dt_bauhaus_slider_from_params(dt_iop_module_t *self, const char *param)
#define IOP_GUI_ALLOC(module)
static float kernel(const float *x, const float *y)
GtkWidget * dt_ui_section_label_new(const gchar *str)
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
float *const restrict const size_t k
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
#define DT_ALIGNED_PIXEL
Align a 4-float pixel on 16 bytes, enough for SSE. Same struct-member caveat as DT_ALIGNED_ARRAY,...
#define DT_ALIGNED_ARRAY
Align an object on a cacheline boundary, so AVX2 can load it whole.
#define DT_IS_ALIGNED(x)
Promise the compiler that x is already cacheline-aligned, and return it.
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
#define DT_MODULE_INTROSPECTION(MODVER, PARAMSTYPE)
DT_MODULE() for a module whose params struct is introspected.
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)
#define dt_omploop_sfence()
#define __OMP_DECLARE_SIMD__(...)
#define __OMP_PARALLEL_FOR__(...)
#define __OMP_PARALLEL_FOR_SIMD__(...)
#define dt_pixelpipe_cache_alloc_align(size, pipe)
#define dt_pixelpipe_cache_free_align(mem)
#define dt_pixelpipe_cache_alloc_align_float(pixels, pipe)
#define dt_pixelpipe_cache_alloc_perthread_float(n, padded_size)
#define for_each_channel(_var,...)
float dt_aligned_pixel_simd_t __attribute__((vector_size(16), aligned(16)))
Apply one channel's tone curve to each of the three colour channels, or pass the channel through unto...
#define for_four_channels(_var,...)
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
dt_iop_global_data_t * data
dt_iop_params_t * default_params
struct dt_iop_module_gui_t * gui
dt_iop_global_data_t * global_data
Region of interest passed through the pixelpipe.
#define __DT_CLONE_TARGETS__