C#利用BitmapDataunsafe快速计算二值图像目标质心

许南星
许南星
发布时间:2026-10-13 | 2人浏览过
原创

在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):

  1. 读取当前字节指针指向的三个通道值(BGR格式)。注意:在Format24bppRgb模式下,内存中的排列通常是Blue, Green, Red。
  2. 判断是否为目标色:这里简单判定只要R+G+B不等于0即视为白色/目标(针对二值化图像有效)。
  3. 如果符合条件:
    - M00 自增。
    - M10 累加当前 X 坐标。
    - M01 累加当前 Y 坐标。
  4. 指针前进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#图像处理优化技巧的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表