连通域在图像处理领域用的还是比较多的,在网上搜索连通域提取的算法和代码,比较多的是用C++写的,浏览次数比较多的是这篇博客,但由于一直是用C#编写代码,所以仿照那篇博客中的C++程序,将其改为了C#程序,同时在此基础上添加了质心计算和标记函数。
构造了两个结构体,EqualRun用于记录两个等价run,centroid用于存储与质心计算相关的参数。
public struct EqualRun
{
public int firstRun;
public int secondRun;
};
public struct Centroid
{
public int sumx;
public int sumy;
public int area;
};
此三个函数:fillRunVectors、firstpass、replaceSameLabel是仿照博客写的。函数centroidCalculate用于计算连通域的质心。函数drawCaliResult用于在图中标记出质心位置。
//fillRunVectors函数完成所有团的查找与记录
public void fillRunVectors(Bitmap bwBitmap,ref int NumberOfRuns, ref List<int> stRun,
ref List<int> enRun, ref List<int> rowRun, out List<Point> stPoint, out List<Point> endPoint)
{
stPoint = new List<Point>();
endPoint = new List<Point>();
BitmapData bwBmpData = bwBitmap.LockBits(new Rectangle(0, 0, bwBitmap.Width, bwBitmap.Height), ImageLockMode.ReadWrite, bwBitmap.PixelFormat);
byte* sorPtr = (byte*)bwBmpData.Scan0;
for (int i = 0; i<bwBitmap.Height; i++)//行
{
if (sorPtr[i* bwBmpData.Stride] == 255)//每行的第一个元素
{
NumberOfRuns++;
stRun.Add(0);
rowRun.Add(i);
stPoint.Add(new Point(0, i));
}
for (int j = 1; j<bwBitmap.Width; j++)//列
{
if (sorPtr[i * bwBmpData.Stride + j - 1] == 0 && sorPtr[i * bwBmpData.Stride + j] == 255)//新增一个团
{
NumberOfRuns++;
stRun.Add(j);
rowRun.Add(i);
stPoint.Add(new Point(j, i));
}
else if (sorPtr[i * bwBmpData.Stride + j - 1] == 255 && sorPtr[i * bwBmpData.Stride + j] == 0)//结束一个团
{
enRun.Add(j - 1);
endPoint.Add(new Point(j - 1, i));
}
}
if (sorPtr[i * bwBmpData.Stride + bwBmpData.Width - 1]==255)//每行的最后一个元素
{
enRun.Add(bwBitmap.Width - 1);
endPoint.Add(new Point(bwBitmap.Width - 1, i));
}
}
bwBitmap.UnlockBits(bwBmpData);
}
//firstPass函数完成团的标记与等价对列表的生成 offset=1,8邻域,offset=0,四邻域
public void firstPass(ref List<int> stRun, ref List<int> enRun, ref List<int> rowRun, ref int NumberOfRuns,
ref List<int> runLabels, r