22#ifndef DT_PIXEL_BSPLINE_H
23#define DT_PIXEL_BSPLINE_H
34#define BSPLINE_FSIZE 5
38#define B_SPLINE_SIGMA 1.0553651328015339f
44 return 2.f / sqf(
sigma);
49#define B_SPLINE_TO_LAPLACIAN 3.182727439285017f
50#define B_SPLINE_TO_LAPLACIAN_2 10.129753952777762f
70 float radius = sigma_filter;
71 while(radius < sigma_final)
74 radius = sqrtf(sqf(radius) + sqf((
float)(1 << s) * sigma_filter));
81 return (
size - 1u) / 2u + 1u;
98 result[c] =
MAX(0.0f, filter[0] * buf[indices[0] + c] +
99 filter[1] * buf[indices[1] + c] +
100 filter[2] * buf[indices[2] + c] +
101 filter[3] * buf[indices[3] + c] +
102 filter[4] * buf[indices[4] + c]);
109 result[c] = filter[0] * buf[indices[0] + c] +
110 filter[1] * buf[indices[1] + c] +
111 filter[2] * buf[indices[2] + c] +
112 filter[3] * buf[indices[3] + c] +
113 filter[4] * buf[indices[4] + c];
118 size_t row,
size_t width,
size_t height,
int mult,
const gboolean clip_negatives)
123 indices[0] = 4 *
width *
MAX((
int)
row - 2 * mult, 0);
128 for(
size_t j = 0; j <
width; j++)
137 size_t col,
size_t width,
int mult, const gboolean clip_negatives)
142 indices[0] = 4 *
MAX((
int)col - 2 * mult, 0);
143 indices[1] = 4 *
MAX((
int)col - mult, 0);
144 indices[2] = 4 * col;
145 indices[3] = 4 *
MIN(col + mult,
width-1);
146 indices[4] = 4 *
MIN(col + 2 * mult,
width-1);
154 const
size_t col, const
size_t width,
155 const gboolean clip_negatives)
160 const size_t center = col * 2u;
162 indices[0] = 4 *
MAX((
int)center - 2, 0);
163 indices[1] = 4 *
MAX((
int)center - 1, 0);
164 indices[2] = 4 * center;
165 indices[3] = 4 *
MIN(center + 1,
width - 1);
166 indices[4] = 4 *
MIN(center + 2,
width - 1);
171 float *
const restrict tempbuf,
const size_t padded_size,
172 const gboolean clip_negatives)
176 const gboolean use_replicated_boundary = (coarse_width > 2u && coarse_height > 2u);
185 for(
size_t row = 0;
row < coarse_height; ++
row)
187 for(
size_t col = 0; col < coarse_width; ++col)
190 const size_t sample_row = use_replicated_boundary ? CLAMP((
int)
row, 1, (
int)coarse_height - 2) :
row;
191 const size_t sample_col = use_replicated_boundary ? CLAMP((
int)col, 1, (
int)coarse_width - 2) : col;
192 const size_t center_row = sample_row * 2u;
193 const size_t center_col = sample_col * 2u;
198 for(
int jj = -2; jj <= 2; ++jj)
200 const size_t yy = CLAMP((
int)center_row + jj, 0, (
int)
height - 1);
201 for(
int ii = -2; ii <= 2; ++ii)
203 const size_t xx = CLAMP((
int)center_col + ii, 0, (
int)
width - 1);
204 const float weight = filter[ii + 2] * filter[jj + 2];
205 const size_t index = 4 * (yy *
width + xx);
207 accum[c] +=
weight * in[index + c];
211 const size_t out_index = 4 * (
row * coarse_width + col);
215 out[out_index + c] =
MAX(accum[c], 0.f);
226 const gboolean clip_negatives)
230 const gboolean use_replicated_boundary = (
width > 2u &&
height > 2u && coarse_width > 1u && coarse_height > 1u);
238 for(
size_t col = 0; col <
width; ++col)
240 size_t sample_row =
row;
241 size_t sample_col = col;
242 if(use_replicated_boundary)
246 sample_row = CLAMP((
int)
row, 1, (
int)max_row);
247 sample_col = CLAMP((
int)col, 1, (
int)max_col);
250 const size_t center_row = sample_row >> 1;
251 const size_t center_col = sample_col >> 1;
256 switch((sample_col & 1u) + 2u * (sample_row & 1u))
260 for(
int jj = -1; jj <= 1; ++jj)
261 for(
int ii = -1; ii <= 1; ++ii)
263 const size_t yy = center_row + jj;
264 const size_t xx = center_col + ii;
265 const float weight = 4.f * filter[2 * (jj + 1)] * filter[2 * (ii + 1)];
266 const size_t index = 4 * (yy * coarse_width + xx);
268 accum[c] +=
weight * in[index + c];
274 for(
int jj = -1; jj <= 1; ++jj)
275 for(
int ii = 0; ii <= 1; ++ii)
277 const size_t yy = center_row + jj;
278 const size_t xx = center_col + ii;
279 const float weight = 4.f * filter[2 * (jj + 1)] * filter[2 * ii + 1];
280 const size_t index = 4 * (yy * coarse_width + xx);
282 accum[c] +=
weight * in[index + c];
288 for(
int jj = 0; jj <= 1; ++jj)
289 for(
int ii = -1; ii <= 1; ++ii)
291 const size_t yy = center_row + jj;
292 const size_t xx = center_col + ii;
293 const float weight = 4.f * filter[2 * jj + 1] * filter[2 * (ii + 1)];
294 const size_t index = 4 * (yy * coarse_width + xx);
296 accum[c] +=
weight * in[index + c];
302 for(
int jj = 0; jj <= 1; ++jj)
303 for(
int ii = 0; ii <= 1; ++ii)
305 const size_t yy = center_row + jj;
306 const size_t xx = center_col + ii;
307 const float weight = 4.f * filter[2 * jj + 1] * filter[2 * ii + 1];
308 const size_t index = 4 * (yy * coarse_width + xx);
310 accum[c] +=
weight * in[index + c];
316 const size_t out_index = 4 * (
row *
width + col);
320 out[out_index + c] =
MAX(accum[c], 0.f);
330 float *
const restrict tempbuf,
331 const size_t width,
const size_t height,
const int mult,
const gboolean clip_negatives)
344 for(
size_t j = 0; j <
width; j++)
352 float *
const restrict HF,
353 float *
const restrict LF,
354 const size_t width,
const size_t height,
const int mult,
355 float *
const tempbuf,
size_t padded_size)
368 for(
size_t j = 0; j <
width; j++)
370 const size_t index = 4U * (
i *
width + j);
374 HF[index + c] = in[index + c] - LF[index + c];
static unsigned int num_steps_to_reach_equivalent_sigma(const float sigma_filter, const float sigma_final)
static void _bspline_horizontal_decimated(const float *const restrict temp, float *const restrict out, const size_t col, const size_t width, const gboolean clip_negatives)
static void reduce_2D_Bspline(const float *const restrict in, float *const restrict out, const size_t width, const size_t height, float *const restrict tempbuf, const size_t padded_size, const gboolean clip_negatives)
static void _bspline_horizontal(const float *const restrict temp, float *const restrict out, size_t col, size_t width, int mult, const gboolean clip_negatives)
static void sparse_scalar_product(const dt_aligned_pixel_t buf, const size_t indices[5], dt_aligned_pixel_t result, const gboolean clip_negatives)
static float equivalent_sigma_at_step(const float sigma, const unsigned int s)
static void blur_2D_Bspline(const float *const restrict in, float *const restrict out, float *const restrict tempbuf, const size_t width, const size_t height, const int mult, const gboolean clip_negatives)
static void expand_2D_Bspline(const float *const restrict in, float *const restrict out, const size_t width, const size_t height, const gboolean clip_negatives)
static float normalize_laplacian(const float sigma)
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 size_t decimated_bspline_size(const size_t size)
static void _bspline_vertical_pass(const float *const restrict in, float *const restrict temp, size_t row, size_t width, size_t height, int mult, const gboolean clip_negatives)
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
const dt_colormatrix_t dt_aligned_pixel_t out
static int dwt_interleave_rows(const int rowid, const int height, const int stride)
static void weight(const float *c1, const float *c2, const float sharpen, dt_aligned_pixel_t weight)
#define DT_ALIGNED_ARRAY
Align an object on a cacheline boundary, so AVX2 can load it whole.
static int dt_get_thread_num()
Index of the calling thread within its parallel region, 0 outside one.
#define __OMP_DECLARE_SIMD__(...)
#define __OMP_PARALLEL_FOR__(...)
#define dt_get_perthread(buf, padsize)
DT_ALIGNED_PIXEL float dt_aligned_pixel_t[4]
#define for_each_channel(_var,...)
static void copy_pixel_nontemporal(float *const __restrict__ out, const float *const __restrict__ in)
#define for_four_channels(_var,...)