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

 

posted @ 2020-02-21 22:11  狂奔的小学生  阅读(8186)  评论(0编辑  收藏  举报