文章目录
- 一、轮廓的外接矩形
- 二、轮廓的面积
- 三、两个函数的简单应用
- 1.原始素材
- 2.代码
- 3.运行结果
一、轮廓的外接矩形
轮廓的外接矩形,函数是:
public static Rectangle BoundingRectangle
(IInputArray points // 输入的轮廓
)
函数返回的是一个矩形,由此就可以得到一个物体轮廓的最小外接矩形。注意了,这个矩形是不带旋转的正矩形。
二、轮廓的面积
计算轮廓面积的函数是:
public static double ContourArea
(IInputArray contour, // 输入的轮廓bool oriented = false // 有默认值false,面向区域标识符,如果为true,该函数返回一个带符号的面积,其正负取决于轮廓的方向(顺时针还是逆时针)。根据这个特性可以根据面积的符号来确定轮廓的位置。如果是默认值false,则面积以绝对值的形式返回。
)
面积函数返回的是双精度浮点数,一般在计算的时候,oriented 变量设置为false,或者干脆不设置。
三、两个函数的简单应用
1.原始素材
原始素材srcMat如下图:
2.代码
利用如下代码,计算图片中白色物体的所有轮廓,并按照轮廓面积大小降序排列,并且在图片中要标注出轮廓的序号,代码如下:
Mat tempMat = srcMat.Clone();
Mat dstMat = srcMat.Clone();
Mat gray = new Mat();
int threshold = 40;// 转成灰度图再二值化
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();CvInvoke.FindContours(gray, contours, hierarchy, RetrType.List, ChainApproxMethod.ChainApproxNone);Dictionary<int, double> dict = new Dictionary<int, double>();
if (contours.Size > 0)
{for (int i = 0; i < contours.Size; i++){double area = CvInvoke.ContourArea(contours[i]);Rectangle rect = CvInvoke.BoundingRectangle(contours[i]);if (rect.Width > 10 && rect.Height > 1 && area < 3000000){dict.Add(i, area);}}
}var item = dict.OrderByDescending(v => v.Value); // v.Value就代表面积,是降序排列
int index = 1;
foreach (var it in item)
{int key = it.Key;int area = Convert.ToInt32(it.Value);Rectangle rect = CvInvoke.BoundingRectangle(contours[key]);CvInvoke.Rectangle(dstMat, rect, new MCvScalar(255, 255, 255), 3);CvInvoke.PutText(dstMat, "Contour:" + index.ToString() + ",area:" + area, new System.Drawing.Point(rect.X, rect.Y - 10), FontFace.HersheyComplex, 0.4, new Bgr(0, 255, 0).MCvScalar, 1, LineType.EightConnected, false);index++;
}CvInvoke.PutText(dstMat, "Contours number:" + dict.Count(), new System.Drawing.Point(20, 20), FontFace.HersheyComplex, 0.5, new Bgr(0, 255, 0).MCvScalar, 1, LineType.EightConnected, false);
CvInvoke.DrawContours(dstMat, contours, -1, new MCvScalar(0, 255, 0), 2, LineType.EightConnected, hierarchy);
CvInvoke.Imshow("Final result image, " + dstMat.Size.ToString(), dstMat); // 显示最终结果
3.运行结果
轮廓检索模式要选择RetrType.List, 如下所示:
- 一共是7个轮廓,面积最大的是68522个像素(编号是1),面积最小的是63个像素(编号7)。
- 利用DrawContours()函数,将每个轮廓都画成绿色。
- 利用BoundingRectangle()函数,求出每个轮廓的最小外接矩形,并在后面用白色线条画出来。
- 最重要的一点,在将轮廓逐个添加到 dict 字典时,我用了一个筛选条件,也就是如果轮廓的外接矩形宽、高都不太小,而且轮廓面积不太大,才是希望得到的结果。因为在某些二值化图像中,经常会出现一两个像素点组成的轮廓,即使用了形态学处理,这种情况也会发生。因此很有必要对轮廓进行过滤。
原创不易,请勿抄袭。共同进步,相互学习。