feat: improve background removal feathering

- replace hard binary thresholding with smooth
  linear alpha mapping to reduce halos around
  foreground edges especially in low
  resolution images
- normalize now uses a quadratic curve instead
  of hard binarization so that gradient info
  from the model output is preserved
- removebackgroundasync applies a configurable
  linear interpolation between the set min and
  max feathering thresholds so you have partial
  transparency at the edges
This commit is contained in:
Stevan Freeborn
2026-07-15 10:52:35 -05:00
parent 51abe75e07
commit e099144127
5 changed files with 62 additions and 19 deletions
@@ -72,7 +72,7 @@ public class RemovalCommandTests : IDisposable
.ReturnsAsync(maskStream);
_imageProcessorMock
.Setup(p => p.RemoveBackgroundAsync(image.Data, maskStream))
.Setup(p => p.RemoveBackgroundAsync(image.Data, maskStream, It.IsAny<byte>(), It.IsAny<byte>()))
.ReturnsAsync(outputStream);
var commandContext = new CommandContext(
@@ -91,7 +91,7 @@ public class RemovalCommandTests : IDisposable
_imageProcessorMock.Verify(p => p.CreateTensorInputAsync(image.Data, model), Times.Once);
_inferenceRunnerMock.Verify(r => r.Run(model.Bytes, inputTensor), Times.Once);
_imageProcessorMock.Verify(p => p.GenerateMaskAsync(outputTensor, image.Width, image.Height), Times.Once);
_imageProcessorMock.Verify(p => p.RemoveBackgroundAsync(image.Data, maskStream), Times.Once);
_imageProcessorMock.Verify(p => p.RemoveBackgroundAsync(image.Data, maskStream, It.IsAny<byte>(), It.IsAny<byte>()), Times.Once);
_imageProcessorMock.Verify(p => p.SaveImageAsync(outputStream, It.IsAny<string>()), Times.AtLeastOnce);
File.Delete(imagePath);