c# - 如何在二进制图像中找到最大的“斑点”
问题描述
我有一个包含二进制图像的二维数组,所有值都设置为 0 或 255。示例图像如下:
我想知道每个“blob”的大小是多少。一个 blob 是连接的白色像素的数量。
我试图实现一个距离变换算法:( 注意“MatrixData”类本质上是一个double[,])
public static MatrixData CalculateDistanceXform(this MatrixData input, int searchDistance)
{
MatrixData output = new MatrixData(input.NumberOfRows,input.NumberOfColumns);
for (int r = 0; r < input.NumberOfRows; r++)
{
for(int c = 0; c < input.NumberOfColumns; c++)
{
//skip black pixels
if (input[r,c]==0) continue;
int steps = 0;
int fxMin = Math.Max(r - searchDistance, 0);
int fxMax = Math.Min(r + searchDistance, input.NumberOfRows);
int fyMin = Math.Max(c - searchDistance, 0);
int fyMax = Math.Min(c + searchDistance, input.NumberOfColumns);
for (int fx = fxMin; fx < fxMax-1; ++fx)
{
for (int fy = fyMin; fy < fyMax-1; ++fy)
{
if(input[fx,fy]==255)
{
int tempStep = ((fx - fxMin) + (fy - fyMin));
if(tempStep > steps) steps = tempStep;
}
}
}
output[r,c] = steps;
}
}
return output.HistEQ();
}
然而,这并没有给我想要的结果,因为我的 blob 大小不均匀。关于如何解决这个问题的任何想法?我基本上想找到图像最大斑点中的 ax 和 y 坐标。
解决方案
遵循@TheGeneral 的建议,自定义洪水填充算法有效
还要感谢洪水填充递归算法
这些方法返回一个 double[,] (MatrixData),其中只有最大的 blob 和最大 blob 的点的中心。
public static MatrixData GetLargestBlob(this MatrixData input, ref Tuple<int, int> blobMid)
{
MatrixData output = new MatrixData(input.NumberOfRows,input.NumberOfColumns);
List<Tuple<int,int>> checkedPixels = new List<Tuple<int, int>>();
List<Tuple<int,int>> blobs = new List<Tuple<int, int>>();
List<Tuple<int,int>> largestBlob = new List<Tuple<int, int>>();
Random rand = new Random();
for (int r = 0; r < input.NumberOfRows; r++)
{
for(int c = 0; c < input.NumberOfColumns; c++)
{
//skip black pixels
if (input[r,c]==0) continue;
int replace = rand.Next(256,int.MaxValue);
if (checkedPixels.Count==0)
{
List<Tuple<int,int>> blob = new List<Tuple<int, int>>();
blobs.Add(new Tuple<int, int>(Fill(input,r,c,replace,ref checkedPixels,ref blob), replace));
if(blob.Count > largestBlob.Count) largestBlob = blob;
}
else
{
if(!checkedPixels.Contains(new Tuple<int, int>(r, c)))
{
List<Tuple<int,int>> blob = new List<Tuple<int, int>>();
blobs.Add(new Tuple<int, int>(Fill(input,r,c,replace,ref checkedPixels,ref blob), replace));
if(blob.Count > largestBlob.Count) largestBlob = blob;
}
}
}
}
//set the output to only show the largest blob
Tuple<int,int> largest = blobs.Where(r => r.Item1 == (blobs.Max(m => m.Item1))).First();
for (int r = 0; r < input.NumberOfRows; r++)
{
for(int c = 0; c < input.NumberOfColumns; c++)
{
output[r,c] = (input[r,c]==largest.Item2)? 255 : 0;
}
}
//calculate the center of the largest blob
int xMin = largestBlob.Min(m => m.Item1);
int xMax = largestBlob.Max(m => m.Item1);
int yMin = largestBlob.Min(m => m.Item2);
int yMax = largestBlob.Max(m => m.Item2);
int centerX = ((xMax - xMin) / 2) + xMin;
int centerY = ((yMax - yMin) / 2) + yMin;
blobMid = new Tuple<int, int>(centerX, centerY);
return output;
}
public static int Fill(MatrixData array, int x, int y, int newInt, ref List<Tuple<int,int>> checkedPixels,ref List<Tuple<int,int>> blobPixels)
{
int initial = array[x,y];
int counter = 0;
Queue<Tuple<int,int>> queue = new Queue<Tuple<int,int>>();
queue.Enqueue(new Tuple<int, int>(x, y));
while (queue.Any())
{
Tuple<int, int> point = queue.Dequeue();
if (array[point.Item1, point.Item2] != initial)
continue;
array[point.Item1, point.Item2] = newInt;
checkedPixels.Add(point);
blobPixels.Add(point);
counter++;
EnqueueIfMatches(array, queue, point.Item1 - 1, point.Item2, initial);
EnqueueIfMatches(array, queue, point.Item1 + 1, point.Item2, initial);
EnqueueIfMatches(array, queue, point.Item1, point.Item2 - 1, initial);
EnqueueIfMatches(array, queue, point.Item1, point.Item2 + 1, initial);
}
return counter;
}
private static void EnqueueIfMatches(MatrixData array, Queue<Tuple<int, int>> queue, int x, int y, int initial)
{
if (x < 0 || x >= array.Data.GetLength(0) || y < 0 || y >= array.Data.GetLength(1))
return;
if (array[x, y] == initial)
queue.Enqueue(new Tuple<int, int>(x, y));
}
推荐阅读
- flutter - 如何从flutter web中字符串中的给定目录路径获取文件列表?
- excel - Sendkey值粘贴后消失
- java - 使用 lambda 函数的阶乘递归实现
- networking - 计算机网络计数到无穷大问题
- python - 使用python与whatsapp web交互
- bootstrap-4 - Align element on the right in
- reactjs - 创建反应应用程序 | 当浏览器连接到应用程序时,是否可以从后端提供文件而不是提供 index.html
- recommendation-engine - 如何建立零售银行产品推荐系统的训练集
- django - 如何将 mixpanel 集成到 django 后端
- .net - “GetFileHash”任务意外失败