opencv(32) 图像轮廓之一:轮廓的查找和绘制

前面我们通过形态学操作、边缘检测得到了一些图像的边缘。

边缘检测虽然能够检测出边缘,但边缘是不连续的,检测到的边缘并不是一个整体。图像轮廓是指将边缘连接起来形成的一个整体,用于后续的计算。图像轮廓是图像中非常重要的一个特征信息,通过对图像轮廓的操作,我们能够获取目标图像的大小、位置、方向等信息。

轮廓是一些列相连的点组成的曲线,代表了物体的基本外形,相对于边缘,轮廓是连续的,边缘并不全是连续的。

1 图像轮廓的概念

轮廓是一系列相连的点组成的曲线,代表了物体的基本外形。
谈起轮廓不免想到边缘,它们确实很像。简单的说,轮廓是连续的,边缘并不全都连续。

其实边缘主要是作为图像的特征使用,比如可以用边缘特征可以区分脸和手;

而轮廓主要用来分析物体的形态,比如物体的周长和面积等,可以说边缘包括轮廓。

2 轮廓的查找与绘制

2.1 cv2.findContours()寻找轮廓

寻找轮廓的操作一般用于二值图像,所以通常会使用阈值分割或Canny边缘检测先得到二值图。

注意:寻找轮廓是针对白色物体的,一定要保证物体是白色,而背景是黑色,不然很多人在寻找轮廓时会找到图片最外面的一个框

函数原型:

contours,hierarchy=cv2.findContours(img,mode,method)

参数:

img 输入原始图。8位单通道。

mode 轮廓检 索模式,决定了轮廓的提取方式。

  • cv2.RETR_EXTERNAL 只检测外轮廓,所有子轮廓被忽略
  • cv2.RETR_LIST检测的轮廓不建立等级关系,所有轮廓属于同一等级
  • cv2.RETR_CCOMP返回所有的轮廓,只建立两个等级的轮廓。一个对象的外轮廓为第 1 级组织结构。而对象内部中空洞的轮廓为 2 级组织结构,空洞中的任何对象的轮廓又是第 1 级组织结构。
  • cv2.RETR_TREE建立一个等级树结构的轮廓,返回所有的轮廓,建立一个完整的组织结构的轮廓。

method 轮廓的近似方法,决定了如何表达轮廓。

  • cv2.CHAIN_APPROX_NONE存储所有的轮廓点,相邻的两个点的像素位置差不超过1
  • cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息。

返回值:

1 binary返回的二值图像

2 contours 图像中的轮廓,所有轮廓的列表结构,每个轮廓是目标对象边界点的坐标的数组

  •    len(contours)是轮廓的个数。
  •    contours[i]表示第i个轮廓中的像素个数

3 hierarchy 图像的拓扑信息(轮廓层次)。

在检测轮廓时:有时对象可能位于不同的位置,也有可能一个形状在另外一个形状的内部,这种情况下我们称外部的形状为父,内部的形状为子。

按照这种方式分类,一幅图像中的所有轮廓之间就建立父子关系。这样我们就可以确定一个轮廓与其他轮廓是怎样连接的,比如它是不是某个轮廓的子轮廓,或者是父轮廓。这种关系就是轮廓的层次关系。

在这幅图像中,我给这几个形状编号为 0-5。2 和 2a 分别代表最外边矩形的外轮廓和内轮廓。

在这里边轮廓 0,1,2 在外部或最外边。我们可以称他们为 0 级,简单来说就是他们属于同一级,接下来轮廓 2a,把它当成轮廓 2 的子轮廓。它就成为第 1 级。轮廓 3 是轮廓 2a 的子轮廓,成为第 3 级。轮廓 3a 是轮廓 3 的子轮廓,成为第 4 级,最后轮廓 4,5 是轮廓 3a 的子轮廓,成为5级,这样我们就构建的轮廓的层级关系。

我们再回到返回值中,不管层次结构是什么样的, 每一个轮廓都包含自己的信息。hierarchy使用包含四个元素的数组来表示:

[NextPrevious First_ChildParent]

其中:

Next 表示同一级组织结构中的下一个轮廓。以上图中的轮廓 0 为例,轮廓 1 就是他的 Next。同样,轮廓 1 的 Next 是 2,Next=2。 那轮廓 2 呢?在同一级没有 Next。这时 Next=-1。而轮廓 4 的 Next 为 5,所以它的 Next=5。

Previous 表示同一级结构中的前一个轮廓。轮廓 1 的 Previous 为轮廓 0,轮廓 2 的 Previous 为轮 廓 1。轮廓 0 没有 Previous,所以 Previous=-1。

First_Child 表示它的第一个子轮廓。轮廓 2 的子轮廓为 2a。 所以它的 First_Child 为 2a。那轮廓 3a 呢?它有两个子轮廓。但是我们只要第一个子轮廓,所以是轮 廓 4(按照从上往下,从左往右的顺序排序)。

Parent 表示它的父轮廓。与 First_Child 刚好相反。轮廓 4 和 5 的父轮廓是轮廓 3a。而轮廓 3a 的父轮廓是 3。

注意:如果轮廓没有父轮廓或子轮廓时,则将其置为-1。

2.2 cv.drawContours()绘制轮廓

函数原型:

img=cv2.drawContours(img, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None)

参数:

  1. img 待绘制轮廓的图像。
  2. contours 需要绘制的轮廓。
  3. contourIdx 需要绘制的边缘索引,如果为-1,则表示绘制全部轮廓。
  4. color 绘制的颜色,opencv中使用的是BGR格式,不是我们平时说的RGB。色彩空间转换。
  5. thickness 可选参数,表示绘制轮廓时使用画笔粗细,如果为-1,则表示填充,画出实心轮廓。
  6. line Type 可选参数,表示绘制轮廓时所使用的线型。
  7. hierarchy 对应函数cv2.findContours()所输出的层次信息。
  8. maxLevel 绘制轮廓层次的深度。
  9. offset: 偏移参数,该参数使轮廓偏移到不同的位置展示出来。

 2.3 示例

 

import cv2
import numpy as np

img = cv2.imread('C:\\Users\\xxx\\Downloads\\contourImg.png')    #读取图像
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转为灰度值图
ret, binary = cv2.threshold(gray,0,255,cv2.THRESH_BINARY) #转为二值图

#######轮廓查找############
'''
contours,hierarchy=cv2.findContours(img,mode,method)
参数:
    img: 输入原始图。8位单通道。
    mode: 轮廓检 索模式,决定了轮廓的提取方式。
    cv2.RETR_EXTERNAL 只检测外轮廓
    cv2.RETR_LIST检测的轮廓不建立等级关系
    cv2.RETR_CCOMP建立两个等级的轮廓
    cv2.RETR_TREE建立一个等级树结构的轮廓
    method: 轮廓的近似方法,决定了如何表达轮廓。
    cv2.CHAIN_APPROX_NONE存储所有的轮廓点
    cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,
        只保留该方向的终点坐标,例如一个矩形轮廓只需4个点来保存轮廓信息。
返回值:
    contours: 图像中的轮廓,数组。
                len(contours)是轮廓的个数。
                contours[i]表示第i个轮廓中的像素个数
    hierarchy: 图像的拓扑信息(轮廓层次)。

'''
contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
n=len(contours)       #轮廓个数
print(n)
for i in range(n):
    print(len(contours[i]))       #轮廓i像素数目
    print(contours[i])            #轮廓i每个像素的位置

#######轮廓绘制############
'''
img=cv2.drawContours(img, contours, contourIdx, color, thickness=None,
                     lineType=None, hierarchy=None, maxLevel=None, offset=None)
    img: 待绘制轮廓的图像。
    contours: 需要绘制的轮廓。
    contourIdx: 需要绘制的边缘索引,如果为-1,则表示绘制全部轮廓。
    color: 绘制的颜色,opencv中使用的是BGR格式,不是我们平时说的RGB。色彩空间转换。
    thickness: 可选参数,表示绘制轮廓时使用画笔粗细,如果为-1,则表示填充,画出实心轮廓。
    line Type: 可选参数,表示绘制轮廓时所使用的线型。
    hierarchy: 对应函数cv2.findContours()所输出的层次信息。
    maxLevel: 绘制轮廓层次的深度。
    offset: 偏移参数,该参数使轮廓偏移到不同的位置展示出来。
'''
img2 = img.copy()
img2 = cv2.drawContours(img2,contours,-1,(0,255,0),5)

#显示原图,灰度图,二值图,轮廓图
names = ['Original','gray','binary','contours']
images = [img,gray,binary,img2]

for i in range(4):
    cv2.imshow(names[i],images[i])

cv2.waitKey(0)
cv2.destroyAllWindows()

 运行结果如下:

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值