Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Kawase Blur #276

Merged
merged 9 commits into from
Apr 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions data/effects/kawase_blur.effect
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
uniform float4x4 ViewProj;
uniform texture2d image;

uniform float xOffset;
uniform float yOffset;

sampler_state textureSampler {
Filter = Linear;
AddressU = Clamp;
AddressV = Clamp;
};

struct VertDataIn {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};

struct VertDataOut {
float4 pos : POSITION;
float2 uv : TEXCOORD0;
};

VertDataOut VSDefault(VertDataOut v_in)
{
VertDataOut vert_out;
vert_out.pos = mul(float4(v_in.pos.xyz, 1.0), ViewProj);
vert_out.uv = v_in.uv;
return vert_out;
}

float4 PSKawaseBlur(VertDataOut v_in) : TARGET
{
float4 sum = float4(0.0, 0.0, 0.0, 0.0);
sum += image.Sample(textureSampler, v_in.uv + float2( xOffset, yOffset));
sum += image.Sample(textureSampler, v_in.uv + float2(-xOffset, yOffset));
sum += image.Sample(textureSampler, v_in.uv + float2( xOffset, -yOffset));
sum += image.Sample(textureSampler, v_in.uv + float2(-xOffset, -yOffset));
sum *= 0.25;
return sum;
}

technique Draw
{
pass
{
vertex_shader = VSDefault(v_in);
pixel_shader = PSKawaseBlur(v_in);
}
}
17 changes: 2 additions & 15 deletions data/effects/mask_alpha_filter.effect
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ uniform texture2d alphamask; // alpha mask
uniform int blurSize; // Size of the image blur kernel. 0 = no blur
uniform float xTexelSize; // Size of texel in X coord
uniform float yTexelSize; // Size of texel in Y coord
uniform texture2d blurredBackground; // input RGBA

sampler_state textureSampler {
Filter = Linear;
Expand All @@ -30,28 +31,14 @@ VertDataOut VSDefault(VertDataIn v_in)
return vert_out;
}

// Simple box blur around a point. k_size = left and right offset from middle
float4 Blur(float2 texCoord, int k_size)
{
float4 pixelsum = float4(0.0, 0.0, 0.0, 0.0);

for (int i = -k_size; i <= k_size; i++) {
for (int j = -k_size; j <= k_size; j++) {
pixelsum += image.Sample(textureSampler, texCoord + float2(i * xTexelSize, j * yTexelSize));
}
}

return pixelsum / ((k_size*2+1) * (k_size*2+1));
}

float4 PSAlphaMaskRGBAWithBlur(VertDataOut v_in) : TARGET
{
float4 inputRGBA = image.Sample(textureSampler, v_in.uv);
inputRGBA.rgb = max(float3(0.0, 0.0, 0.0), inputRGBA.rgb / inputRGBA.a);

float4 outputRGBA;
float a = (1.0 - alphamask.Sample(textureSampler, v_in.uv).r) * inputRGBA.a;
outputRGBA.rgb = inputRGBA.rgb * a + Blur(v_in.uv, blurSize).rgb * (1.0 - a);
outputRGBA.rgb = inputRGBA.rgb * a + blurredBackground.Sample(textureSampler, v_in.uv).rgb * (1.0 - a);
outputRGBA.a = 1;
return outputRGBA;
}
Expand Down
53 changes: 53 additions & 0 deletions src/background-filter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const char *USEGPU_TENSORRT = "tensorrt";
const char *USEGPU_COREML = "coreml";

const char *EFFECT_PATH = "effects/mask_alpha_filter.effect";
const char *KAWASE_BLUR_EFFECT_PATH = "effects/kawase_blur.effect";

struct background_removal_filter {
std::unique_ptr<Ort::Session> session;
Expand All @@ -70,6 +71,7 @@ struct background_removal_filter {
gs_texrender_t *texrender;
gs_stagesurf_t *stagesurface;
gs_effect_t *effect;
gs_effect_t *kawaseBlurEffect;

cv::Mat backgroundMask;
int maskEveryXFrames = 1;
Expand Down Expand Up @@ -297,6 +299,11 @@ static void filter_update(void *data, obs_data_t *settings)
tf->effect = gs_effect_create_from_file(effect_path, NULL);
bfree(effect_path);

char *kawaseBlurEffectPath = obs_module_file(KAWASE_BLUR_EFFECT_PATH);
gs_effect_destroy(tf->kawaseBlurEffect);
tf->kawaseBlurEffect = gs_effect_create_from_file(kawaseBlurEffectPath, NULL);
bfree(kawaseBlurEffectPath);

obs_leave_graphics();
}

Expand Down Expand Up @@ -491,6 +498,45 @@ void filter_video_tick(void *data, float seconds)
UNUSED_PARAMETER(seconds);
}

static gs_texture_t *blur_background(struct background_removal_filter *tf, uint32_t width,
uint32_t height)
{
if (tf->blurBackground == 0.0 || !tf->kawaseBlurEffect) {
return nullptr;
}
gs_texture_t *blurredTexture = gs_texture_create(width, height, GS_BGRA, 1, nullptr, 0);
gs_copy_texture(blurredTexture, gs_texrender_get_texture(tf->texrender));
gs_eparam_t *image = gs_effect_get_param_by_name(tf->kawaseBlurEffect, "image");
gs_eparam_t *xOffset = gs_effect_get_param_by_name(tf->kawaseBlurEffect, "xOffset");
gs_eparam_t *yOffset = gs_effect_get_param_by_name(tf->kawaseBlurEffect, "yOffset");

for (int i = 0; i < (int)tf->blurBackground; i++) {
gs_texrender_reset(tf->texrender);
if (!gs_texrender_begin(tf->texrender, width, height)) {
blog(LOG_INFO, "Could not open background blur texrender!");
return blurredTexture;
}

gs_effect_set_texture(image, blurredTexture);
gs_effect_set_float(xOffset, (i + 0.5f) / width);
gs_effect_set_float(yOffset, (i + 0.5f) / height);

struct vec4 background;
vec4_zero(&background);
gs_clear(GS_CLEAR_COLOR, &background, 0.0f, 0);
gs_ortho(0.0f, static_cast<float>(width), 0.0f, static_cast<float>(height), -100.0f, 100.0f);
gs_blend_state_push();
gs_blend_function(GS_BLEND_ONE, GS_BLEND_ZERO);
while (gs_effect_loop(tf->kawaseBlurEffect, "Draw")) {
gs_draw_sprite(blurredTexture, 0, width, height);
}
gs_blend_state_pop();
gs_texrender_end(tf->texrender);
gs_copy_texture(blurredTexture, gs_texrender_get_texture(tf->texrender));
}
return blurredTexture;
}

static void filter_video_render(void *data, gs_effect_t *_effect)
{
UNUSED_PARAMETER(_effect);
Expand Down Expand Up @@ -554,6 +600,8 @@ static void filter_video_render(void *data, gs_effect_t *_effect)

// Output the masked image

gs_texture_t *blurredTexture = blur_background(tf, width, height);

if (!tf->effect) {
// Effect failed to load, skip rendering
obs_source_skip_video_filter(tf->source);
Expand All @@ -580,11 +628,15 @@ static void filter_video_render(void *data, gs_effect_t *_effect)
gs_eparam_t *blurSize = gs_effect_get_param_by_name(tf->effect, "blurSize");
gs_eparam_t *xTexelSize = gs_effect_get_param_by_name(tf->effect, "xTexelSize");
gs_eparam_t *yTexelSize = gs_effect_get_param_by_name(tf->effect, "yTexelSize");
gs_eparam_t *blurredBackground = gs_effect_get_param_by_name(tf->effect, "blurredBackground");

gs_effect_set_texture(alphamask, alphaTexture);
gs_effect_set_int(blurSize, (int)tf->blurBackground);
gs_effect_set_float(xTexelSize, 1.0f / width);
gs_effect_set_float(yTexelSize, 1.0f / height);
if (tf->blurBackground > 0.0) {
gs_effect_set_texture(blurredBackground, blurredTexture);
}

gs_blend_state_push();
gs_reset_blend_state();
Expand All @@ -601,6 +653,7 @@ static void filter_video_render(void *data, gs_effect_t *_effect)
gs_blend_state_pop();

gs_texture_destroy(alphaTexture);
gs_texture_destroy(blurredTexture);
}

struct obs_source_info background_removal_filter_info = {
Expand Down