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;
333 p.variance_threshold = 0.f;
334 p.regularization = 2.5f;
341 p.anisotropy_first = 2.f;
342 p.anisotropy_second = 0.f;
343 p.anisotropy_third = 2.f;
344 p.anisotropy_fourth = 0.f;
363 p.variance_threshold = -0.f;
364 p.regularization = 2.5f;
366 p.anisotropy_first = +2.f;
367 p.anisotropy_second = 0.f;
368 p.anisotropy_third = +2.f;
369 p.anisotropy_fourth = 0.f;
404 p.variance_threshold = 0.f;
405 p.regularization = 4.f;
407 p.anisotropy_first = +4.f;
408 p.anisotropy_second = +4.f;
409 p.anisotropy_third = +4.f;
410 p.anisotropy_fourth = +4.f;
422 p.variance_threshold = 0.f;
423 p.regularization = 0.f;
425 p.anisotropy_first = 0.f;
426 p.anisotropy_second = 0.f;
427 p.anisotropy_third = 0.f;
428 p.anisotropy_fourth = 0.f;
440 p.variance_threshold = 0.f;
441 p.regularization = 1.f;
443 p.anisotropy_first = +1.f;
444 p.anisotropy_second = +1.f;
445 p.anisotropy_third = +1.f;
446 p.anisotropy_fourth = +1.f;
461 p.variance_threshold = 0.f;
462 p.regularization = 2.f;
464 p.anisotropy_first = 0.f;
465 p.anisotropy_second = 0.f;
466 p.anisotropy_third = +4.f;
467 p.anisotropy_fourth = +4.f;
479 p.variance_threshold = 0.f;
480 p.regularization = 4.f;
482 p.anisotropy_first = -5.f;
483 p.anisotropy_second = -5.f;
484 p.anisotropy_third = -5.f;
485 p.anisotropy_fourth = -5.f;
496 p.variance_threshold = 0.f;
498 p.anisotropy_first = -2.5f;
499 p.anisotropy_second = 0.f;
500 p.anisotropy_third = 0.f;
501 p.anisotropy_fourth = -2.5f;
510 p.radius_center = 512;
511 p.regularization = 0.1f;
519 p.variance_threshold = 0.f;
520 p.regularization = 0.f;
522 p.anisotropy_first = +0.f;
523 p.anisotropy_second = +0.f;
524 p.anisotropy_third = +0.f;
525 p.anisotropy_fourth = +2.f;
538 p.variance_threshold = 0.f;
539 p.regularization = 0.f;
541 p.anisotropy_first = 0.f;
542 p.anisotropy_second = 0.f;
543 p.anisotropy_third = 5.f;
544 p.anisotropy_fourth = 0.f;
554 p.radius_center = 512;
558 p.variance_threshold = 0.f;
559 p.regularization = 0.f;
562 p.anisotropy_first = 0.f;
563 p.anisotropy_second = 0.f;
564 p.anisotropy_third = 5.f;
565 p.anisotropy_fourth = 0.f;
585 const int max_filter_radius = (1 << scales);
590 tiling->factor = 6.0625f + scales;
591 tiling->factor_cl = 6.0625f + scales;
596 tiling->overlap = max_filter_radius;
618static inline __attribute__((always_inline))
void find_gradients(
const dt_aligned_pixel_simd_t pixels[9],
619 dt_aligned_pixel_simd_t xy[2])
623 const dt_aligned_pixel_simd_t half =
dt_simd_set1(0.5f);
624 xy[0] = (pixels[7] - pixels[1]) * half;
625 xy[1] = (pixels[5] - pixels[3]) * half;
628static inline __attribute__((always_inline))
void find_laplacians(
const dt_aligned_pixel_simd_t pixels[9],
629 dt_aligned_pixel_simd_t xy[2])
634 xy[0] = (pixels[7] + pixels[1]) - two * pixels[4];
635 xy[1] = (pixels[5] + pixels[3]) - two * pixels[4];
639static inline __attribute__((always_inline))
void rotation_matrix_isophote(
640 const dt_aligned_pixel_simd_t
c2,
const dt_aligned_pixel_simd_t cos_theta_sin_theta,
641 const dt_aligned_pixel_simd_t cos_theta2,
const dt_aligned_pixel_simd_t sin_theta2,
642 dt_aligned_pixel_simd_t a[2][2])
649 a[0][0] = cos_theta2 +
c2 * sin_theta2;
650 a[1][1] =
c2 * cos_theta2 + sin_theta2;
654static inline __attribute__((always_inline))
void rotation_matrix_gradient(
655 const dt_aligned_pixel_simd_t
c2,
const dt_aligned_pixel_simd_t cos_theta_sin_theta,
656 const dt_aligned_pixel_simd_t cos_theta2,
const dt_aligned_pixel_simd_t sin_theta2,
657 dt_aligned_pixel_simd_t a[2][2])
664 a[0][0] =
c2 * cos_theta2 + sin_theta2;
665 a[1][1] = cos_theta2 +
c2 * sin_theta2;
670static inline __attribute__((always_inline))
void build_matrix(
const dt_aligned_pixel_simd_t a[2][2],
671 dt_aligned_pixel_simd_t
kernel[9])
673 const dt_aligned_pixel_simd_t half =
dt_simd_set1(0.5f);
674 const dt_aligned_pixel_simd_t minus_two =
dt_simd_set1(-2.f);
675 const dt_aligned_pixel_simd_t b11 =
a[0][1] * half;
676 const dt_aligned_pixel_simd_t b13 = -b11;
677 const dt_aligned_pixel_simd_t b22 = minus_two * (
a[0][0] +
a[1][1]);
700static inline __attribute__((always_inline))
void isotrope_laplacian(dt_aligned_pixel_simd_t
kernel[9])
704 const dt_aligned_pixel_simd_t corner =
dt_simd_set1(0.25f);
705 const dt_aligned_pixel_simd_t edge =
dt_simd_set1(0.5f);
706 const dt_aligned_pixel_simd_t center =
dt_simd_set1(-3.f);
718static inline __attribute__((always_inline))
void compute_kernel(
719 const dt_aligned_pixel_simd_t
c2,
const dt_aligned_pixel_simd_t cos_theta_sin_theta,
720 const dt_aligned_pixel_simd_t cos_theta2,
const dt_aligned_pixel_simd_t sin_theta2,
725 switch(isotropy_type)
730 isotrope_laplacian(
kernel);
736 rotation_matrix_isophote(
c2, cos_theta_sin_theta, cos_theta2, sin_theta2, a);
743 rotation_matrix_gradient(
c2, cos_theta_sin_theta, cos_theta2, sin_theta2, a);
751static inline void heat_PDE_diffusion(
const float *
const restrict high_freq,
const float *
const restrict low_freq,
752 const uint8_t *
const restrict mask,
const int has_mask,
753 float *
const restrict output,
const size_t width,
754 const size_t height,
const dt_aligned_pixel_simd_t anisotropy,
756 const float variance_threshold,
const int mult,
757 const float normalized_regularization,
758 const dt_aligned_pixel_simd_t
ABCD,
const float strength,
759 const int use_nontemporal)
774 const dt_aligned_pixel_simd_t flt_min =
dt_simd_set1(1e-8f);
775 const dt_aligned_pixel_simd_t variance_threshold_v =
dt_simd_set1(variance_threshold);
776 const dt_aligned_pixel_simd_t normalized_regularization_v =
dt_simd_set1(normalized_regularization);
785 const size_t i_neighbours[3]
789 for(
size_t j = 0; j <
width; ++j)
791 const size_t idx = (
i *
width + j);
792 const size_t index = idx * 4;
793 const uint8_t opacity = (has_mask) ? mask[idx] : 1;
798 const size_t j_neighbours[3]
799 = {
MAX((
int)(j - mult *
H), (
int)0),
801 MIN((
int)(j + mult *
H), (
int)
width - 1) };
804 dt_aligned_pixel_simd_t neighbour_pixel_HF[9];
805 dt_aligned_pixel_simd_t neighbour_pixel_LF[9];
806 dt_aligned_pixel_simd_t energy = zero;
808 for(
size_t ii = 0; ii < 3; ii++)
809 for(
size_t jj = 0; jj < 3; jj++)
811 const size_t neighbor = 4 * (i_neighbours[ii] + j_neighbours[jj]);
812 const dt_aligned_pixel_simd_t hf_value = dt_load_simd_aligned(HF + neighbor);
813 const dt_aligned_pixel_simd_t lf_value = dt_load_simd_aligned(LF + neighbor);
814 neighbour_pixel_HF[3 * ii + jj] = hf_value;
815 neighbour_pixel_LF[3 * ii + jj] = lf_value;
818 const dt_aligned_pixel_simd_t safe_lf = dt_simd_max_zero(lf_value - flt_min) + flt_min;
819 const dt_aligned_pixel_simd_t ratio = hf_value / safe_lf;
820 energy += ratio * ratio;
826 energy = dt_simd_max_zero(variance_threshold_v + energy * normalized_regularization_v - flt_min) + flt_min;
829 dt_aligned_pixel_simd_t lf_gradient[2], hf_gradient[2];
830 find_gradients(neighbour_pixel_LF, lf_gradient);
831 find_gradients(neighbour_pixel_HF, hf_gradient);
834 dt_aligned_pixel_simd_t
c2[4];
835 dt_aligned_pixel_simd_t grad_x = lf_gradient[0];
836 dt_aligned_pixel_simd_t grad_y = lf_gradient[1];
837 dt_aligned_pixel_simd_t c2_first = zero;
838 dt_aligned_pixel_simd_t c2_third = zero;
839 dt_aligned_pixel_simd_t cos_theta_grad_sq = zero;
840 dt_aligned_pixel_simd_t sin_theta_grad_sq = zero;
841 dt_aligned_pixel_simd_t cos_theta_sin_theta_grad = zero;
844 const float magnitude_grad = dt_fast_hypotf(grad_x[c], grad_y[c]);
845 c2_first[c] = -magnitude_grad * anisotropy[0];
846 c2_third[c] = -magnitude_grad * anisotropy[2];
849 const float nonzero = (magnitude_grad != 0.f);
850 const float inv_mag = 1.f / (magnitude_grad + (1.f - nonzero));
851 grad_x[c] = grad_x[c] * inv_mag + (1.f - nonzero);
852 grad_y[c] = grad_y[c] * inv_mag;
854 cos_theta_grad_sq[c] = sqf(grad_x[c]);
855 sin_theta_grad_sq[c] = sqf(grad_y[c]);
856 cos_theta_sin_theta_grad[c] = grad_x[c] * grad_y[c];
861 dt_aligned_pixel_simd_t lapl_x = hf_gradient[0];
862 dt_aligned_pixel_simd_t lapl_y = hf_gradient[1];
863 dt_aligned_pixel_simd_t c2_second = zero;
864 dt_aligned_pixel_simd_t c2_fourth = zero;
865 dt_aligned_pixel_simd_t cos_theta_lapl_sq = zero;
866 dt_aligned_pixel_simd_t sin_theta_lapl_sq = zero;
867 dt_aligned_pixel_simd_t cos_theta_sin_theta_lapl = zero;
870 const float magnitude_lapl = dt_fast_hypotf(lapl_x[c], lapl_y[c]);
871 c2_second[c] = -magnitude_lapl * anisotropy[1];
872 c2_fourth[c] = -magnitude_lapl * anisotropy[3];
875 const float nonzero = (magnitude_lapl != 0.f);
876 const float inv_mag = 1.f / (magnitude_lapl + (1.f - nonzero));
877 lapl_x[c] = lapl_x[c] * inv_mag + (1.f - nonzero);
878 lapl_y[c] = lapl_y[c] * inv_mag;
880 cos_theta_lapl_sq[c] = sqf(lapl_x[c]);
881 sin_theta_lapl_sq[c] = sqf(lapl_y[c]);
882 cos_theta_sin_theta_lapl[c] = lapl_x[c] * lapl_y[c];
888 for(
size_t k = 0;
k < 4;
k++)
891 dt_aligned_pixel_simd_t kern_first[9], kern_second[9], kern_third[9], kern_fourth[9];
892 compute_kernel(
c2[0], cos_theta_sin_theta_grad, cos_theta_grad_sq, sin_theta_grad_sq, isotropy_type[0],
894 compute_kernel(
c2[1], cos_theta_sin_theta_lapl, cos_theta_lapl_sq, sin_theta_lapl_sq, isotropy_type[1],
896 compute_kernel(
c2[2], cos_theta_sin_theta_grad, cos_theta_grad_sq, sin_theta_grad_sq, isotropy_type[2],
898 compute_kernel(
c2[3], cos_theta_sin_theta_lapl, cos_theta_lapl_sq, sin_theta_lapl_sq, isotropy_type[3],
901 dt_aligned_pixel_simd_t derivatives[4] = { zero, zero, zero, zero };
908 for(
size_t k = 0;
k < 9;
k++)
910 derivatives[0] = kern_first[
k] * neighbour_pixel_LF[
k] + derivatives[0];
911 derivatives[1] = kern_second[
k] * neighbour_pixel_LF[
k] + derivatives[1];
912 derivatives[2] = kern_third[
k] * neighbour_pixel_HF[
k] + derivatives[2];
913 derivatives[3] = kern_fourth[
k] * neighbour_pixel_HF[
k] + derivatives[3];
917 dt_aligned_pixel_simd_t update = derivatives[0] *
ABCD[0];
918 update = derivatives[1] *
ABCD[1] + update;
919 update = derivatives[2] *
ABCD[2] + update;
920 update = derivatives[3] *
ABCD[3] + update;
921 const dt_aligned_pixel_simd_t acc = neighbour_pixel_HF[4] * strength_v + update / energy;
924 dt_store_simd_nontemporal(
out + index, dt_simd_max_zero(acc + neighbour_pixel_LF[4]));
932 dt_store_simd_nontemporal(
out + index, dt_simd_max_zero(dt_load_simd_aligned(HF + index)
933 + dt_load_simd_aligned(LF + index)));
936 + dt_load_simd_aligned(LF + index)));
951 return sqf(user_param);
956static void dump_PFM(
const char *filename,
const float*
out,
const uint32_t w,
const uint32_t h)
958 FILE *
f = g_fopen(filename,
"wb");
959 fprintf(
f,
"PF\n%d %d\n-1.0\n", w, h);
960 for(
int j = h - 1 ; j >= 0 ; j--)
961 for(
int i = 0 ;
i < w ;
i++)
962 for(
int c = 0 ;
c < 3 ;
c++)
963 fwrite(
out + (j * w +
i) * 4 + c, 1,
sizeof(
float),
f);
969static inline int wavelets_process(
const float *
const restrict in,
float *
const restrict reconstructed,
970 const uint8_t *
const restrict mask,
const size_t width,
972 const float zoom,
const int scales,
975 float *
const restrict LF_odd,
976 float *
const restrict LF_even)
978 const dt_aligned_pixel_simd_t anisotropy
990 const float regularization = powf(10.f, data->
regularization) - 1.f;
996 float *restrict residual;
1002 for(
int s = 0; s < scales; ++s)
1004 const int mult = 1 << s;
1006 const float *restrict buffer_in;
1007 float *restrict buffer_out;
1012 buffer_out = LF_odd;
1017 buffer_out = LF_even;
1021 buffer_in = LF_even;
1022 buffer_out = LF_odd;
1027 residual = buffer_out;
1031 sprintf(
name,
"/tmp/scale-input-%i.pfm", s);
1034 sprintf(
name,
"/tmp/scale-blur-%i.pfm", s);
1041 float *restrict temp = (residual == LF_even) ? LF_odd : LF_even;
1044 for(
int s = scales - 1; s > -1; --s)
1046 const int mult = 1 << s;
1048 const float real_radius = current_radius * zoom;
1051 const float normalized_regularization =
1052 (data->normalize_band_energy)
1053 ? regularization * sqf(real_radius) / 9.f
1054 : regularization / 9.f;
1056 const float normalized_regularization = regularization / 9.f * sqf(real_radius);
1059 const float norm = expf(-sqf(real_radius - (
float)data->
radius_center) / sqf(data->
radius));
1061 const dt_aligned_pixel_simd_t
ABCD = { data->
first *
KAPPA * norm,
1067 const float *restrict buffer_in;
1068 float *restrict buffer_out;
1072 buffer_in = residual;
1075 else if(count % 2 != 0)
1078 buffer_out = residual;
1082 buffer_in = residual;
1086 if(s == 0) buffer_out = reconstructed;
1089 anisotropy, isotropy_type, variance_threshold, mult,
1100static inline void build_mask(
const float *
const restrict input, uint8_t *
const restrict mask,
1113static inline void inpaint_mask(
float *
const restrict inpainted,
const float *
const restrict original,
1114 const uint8_t *
const restrict mask,
const size_t width,
1124 const uint32_t j =
k -
i;
1134 inpainted[
k + c] = fabsf(gaussian_noise(original[
k + c], original[
k + c],
i % 2 || j % 2,
state));
1139 inpainted[
k + c] = original[
k + c];
1147 const void *
const restrict ivoid,
void *
const restrict
ovoid)
1153 float *restrict in =
DT_IS_ALIGNED((
float *
const restrict)ivoid);
1159 float *restrict temp_in = NULL;
1160 float *restrict temp_out = NULL;
1164 sizeof(uint8_t) * roi_out->
width * roi_out->
height,
1173 const int iterations =
MAX((
int)ceilf((
float)data->
iterations), 1);
1180 for(
int s = 0; s < scales; s++)
1183 if(!HF[s]) out_of_memory =
TRUE;
1198 const int has_mask = (data->
threshold > 0.f);
1211 for(
int it = 0; it < iterations; it++)
1218 else if(it % 2 == 0)
1229 if(it == (
int)iterations - 1)
1233 data, zoom, scales, has_mask, HF, LF_odd, LF_even))
1246 for(
int s = 0; s < scales; s++)
1253 const size_t sizes[3],
const int width,
const int height,
1256 const float zoom,
const int scales,
1264 const dt_aligned_pixel_simd_t anisotropy
1286 const float regularization = powf(10.f, data->
regularization) - 1.f;
1291 for(
int s = 0; s < scales; ++s)
1293 const int mult = 1 << s;
1301 buffer_out = LF_odd;
1306 buffer_out = LF_even;
1310 buffer_in = LF_even;
1311 buffer_out = LF_odd;
1315 const int clamp_lf = 1;
1318 .yoffset = 0, .yfactor = 1,
1319 .cellsize = 4 *
sizeof(float), .overhead = 0,
1320 .sizex = 1 << 16, .sizey = 1 };
1322 hblocksize = hlocopt.
sizex;
1330 .yoffset = 2 * mult, .yfactor = 1,
1331 .cellsize = 4 *
sizeof(float), .overhead = 0,
1332 .sizex = 1, .sizey = 1 << 16 };
1334 vblocksize = vlocopt.
sizey;
1341 const size_t vertical_local[3] = { 1, vblocksize, 1 };
1349 (vblocksize + 4 * mult) * 4 *
sizeof(
float), NULL);
1351 vertical_sizes, vertical_local);
1363 if(err != CL_SUCCESS)
return err;
1368 const size_t horizontal_local[3] = { hblocksize, 1, 1 };
1376 (hblocksize + 4 * mult) * 4 *
sizeof(
float), NULL);
1378 horizontal_sizes, horizontal_local);
1390 if(err != CL_SUCCESS)
return err;
1400 if(err != CL_SUCCESS)
return err;
1402 residual = buffer_out;
1406 cl_mem temp = (residual == LF_even) ? LF_odd : LF_even;
1409 for(
int s = scales - 1; s > -1; --s)
1411 const int mult = 1 << s;
1413 const float real_radius = current_radius * zoom;
1416 const float normalized_regularization =
1417 (data->normalize_band_energy)
1418 ? regularization * sqf(real_radius) / 9.f
1419 : regularization / 9.f;
1421 const float normalized_regularization = regularization / 9.f * sqf(real_radius);
1424 const float norm = expf(-sqf(real_radius - (
float)data->
radius_center) / sqf(data->
radius));
1426 const dt_aligned_pixel_simd_t
ABCD = { data->
first *
KAPPA * norm,
1437 buffer_in = residual;
1440 else if(count % 2 != 0)
1443 buffer_out = residual;
1447 buffer_in = residual;
1451 if(s == 0) buffer_out = reconstructed;
1469 if(err != CL_SUCCESS)
return err;
1484 int out_of_memory =
FALSE;
1488 const int devid = pipe->
devid;
1499 cl_mem temp_in = NULL;
1500 cl_mem temp_out = NULL;
1509 const int iterations =
MAX((
int)ceilf((
float)data->
iterations), 1);
1514 for(
int s = 0; s < scales; s++)
1517 if(!HF[s]) out_of_memory =
TRUE;
1528 err = CL_MEM_OBJECT_ALLOCATION_FAILURE;
1532 const int has_mask = (data->
threshold > 0.f);
1543 if(err != CL_SUCCESS)
goto error;
1552 if(err != CL_SUCCESS)
goto error;
1557 for(
int it = 0; it < iterations; it++)
1564 else if(it % 2 == 0)
1575 if(it == (
int)iterations - 1) temp_out = dev_out;
1577 data, gd, zoom, scales, has_mask, HF, LF_odd, LF_even);
1578 if(err != CL_SUCCESS)
goto error;
1604 const int program = 33;
1612 const int wavelets = 35;
1647 gtk_widget_set_tooltip_text(
g->iterations,
1648 _(
"more iterations make the effect stronger but the module slower.\n"
1649 "this is analogous to giving more time to the diffusion reaction.\n"
1650 "if you plan on sharpening or inpainting, \n"
1651 "more iterations help reconstruction."));
1656 gtk_widget_set_tooltip_text(
1657 g->radius_center, _(
"main scale of the diffusion.\n"
1658 "zero makes diffusion act on the finest details more heavily.\n"
1659 "non-zero defines the size of the details to diffuse heavily.\n"
1660 "for deblurring and denoising, set to zero.\n"
1661 "increase to act on local contrast instead."));
1666 gtk_widget_set_tooltip_text(
1667 g->radius, _(
"width of the diffusion around the central radius.\n"
1668 "high values diffuse on a large band of radii.\n"
1669 "low values diffuse closer to the central radius.\n"
1670 "if you plan on deblurring, \n"
1671 "the radius should be around the width of your lens blur."));
1679 gtk_widget_set_tooltip_text(
g->first, _(
"diffusion speed of low-frequency wavelet layers\n"
1680 "in the direction of 1st order anisotropy (set below).\n\n"
1681 "negative values sharpen, \n"
1682 "positive values diffuse and blur, \n"
1683 "zero does nothing."));
1688 gtk_widget_set_tooltip_text(
g->second, _(
"diffusion speed of low-frequency wavelet layers\n"
1689 "in the direction of 2nd 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->third, _(
"diffusion speed of high-frequency wavelet layers\n"
1698 "in the direction of 3rd 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->fourth, _(
"diffusion speed of high-frequency wavelet layers\n"
1707 "in the direction of 4th order anisotropy (set below).\n\n"
1708 "negative values sharpen, \n"
1709 "positive values diffuse and blur, \n"
1710 "zero does nothing."));
1718 gtk_widget_set_tooltip_text(
g->anisotropy_first, _(
"direction of 1st order speed (set above).\n\n"
1719 "negative values follow gradients more closely, \n"
1720 "positive values rather avoid edges (isophotes), \n"
1721 "zero affects both equally (isotropic)."));
1726 gtk_widget_set_tooltip_text(
g->anisotropy_second,_(
"direction of 2nd order speed (set above).\n\n"
1727 "negative values follow gradients more closely, \n"
1728 "positive values rather avoid edges (isophotes), \n"
1729 "zero affects both equally (isotropic)."));
1734 gtk_widget_set_tooltip_text(
g->anisotropy_third,_(
"direction of 3rd order speed (set above).\n\n"
1735 "negative values follow gradients more closely, \n"
1736 "positive values rather avoid edges (isophotes), \n"
1737 "zero affects both equally (isotropic)."));
1742 gtk_widget_set_tooltip_text(
g->anisotropy_fourth,_(
"direction of 4th order speed (set above).\n\n"
1743 "negative values follow gradients more closely, \n"
1744 "positive values rather avoid edges (isophotes), \n"
1745 "zero affects both equally (isotropic)."));
1751 gtk_widget_set_tooltip_text(
g->sharpness,
1752 _(
"increase or decrease the sharpness of the highest frequencies.\n"
1753 "can be used to keep details after blooming,\n"
1754 "for standalone sharpening set speed to negative values."));
1757 gtk_widget_set_tooltip_text(
g->regularization,
1758 _(
"define the sensitivity of the variance penalty for edges.\n"
1759 "increase to exclude more edges from diffusion,\n"
1760 "if fringes or halos appear."));
1763 gtk_widget_set_tooltip_text(
g->variance_threshold,
1764 _(
"define the variance threshold between edge amplification and penalty.\n"
1765 "decrease if you want pixels on smooth surfaces get a boost,\n"
1766 "increase if you see noise appear on smooth surfaces or\n"
1767 "if dark areas seem oversharpened compared to bright areas."));
1775 gtk_widget_set_tooltip_text(
g->threshold,
1776 _(
"luminance threshold for the mask.\n"
1777 "0. disables the luminance masking and applies the module on the whole image.\n"
1778 "any higher value excludes pixels with luminance lower than the threshold.\n"
1779 "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)
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 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__