• opencv —— findContours、drawContours 寻找并绘制轮廓


    轮廓图像与 Canny 图像的区别

    一个轮廓一般对应一系列的点,也就是图像中的一条曲线。轮廓图像和 Canny 图像乍看起来表现几乎是一致的,但其实组成两者的数据结构差别很大:

    • Canny 边缘图像是一个点的集合,点与点之间没有联系。

    •  轮廓图像是一个点集的集合,每个点集(即轮廓)内的点都是相邻的,点集与点集之间也存在前后、父内等关系。

    寻找轮廓:findContours 函数

    findContours 函数用于在二值图像中寻找轮廓。

    void findContours(InputArray image, OutputArrays contours, OutputArray hierarchy, int mode, int method, Point offset = Point());

    • image,输入图像,即源图像,填 Mat 类的对象即可,可以是灰度图(非零像素被视为 1),但更常用的是二值图像,一般是经过Canny、拉普拉斯等边缘检测算子处理过的二值图像。
    • contours,检测到的所有轮廓均会被存在这里。每个轮廓为一个点集,用 Point 类型的 vector 表示。所以会被定义为

    vector<vector<Point> > contours

    • hierarchy,每个轮廓 contours[i] 对应四个 hierarchy[i][0] ~ hierarchy[i][3],分别表示与当前轮廓平级的后一个轮廓的的索引编号、与当前轮廓平级的前一个轮廓的索引编号、当前轮廓的子轮廓的索引编号、当前轮廓的父轮廓的索引编号。如果没有对应项,hierarchy[i][x] = -1。
    • mode,轮廓检索模式,取值如下:

    标识符 含义
    RETR_EXTERNAL

    只检测最外层轮廓,包含在外围轮廓内的内围轮廓被忽略。不存在父轮廓或内嵌轮廓

    (hierarchy[i][2] = hierarchy[i][3] = -1)。

    RETR_LIST

    提取所有轮廓,并且放置在 list 中。不存在父轮廓或内嵌轮廓

    (hierarchy[i][2] = hierarchy[i][3] = -1)。

    再举个例子:

     

    RETR_CCOMP

    提取所有轮廓,无论嵌套个数多少,都将其组织为双层结构(外层、内层)。

    再举个例子:

    RETR_TREE

    提取所有轮廓,并建立网状的轮廓结构(最外层轮廓为根)。

    再举个例子:

     

    • method,轮廓的近似办法,取值如下:
    标识符 含义
    CHAIN_APPROX_NONE 获取每个轮廓的每个像素,相邻的两个像素位差不超过 1 像素。
    CHAIN_APPROX_SIMPLE 仅保存轮廓的拐点信息,拐点与拐点之间直线段上的信息点不予保留。例如一个矩形轮廓只需 4 个点来保留轮廓信息。

    CHAIN_APPROX_TC89_L1

    CHAIN_APPROX_TC89_KCOS

    使用 teh-Chinl chain 近似算法。
    • offset,所有的轮廓信息相对于原始图像对应点的偏移量,相当于在每一个检测出的轮廓点上加上该偏移量,有默认值 Point() 。对 ROI 区域(感兴趣区域)中找出的轮廓,并要在整个图像中进行分析时,这个参数便可派上用场。

    绘制轮廓:drawContours 函数

    void drawContours(InputOutputArray image, InputOutputArrays contours, int contourIdx, const Scalar& color, int thickness = 1, int lineType = 8, InputArray hierarchy = noArray(), int maxLevel = INT_MAX, Point offset = Point());

    • image,目标图像,填 Mat 类对象即可。
    • contours,输入的轮廓,每个轮廓都是一组点集,可用 Point 类型的 vector 表示。
    • contourIdx,轮廓的索引编号。若为负值,则绘制所有轮廓。
    • color,轮廓颜色。
    • thickness,轮廓线条的粗细程度,有默认值 1。若其为负值,便会填充轮廓内部空间。
    • lineType,线条的类型,有默认值 8。可去类型如下:
    类型 含义
    8 8 连通线型
    4 4 连通线型
    LINE_AA 抗锯齿线型
    • hierarchy,可选的层次结构信息,有默认值 noArray()。
    • maxLevel,用于绘制轮廓的最大等级,有默认值 INT_MAX。
    • offset,轮廓信息相对于目标图像对应点的偏移量,相当于在每一个轮廓点上加上该偏移量,有默认值 Point() 。在 ROI 区域(感兴趣区域)绘制轮廓时,这个参数便可派上用场。

    代码示例:

    #include<opencv.hpp>
    #include<iostream>
    #include<vector>
    using namespace std;
    using namespace cv;
    int main() {
        Mat src = imread("C:/Users/齐明洋/Desktop/3.jpg");
        imshow("src", src);
    
        Mat canny_img;
        Canny(src, canny_img, 55, 110, 3);
        //闭操作,先膨胀后腐蚀,可消除小黑点
        Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
        morphologyEx(canny_img, canny_img, MORPH_CLOSE, kernel);
        imshow("canny_img", canny_img);
    
        Mat dst = Mat(src.rows, src.cols, CV_8UC3, Scalar(0, 0, 0));
        vector<vector<Point> >contours;
        
        ////写法一
        //vector<Vec4i>hierarchy;
        //findContours(canny_img, contours,hierarchy, RETR_TREE, CHAIN_APPROX_NONE);
        //for (int i = 0; i < contours.size(); i++) {
        //    drawContours(dst, contours, i, Scalar(0, 0, 255), 1, 8, hierarchy);
        //}
        
        //写法二
        findContours(canny_img, contours, RETR_TREE, CHAIN_APPROX_NONE);
        drawContours(dst, contours, -1, Scalar(0, 255, 0), 1);
    
        imshow("dst", dst);
    
        waitKey(0);
    }

    效果演示:

    借鉴博客:https://www.cnblogs.com/GaloisY/p/11062065.html

    https://blog.csdn.net/qq_35239859/article/details/99676501

  • 相关阅读:
    卡常技巧
    Java经典习题3
    Java经典习题4
    VC++ MFC 文件处理unicode
    批处理更换ip地址
    C#实现系统托盘
    驱动打印
    c++ vs2010 GetWindowText GetWindowTextW
    VC++ MFC ListBox 复选框
    C# 获取本机ip地址
  • 原文地址:https://www.cnblogs.com/bjxqmy/p/12343385.html
Copyright © 2020-2023  润新知