OpenCV-Python教程:查找轮廓、绘制轮廓

原文链接:http://www.juzicode.com/opencv-python-findcontours-drawcontours

返回Opencv-Python教程

图像轮廓用来描述图像中连续的点,它们有同样的颜色和灰度级。为了更精确地进行检测,在查找轮廓前需要先将图像做二值化处理或者使用canny边沿检测。在OpenCV中轮廓检测只查找白色目标,黑色背景会被忽略。

1、查找轮廓 findContours()

contours,hierarchy=cv2.findContours(image,mode,method[,contours[,hierarchy[,offset]]])
  • 参数含义:
  • image:输入图像,8bit单通道;图像元素的值为0表示背景,非0值表示前景,为了精确查找轮廓,最好对原始图像做二值化处理。如果mode参数为RETR_CCOMP或RETR_FLOODFILL输入图像也可以是32bit单通道图像(CV_32SC1)。但是floodfill不支持cv-8u类型
  • mode:轮廓提取模式。
  • method:轮廓近似方法。
  • contours:找到的轮廓。
  • hierarchy:找到轮廓层次结构。
  • offset:偏移值,使用ROI时用来计算原始位置。

mode的名称和含义:

mode含义
 cv2.RETR_EXTERNAL只提取外部轮廓,设置hierarchy[i][2]=hierarchy[i][3]=-1
 cv2.RETR_LIST提取所有轮廓,不包含轮廓间的层次关系
 cv2.RETR_CCOMP提取所有轮廓,包含2层层次关系,顶层是外围边界,底层是内部hole。如果有多层嵌套,仍然按照2层组织。
 cv2.RETR_TREE按照完整的层次关系组织
 cv2.RETR_FLOODFILL

method 的名称和含义:

method含义
cv2.CHAIN_APPROX_NONE存储所有的边间点,不管是垂直方向、水平方向或者对角线方向
cv2.CHAIN_APPROX_SIMPLE垂直方向、水平方向或对角线方向只保留终点,比如一个长方形就只包含4个顶点
cv2.CHAIN_APPROX_TC89_L1使用teh-Chini近似算法
cv2.CHAIN_APPROX_TC89_KCOS使用teh-Chini近似算法

下面是一个查找轮廓的例子,读入图像,灰度化后再进行二值化,然后调用findContours()查找轮廓:

import numpy as np
import cv2
print('VX公众号: 桔子code / juzicode.com')

#读入图像、灰度、二值化
img_src = cv2.imread('..\\samples\\picture\\contours1.bmp')  
img_gray = cv2.cvtColor(img_src, cv2.COLOR_BGR2GRAY) 
val, img_bin = cv2.threshold(img_gray,127,255, cv2.THRESH_BINARY) 
#cv2.imwrite('contours-bin.bmp',img_bin)
#查找轮廓
contours, hierarchy=cv2.findContours(img_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE )
print('contours:',contours)
print('type(contours):',type(contours))
print('len(contours):',len(contours))

print('type(contours[0]):',type(contours[0]))
print('contours[0].shape:',contours[0].shape)

print('hierarchy:',hierarchy)
print('type(hierarchy):',type(hierarchy))
print('len(hierarchy):',len(hierarchy))
print('hierarchy.shape:',hierarchy.shape)

运行结果:

VX公众号: 桔子code / juzicode.com
contours: [array([[[159, 150]],

       [[159, 241]],

       [[307, 241]],

       [[307, 150]]], dtype=int32), array([[[330,  28]],

       [[330, 100]],

       [[434, 100]],

       [[434,  28]]], dtype=int32), array([[[ 23,  20]],

       [[ 23, 114]],

       [[172, 114]],

       [[172,  20]]], dtype=int32)]
type(contours): <class 'list'>
len(contours): 3

type(contours[0]): <class 'numpy.ndarray'>
contours[0].shape: (4, 1, 2)

hierarchy: [[[ 1 -1 -1 -1]
  [ 2  0 -1 -1]
  [-1  1 -1 -1]]]
type(hierarchy): <class 'numpy.ndarray'>
len(hierarchy): 1
hierarchy.shape: (1, 3, 4)

contours是找到的轮廓列表,是由n个轮廓组成的list,每个轮廓是一个numpy数组,它的shape为(m,1,2),m为轮廓构成的像素的个数,每个点有2个数值,分别为x和y坐标。

hierarchy的shape为(1,n,4),n对应contours的个数n,所以要访问第i个轮廓的hierarchy时用hierarchy[0][i]表示。每个hierarchy的元素有4个值组成,依次为next,previous,first child和parent,表示下一个节点,上一个节点,第一个子节点,父节点。

2、绘制轮廓 drawContours

drawContours(image,contours,contourIdx,color[,thickness[,lineType[,hierarchy[,maxLevel[,offset]]]]])->image
  • 参数含义:
  • image:要绘制边框的图像,调用后会修改该图像。
  • contours:轮廓列表,一般传入findContours()找到的边框。
  • contourIdx:contours的索引,也就是要表示的第几个边框,如果要绘制所有的边框,设置为负数即可。
  • color:颜色,bgr三个参数构成的tuple。
  • thickness:边框的宽度。
  • lineType:边界连线类型。
  • hierarchy:依赖maxLevel使用,如果maxLevel设置为1和2时用到该参数,
  • maxLevel:
  • offset:边框偏移位置

下面这个例子查找轮廓后依次绘制轮廓:

import numpy as np
import cv2
print('VX公众号: 桔子code / juzicode.com')
#读入图像、灰度、二值化
img_src = cv2.imread('..\\samples\\picture\\contours1.bmp')  
cv2.imshow('img_src',img_src)
img_gray = cv2.cvtColor(img_src, cv2.COLOR_BGR2GRAY) 
val, img_bin = cv2.threshold(img_gray,127,255,cv2.THRESH_BINARY) 
#查找轮廓
contours, hierarchy=cv2.findContours(img_bin, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE )
print('len(contours):',len(contours))
#绘制轮廓
for ind in range(len(contours)):  
    cv2.drawContours(img_src, contours, ind, (0,0,255), 3)
    cv2.imshow('con',img_src)
    cv2.waitKey()

运行结果:

还可以将contourIdx设置为-1,一次性绘制所有轮廓:

#设置为-1,绘制所有轮廓    
cv2.drawContours(img_src, contours, -1, (0,0,255), 3)
cv2.imshow('con',img_src)
cv2.waitKey()

设置offset参数:

cv2.drawContours(img_src, contours, -1, (0,0,255), 3, offset=(10,10))

绘制的边框整体偏移了offset个像素:

  

 

扩展阅读:

  1. OpenCV-Python教程

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注