查找并绘制轮廓---OpenCV-Python开发指南(24)

简介: 查找并绘制轮廓---OpenCV-Python开发指南(24)

什么是图像轮廓


在前面的边缘检测中,虽然我们能够检测出边缘信息,但边缘是不连续的,检测到的边缘并不是一个整体。而图像的轮廓负责将边缘连接起来形成一个整体,用于后续的计算。


需要特别注意,图像的轮廓是非常重要的一个特征信息,通过对图像轮廓的操作,我们能够获取目标图像的大小,位置以及方向等信息。


查找图像轮廓


图像中一个轮廓对应着一系列的点,这些点以某种形式表示图像中的一条曲线。在OpenCV中,它给我们提供了函数cv2.findContours()用于查找图像的轮廓,并能够根据参数返回特定表示方式的轮廓。


该函数的完整定义如下:

def findContours(image, mode, method, contours=None, hierarchy=None):

image:原始图像,所有非0值处理为1,所有0值保持不变


mode:轮廓检索模式

参数

含义
cv2.RETR_EXTERNAL 只检测外轮廓
cv2.RETR_LIST 对检测到的轮廓不建立等级关系
cv2.RETR_CCOMP 检测所有轮廓并将它们组织成两级层次关系。上层为外边界,下层为内孔边界。如果内孔内还有一个连同物体,那么这个物体的边界仍然位于顶层
cv2.RETR_TREE 建立一个等级树结构轮廓

method:轮廓的近似方法

参数

含义
cv2.CHAIN_APPROX_NONE 存储所有的轮廓点,相邻两个点的像素位置差不超过1
cv2.CHAIN_APPROX_SIMPLE 压缩水平方向,垂直方向,对象线方向的元素,只保留该方向的终点坐标。例如,在极端的情况下,一个矩形只需要用4个点来保存轮廓信息
cv2.CHAIN_APPROX_TC89_L1 使用teh_Chinl chain近似算法的一种风格

cv2.CHAIN_APPROX_TC89_KCOS

使用teh_Chinl chain近似算法的一种风格

contours:返回的轮廓。比如一个图像中有3个不交叉的形状:圆,矩形以及正反向。那么它就是一个长度为3的list,也就是有3个轮廓,contours[i][j]就是第i个轮廓的第j个点。


当然,图像的轮廓并不一定是不交叉的,假如几个形状的轮廓相互交叉,那么就形成了父子关系,contours[i]用4个元素来说明轮廓的层次关系。


Next:后一个轮廓的索引编号

Previous:前一个轮廓的索引编号

First_Child:第一个子轮廓的索引编号

Parent:父轮廓的索引编号

如果上面参数都为空,也就是前面讲的各个形状轮廓不交叉的情况。且值为“-1”。


特别注意,轮廓的层次结构是由参数mode决定的,也就是说,使用不同的mode,得到的轮廓编号是不一样的,hierarchy也不一样。


hierarchy:图像的拓扑信息


其返回值为3个参数:image,contours以及hierarchy。而在OpenCV4.X版本中,该函数返回值只有两个:contours,hierarchy。


下面,我们重点讲解参数mode。


参数mode


(1) cv2.RETR_EXTERNAL (只检测外轮廓)


假如我们现在我们图像如上图所示,当我们采用 cv2.RETR_EXTERNAL参数时,hierarchy的拓扑信息为:


[[

[1 -1 -1 -1]

[-1 0 -1 -1]

]]


[1 -1 -1 -1]这4个参数分别对应contours的4个元素。


Next1:也就是表示它后一个轮廓,这里0的后一个轮廓为1


Previous-1:第0个轮廓没有前一个轮廓


First_Child-1:0它不存在子轮廓


Parent-1:0它也不存在父轮廓


[-1 0 -1 -1]对应图像1,意思分别如下:


-1 :1轮廓不存在下一个轮廓


0:第1个轮廓有前一个0轮廓,所以为0


-1 :1它不存在子轮廓


-1:1它也不存在父轮廓


其拓扑结构如下:


(2) cv2.RETR_LIST(对检测到的轮廓不建立等级关系)


假设我们使用原图如上所示,那么hierarchy的值为:


[[

[1 -1 -1 -1]

[2 0 -1 -1]

[-1 1 -1 -1]

]]


[1 -1 -1 -1]含义:


1 :0轮廓的下一个轮廓是1,故返回1


-1:第0个轮廓没有前轮廓,所以为-1


-1 :0它不存在子轮廓


-1:0它也不存在父轮廓


[2 0 -1 -1]含义:


2:1轮廓的下一个轮廓是2,故返回2


0:第1个轮廓前轮廓为0,所以值为0


-1 :1它不存在子轮廓


-1:1它也不存在父轮廓


[-1 1 -1 -1]含义:


-1:2轮廓没有下一个轮廓,故返回-1


1:第2个轮廓前轮廓为1,所以值为1


-1 :2它不存在子轮廓


-1:2它也不存在父轮廓


此关系的拓扑结构为:


(3) cv2.RETR_CCOMP(建立两个等级的轮廓)


当mode参数为 cv2.RETR_CCOMP,原图如上所示,其hierarchy值为:


[[

[1 -1 -1 -1]

[-1 0 2 -1]

[-1 -1 -1 1]

]]


[1 -1 -1 -1]含义如下:


1:0轮廓的下一个轮廓为1,故返回1


-1:第0个轮廓没有前轮廓,所以值为-1


-1 :0它不存在子轮廓


-1:0它也不存在父轮廓


[-1 0 2 -1]含义如下:


-1:1轮廓没有下一个轮廓,故返回-1


0:第1个轮廓前轮廓为0,所以值为0


2 :第1个轮廓的子轮廓为2,所以值为2


-1:第1个轮廓它也不存在父轮廓


[-1 -1 -1 1]含义如下:


-1:2轮廓没有下一个轮廓,故返回-1


-1:第2个轮廓前轮廓不存在,所以值为-1


-1:第2个轮廓也不存在子轮廓


1:第2个轮廓父轮廓为1,所以取值为1


其拓扑结构如下:



(4) cv2.RETR_TREE(建立一个等级树结构轮廓)


当图还是(3)图时,其mode取值为 cv2.RETR_TREE,返回的hierarchy的值为:


[[

[1 -1 -1 -1]

[-1 0 2 -1]

[-1 -1 -1 1]

]]


[1 -1 -1 -1]含义如下:


1:0轮廓下一个轮廓为1,故返回1


-1:第0个轮廓前轮廓不存在,所以值为-1


-1:第0个轮廓也不存在子轮廓


-1:第0个轮廓也不存在父轮廓


[-1 0 2 -1]含义如下:


-1:1轮廓没有下一个轮廓,故返回-1


0:第1个轮廓前轮廓为0,所以值为0


2:第1个轮廓存在子轮廓2,所以取值为2


-1:第1个轮廓不存在父轮廓


[-1 -1 -1 1]含义如下:


-1:2轮廓没有下一个轮廓,故返回-1


-1:第2个轮廓没有前轮廓,所以值为-1


-1:第2个轮廓不存在子轮廓


1:第2个轮廓存在父轮廓1,取值为1


拓扑结构也是(3)图。


绘制图像轮廓


在OpenCV中,它给我们提供了cv2.drawContours()来绘制图像轮廓,其完整定义如下:

def drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None):

image:待绘制轮廓的图像


contours:需要绘制的轮廓


contourIdx:需要绘制的边缘索引,-1表示绘制所有,0以及正数表示绘制对应的轮廓。


color:绘制的颜色


thickness:绘制轮廓的画笔,取值为“-1”表示绘制实心轮廓


lineType:绘制轮廓的线型


hierarchy:对应函数cv2.findContours()所输出的层次信息


maxLevel:控制所绘制的轮廓层次的深度,如果值为0表示只绘制第0层


offset:偏移参数,是绘制的轮廓偏移一定的位置


下面,我们来实战绘制图像的轮廓,具体代码如下所示:

import cv2
img = cv2.imread("24.jpg")
cv2.imshow("img", img)
# 转换为灰度图像
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 转换为二值图
ret, binary = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
# 获取图像的轮廓参数
contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
result = cv2.drawContours(img, contours, -1, (0, 0, 255), 5)
cv2.imshow("result", result)
cv2.waitKey()
cv2.destroyAllWindows()


运行之后,效果如下:


不过这种并不是终极目的,我们获取轮廓的目的是将图像分离,也就是我现在向获取这3个轮廓的单一子图怎么办呢?直接上代码吧。

import cv2
import numpy as np
img = cv2.imread("24.jpg")
cv2.imshow("img", img)
# 转换为灰度图像
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 转换为二值图
ret, binary = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
# 获取图像的轮廓参数
contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
result = []
for i in range(len(contours)):
    temp = np.zeros(img.shape, dtype=np.uint8)
    result.append(temp)
    result[i] = cv2.drawContours(result[i], contours, i, (0, 0, 255), 5)
    cv2.imshow(str(i), result[i])
cv2.waitKey()
cv2.destroyAllWindows()


运行之后,我们就能分离出各个图形了。


图像轮廓结合按位与获取图像前景对象


除了分离纯粹的图像轮廓用于机器学习识别之外,我们还可以获取图像的前景对象。这里,我们只需要更换图像,修改最后几行代码。


具体代码如下所示:

import cv2
import numpy as np
img = cv2.imread("4.jpg")
cv2.imshow("img", img)
# 转换为灰度图像
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 转换为二值图
ret, binary = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
# 获取图像的轮廓参数
contours, hierarchy = cv2.findContours(binary, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
mask = np.zeros(img.shape, dtype=np.uint8)
mask = cv2.drawContours(mask, contours, -1, (255, 255, 255), -1)
cv2.imshow("MASK",mask)
result=cv2.bitwise_and(img,mask)
cv2.imshow("result",result)
cv2.waitKey()
cv2.destroyAllWindows()


运行之后,效果如下所示:

最左边的是原始图像


中间的是从原始图像得到的人物实心轮廓


最右边的是提取的前景对象人物

相关文章
|
2月前
|
数据采集 存储 XML
深入浅出:基于Python的网络数据爬虫开发指南
【2月更文挑战第23天】 在数字时代,数据已成为新的石油。企业和个人都寻求通过各种手段获取互联网上的宝贵信息。本文将深入探讨网络爬虫的构建与优化,一种自动化工具,用于从网页上抓取并提取大量数据。我们将重点介绍Python语言中的相关库和技术,以及如何高效、合法地收集网络数据。文章不仅为初学者提供入门指导,也为有经验的开发者提供进阶技巧,确保读者能够在遵守网络伦理和法规的前提下,充分利用网络数据资源。
|
5月前
|
计算机视觉 Python
OpenCV轮廓拟合与凸包的讲解与实战应用(附Python源码)
OpenCV轮廓拟合与凸包的讲解与实战应用(附Python源码)
62 0
|
7月前
|
计算机视觉
OpenCV-计算轮廓周长cv::arcLength
OpenCV-计算轮廓周长cv::arcLength
|
16天前
|
存储 计算机视觉 索引
【OpenCV】-查找并绘制轮廓
【OpenCV】-查找并绘制轮廓
|
5月前
|
算法 计算机视觉 开发者
OpenCV图形检测中绘制图像的轮廓讲解与实战应用(附Python源码)
OpenCV图形检测中绘制图像的轮廓讲解与实战应用(附Python源码)
78 0
|
2月前
|
计算机视觉
OpenCV(三十四):轮廓外接最大、最小矩形和多边形拟合
OpenCV(三十四):轮廓外接最大、最小矩形和多边形拟合
119 0
|
2月前
|
计算机视觉
OpenCV(三十三):计算轮廓面积与轮廓长度
OpenCV(三十三):计算轮廓面积与轮廓长度
70 0
|
2月前
|
计算机视觉 索引
OpenCV(三十二):轮廓检测
OpenCV(三十二):轮廓检测
20 0
|
7月前
|
计算机视觉
OpenCV-计算轮廓面积cv::contourArea
OpenCV-计算轮廓面积cv::contourArea
105 0
|
9月前
|
存储 算法 计算机视觉
【OpenCV图像处理8】图像轮廓
【OpenCV图像处理8】图像轮廓
214 0