C#利用BitmapDataunsafe快速计算二值图像目标质心
在C#图像处理中,快速获取二值化图像的目标中心(质心)常需考虑性能。本文展示如何利用BitmapData结合unsafe指针直接操作内存,避免逐像素调用导致的开销,从而高效计算出目标的X、Y坐标。
实现原理
计算质心的数学基础是对所有属于目标的像素坐标进行加权平均。假设图像已预处理为二值化状态,通常设定黑色(RGB: 0,0,0)为背景,白色(RGB: 255,255,255)为目标。我们需要遍历整个图像区域,统计白色像素的数量以及它们横纵坐标的总和。最终质心坐标即为:
- X = Σx / N
- Y = Σy / N
其中N为目标像素总数。
准备条件
为了直接在内存中读写像素数据,代码需要使用不安全上下文。确保项目属性中已启用“允许不安全代码”(Unsafe Code),并在源代码文件头部包含#pragma warning disable CS0618或相应配置以处理可能的相关警告。
操作步骤
第1步:锁定图像内存并定义变量
首先创建一个矩形区域覆盖整张图,并使用LockBits将位图数据锁在内存中,防止GC移动数据影响指针。同时初始化存储质心的数组及三个累加器:
M00:累计白色像素个数(一阶矩为零的情况下的计数)。M10:累计白色像素的X坐标之和。M01:累计白色像素的Y坐标之和。
第2步:Unsafe遍历像素
进入unsafe块,获取扫描线指针pIn和步长stride。遍历每一行(y)和每一列(x):
- 读取当前字节指针指向的三个通道值(BGR格式)。注意:在
Format24bppRgb模式下,内存中的排列通常是Blue, Green, Red。 - 判断是否为目标色:这里简单判定只要R+G+B不等于0即视为白色/目标(针对二值化图像有效)。
- 如果符合条件:
- M00 自增。
- M10 累加当前 X 坐标。
- M01 累加当前 Y 坐标。 - 指针前进3个字节(一个像素的大小)。
第3步:处理行尾偏移与解锁
每行循环结束后,指针需要从scan0起始位置跳到下一行对应处。由于stride可能包含填充字节,必须执行pIn += stride - src.Width * 3。
全部像素遍历完成后,释放锁定的内存块。
完整代码实现
//采用二值化图像,图像中黑色表示背景,白色表示目标
//定义质心计算函数
private int[] CentPoints(Bitmap src)
{
//定义存储质心坐标的数组变量
int[] CentreP = new int[2];
int M00 = 0, M01 = 0, M10 = 0;
Rectangle rect = new Rectangle(0, 0, src.Width, src.Height);
System.Drawing.Imaging.BitmapData bmpData = src.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
unsafe
{
int stride = bmpData.Stride;
byte* p;
byte* pIn = (byte*)bmpData.Scan0.ToPointer();
int R, G, B;
for (int y = 0; y < src.Height; y++)
{
for (int x = 0; x < src.Width; x++)
{
p = pIn;
R = p[2];
G = p[1];
B = p[0];
if (R + G + B != 0)
{
M00++;
M01 += y;
M10 += x;
}
pIn += 3;
}
pIn += stride - src.Width * 3;
}
CentreP[0] = (int)(M10 / M00);
CentreP[1] = (int)(M01 / M00);
}
src.UnlockBits(bmpData);
return CentreP;
//返回一个数组,该数组中第一个元素是质心的X坐标,
//第二个元素是质心的Y坐标
}
结果与注意事项
调用该方法后,返回的int[]数组包含两个整数:
- CentreP[0]:质心的 X 坐标。
- CentreP[1]:质心的 Y 坐标。
该方法仅适用于已经过二值化处理且目标为白色的图像。若原图包含复杂色彩或非白色目标,需先提取感兴趣区域(ROI)并进行阈值转换。此外,当图像中不存在任何目标像素(即M00=0)时,上述代码会产生除以零异常,生产环境中建议加入M00 == 0的判断保护。
总结
通过使用unsafe指针和BitmapData直接操作内存,我们可以极大地提升C#中进行底层图像处理时的速度,特别是在需要高频次获取多个目标几何属性的场景中。以上就是C#利用BitmapData和Unsafe指针计算图像目标质心的详细内容,更多关于C#图像处理优化技巧的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









