OpenCV学习笔记-初识轮廓

一、什么是轮廓

轮廓可以简单认为成将连续的点(连着边界)连在一起的曲线,具有相同的颜色或者灰度。轮廓在形状分析和物体的检测和识别中很有用。
    1、为了更加准确,要使用二值化图像。在寻找轮廓之前,在进行阈值化处理或者canny边界检测。
    2、查找轮廓的函数会修改原始图像。如果你在找到轮廓之后还想使用原始图像的话,你应该将原始图像存储到其他变量中。
    3、在OpenCV中,查找轮廓就像在黑色背景中超白色物体。你应该记住,要找的物体应该是白色而背景应该是黑色。

二、函数详解

查找轮廓函数:在一个二值图像中查找轮廓
findContours(image, mode, method, contours=None, hierarchy=None, offset=None)
   
     image: 输入图像,需要为8位单通道图像,此函数会在提取图像轮廓的同时修改图像内容
   
    mode: 检索模式,可选模式包括:
            RETR_EXTERNAL:只监测最外层轮廓。hierarchy[i][2] = hierarchy[i][3] = -1
            RETR_LIST:提取所有轮廓,并放置在list中。检测的轮廓不建立等级关系
            RETR_CCOMP:提取所有轮廓,并将其组织为双层结构,顶层为联通域的外围边界,次层为空的内层边界,即是'洞'
            RETR_TREE:提取所有轮廓,并重新建立网状的轮廓结构。
           
    method:轮廓的近似方法:
            CHAIN_APPROX_NONE:获取每个轮廓的每个像素,相邻两点像素位置差不超过1,max(abs(x1-x2), abs(y1-y2)) == 1
            CHAIN_APPROX_SIMPLE:压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标
            CHAIN_APPROX_TC89_L1/CHAIN_APPROX_TC89_KCOS:使用Ten-Chinl链逼近算法中的一个
           
    contours:是一个Python列表,其中存储着图像中的所有轮廓。每一个轮廓都是一个numpy数组,包含对象边界点(x, y)的坐标。
   
    hierarchy:可选的输出向量,包含图像的拓扑信息。每个轮廓contours[i]
                hierarchy[i][0]:后一个轮廓
                hierarchy[i][1]:前一个轮廓
                hierarchy[i][2]:父轮廓
                hierarchy[i][3]:内嵌轮廓的索引编号
                如果没有对应项,hierarchy[i]的对应项设为负数
   
    offset: 每个轮廓点的可选偏移量,默认point(),当ROI图像中找出的轮廓需要在整个图中进行分析时,可利用这个参数


绘制轮廓函数:它可以根据你提供的边界点绘制任何形状

drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None)
       
         image:目标图像
       
        contours: 输入轮廓,每个轮廓存储为一个点向量
       
        contourIdx: 需要绘制的轮廓的编号,如果为-1,绘制所有的轮廓
       
        color: 轮廓的颜色
       
        thickness:轮廓线条粗细度,如果为-1 ,填充
       
        lineType: 线条类型:
                    cv.LINE_AA:抗锯齿线条
                    cv.LINE_4: 4连通线型
                    cv.LINE_8:8连通线型
       
        hierarchy: 可选层次结构
       
        maxLevel:绘制轮廓的最大等级
       
        offset: 可选轮廓偏移参数

三、轮廓的近似方法

上面我们已经提到轮廓是一个形状具有相同灰度值的边界。它会存储形状边界上所以的(x, y)坐标。但是需要将所有的边界点都存贮吗?这就是这个参数要告诉findContours的
CHAIN_APPROX_NONE:所有的边界点都会被存储。当我们找到的边界是一条直线时。你会用所有的点表示一条直线吗?不会,我们只需要这条直线的两个端点而已。这就是 CHAIN_APPROX_SIMPLE要做的。它会将轮廓上的冗余点都去掉,压缩轮廓,从而节省内存开支。
我们来通过效果对比:

第一图是 CHAIN_APPROX_NONE,第二图是 CHAIN_APPROX_SIMPLE

四、具体代码

def contours_demo(img):
    #高斯模糊,去除噪声
    dst = cv.GaussianBlur(img, (3, 3), 0)
    #灰度化
    gray = cv.cvtColor(dst, cv.COLOR_BGR2GRAY)
    #二值化
    ret, binary = cv.threshold(gray, 0, 255, cv.THRESH_BINARY | cv.THRESH_OTSU)
    cv.imshow('binary image', binary)

    # binary = edge_demo(img)

    #调用API 发现轮廓
    cloneImage, contours, heriachy = cv.findContours(binary, cv.RETR_EXTERNAL, cv.CHAIN)
    
    #绘制轮廓
    for i, contour in enumerate(contours):
        cv.drawContours(img, contours, i, (0, 0, 255), lineType=cv.LINE_AA)
        print(i)
    cv.imshow('contours image', img)

轮廓查找最难理解的是轮廓的层级结构,所以我单独拿出来记录。 轮廓的层级结构

参考文章:

https://blog.csdn.net/guduruyu/article/details/69220296
https://mp.weixin.qq.com/s?__biz=MzU2MDAyNzk5MA==&mid=2247483695&idx=1&sn=e6068895b92749da4cf43c0ef7e87ed8&chksm=fc0f0116cb78880042081292735c468d1bbae57afb3e998468667d39a15a3bee7b1ebe7d9aa7#rd
https://www.cnblogs.com/Xiaoyan-Li/p/5761510.html


 
 


猜你喜欢

转载自blog.csdn.net/qq_36387683/article/details/80455300