当前位置: 首页 > 工具软件 > Contour > 使用案例 >

OpenCV contour detection(C++实现)(二)

瞿兴朝
2023-12-01

上一篇OpenCV contour detection(C++实现)(一)实现了image的读取、灰度处理、高斯模糊、canny边缘检测、轮廓检测、轮廓绘制。本篇在之前基础上对检测到的轮廓进行多边形逼近(使用多边形逼近轮廓,减少表示轮廓的Point)。

  1. conPoly变量保存多边形逼近后的轮廓

    vector<vector<cv::Point>> conPoly(contours.size());
    

    回顾一下,contoursconPoly变量第一维是每一个轮廓的序号,第二维是每一个轮廓包含的点集。

  2. 通过轮廓面积筛选轮廓
    contourArea()函数,定义:

    double contourArea( InputArray contour, bool oriented = false );
    

    参数:
    contour:一个轮廓
    oriented:为true时,返回结果带符号,取决于轮廓是顺时针还是逆时针(点集也可以看成向量集),一般取默认值false即可
    可以计算每个轮廓的面积:

    int area = contourArea(contours[i]);
    
  3. 多边形逼近
    函数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);
    
  4. 多边形轮廓分类
    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:矩形的一对相对的顶点
    recRect
    colorScalar(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的左下角,否则是左上角

 类似资料: