第12章 图像轮廓 -- 12.1 查找图像轮廓 cv2.findContours(),绘制图像轮廓 cv2.drawContours()

《OpenCV 轻松入门 面向Python》 学习笔记

  • 边缘:上一章学习的边缘检测。边缘检测虽能过检测出边缘,但边缘不是连续的,检测到的边缘并不是一个整体。
  • 轮廓:图像轮廓是指将边缘连接起来形成一个整体,用于后续的计算。

opencv 提供了查找图像轮廓的函数 cv2.findContours(),和 绘制图像轮廓的函数cv2.drawContours()


查找图像轮廓 cv2.findContours()

函数原型:

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

返回值:

  • image:与函数参数中的原始图像image一致。返回的轮廓
  • contours:返回的轮廓
  • hierarchy:图像的拓扑信息(轮廓层次)

参数:

  • image:原始图像, 8位单通道图像。所有非0值被处理为1,所有0值保持不变。也就是说灰度图像会自动被处理成二值图像。
  • mode:轮廓的检索模式
  • method:轮廓的近似方法

函数cv2.findContours()的返回值及参数的含义比较丰富,下面逐一作出说明。


1. 返回值 image

该返回值与参数image是一样的,就是原始输入图像。在openCV 4.X中,该返回值已经被取消,只有contours, hierarchy两个返回值。函数格式为:
contours, hierarchy = cv2.findContours(image, mode, method)


2. 返回值 contours

返回值 contours 返回的是一组轮廓信息,包含:

  • n 个轮廓:第i个轮廓表示为 contours[i],数据类型是 list
  • 以及每个轮廓由若干个点构成:第i个轮廓内的第j个点表示为 contours[i][j] , 数据类型是ndarray。

比如如下图像:
在这里插入图片描述

# 轮廓的数据类型
print(type(contours))    # <class 'list'>

# 轮廓的个数
print(len(contours))      # 3 

# 轮廓中每个轮廓元素的数据类型
print(type(contours[0]))    # <class 'lumpy. nndarray'>

# 组成轮廓的点的个数
print(len(contours[0]))     # 4 
print(len(contours[1]))     # 60 
print(len(contours[2]))     # 184 
print(contours[0].shape)     # (4, 1, 2) 
print(contours[0].shape)     # (60, 1, 2) 
print(contours[0].shape)     # (184, 1, 2) 

# 轮廓内的点
print(contours[0]) 
							# [[[79, 270]]
							#  [[79, 383]]
							#  [[195, 383]]
							#  [[195, 270]]]

3. 返回值 hierarchy

图像的轮廓可能位于不同的位置,若果一个轮廓位于另一个轮廓的内部,我们就称外部的轮廓为父轮廓, 里面的轮廓为子轮廓。这种关系被称为层次

每个轮廓(contours[i])对应4个元素来说明当前轮廓的层次关系:[Nest, Previous, First_Child, Parent]

Nest:后一个轮廓的索引编号
Previous:前一个轮廓的索引编号
First_Child:第一个字轮廓的索引编号
Parent:父轮廓的索引编号
如果上述各个参数所对应的关系为空时, 也就是没有对应关系时,用 -1 表示

使用打印语句 print(hierarchy) 查看hierarchy 的值。

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


4. 参数 image

输入图像,其必须是8位单通道灰度二值图。一般情况下,都要预先对图像进行阈值分割或者边缘检测处理,得到满意的二值图像后,再将其作为参数使用。


5. 参数 mode

参数 mode 决定了轮廓的提取方式:

  • cv2.RETR_EXTERNAL:只检测外轮廓。
  • cv2.RETR_LIST:对检测到的外轮廓不建立等级关系
  • cv2.CCOMP:检索所有轮廓,并将他们组织成两级层次结构。
  • cv2.Tree:建立一个等级树结构的轮廓

6. 参数 method

参数 method 决定了如何表达轮廓:

  • cv2.CHAIN_APPROX_NONE:存储所有的轮廓点
  • cv2.CHAIN_APPROX_SIMPLE:压缩水平,垂直和对角线段,只留下端点。 例如矩形轮廓可以用4个点编码。
  • cv2.CHAIN_APPROX_TC89_L1, cv2.CHAIN_APPROX_TC89_KCOS: 使用Teh-Chini chain近似算法

7. 注意:

(1) 待处理的原图像必须是灰度二值图。一般情况下,都要预先对图像进行阈值分割或者边缘检测处理,得到满意的二值图像后,再将其作为参数使用。

(2)在opencv中,都是从黑色背景中查找白色对象。对象必须是白的,背景必须是黑的。

(3)在openCV 4.X中,返回值image已经被取消,只有contours, hierarchy两个返回值。函数格式为:contours, hierarchy = cv2.findContours(image, mode, method)


绘制图像轮廓 cv2.drawContours()

函数原型:

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

参数:

  • image:原图像。cv2.drawContours() 函数会直接在原图像上绘制轮廓,也就是说会改变原图。如果图像image还有其他用途的话,则需要预先复制一份,将该副本图像传递给 cv2.drawContours() 函数使用。
  • 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表示只绘制contourIdx指定的轮廓,等于1表示绘制contourIdx指定轮廓及其下一级子轮廓,等于2表示绘制contourIdx指定轮廓及其所有子轮廓
  • offset:(可选参数)轮廓点的偏移量

举例:

import cv2

o = cv2.imread("/Users/manmi/Desktop/contours.bmp")
cv2.imshow('original_image', o)
gray = cv2.cvtColor(o, cv2.COLOR_BGR2GRAY)
threshold, binary_img = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

image, contours, hierrarchy = cv2.findContours(binary_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
o = cv2.drawContours(o, contours, -1, (0, 0, 255), 5)

cv2.imshow('contours_image', o)
cv2.waitKey()
cv2.destroyAllWindows()

输出:
在这里插入图片描述

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Enzo 想砸电脑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值