C#图像处理:基于YCbCr颜色空间的头发区域检测实现
在进行图像前景提取时,利用颜色空间转换是常用手段。本文展示如何使用C#直接操作位图内存,将RGB数据映射至YCbCr空间,并通过特定的数值范围阈值来检测与分离头发区域,最后输出经过二值化处理的结果图像。
技术原理与目标
RGB颜色模型虽然直观,但在区分肤色和深色头发时常受光照影响较大。相比之下,YCbCr颜色空间将亮度(Y)与色度(Cb, Cr)分离,能更稳定地表现皮肤和头发的色调差异。本方案旨在通过计算每个像素的Cb、Cr值及其原始亮度,设定严格的边界值,从而在复杂的背景中“提取”出符合特征的头发像素,并将非目标区域置白。
第1步:锁定图像内存获取像素数据
直接访问 System.Drawing.Image 的属性效率较低且限制多。为了提高性能,需使用 LockBits 方法将图像数据复制到非托管内存块中。
- 入口参数:指定
Format24bppRgb格式(即每像素8位R/G/B),允许读写权限。 - 关键参数:
Stride表示扫描行的大小,必须考虑内存对齐带来的填充字节,循环时需跳过这些填充部分。
第2步:坐标遍历与RGB转YCbCr转换
在指针操作的循环中,依次读取当前像素的蓝色(B)、绿色(G)、红色(R)分量。根据标准转换公式计算对应的YCbCr值:
Cb = 128 - 0.169 * R - 0.331 * G + 0.5 * B
Cr = 128 + 0.5 * R - 0.419 * G - 0.081 * B
注意:实际工程中使用的系数可能因具体实现略有不同,下文代码采用了一种常见近似公式进行演示。
第3步:应用阈值判断逻辑
这是核心步骤。为了过滤掉非头发部分,代码定义了以下判定条件:
- Cb 范围:[115, 141]
- Cr 范围:[115, 143]
- 亮度限制:R < 35 (暗示较暗的颜色)
如果像素满足上述所有条件,则视为潜在头发区域保留;否则,强制将该像素的RGB值全部设为 255(白色),从而实现背景消除的效果。
以下是完整的C#实现代码:
//发色检测(YCbCr颜色空间)
public Bitmap HairD(Bitmap a)
{
Rectangle rect = new Rectangle(0, 0, a.Width, a.Height);
// 锁定图像数据以进行底层内存操作
System.Drawing.Imaging.BitmapData bmpData = a.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
int stride = bmpData.Stride;
unsafe
{
byte* pIn = (byte*)bmpData.Scan0.ToPointer();
byte* p;
int R, G, B;
double Cr, Cb,BrightV;
for (int y = 0; y < a.Height; y++)
{
for (int x = 0; x < a.Width; x++)
{
p = pIn;
// BGR顺序读取(24位RGB在内存中通常按B-G-R排列)
R = p[2];
G = p[1];
B = p[0];
// 简单的线性近似转换公式
Cb = 128 - 37.797 * R / 255 - 74.203 * G / 255 + 112 * B / 255;
Cr = 128 + 112 * R / 255 - 93.768 * G / 255 - 18.214 * B / 255;
BrightV = (R + G + B) / 3;
// 阈值判断:Cb/Cr落在特定区间,且亮度较低
if (!(Cb >= 115 && Cb <= 141 && Cr >= 115 && Cr <= 143 && (R < 35)))
{
// 非头发区域置为白色
pIn[0] = (byte)255; // B
pIn[1] = (byte)255; // G
pIn[2] = (byte)255; // R
}
pIn += 3;
}
// 跨行跳跃,扣除每一行的填充字节(padding bytes)
pIn += stride - a.Width * 3;
}
}
a.UnlockBits(bmpData);
return a;
}
//定义最小值函数
public double Min(double a, double b, double c)
{
double e = (a <= b ? a : b) <= c ? (a <= b ? a : b) : c;
return e;
}
//定义最大值函数
public int Max(int a, int b, int c)
{
int e = (a >= b ? a : b) <= c ? c : (a >= b ? a : b);
return e;
}
效果验证
运行上述程序后,输入包含人物头部的源图像,算法将对图像中的像素逐一筛查。下图展示了处理后的最终效果,成功去除了大部分非头发背景,仅保留了符合设定的特征区域:
以上就是C#图像处理中基于YCbCr模型的头发区域检测方法的全部内容。该算法依赖于固定的色彩阈值,在面对复杂光照或不同发色(如金色、红色)时可能需要进行参数微调。更多关于C#图形编程的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













