一、概念
图像的连通域是指图像中具有相同像素值并且位置相邻的像素组成的区域,连通域分析是指在图像中寻找出彼此互相独立的连通域并将其标记出来。
上一篇讲的是利用ConnectedComponentsWithStats查找连通区域,如果我们已经得到了一个由n个点组成的轮廓,想把这个区域填充成某个颜色,怎么办呢,Emgu CV中有这样一个函数:
public static FillPoly
(
IInputOutputArray img, // 输入输出图像
IInputArray points, // 点的集合,或者是轮廓
MCvScalar color, // 要填充的颜色
LineType lineType = LineType.EightConnected, // 线形
int shift = 0, // 不知道,一般用不上
Point offset = default(Point) // 不知道,一般用不上
)
此函数输入图像和输出图像使用一个变量传入,然后只需要再设定points和color两个参数就行。
二、填充不规则图形
1.原始素材
原始素材srcMat如下图:
图像宽737,长349。
2.代码
下面代码实现随机的五边形,填充到原始图像中:
Mat dstMat = srcMat.Clone();
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
VectorOfPoint vPoints1 = new VectorOfPoint();
System.Drawing.Point[] pt = new System.Drawing.Point[1];
int width = dstMat.Width;
int height = dstMat.Height;
Random random = new Random();
for (int i = 0; i < 5; i++)
{
pt[0].X = Convert.ToInt32(random.Next(0, width));
pt[0].Y = Convert.ToInt32(random.Next(0, height));
vPoints1.Push(pt);
}
contours.Push(vPoints1);
CvInvoke.FillPoly(dstMat, contours, new MCvScalar(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255)));
CvInvoke.Imshow("Final result image, " + dstMat.Size.ToString(), dstMat);
3.运行结果
上面的代码很简单,直接上运行结果:
二、最大轮廓填充颜色
1.原始素材
原始素材srcMat如下图:
图像宽979,长755。
2.代码
Mat tempMat = srcMat.Clone();
Mat dstMat = srcMat.Clone();
Mat gray = new Mat();
int threshold = Convert.ToInt16(TextBoxThreshold.Text.Trim().ToString());
// 转成灰度图再二值化
CvInvoke.CvtColor(tempMat, gray, ColorConversion.Bgr2Gray);
CvInvoke.Threshold(gray, gray, threshold, 255, ThresholdType.Binary);
CvInvoke.Imshow("Gray and threshold", gray);
// 定义轮廓集合
VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
VectorOfRect hierarchy = new VectorOfRect();
// 根据下拉框选择轮廓检索模式,查找轮廓并绘制
switch (ComboBoxType.Text)
{
case "External":
CvInvoke.FindContours(gray, contours, hierarchy, RetrType.External, ChainApproxMethod.ChainApproxNone);
break;
case "List":
CvInvoke.FindContours(gray, contours, hierarchy, RetrType.List, ChainApproxMethod.ChainApproxNone);
break;
case "Ccomp":
CvInvoke.FindContours(gray, contours, hierarchy, RetrType.Ccomp, ChainApproxMethod.ChainApproxNone);
break;
case "Tree":
CvInvoke.FindContours(gray, contours, hierarchy, RetrType.Tree, ChainApproxMethod.ChainApproxNone);
break;
default:
CvInvoke.FindContours(gray, contours, hierarchy, RetrType.Tree, ChainApproxMethod.ChainApproxNone);
break;
}
// 在一张黑色图中画出所有轮廓
Mat allContours = new Mat(new System.Drawing.Size(gray.Cols, gray.Rows), DepthType.Cv8U, 1);
allContours.SetTo(new MCvScalar(0, 0, 0));
CvInvoke.DrawContours(allContours, contours, -1, new MCvScalar(255, 255, 255), 1);
// 按照面积筛选,太小的轮廓不计算
Dictionary<int, double> dict = new Dictionary<int, double>();
if (contours.Size > 0)
{
for (int i = 0; i < contours.Size; i++)
{
double girth = CvInvoke.ArcLength(contours[i], true);
if (girth > 10 && girth < 3000000)
{
dict.Add(i, girth);
}
}
}
var item = dict.OrderByDescending(v => v.Value); // v.Value就代表周长,是降序排列
// 给最大轮廓绘制颜色
Random random = new Random();
foreach (var it in item)
{
int key = it.Key;
CvInvoke.FillPoly(dstMat, contours[key], new MCvScalar(random.Next(0, 255), random.Next(0, 255), random.Next(0, 255)));
break;
}
CvInvoke.Imshow("All contours, " + dict.Count(), allContours);
CvInvoke.Imshow("Final result image, " + dstMat.Size.ToString(), dstMat);
3.运行结果
二值化阈值选择40,轮廓检索模式选择External,运行结果:
二值化图形中,轮廓周长最大的,就是下面的那个球,所以整体都被填充成新的颜色了。
原创不易,请勿抄袭。共同进步,相互学习。