Skip to content

Commit

Permalink
Add preserve_alpha to box_blur
Browse files Browse the repository at this point in the history
This allows the user to disable alpha blur so the filter works as
expected with mask_start/mask_apply
  • Loading branch information
bmatherly committed Aug 19, 2023
1 parent b2787f9 commit 3cfc21e
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 15 deletions.
5 changes: 3 additions & 2 deletions src/modules/core/filter_box_blur.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* filter_box_blur.c
* Copyright (C) 2011-2021 Meltytech, LLC
* Copyright (C) 2011-2023 Meltytech, LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
Expand Down Expand Up @@ -41,6 +41,7 @@ static int filter_get_image(mlt_frame frame,
mlt_profile profile = mlt_service_profile(MLT_FILTER_SERVICE(filter));
double hradius = mlt_properties_anim_get_double(properties, "hradius", position, length);
double vradius = mlt_properties_anim_get_double(properties, "vradius", position, length);
int preserve_alpha = mlt_properties_get_int(properties, "preserve_alpha");
// Convert from percent to pixels as a factor of 10% image width.
double pixelScale = (double) profile->width * mlt_profile_scale_width(profile, *width) / 1000.0;
hradius = MAX(round(hradius * pixelScale), 0);
Expand All @@ -56,7 +57,7 @@ static int filter_get_image(mlt_frame frame,
if (error == 0) {
struct mlt_image_s img;
mlt_image_set_values(&img, *image, *format, *width, *height);
mlt_image_box_blur(&img, hradius, vradius);
mlt_image_box_blur(&img, hradius, vradius, preserve_alpha);
}
}
return error;
Expand Down
9 changes: 8 additions & 1 deletion src/modules/core/filter_box_blur.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ schema_version: 7.0
type: filter
identifier: box_blur
title: Box Blur
version: 1
version: 2
copyright: Meltytech, LLC
license: LGPLv2.1
language: en
Expand Down Expand Up @@ -33,3 +33,10 @@ parameters:
animation: yes
minimum: 0
default: 1

- identifier: preserve_alpha
title: Preserve Alpha
type: boolean
description: Exclude the alpha channel from the blur operation
mutable: yes
default: 0
4 changes: 2 additions & 2 deletions src/modules/core/filter_pillar_echo.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* filter_pillar_echo.c -- filter to interpolate pixels outside an area of interest
* Copyright (c) 2020-2021 Meltytech, LLC
* Copyright (c) 2020-2023 Meltytech, LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
Expand Down Expand Up @@ -265,7 +265,7 @@ static int filter_get_image(mlt_frame frame,

bilinear_scale_rgba(&src, &dst, rect);
if (blur != 0) {
mlt_image_box_blur(&dst, blur, blur);
mlt_image_box_blur(&dst, blur, blur, 0);
}
blit_rect(&src, &dst, rect);

Expand Down
164 changes: 156 additions & 8 deletions src/modules/core/image_proc.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Meltytech, LLC
* Copyright (c) 2022-2023 Meltytech, LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
Expand Down Expand Up @@ -30,7 +30,7 @@ typedef struct
int radius;
} blur_slice_desc;

static int blur_h_proc(int id, int index, int jobs, void *data)
static int blur_h_proc_rgba(int id, int index, int jobs, void *data)
{
(void) id; // unused
blur_slice_desc *desc = ((blur_slice_desc *) data);
Expand Down Expand Up @@ -108,7 +108,7 @@ static int blur_h_proc(int id, int index, int jobs, void *data)
return 0;
}

static int blur_v_proc(int id, int index, int jobs, void *data)
static int blur_v_proc_rgba(int id, int index, int jobs, void *data)
{
(void) id; // unused
blur_slice_desc *desc = ((blur_slice_desc *) data);
Expand Down Expand Up @@ -186,6 +186,146 @@ static int blur_v_proc(int id, int index, int jobs, void *data)
return 0;
}

static int blur_h_proc_rgbx(int id, int index, int jobs, void *data)
{
(void) id; // unused
blur_slice_desc *desc = ((blur_slice_desc *) data);
int slice_line_start,
slice_height = mlt_slices_size_slice(jobs, index, desc->src->height, &slice_line_start);
int slice_line_end = slice_line_start + slice_height;
int accumulator[] = {0, 0, 0};
int x = 0;
int y = 0;
int step = 4;
int linesize = step * desc->src->width;
int radius = desc->radius;

if (desc->radius > (desc->src->width / 2)) {
radius = desc->src->width / 2;
}
double diameter = (radius * 2) + 1;

for (y = slice_line_start; y < slice_line_end; y++) {
uint8_t *first = desc->src->data + (y * linesize);
uint8_t *last = first + linesize - step;
uint8_t *s1 = first;
uint8_t *s2 = first;
uint8_t *d = desc->dst->data + (y * linesize);
accumulator[0] = first[0] * (radius + 1);
accumulator[1] = first[1] * (radius + 1);
accumulator[2] = first[2] * (radius + 1);

for (x = 0; x < radius; x++) {
accumulator[0] += s1[0];
accumulator[1] += s1[1];
accumulator[2] += s1[2];
s1 += step;
}
for (x = 0; x <= radius; x++) {
accumulator[0] += s1[0] - first[0];
accumulator[1] += s1[1] - first[1];
accumulator[2] += s1[2] - first[2];
d[0] = lrint((double) accumulator[0] / diameter);
d[1] = lrint((double) accumulator[1] / diameter);
d[2] = lrint((double) accumulator[2] / diameter);
s1 += step;
d += step;
}
for (x = radius + 1; x < desc->src->width - radius; x++) {
accumulator[0] += s1[0] - s2[0];
accumulator[1] += s1[1] - s2[1];
accumulator[2] += s1[2] - s2[2];
d[0] = lrint((double) accumulator[0] / diameter);
d[1] = lrint((double) accumulator[1] / diameter);
d[2] = lrint((double) accumulator[2] / diameter);
s1 += step;
s2 += step;
d += step;
}
for (x = desc->src->width - radius; x < desc->src->width; x++) {
accumulator[0] += last[0] - s2[0];
accumulator[1] += last[1] - s2[1];
accumulator[2] += last[2] - s2[2];
d[0] = lrint((double) accumulator[0] / diameter);
d[1] = lrint((double) accumulator[1] / diameter);
d[2] = lrint((double) accumulator[2] / diameter);
s2 += step;
d += step;
}
}
return 0;
}

static int blur_v_proc_rgbx(int id, int index, int jobs, void *data)
{
(void) id; // unused
blur_slice_desc *desc = ((blur_slice_desc *) data);
int slice_row_start,
slice_width = mlt_slices_size_slice(jobs, index, desc->src->width, &slice_row_start);
int slice_row_end = slice_row_start + slice_width;
int accumulator[] = {0, 0, 0};
int x = 0;
int y = 0;
int step = 4;
int linesize = step * desc->src->width;
int radius = desc->radius;

if (desc->radius > (desc->src->height / 2)) {
radius = desc->src->height / 2;
}
double diameter = (radius * 2) + 1;

for (x = slice_row_start; x < slice_row_end; x++) {
uint8_t *first = desc->src->data + (x * step);
uint8_t *last = first + (linesize * (desc->src->height - 1));
uint8_t *s1 = first;
uint8_t *s2 = first;
uint8_t *d = desc->dst->data + (x * step);
accumulator[0] = first[0] * (radius + 1);
accumulator[1] = first[1] * (radius + 1);
accumulator[2] = first[2] * (radius + 1);

for (y = 0; y < radius; y++) {
accumulator[0] += s1[0];
accumulator[1] += s1[1];
accumulator[2] += s1[2];
s1 += linesize;
}
for (y = 0; y <= radius; y++) {
accumulator[0] += s1[0] - first[0];
accumulator[1] += s1[1] - first[1];
accumulator[2] += s1[2] - first[2];
d[0] = lrint((double) accumulator[0] / diameter);
d[1] = lrint((double) accumulator[1] / diameter);
d[2] = lrint((double) accumulator[2] / diameter);
s1 += linesize;
d += linesize;
}
for (y = radius + 1; y < desc->src->height - radius; y++) {
accumulator[0] += s1[0] - s2[0];
accumulator[1] += s1[1] - s2[1];
accumulator[2] += s1[2] - s2[2];
d[0] = lrint((double) accumulator[0] / diameter);
d[1] = lrint((double) accumulator[1] / diameter);
d[2] = lrint((double) accumulator[2] / diameter);
s1 += linesize;
s2 += linesize;
d += linesize;
}
for (y = desc->src->height - radius; y < desc->src->height; y++) {
accumulator[0] += last[0] - s2[0];
accumulator[1] += last[1] - s2[1];
accumulator[2] += last[2] - s2[2];
d[0] = lrint((double) accumulator[0] / diameter);
d[1] = lrint((double) accumulator[1] / diameter);
d[2] = lrint((double) accumulator[2] / diameter);
s2 += linesize;
d += linesize;
}
}
return 0;
}

/** Perform a box blur
*
* This function uses a sliding window accumulator method - applied
Expand All @@ -194,9 +334,10 @@ static int blur_v_proc(int id, int index, int jobs, void *data)
* \param self the Image object
* \param hradius the radius of the horizontal blur in pixels
* \param vradius radius of the vertical blur in pixels
* \param preserve_alpha exclude the alpha channel from the blur operation
*/

void mlt_image_box_blur(mlt_image self, int hradius, int vradius)
void mlt_image_box_blur(mlt_image self, int hradius, int vradius, int preserve_alpha)
{
if (self->format != mlt_image_rgba) {
mlt_log(NULL,
Expand All @@ -215,10 +356,17 @@ void mlt_image_box_blur(mlt_image self, int hradius, int vradius)
}

blur_slice_desc desc;
desc.src = self, desc.dst = &tmpimage, desc.radius = hradius,
mlt_slices_run_normal(0, blur_h_proc, &desc);
desc.src = &tmpimage, desc.dst = self, desc.radius = vradius,
mlt_slices_run_normal(0, blur_v_proc, &desc);
if (preserve_alpha) {
desc.src = self, desc.dst = &tmpimage, desc.radius = hradius,
mlt_slices_run_normal(0, blur_h_proc_rgbx, &desc);
desc.src = &tmpimage, desc.dst = self, desc.radius = vradius,
mlt_slices_run_normal(0, blur_v_proc_rgbx, &desc);
} else {
desc.src = self, desc.dst = &tmpimage, desc.radius = hradius,
mlt_slices_run_normal(0, blur_h_proc_rgba, &desc);
desc.src = &tmpimage, desc.dst = self, desc.radius = vradius,
mlt_slices_run_normal(0, blur_v_proc_rgba, &desc);
}

mlt_image_close(&tmpimage);
}
4 changes: 2 additions & 2 deletions src/modules/core/image_proc.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2022 Meltytech, LLC
* Copyright (c) 2022-20023 Meltytech, LLC
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
Expand All @@ -22,6 +22,6 @@
#include <framework/mlt_events.h>
#include <framework/mlt_image.h>

void mlt_image_box_blur(mlt_image self, int hradius, int vradius);
void mlt_image_box_blur(mlt_image self, int hradius, int vradius, int preserve_alpha);

#endif // IMAGE_PROC_H

0 comments on commit 3cfc21e

Please sign in to comment.