TASK 51 slice 2: Blur — background at 1/4 res, 3 separable box passes (~gaussian, radius by strength), mask-blended; person untouched; Remove gains strength = edge feather; mask computed once, rendered per effect (Unit: bg blur)

This commit is contained in:
2026-10-09 10:18:00 -07:00
parent fbeb63ba79
commit 227ee8fca6
5 changed files with 261 additions and 33 deletions
@@ -99,6 +99,54 @@ public class BackgroundEffectEngineTests
Assert.InRange(100.0 * person / total, 45, 60); // reference: 52.5% person
}
/// <summary>Slice 2 integration test: Blur keeps the person pixel-for-pixel and smooths the
/// background — a 1px black/white checkerboard behind the "person" comes back as mid-tones,
/// opaque, same size.</summary>
[Fact]
public void Blur_keeps_the_person_sharp_and_smooths_the_background()
{
const int w = 64, h = 32;
var pixels = new byte[w * h * 4];
for (var y = 0; y < h; y++)
for (var x = 0; x < w; x++)
{
var p = (y * w + x) * 4;
if (x < w / 2)
{
pixels[p] = 100; pixels[p + 1] = 150; pixels[p + 2] = 200;
}
else
{
var v = (byte)(((x + y) & 1) == 0 ? 0 : 255);
pixels[p] = v; pixels[p + 1] = v; pixels[p + 2] = v;
}
pixels[p + 3] = 255;
}
var frame = new VideoFrame(w, h, pixels) { IsOpaque = true };
var mask = new SegmentationMask(4, 2, new[] { 1f, 1f, 0f, 0f, 1f, 1f, 0f, 0f });
var processor = new BackgroundEffectProcessor(new FakeSegmenter(mask));
var result = processor.Apply(frame, BackgroundEffect.Blur);
Assert.NotSame(frame, result);
Assert.True(result.IsOpaque);
Assert.Equal(w, result.Width);
Assert.Equal(h, result.Height);
for (var y = 0; y < h; y++)
{
for (var x = 0; x < 24; x++) // person: untouched
for (var c = 0; c < 4; c++)
Assert.Equal(pixels[(y * w + x) * 4 + c], result.BgraPixels[(y * w + x) * 4 + c]);
for (var x = 44; x < w; x++) // background: checkerboard smoothed away
{
var p = (y * w + x) * 4;
for (var c = 0; c < 3; c++)
Assert.InRange(result.BgraPixels[p + c], (byte)30, (byte)225);
Assert.Equal(255, result.BgraPixels[p + 3]);
}
}
}
private static int Alpha(VideoFrame f, int x, int y) => f.BgraPixels[(y * f.Width + x) * 4 + 3];
private static string Fixture(string name) => Path.Combine(AppContext.BaseDirectory, "Fixtures", name);