图像轮廓是图像中重要的信息,通过对图像轮廓的操作,可以得到图像的大小、位置和方向等信息。本节介绍如何查找和绘制图像轮廓。

查找图像轮廓cv2.findContours

OpenCV中,函数cv2.findContours()用于查找图像的轮廓,并能够根据参数返回特定表示方式的轮廓(曲线)。

语法格式为:

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

返回值image与输入的image是一样的,在OpenCV4.x中,返回值img已经被取消。即语法格式为:

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

返回值contours

该返回值返回的是一组轮廓信息,每个轮廓都是由若干个点组成的。

contours[i]是第[i]个轮廓(从0开始为第一个)。contours[i][j]是第i个轮廓内的第j个点。

(1)type属性

contours的type属性是list,list的每个元素都是图像的一个轮廓,用Numpy中的ndarray结构表示。

(2)轮廓的个数

countNum = len(contours)

若countNum的结果为3,则表示数出来三个轮廓。

(3)每个轮廓的点数

PointNum0 = len(contours[0])  #第0个轮廓点的个数
PointNum1 = len(contours[1])  #第1个轮廓点的个数

(4)轮廓的位置

Point0 = print(contours[0])  #第0个轮廓点的位置
Point1 = print(contours[1])  #第1个轮廓点的位置

返回值hierarchy

图像内的轮廓可能位于不同的位置,例如一个图像在另一个图像的内部,称外部轮廓为父轮廓,内部轮廓为子轮廓。

每个轮廓contours[i]对应4个元素来说明当前轮廓的层次关系。其形式为:

[Next, Previous, First_Child, Parent]

  • Next: 后一个轮廓的索引编号
  • Previous: 前一个轮廓的索引编号
  • First_Child: 第一个子轮廓的索引编号
  • Parent: 父轮廓的索引编号

上面四个元素任何一个元素为空时,将其对应的参数设置为-1

需要注意的是,轮廓的层次结构是由参数mode决定的。不同的mode得到不一样的结果

参数mode

mode决定了轮廓的提取方式,具体有以下四种:

  • cv2.RETR_EXTERNAL : 只检测外轮廓
  • cv2.RETR_LIST:对检测的轮廓不建立等级关系
  • cv2.RETR_CCOMP:检索所有的轮廓并将它们组织成两级层次结构。上面的一层为外边界,下面的一层为内孔的边界
  • cv2.RETR_TREE:建立一个等级树结构的轮廓

参数method

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

  • cv2.CHAIN_APPROX_NONE:存储所有的轮廓点,相邻的两个点的像素位置差不超过1
  • cv2.CHAIN_APPROX_SIMPLE:压缩水平方向、垂直方向、对角线方向的元素,只保留该方向的终点坐标。例如,在极端的情况下,一个矩阵只需要四个点就能存储轮廓信息。
  • cv2.CHAIN_APPROX_TC89_L1:使用teh-Chinl chain近似算法的一种风格
  • cv2.CHAIN_APPROX_TC89_KCOS:使用teh-Chinl chain近似算法的一种风格

注意事项

1、待处理的必须是灰度二值图。所以在通常情况下,都要对图像进行阈值分割或者边缘检测处理,得到满意的二值图像后再继续操作。

2、在OpenCV中,都是从黑色背景中查找白色对象。因此,对象必须是白色的,背景必须是黑色的

3、在OpenCV 4.x中,函数cv2.findContours()仅有两个返回值

绘制图像轮廓cv2.drawContours

image = cv2.drawContours(image,contours,contoursIdx,color[,thickness[,lineType[,hierarchy[,maxlevel[,offset]]]]])
  • image:待绘制轮廓的图像。需要注意的是,cv2.drawContours()会在图像上直接绘制轮廓,也就是说函数执行完以后不再是原始图像,而是包含了轮廓的图像。因此,如果图像image还有其他用途的话,则需要预先复制一份,将该副本图像传递给cv2.drawContours()使用。
  • contours:需要绘制的轮廓
  • contoursIdx:需要绘制的边缘索引。告诉函数要绘制某一条轮廓,还是全部轮廓,如果该参数是一个整数或者为0,则表示绘制对应索引号的轮廓,如果该值为负数,则表示绘制全部轮廓。
  • color:绘制的颜色。
  • thickness:可选参数表示绘制轮廓时所用画笔的粗细。-1时表示绘制实心轮廓。
  • lineType:绘制边缘所用的线型
  • hierarchy:输出的层次信息
  • maxlevel:控制所绘制的轮廓的层次的深度
  • offset:偏移参数,该参数使轮廓偏移到不同的位置展示出来

参数说明

实例展示

例1:绘制一幅图像内所有的轮廓。

import cv2
img = cv2.imread('E:\Blog\OpenCV\lunkuo.png')
cv2.imshow('IMG',img)
# ====处理为二值图=====
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)   
ret,binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY) #阈值处理

contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
img = cv2.drawContours(img,contours,-1,(0,0,255),5)
cv2.imshow('RESULT',img)
cv2.waitKey()

轮廓效果

例2:逐个显示一幅图像内的边缘信息。

如果要绘制图像内的某个具体的轮廓,需要将函数cv2.drawContours()的参数contourIdx设置为具体的索引值。

import cv2
import numpy as np
img = cv2.imread('E:\Blog\OpenCV\lunkuo.png')
cv2.imshow('IMG',img)
# ====处理为二值图=====
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)   
ret,binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY) #阈值处理

# =====查找轮廓=======
contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

n = len(contours)  #有n个轮廓
contoursImg = []   #构建空白画板
for i in range(n):
    temp = np.zeros(img.shape,np.uint8)
    contoursImg.append(temp)  #在画板上建立了一个和img一模一样大小的黑背景
    contoursImg[i] = cv2.drawContours(contoursImg[i],contours,i,(0,0,255),5)
    cv2.imshow('NO-'+str(i),contoursImg[i])
cv2.waitKey()

绘制效果

例3:使用轮廓绘制功能,提取前景对象。

将函数cv2.drawContours()的参数thickness的值设置为“-1”,可以绘制前景对象的实心轮廓,将该实心轮廓与原始图像进行按位与操作,即可将前景对象从原始图像中提取出来。

import cv2
import numpy as np
img = cv2.imread('E:\Blog\OpenCV\Process\pu.png')
cv2.imshow('IMG',img)
# ====处理为二值图=====
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)   
ret,binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY) #阈值处理

# =====查找轮廓=======
contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

mask = np.zeros(img.shape,np.uint8)
mask = cv2.drawContours(mask,contours,-1,(255,255,255),-1)

cv2.imshow('mask',mask)
loc = cv2.bitwise_and(img,mask)

cv2.imshow('location',loc)
cv2.waitKey()

显示前景对象的轮廓及前景对象


博主个人公众号
版权声明 ▶ 本网站名称:陶小桃Blog
▶ 本文链接:https://www.52txr.cn/2022/OpenCV34.html
▶ 本网站的文章部分内容可能来源于网络,仅供大家学习与参考,如有侵权,请联系站长进行核实删除。
▶ 转载本站文章需要遵守:商业转载请联系站长,非商业转载请注明出处!!

最后修改:2022 年 05 月 27 日
如果觉得我的文章对你有用,请随意赞赏