public float ToBlackAndWhite(BlackWhiteMode mode)
{
var data = _bmp.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadWrite, _bmp.PixelFormat);
var IsWhite = mode switch
{
BlackWhiteMode.Brightness => new Predicate<Color>(x => x.GetBrightness() > 0.5),
BlackWhiteMode.Hue => new Predicate<Color>(x => x.GetHue() > 180),
_ => new Predicate<Color>(x => x.GetSaturation() > 0.5)
};
int sum = 0;
unsafe
{
var pixelSize = Image.GetPixelFormatSize(_bmp.PixelFormat) / 8;
var ptr = (byte*)data.Scan0;
byte* row;
byte* pixel;
for (int y = 0; y < data.Height; y++)
{
row = ptr + y * data.Stride;
for (int x = 0; x < data.Width; x++)
{
pixel = row + x * pixelSize;
if (IsWhite(new(pixel[2], pixel[1], pixel[0])))
{
pixel[2] = MAX;
pixel[1] = MAX;
pixel[0] = MAX;
sum--;
}
else
{
pixel[2] = MIN;
pixel[1] = MIN;
pixel[0] = MIN;
sum++;
}
}
}
}
_bmp.UnlockBits(data);
return (float)Math.Abs(sum) / PixelCount;
}
This method locks a System.Drawing.Bitmap and replaces all pixels with black or white pixels based of the IsWhite Predicate (Pixel nearer to black = black, nearer to white = white). But every image I tried only returns a full white or full black image. Why does that happen?
I also have this method that replaces transparent pixels with full visible pixels that uses the same method and it works fine.
public void InvertTransparency()
{
var data = _bmp.LockBits(new Rectangle(0, 0, Width, Height), ImageLockMode.ReadWrite, _bmp.PixelFormat);
unsafe
{
var pixelSize = Image.GetPixelFormatSize(_bmp.PixelFormat) / 8;
var ptr = (byte*)data.Scan0;
byte* row;
byte* pixel;
ulong r = 0;
ulong g = 0;
ulong b = 0;
for (int y = 0; y < data.Height; y++)
{
row = ptr + y * data.Stride;
for (int x = 0; x < data.Width; x++)
{
pixel = row + x * pixelSize;
r += pixel[2];
g += pixel[1];
b += pixel[0];
}
}
var invertedAvg = new Color(
MAX - (r / (ulong)PixelCount),
MAX - (g / (ulong)PixelCount),
MAX - (b / (ulong)PixelCount));
for (int y = 0; y < data.Height; y++)
{
row = ptr + y * data.Stride;
for (int x = 0; x < data.Width; x++)
{
pixel = row + x * pixelSize;
if (pixel[3] < 128)
{
pixel[3] = MAX;
pixel[2] = invertedAvg.R;
pixel[1] = invertedAvg.G;
pixel[0] = invertedAvg.B;
continue;
}
if (pixel[3] != MAX)
pixel[3] = MAX;
}
}
}
_bmp.UnlockBits(data);
}
Thank you for helping :)
The way you check for a color to be white is wrong, these
Colormethods are based on the HSL color space:https://learn.microsoft.com/en-us/dotnet/api/system.drawing.color.gethue?view=net-7.0
https://learn.microsoft.com/en-us/dotnet/api/system.drawing.color.getsaturation?view=net-7.0
https://learn.microsoft.com/en-us/dotnet/api/system.drawing.color.getbrightness?view=net-7.0
The only thing you need to do is
.GetBrightness() >= 1.0f:https://www.w3schools.com/colors/colors_hsl.asp