Page MenuHome
Paste P2880

Quick gaussian blur
ActivePublic

Authored by Lukas Stockner (lukasstockner97) on Apr 4 2022, 2:30 AM.
void IMB_filter_convolve(const ImBuf *source, ImBuf *dest, const float *kernel, int kernel_width)
{
unsigned char *input = (unsigned char *)source->rect;
unsigned char *output = (unsigned char *)dest->rect;
BLI_assert(input && output);
/* Note: This is not particularly optimized. */
int width = source->x;
int height = source->y;
int stride = source->x;
/* Vertical convolution step. */
float *temp_row_v = MEM_mallocN(4 * width * sizeof(float), __func__);
for (int y = 0; y < height; y++) {
memset(temp_row_v, 0, 4 * width * sizeof(float));
for (int dy = max_ii(-kernel_width + 1, -y); dy < min_ii(kernel_width, height - y); dy++) {
for (int x = 0; x < width; x++) {
float pixel[4];
srgb_to_linearrgb_uchar4(pixel, &input[4 * ((y + dy)*stride + x)]);
madd_v4_v4fl(temp_row_v + 4*x, pixel, kernel[abs(dy)]);
}
}
for (int x = 0; x < width; x++) {
linearrgb_to_srgb_uchar4(&output[4 * (y*stride + x)], temp_row_v + 4*x);
}
}
MEM_freeN(temp_row_v);
/* Horizontal convolution step. */
unsigned char *temp_row_h = MEM_mallocN(4 * width * sizeof(unsigned char), __func__);
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
float accum[4], pixel[4];
zero_v4(accum);
for (int dx = max_ii(-kernel_width + 1, -x); dx < min_ii(kernel_width, width - x); dx++) {
srgb_to_linearrgb_uchar4(pixel, &output[4 * (y*stride + x + dx)]);
madd_v4_v4fl(accum, pixel, kernel[abs(dx)]);
}
linearrgb_to_srgb_uchar4(&temp_row_h[4 * x], accum);
}
memcpy(output + 4*y*stride, temp_row_h, 4 * width * sizeof(unsigned char));
}
MEM_freeN(temp_row_h);
}
void IMB_filter_gaussian(const struct ImBuf *source, struct ImBuf *dest, float sigma)
{
int w = 3 * ((int) sigma);
float *kernel = MEM_mallocN(sizeof(float) * w, __func__);
/* Compute gaussian kernel. */
float fac1 = 0.5f / (sigma * sigma), fac2 = 1.0f / (sqrtf(2.0f * M_PI) * sigma);
float scale = 0.0f;
for (int i = 0; i < w; i++) {
kernel[i] = fac2 * expf(-i*i * fac1);
scale += kernel[i];
if (i > 0) {
scale += kernel[i];
}
}
/* Normalize kernel. */
scale = 1.0f / scale;
for (int i = 0; i < w; i++) {
kernel[i] *= scale;
}
IMB_filter_convolve(source, dest, kernel, w);
MEM_freeN(kernel);
}

Event Timeline