图像转黑白的ToBlackAndWhite方法失效,输出全黑/全白图像求助
问题分析:ToBlackAndWhite方法输出全黑/全白图像的原因
核心问题:错误实例化System.Drawing.Color结构体
System.Drawing.Color是特殊结构体,没有公开的实例构造函数,不能直接通过new Color(r, g, b)创建有效实例。你代码中用new(pixel[2], pixel[1], pixel[0])创建的Color对象内部ARGB值不符合预期,导致GetBrightness()、GetHue()、GetSaturation()等方法返回结果全部偏向一侧(要么全满足阈值条件,要么全不满足),最终所有像素被统一设为黑色或白色。
其他潜在问题:忽略Alpha通道(针对带透明的像素格式)
你的InvertTransparency方法处理了pixel[3](Alpha通道),说明位图大概率是32位ARGB格式,但ToBlackAndWhite方法存在两个疏漏:
- 创建Color时未传入Alpha值,导致颜色计算未考虑透明度,影响亮度/色相/饱和度的判断准确性;
- 修改像素时未设置Alpha通道,可能导致最终图像出现透明区域(视觉上显示为黑色)。
修复步骤
1. 正确创建Color实例
使用Color.FromArgb()静态方法替代直接实例化:
- 若位图为带Alpha通道格式(如Format32bppArgb):
var color = Color.FromArgb(pixel[3], pixel[2], pixel[1], pixel[0]); - 若为无Alpha通道格式(如Format24bppRgb):
var color = Color.FromArgb(255, pixel[2], pixel[1], pixel[0]);
2. 同步处理Alpha通道(若适用)
如果位图包含Alpha通道,修改像素时需同步设置Alpha值为不透明,避免出现透明区域:
if (IsWhite(color)) { pixel[2] = MAX; // R pixel[1] = MAX; // G pixel[0] = MAX; // B if (pixelSize == 4) // 32位ARGB格式 pixel[3] = MAX; // Alpha设为不透明 sum--; } else { pixel[2] = MIN; pixel[1] = MIN; pixel[0] = MIN; if (pixelSize == 4) pixel[3] = MAX; sum++; }
3. 验证MAX和MIN常量值
确保MAX为255、MIN为0,这是8位颜色分量的正确极值。
修复后的ToBlackAndWhite方法示例
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 isArgb = pixelSize == 4; // 判断是否为32位带Alpha格式 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; Color color; // 正确创建Color实例 if (isArgb) color = Color.FromArgb(pixel[3], pixel[2], pixel[1], pixel[0]); else color = Color.FromArgb(255, pixel[2], pixel[1], pixel[0]); if (IsWhite(color)) { pixel[2] = 255; // MAX pixel[1] = 255; pixel[0] = 255; if (isArgb) pixel[3] = 255; sum--; } else { pixel[2] = 0; // MIN pixel[1] = 0; pixel[0] = 0; if (isArgb) pixel[3] = 255; sum++; } } } } _bmp.UnlockBits(data); return (float)Math.Abs(sum) / PixelCount; }
内容的提问来源于stack exchange,提问作者Simon
相关产品推荐
相关产品推荐

