上一篇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的左下角,否则是左上角