opencv:图像轮廓检测 cv2.findContours() 与 cv2.drawContours()

1 cv2.findContours()

OpenCV-Python接口中使用cv2.findContours()函数来查找检测物体的轮廓。

cv2.findContours(image, mode, method, contours=None, hierarchy=None, offset=None)
参数描述返回
image寻找轮廓的图像,注意输入的图片必须为二值图片。若输入的图片为彩色图片,必须先进行灰度化和二值化

opencv2返回两个值:一个是轮廓本身contours,还有一个是每条轮廓对应的属性hierarchy

opencv3返回三个值:img, countours, hierarchy

mode轮廓的检索模式,有4种
method轮廓的近似办法,有4种
contours使用findContours检测到的轮廓数据,每个轮廓以点向量的形式存储,point类型的vector 
hierarchy可选层次结构信息
offset可选轮廓偏移参数,用制定偏移量offset=(dx, dy)给出绘制轮廓的偏移量
  • 轮廓的检索模式:
mode描述
cv2.RETR_EXTERNAL只检测外轮廓
 cv2.RETR_LIST提取所有轮廓,并放置在list中,检测的轮廓不建立等级关系 
cv2.RETR_CCOMP建立两个等级的轮廓,上面的一层为外边界,里面的一层为内孔的边界信息。如果内孔内还有一个连通物体,这个物体的边界也在顶层。
 cv2.RETR_TREE检测所有轮廓,建立完整的层次结构,建立网状轮廓结构 
  • 轮廓的近似办法
method描述
cv2.CHAIN_APPROX_NONE获取每个轮廓的每个像素,相邻的两个点的像素位置差不超过1
cv2.CHAIN_APPROX_SIMPLE压缩水平方向,垂直方向,对角线方向的元素,值保留该方向的重点坐标,如果一个矩形轮廓只需4个点来保存轮廓信息 
cv2.CHAIN_APPROX_TC89_L1使用Teh-Chini chain近似算法
cv2.CHAIN_APPROX_TC89_KCOS使用Teh-Chini chain近似算法

1.1 contour返回值

cv2.findContours()函数首先返回一个list,list中每个元素都是图像中的一个轮廓信息,list中每个元素(轮廓信息)类型为ndarray。len(contours[1]) 表示第一个轮廓储存的元素个数,即该轮廓中储存的点的个数。

1.2 hierarchy返回值

该函数还可返回一个可选的hiararchy结果,这是一个ndarray,其中的元素个数和轮廓个数相同,每个轮廓contours[i]对应4个hierarchy元素hierarchy[i][0] ~hierarchy[i][3],分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引编号,如果没有对应项,则该值为-1。

  • 第一个数:表示同一级轮廓的下个轮廓的编号,如果这一级轮廓没有下一个轮廓,一般是这一级轮廓的最后一个的时候,则为-1。
  • 第二个数:表示同一级轮廓的上个轮廓的编号,如果这一级轮廓没有上一个轮廓,一般是这一级轮廓的第一个的时候,则为-1。
  • 第三个数:表示该轮廓包含的下一级轮廓的第一个的编号,假如没有,则为-1。
  • 第四个数: 表示该轮廓的上一级轮廓的编号,假如没有上一级,则为-1。

1.3 栗子

img:

  • 以一个参数去接收返回值,则该参数会接收三个返回值
import cv2

img = cv2.imread('../../DAVIS-2016/Annotations/1080p/flamingo/00007.png', 0)
img = cv2.resize(img, (16, 16))

returns = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print(len(returns))
print(type(returns))


# results

3
<class 'tuple'>

可以看出,returns的长度为3, 说明returns接受3个值,这是由于opencv3版本中的cv2.findContours()函数的返回了3个值,都是元组类型,故以一个参数去接收,那么就会接收3个值。(opencv2版本中只返回两个值)。

  • 以两个参数去接收返回值,会出错。

import cv2

img = cv2.imread('../../DAVIS-2016/Annotations/1080p/flamingo/00007.png', 0)
img = cv2.resize(img, (16, 16))  # 为了方便显示,调整下尺寸
# print(img.shape)

return1, return2 = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# print(returns)
# print(len(returns))
# print(type(returns))


# results

ValueError: too many values to unpack (expected 2)

可以看出,代码执行错误。ValueError: too many values to unpack (expected 2)

  • 以三个参数去接收返回值,每个参数各接收一个返回值
import cv2

img = cv2.imread('../../DAVIS-2016/Annotations/1080p/flamingo/00007.png', 0)
img = cv2.resize(img, (16, 16))
# print(img.shape)

image, contours, hierarchy = cv2.findContours(img, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

print(image)
print(contours)
print(hierarchy)

输出结果:

[[  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0 255   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0 255 255   0 255 255   0   0   0]
 [  0   0   0   0   0   0   0 255 255 255   0   0   0   0   0   0]
 [  0   0   0   0   0   0 255 255 255   0 255   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0 255   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]]

[array([[[ 8, 10]]], dtype=int32), array([[[11,  5]],

       [[12,  5]]], dtype=int32), array([[[ 9,  4]],

       [[ 6,  7]],

       [[ 8,  7]],

       [[ 9,  6]],

       [[10,  7]],

       [[ 9,  6]]], dtype=int32)]

[[[ 1 -1 -1 -1]
  [ 2  0 -1 -1]
  [-1  1 -1 -1]]]
  • 第一个返回值,返回了所处理的图像
  • 第二个返回值就是我们要找的轮廓的点集
print(type(contours))         # 输出为:<class 'list'>
print(type(contours[0]))      # 输出为:<class 'numpy.ndarray'>
print(len(contours))          # 图像中轮廓的数量,输出为:3
print(len(contours[0]))       # 轮廓0中的元素(点)的数量,输出为:1


# results

<class 'list'>
<class 'numpy.ndarray'>
3
1
 
  • 第三个返回值为各层轮廓的索引
print(hierarchy)


# results

[[[ 1 -1 -1 -1]
  [ 2  0 -1 -1]
  [-1  1 -1 -1]]]

具体意义不做解释,可查看1.2,自行理解。

2 cv2.drawContours()

OpenCV中通过cv2.drawContours在图像上绘制轮廓。 

cv2.drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None)
参数描述返回值
image需要绘制轮廓的目标图像,注意会改变原图绘制的图像array
contours轮廓点,上述函数cv2.findContours()的第一个返回值
contourIdx轮廓的索引,表示绘制第几个轮廓,-1表示绘制所有的轮廓
color绘制轮廓的颜色
thickness(可选参数)轮廓线的宽度,-1表示填充
lineType可选参数)轮廓线型,包括cv2.LINE_4,cv2.LINE_8(默认),cv2.LINE_AA,分别表示4邻域线,8领域线,抗锯齿线(可以更好地显示曲线)
hierarchy(可选参数)层级结构,上述函数cv2.findContours()的第二个返回值,配合maxLevel参数使用
maxLevel(可选参数)等于0表示只绘制指定的轮廓,等于1表示绘制指定轮廓及其下一级子轮廓,等于2表示绘制指定轮廓及其所有子轮廓
offset(可选参数)轮廓点的偏移量

3 实例

  • 读入的为二值图
import cv2
import numpy as np

# 读入的为二值图
img = cv2.imread('../../DAVIS-2016/Annotations/1080p/flamingo/00007.png')
img = cv2.resize(img, (224, 224))
# 灰度图
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# 获取轮廓
image, contours, hierarchy = cv2.findContours(img_gray, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# 创建白色幕布,画图
temp = np.ones(img_gray.shape, np.uint8) * 255

# 画轮廓:temp为白色幕布,contours为轮廓, -1表示画所有轮廓,颜色:绿色,厚度
cv2.drawContours(temp, contours, -1, (0, 255, 0), 3)

cv2.imshow('pic', img)
cv2.waitKey()
cv2.imshow('contour', temp)
cv2.waitKey()

结果:

  • 读入RGB图像:灰度化、二值化

原图:

import cv2
import numpy as np

# 读入RGB图像图像
img = cv2.imread('../../DAVIS-2016/JPEGImages/1080p/flamingo/00007.jpg')
img = cv2.resize(img, (224, 224))

# 灰度化
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 二值化
ret, binary = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)

# 获取轮廓
image, contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# 白色幕布
temp = np.ones(img_gray.shape, np.uint8) * 255
# 绘制轮廓,在白色幕布上绘制,也可以在原图上绘制
cv2.drawContours(temp, contours, -1, (0, 0, 255), 3)

cv2.imshow('img', img)  # 原图
cv2.waitKey()
cv2.imshow('gray', img_gray)  # 灰度图
cv2.waitKey()
cv2.imshow('binary', binary)  # 二值图
cv2.waitKey()
cv2.imshow('result', temp)
cv2.waitKey()

结果:

  • 在白色幕布上绘制

  • 在原图上绘制

参考:

  • 33
    点赞
  • 257
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值