上一篇OpenCV contour detection(C++实现)(一)实现了image的读取、灰度处理、高斯模糊、canny边缘检测、轮廓检测、轮廓绘制。本篇在之前基础上对检测到的轮廓进行多边形逼近(使用多边形逼近轮廓,减少表示轮廓的Point)。
-
用
conPoly
变量保存多边形逼近后的轮廓vector<vector<cv::Point>> conPoly(contours.size());
回顾一下,
contours
、conPoly
变量第一维是每一个轮廓的序号,第二维是每一个轮廓包含的点集。 -
通过轮廓面积筛选轮廓
contourArea()
函数,定义:double contourArea( InputArray contour, bool oriented = false );
参数:
contour
:一个轮廓
oriented
:为true时,返回结果带符号,取决于轮廓是顺时针还是逆时针(点集也可以看成向量集),一般取默认值false即可
可以计算每个轮廓的面积:int area = contourArea(contours[i]);
-
多边形逼近
函数approxPolyDP()
,定义:void approxPolyDP( InputArray curve, OutputArray approxCurve, double epsilon, bool closed );
参数:
curve
:保存2D Point的集合,可以是vector<cv::Point>
或cv::Mat
类
approxCurve
:保存逼近结果,需要和curve
类型相同
epsilon
:用来指定逼近精度,表示原始轮廓到近似轮廓之间的最大距离
closed
:为true时,近似轮廓首尾顶点相连
事实上,对不同大小的contour一般会指定不同大小的epsilon
,常用加权的轮廓周长,计算轮廓周长使用arcLength
函数:double arcLength( InputArray curve, bool closed );
参数同
approxPolyDP
,多边形逼近过程可以写做如下(示例):double param = arcLength(contours[i], true); approxPolyDP(contours[i], conPoly[i], 0.02*param, true);
-
多边形轮廓分类
conPoly
中有几个Point,逼近轮廓就是几边形,可以以此来对conPoly分类。用长方形边框框出每一个conPoly:
boundingRect()
函数:Rect boundingRect( InputArray array );
输入灰度图或者2D Point集,返回点集或灰度图像的非零像素的最小边界矩形。返回类型
Rect
是OpenCV内的矩形类。
接下来还需要把这个矩形绘制出来,使用rectangle()
函数:void rectangle(InputOutputArray img, Point pt1, Point pt2, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0); //overload void rectangle(InputOutputArray img, Rect rec, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0);
参数:
img
:图像
pt1、pt2
:矩形的一对相对的顶点
rec
:Rect
类
color
:Scalar(B, G, R)
类,矩形框颜色
thickness
:矩形框粗细
lineType
:线型,上一篇有介绍
shift
:坐标点的小数点位数
那么分类多边形轮廓边数、绘制矩形框过程可以写做如下://其实需要一个循环遍历contours、conPoly和boundRect //这里是伪代码,只写一个下标作为示例 //多边形逼近 double param = arcLength(contours[i], true);//轮廓周长 approxPolyDP(contours[i], conPoly[i], 0.02*param, true);//多边形逼近 //多边形分类 string objType;//多边形类型 int objCor = (int)conPoly[i].size();//轮廓的角点数量 if(objCor == 3) objType = "Tri";//若角点数量为3,则多边形轮廓为三角形...以此类推 //绘制边界框 vector<Rect> boundRect(contours.size());//这个变量保存每个轮廓对应的边界框 boundRect[i] = boundingRect(conPoly[i]);//获取边界矩形 //Rect类的成员函数tl()、br()是矩形的左上角(top_left)、右下角(bottom_right)点 rectangle(img, boundRect[i].tl, boundRect[i].br, Scalar(255, 0, 255), 4);//绘制边界框 //最后给边框加上文字标注 putText(img, objType, {boundRect[i].x, boundRect[i].y - 5}, FONT_HERSHEY_PLAIN, 1, Scalar(0, 69, 255), 1);
最后补充下创建文本操作,使用
putText
函数,定义:void putText( InputOutputArray img, const String& text, Point org, int fontFace, double fontScale, Scalar color, int thickness = 1, int lineType = LINE_8, bool bottomLeftOrigin = false );
部分参数:
org
:text的origin坐标
fontFace
:字体
fontScale
:字体大小
bottomLeftOrigin
:为true时,origin坐标是text的左下角,否则是左上角