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:
@@ -67,7 +67,7 @@ internal class ImageSharpProcessor : ImageProcessor
|
||||
return stream;
|
||||
}
|
||||
|
||||
public override async Task<Stream> RemoveBackgroundAsync(Stream image, Stream mask)
|
||||
public override async Task<Stream> RemoveBackgroundAsync(Stream image, Stream mask, byte featherMin, byte featherMax)
|
||||
{
|
||||
image.Position = 0;
|
||||
mask.Position = 0;
|
||||
@@ -76,19 +76,14 @@ internal class ImageSharpProcessor : ImageProcessor
|
||||
var maskImage = await Image.LoadAsync<Rgba32>(mask);
|
||||
using var imageWithBgRemoved = new Image<Rgba32>(imageWithBg.Width, imageWithBg.Height);
|
||||
|
||||
const byte alphaThreshold = 20;
|
||||
var transparentPixel = new Rgba32(0, 0, 0, 0);
|
||||
|
||||
WalkImage(imageWithBg.Height, imageWithBg.Width, (x, y) =>
|
||||
{
|
||||
var sourcePixel = imageWithBg[x, y];
|
||||
var maskPixel = maskImage[x, y];
|
||||
|
||||
var alpha = maskPixel.R;
|
||||
var alpha = AdjustAlpha(maskPixel.R, featherMin, featherMax);
|
||||
|
||||
imageWithBgRemoved[x, y] = alpha > alphaThreshold
|
||||
? new Rgba32(sourcePixel.R, sourcePixel.G, sourcePixel.B, sourcePixel.A)
|
||||
: transparentPixel;
|
||||
imageWithBgRemoved[x, y] = new Rgba32(sourcePixel.R, sourcePixel.G, sourcePixel.B, alpha);
|
||||
});
|
||||
|
||||
var result = new MemoryStream();
|
||||
@@ -107,12 +102,7 @@ internal class ImageSharpProcessor : ImageProcessor
|
||||
|
||||
private static float Normalize(float value)
|
||||
{
|
||||
const float binarizationThreshold = 0.5f;
|
||||
const float normalizationFactor = 2f;
|
||||
|
||||
return value > binarizationThreshold
|
||||
? (value - binarizationThreshold) * normalizationFactor
|
||||
: 0f;
|
||||
return value * value;
|
||||
}
|
||||
|
||||
private static byte ConvertToGreyscale(float value)
|
||||
@@ -129,4 +119,15 @@ internal class ImageSharpProcessor : ImageProcessor
|
||||
|
||||
return sigmoidScale / (sigmoidShift + MathF.Exp(sigmoidDivisor * x));
|
||||
}
|
||||
|
||||
private static byte AdjustAlpha(byte maskValue, byte minVal, byte maxVal)
|
||||
{
|
||||
if (maskValue <= minVal)
|
||||
return 0;
|
||||
if (maskValue >= maxVal)
|
||||
return 255;
|
||||
|
||||
float proportion = (maskValue - minVal) / (float)(maxVal - minVal);
|
||||
return (byte)(proportion * 255f);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user