56#define SLICE_HEIGHT 60
80#if !(defined(__x86_64__) || defined(__i386__))
81# define _mm_prefetch(where,hint)
84static inline float gh(
const float f)
89static inline int sign(
int a)
91 return (a > 0) - (a < 0);
95static int scatter(
const float scale,
const float scattering,
const int index1,
const int index2)
101 const int abs_i1 = abs(index1);
102 const int abs_i2 = abs(index2);
103 return scale * ((abs_i1 * abs_i1 * abs_i1 + 7.0 * abs_i1 * sqrt(abs_i2)) *
sign(index1) * scattering / 6.0 + index1);
110 const int search_radius = params->search_radius;
111 const float scale = params->scale;
112 const float scattering = params->scattering;
113 int decimate = params->decimate;
115 int n_patches = (2 * search_radius + 1) * (2 * search_radius + 1);
117 n_patches = (n_patches + 1) / 2;
118 *num_patches = n_patches ;
126 for (
int row_index = -search_radius; row_index <= search_radius; row_index++)
128 for (
int col_index = -search_radius; col_index <= search_radius; col_index++)
130 if (decimate && (++decimate & 1))
continue;
131 int r =
scatter(scale,scattering,row_index,col_index);
132 int c =
scatter(scale,scattering,col_index,row_index);
133 patches[patch_num].
rows =
r;
134 patches[patch_num].
cols = c;
135 if (
r > shift) shift =
r;
136 else if (-
r > shift) shift = -
r;
137 if (c > shift) shift = c;
138 else if (-c > shift) shift = -c;
139 patches[patch_num].
offset = (
r * stride + c * 4);
151 const int width = 2 * radius + 1;
161 const float diff = pix1[
i] - pix2[
i];
162 sum[
i] = diff * diff * norm[
i];
164 return sum[0] + sum[1] + sum[2];
169 const float*
const pix3,
const float* pix4,
175 const float diff1 = pix1[
i] - pix2[
i];
176 const float diff2 = pix3[
i] - pix4[
i];
177 sum[
i] = (diff1 * diff1 - diff2 * diff2) * norm[
i];
179 return sum[0] + sum[1] + sum[2];
182#if defined(CACHE_PIXDIFFS) || defined(CACHE_PIXDIFFS_SSE)
183static inline float get_pixdiff(
const float *
const col_sums,
const int radius,
const int row,
const int col)
185 const int stride = 2*(radius+1);
186 const int modrow = 1 + (
row + stride) % stride;
187 const float *
const pixrow = col_sums + (
SLICE_WIDTH + 2*radius)*modrow;
192#if defined(CACHE_PIXDIFFS) || defined(CACHE_PIXDIFFS_SSE)
193static inline void set_pixdiff(
float *
const col_sums,
const int radius,
const int row,
const int col,
196 const int stride = 2*(radius+1);
197 const int modrow = 1 + (
row + stride) % stride;
198 float *
const pixrow = col_sums + (
SLICE_WIDTH + 2*radius)*modrow;
203#if defined(CACHE_PIXDIFFS) || defined(CACHE_PIXDIFFS_SSE)
204static inline float pixdiff_column_sum(
const float *
const col_sums,
const int radius,
const int col)
207 float sum = col_sums[stride+col];
208 for (
int i = 2;
i <= (2*radius+1) ;
i++)
209 sum += col_sums[
i*stride+col];
215 const int row,
const int chunk_left,
const int chunk_right,
216 const int height,
const int width,
const int stride,
217 const int radius,
const float *
const norm)
225 const int scol = patch->
cols;
226 const int col_min = chunk_left -
MIN(radius,
MIN(chunk_left,chunk_left+scol));
227 const int col_max = chunk_right +
MIN(radius,
MIN(
width-chunk_right,
width-(chunk_right+scol)));
229 const int srow = patch->
rows;
232 for (
int col = chunk_left-radius-1; col <
MIN(col_min,chunk_right+radius); col++)
236 for(
int i =
row-radius;
i <=
row+radius;
i++)
237 set_pixdiff(col_sums,radius,
i,col,0.0f);
240 for (
int col = col_min; col < col_max; col++)
243 for (
int r = rmin;
r <= rmax;
r++)
245 const float *pixel = in +
r*stride + 4*col;
248 set_pixdiff(col_sums,radius,
r,col,diff);
255 for (
int col =
MAX(col_min,col_max); col < chunk_right + radius; col++)
259 for(
int i =
row-radius;
i <=
row+radius;
i++)
260 set_pixdiff(col_sums,radius,
i,col,0.0f);
274 for (
int incr = 1; incr < 10; incr++)
279 else if (plus_rem > best)
287 else if (minus_rem > best)
302 int rem =
width % sl_width;
307 rem =
width % sl_width;
322 const dt_aligned_pixel_t invert = { 1.0f - params->luma, 1.0f - params->chroma, 1.0f - params->chroma, 0.0f };
323 const bool skip_blend = (params->luma == 1.0 && params->chroma == 1.0);
330 const size_t stride = 4 * roi_in->
width;
335 const int radius = params->patch_radius;
336#if defined(CACHE_PIXDIFFS)
337 const size_t scratch_size = (2*radius+3)*(
SLICE_WIDTH + 2*radius + 1);
339 const size_t scratch_size =
SLICE_WIDTH + 2*radius + 1 + 48;
341 size_t padded_scratch_size;
348 for (
int chunk_top = 0 ; chunk_top < roi_out->
height; chunk_top += chk_height)
350 for (
int chunk_left = 0; chunk_left < roi_out->
width; chunk_left += chk_width)
354 float *
const restrict tmpbuf =
dt_get_perthread(scratch_buf, padded_scratch_size);
355 float *
const col_sums = tmpbuf + (radius+1) - chunk_left;
357 const int chunk_bot =
MIN(chunk_top + chk_height, roi_out->
height);
359 const int chunk_right =
MIN(chunk_left + chk_width, roi_out->
width);
361 for (
int i = chunk_top;
i < chunk_bot;
i++)
363 memset(outbuf + 4*(
i*roi_out->
width+chunk_left),
'\0',
sizeof(
float) * 4 * (chunk_right-chunk_left));
366 for (
int p = 0;
p < num_patches;
p++)
372 const int row_min =
MAX(chunk_top,
MAX(0,-patch->
rows));
376 const int row_top =
MAX(row_min,
MAX(radius,radius-patch->
rows));
380 const int scol = patch->
cols;
381 const int col_min =
MAX(chunk_left,-scol);
382 const int col_max =
MIN(chunk_right,roi_out->
width - scol);
385 stride,radius,params->norm);
386 for (
int row = row_min;
row < row_max;
row++)
389 float distortion = 0.0;
390 for (
int i = col_min - radius;
i <
MIN(col_min+radius, col_max);
i++)
392 distortion += col_sums[
i];
395 const float *in = inbuf + stride *
row;
396 float *
const out = outbuf + (size_t)4 *
width *
row;
398 const float sharpness = params->sharpness;
399 if (params->center_weight < 0)
402 for (
int col = col_min; col < col_max; col++)
404 distortion += (col_sums[col+radius] - col_sums[col-radius-1]);
405 const float wt =
gh(distortion * sharpness);
406 const float *
const inpx = in+4*col;
410 out[4*col+c] += pixel[c] * wt;
418 for (
int col = col_min; col < col_max; col++)
420 distortion += (col_sums[col+radius] - col_sums[col-radius-1]);
422 / (1.0f + params->center_weight);
423 const float wt =
gh(fmaxf(0.0f, dissimilarity * sharpness - 2.0f));
424 const float *
const inpx = in + 4*col;
428 out[4*col+c] += pixel[c] * wt;
433 const int pcol_min = chunk_left -
MIN(radius,
MIN(chunk_left,chunk_left+scol));
434 const int pcol_max = chunk_right +
MIN(radius,
MIN(
width-chunk_right,
width-(chunk_right+scol)));
435 if (
row <
MIN(row_top, row_bot))
438 const float *bot_row = inbuf + (
row+1+radius)*stride;
439 for (
int col = pcol_min; col < pcol_max; col++)
441 const float *
const bot_px = bot_row + 4*col;
445 set_pixdiff(col_sums,radius,
row+radius+1,col,diff);
447 col_sums[col] += diff;
451 else if (
row < row_bot)
453#ifndef CACHE_PIXDIFFS
454 const float *
const top_row = inbuf + (
row-radius)*stride ;
456 const float *
const bot_row = inbuf + (
row+1+radius)*stride ;
458 for (
int col = pcol_min; col < pcol_max; col++)
461 const float *
const bot_px = bot_row + 4*col;
463 col_sums[col] += diff - get_pixdiff(col_sums,radius,
row-radius,col);
465 set_pixdiff(col_sums,radius,
row+1+radius,col,diff);
467 const float *
const top_px = top_row + 4*col;
468 const float *
const bot_px = bot_row + 4*col;
471 col_sums[col] += diff;
476 else if (
row >= row_top &&
row + 1 < row_max)
479#ifndef CACHE_PIXDIFFS
480 const float *top_row = inbuf + (
row-radius)*stride;
482 for (
int col = pcol_min; col < pcol_max; col++)
485 col_sums[col] -= get_pixdiff(col_sums,radius,
row-radius,col);
487 const float *
const top_px = top_row + 4*col;
497 for (
int row = chunk_top;
row < chunk_bot;
row++)
499 float *
const out = outbuf + 4 *
row * roi_out->
width;
500 for (
int col = chunk_left; col < chunk_right; col++)
504 out[4*col+c] /=
out[4*col+3];
512 for (
int row = chunk_top;
row < chunk_bot;
row++)
514 const float *in = inbuf +
row * stride;
516 for (
int col = chunk_left; col < chunk_right; col++)
520 out[4*col+c] = (in[4*col+c] * invert[c]) + (
out[4*col+c] /
out[4*col+3] *
weight[c]);
543 unsigned int current = *
state;
544 unsigned int next = (current >=
max - 1 ? 0 : current + 1);
554 const int horiz_kernel,
const int vert_kernel)
558 .cellsize =
sizeof(float), .overhead = 0,
559 .sizex = 1 << 16, .sizey = 1 };
565 .cellsize =
sizeof(float), .overhead = 0,
566 .sizex = 1, .sizey = 1 << 16 };
589 const int P,
const int q[2],
const int height,
const int width,
590 const int bwidth,
const int hblocksize)
593 const size_t local[3] = { hblocksize, 1, 1 };
608 cl_mem dev_out,
const int q[2],
const int height,
const int width,
609 const size_t sizes[3])
623 cl_mem dev_in, cl_mem dev_out,
const dt_iop_roi_t *
const roi_in)
627 const int P = params->patch_radius;
628 const float nL2 = params->norm[0] * params->norm[0];
629 const float nC2 = params->norm[1] * params->norm[1];
632 const size_t stride = 4 * roi_in->
width;
639 unsigned int state = 0;
643 if(buckets[
k] == NULL)
goto error;
648 get_blocksizes(&hblocksize, &vblocksize,
P, devid, params->kernel_horiz, params->kernel_vert);
652 if(err != CL_SUCCESS)
goto error;
658 for(
int p = 0;
p < num_patches;
p++)
661 int q[2] = { patch->
rows, patch->
cols };
673 if(err != CL_SUCCESS)
break;
678 if(err != CL_SUCCESS)
break;
682 const size_t local[3] = { 1, vblocksize, 1 };
683 const float sharpness = params->sharpness;
694 if(err != CL_SUCCESS)
break;
698 if(err != CL_SUCCESS)
break;
717 cl_mem dev_in, cl_mem dev_out,
const dt_iop_roi_t *
const roi_in)
721 const int P = params->patch_radius;
722 const float norm = params->sharpness;
725 const size_t stride = 4 * roi_in->
width;
732 unsigned int state = 0;
736 if(buckets[
k] == NULL)
goto error;
741 get_blocksizes(&hblocksize, &vblocksize,
P, devid, params->kernel_horiz, params->kernel_vert);
745 if(err != CL_SUCCESS)
goto error;
751 for(
int p = 0;
p < num_patches;
p++)
754 int q[2] = { patch->
rows, patch->
cols };
764 if(err != CL_SUCCESS)
break;
769 if(err != CL_SUCCESS)
break;
773 const size_t local[3] = { 1, vblocksize, 1 };
774 const float central_pixel_weight = params->center_weight;
787 if(err != CL_SUCCESS)
break;
791 if(err != CL_SUCCESS)
break;
static void error(char *msg)
const dt_colormatrix_t dt_aligned_pixel_t out
int dt_get_num_openmp_threads(void)
Number of OpenMP threads the application decided to use.
static void weight(const float *c1, const float *c2, const float sharpen, dt_aligned_pixel_t weight)
void dt_iop_nap(int32_t usec)
static float kernel(const float *x, const float *y)
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...
static float dt_fast_mexp2f(const float x)
static int bucket_next(unsigned int *state, unsigned int max)
__DT_CLONE_TARGETS__ void nlmeans_denoise(const float *const inbuf, float *const outbuf, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const dt_nlmeans_param_t *const params)
static float gh(const float f)
static void init_column_sums(float *const col_sums, const patch_t *const patch, const float *const in, const int row, const int chunk_left, const int chunk_right, const int height, const int width, const int stride, const int radius, const float *const norm)
static float pixel_difference(const float *const pix1, const float *pix2, const dt_aligned_pixel_t norm)
static int compute_slice_height(const int height)
static void get_blocksizes(int *h, int *v, const int radius, const int devid, const int horiz_kernel, const int vert_kernel)
static cl_int nlmeans_cl_accu(const int devid, const int kernel, cl_mem dev_in, cl_mem dev_U4_tt, cl_mem dev_out, const int q[2], const int height, const int width, const size_t sizes[3])
static int scatter(const float scale, const float scattering, const int index1, const int index2)
int nlmeans_denoise_cl(const dt_nlmeans_param_t *const params, const int devid, cl_mem dev_in, cl_mem dev_out, const dt_iop_roi_t *const roi_in)
int nlmeans_denoiseprofile_cl(const dt_nlmeans_param_t *const params, const int devid, cl_mem dev_in, cl_mem dev_out, const dt_iop_roi_t *const roi_in)
#define _mm_prefetch(where, hint)
static struct patch_t * define_patches(const dt_nlmeans_param_t *const params, const int stride, int *num_patches, int *max_shift)
static float compute_center_pixel_norm(const float center_weight, const int radius)
static cl_int nlmeans_cl_horiz(const int devid, const int kernel, cl_mem dev_U4, cl_mem dev_U4_t, const int P, const int q[2], const int height, const int width, const int bwidth, const int hblocksize)
static int compute_slice_width(const int width)
static float diff_of_pixels_diff(const float *const pix1, const float *pix2, const float *const pix3, const float *pix4, const dt_aligned_pixel_t norm)
static cl_int nlmeans_cl_init(const int devid, const int kernel, cl_mem dev_out, const int height, const int width)
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_buffer(const int devid, const size_t size)
int dt_opencl_micro_nap(const int devid)
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 __OMP_PARALLEL_FOR__(...)
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
#define dt_pixelpipe_cache_free_align(mem)
#define dt_get_perthread(buf, padsize)
#define dt_pixelpipe_cache_alloc_perthread_float(n, padded_size)
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
#define for_each_channel(_var,...)
static const dt_aligned_pixel_simd_t sign
#define for_four_channels(_var,...)
const float uint32_t state[4]
Region of interest passed through the pixelpipe.
#define __DT_CLONE_TARGETS__