【OpenCV-图像处理】图像轮廓1(寻找、绘制轮廓)——OpenCV官方教程翻译(全网最详细)

OpenCV的imgproc 模块:如何找到并画出图像的轮廓?使用函数cv2.findContours、 cv2.drawContours一步搞定

  • 一、目标
  • 二、基本理论
  • 三、图像轮廓
    • 3.1寻找轮廓
      • cv2.findContours()
      • 3.2举例演示
    • 3.2画轮廓
      • cv2.drawContours
      • 举例演示

一、目标

  • 理解轮廓是什么。
  • 学习寻找轮廓线,画轮廓线等
  • 你会看到这些函数:cv2.findContours(), cv2.drawContours()

二、基本理论

轮廓是什么?
轮廓可以简单地解释为一条连接所有连续点(沿边界)的曲线,具有相同的颜色或强度。轮廓是一个有用的工具,它可以用于形状分析和目标检测和识别。

  • 为了更好的准确性,使用二值图像。因此,在寻找轮廓之前,应用阈值或canny边缘检测。
  • 从OpenCV 3.2开始,findContours()不再修改源图像,而是返回一个修改后的图像作为三个返回参数中的第一个。
  • 在OpenCV中,寻找轮廓就像在黑色背景中寻找白色物体。所以请记住,要找到的对象应该是白色的,背景应该是黑色的。

让我们看看如何找到二值图像的轮廓(必须是二值图像作为输入图像

三、图像轮廓

3.1寻找轮廓

cv2.findContours()

	image, contours, hierarchy	= cv2.findContours	(	InputOutputArray 	image,
														int 	mode,
														int 	method,
														Point 	offset = Point() 
)	
参数 说明
image 源,一个8位的单通道图像。非零像素被视为1。零像素仍然是0,所以图像被视为二进制。您可以使用compareinRangethresholdadaptiveThresholdCanny和其他方法创建基于灰度或彩色的二值图像。如果mode等于RETR_CCOMPRETR_FLOODFILL,则输入也可以是32位整数的标签图像(CV_32SC1)。
contours 检测到的轮廓。每个轮廓被存储为点的向量
hierarchy 可选输出向量,包含关于图像拓扑的信息。它的元素和轮廓的数量一样多。对于每一个第i条轮廓线[i],将元素hierarchy[i][0]、hierarchy[i][1]、hierarchy[i][2]、hierarchy[i][3]分别设置为下一个轮廓线和上一个轮廓线(即第一个子轮廓线和父轮廓线)的基于0的轮廓线索引。如果轮廓i没有下一个、上一个、父轮廓或嵌套轮廓,层次结构[i]中的相应元素将为负。
mode 轮廓检索模式,参见RetrievalModes
method 轮廓近似方法,参见ContourApproximationModes
offset 每个轮廓点被移动的可选偏移量。如果从图像感兴趣区提取轮廓,然后在整个图像环境中分析轮廓,这是非常有用的。

在二值图像中寻找轮廓。

该函数使用算法[169]从二值图像中检索轮廓。轮廓是一个有用的工具,用于形状分析和目标检测和识别。

注意我使用的是3.4.1.15版本Opencv,在最新版本的Opencv中(我没有具体的调查从哪一版本开始的)返回参数只有两个(contours, hierarchy)

RetrievalModes(轮廓检索算法的模式)

RetrievalModes参数 说明
cv2.RETR_EXTERNAL 只获取外部轮廓。它设置所有轮廓的hierarchy[i][2]=hierarchy[i][3]=-1。
cv2.RETR_LIST 检索所有轮廓而不建立任何层次关系,将其保存到一条链表当中。
cv2.RETR_CCOMP 检索所有轮廓并将它们组织到一个两级层次结构中。顶层是各部分的外部边界。第二层是空洞的边界。如果有另一个轮廓在一个连接组件的孔内,它仍然放在顶层。
cv2.RETR_TREE 检索所有轮廓并重建嵌套轮廓的完整层次结构。
cv2.RETR_FLOODFILL

ContourApproximationModes(轮廓逼近算法)

ContourApproximationModes参数 说明
cv2.CHAIN_APPROX_NONE 绝对存储所有的轮廓点。即轮廓的任意两个后续点(x1,y1)和(x2,y2)均为水平、垂直或对角线邻居,即max(abs(x1-x2),abs(y2-y1))==1。
cv2.CHAIN_APPROX_SIMPLE 压缩水平、垂直和对角线的线段,只留下它们的端点。例如,一个向上的矩形轮廓用4个点进行编码。
cv2.CHAIN_APPROX_TC89_L1 应用Teh-Chin链近似算法之一[177]
cv2.CHAIN_APPROX_TC89_KCOS 应用Teh-Chin链近似算法之一[177]

上面,我们说轮廓是一个具有相同强度的形状的边界。它存储形状边界的(x,y)坐标。但是它是否存储了所有的坐标呢?这是由轮廓近似法规定的。

如果你通过cv2.CHAIN_APPROX_NONE,所有边界点都被存储。但实际上我们需要所有的点吗?例如,你找到了一条直线的轮廓。需要用直线上的所有点来表示这条直线吗?不,我们只需要这条直线的两个端点。这就是cv2.CHAIN_APPROX_SIMPLE。它去除所有冗余点并压缩轮廓,从而节省内存。

下面的矩形图像演示了这种技术。只需在轮廓数组的所有坐标上画一个圆(用蓝色绘制)。第一张图片显示了我在cv2.CHAIN_APPROX_NONE(734点)和第二张图片显示了一个cv2.CHAIN_APPROX_SIMPLE(只有4点)。看它节省了多少内存!!

所以,一般情况下更建议使用cv2.CHAIN_APPROX_SIMPLE方法!!
【OpenCV-图像处理】图像轮廓1(寻找、绘制轮廓)——OpenCV官方教程翻译(全网最详细)_第1张图片

3.2举例演示

#图像轮廓
import numpy as np
import cv2

im = cv2.imread('contours.png')
imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)   #转化为灰度图
ret, thresh = cv2.threshold(imgray, 127, 255, 0)    #图像二值化,127为界,大于127置为255,小于127置为0
im2, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

cv.findContours()函数有三个参数,第一个是源图像,第二个是轮廓检索模式,第三个是轮廓近似方法。然后输出修改后的图像,轮廓和层次结构。contours是图像中所有轮廓的Python列表。每个单独的轮廓都是对象边界点的(x,y)坐标的Numpy数组。

注:我们将在后面详细讨论第二个和第三个参数以及层次结构。在此之前,代码示例中给它们的值将适用于所有图像。

3.2画轮廓

cv2.drawContours

注意:在drawContours之前,输入图像一定要.copy(),不然原图像就变了!!!

image = cv2.drawContours	(	InputOutputArray 	image,
								InputArrayOfArrays 	contours,
								int 	contourIdx,
								const Scalar & 	color,
								int 	thickness = 1,
								int 	lineType = LINE_8,
								InputArray 	hierarchy = noArray(),
								int 	maxLevel = INT_MAX,
								Point 	offset = Point() 
)	
参数 说明
image 目标图像
contours 所有的输入轮廓。每个轮廓都以点向量的形式存储。
contourIdx 指示要绘制轮廓的参数。如果为负,则绘制所有的轮廓线。
color 轮廓的颜色。
thickness 绘制轮廓线所用线的粗细。如果是负的(例如,厚度=填充),则绘制内部轮廓。
lineType 连接线. 见 LineTypes
hierarchy 关于层次结构的可选信息。只有当你只想绘制部分轮廓时才需要它(参见maxLevel)。
maxLevel 绘制轮廓线的最大级别。如果为0,则只绘制指定的轮廓。如果值为1,函数将绘制等值线和所有嵌套等值线。如果值为2,则该函数绘制轮廓线、所有嵌套轮廓线、所有嵌套到嵌套的轮廓线,以此类推。仅当存在可用的层次结构时才考虑此参数。
offset 可选轮廓位移参数。将所有绘制的轮廓线移动到指定的偏移量=(dx,dy)。

LineTypes线类型

LineTypes参数 说明
cv2.FILLED
cv2.LINE_4 4-connected line
cv2.LINE_8 8-connected line
cv2.LINE_AA 锯齿线

绘制轮廓线或填充轮廓线。

如果厚度≥0,则在图像中绘制轮廓线轮廓线;如果厚度<0,则填充轮廓线所包围的区域。

thickness=FILLED时,该函数被设计来正确处理带有孔的连接组件,即使没有提供层次数据。这是通过使用偶奇规则分析所有的轮廓来完成的。如果你有一个单独检索的轮廓的联合集合,这可能会给出不正确的结果。为了解决这个问题,您需要为每个轮廓子组分别调用drawContours ,或者使用contourIdx参数遍历集合。

为了画出轮廓线,cv2.drawContours函数。它也可以用于绘制任何形状,只要你有它的边界点。它的第一个参数是source image,第二个参数是应该作为Python列表传递的轮廓,第三个参数是轮廓索引(在绘制单个轮廓时很有用)。要绘制所有轮廓线,输入-1),剩下的参数是颜色、厚度等。

  • 画出图像中所有的轮廓线:
cv.drawContours(img, contours, -1, (0,255,0), 3)
  • 要画一个单独的轮廓线,比如第四个轮廓线:
cv.drawContours(img, contours, 3, (0,255,0), 3)
  • 但大多数情况下,常用下面的方法:
cnt = contours[4]
cv.drawContours(img, [cnt], 0, (0,255,0), 3)

注:要画一个单独的轮廓线,最后两个方法是相同的,但是你会发现最后一个方法更常用。

举例演示

#图像轮廓
#Opencv版本3.4.1.15
import numpy as np
import cv2

def cv_show(img,name):
    cv2.imshow(name,img)
    cv2.waitKey()
    cv2.destroyAllWindows()

im = cv2.imread('contours.png')
imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)   #转化为灰度图
ret, thresh = cv2.threshold(imgray, 127, 255, 0)    #图像二值化,127为界,大于127置为255,小于127置为0
im2, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)     #新版本的Opencv返回参数只有contours, hierarchy

#传入绘制图像,轮廓,轮廓索引,颜色模式,线条厚度
# 注意需要copy,要不原图会变。。。
img = im.copy()
res = cv2.drawContours(img, contours,-1, (0, 0, 255), 2)    #红色轮廓

#要画一个单独的轮廓线,比如第四个轮廓线:
img = cv2.drawContours(img, contours, 3, (0,255,0), 2)      #绿色轮廓

#常用这种方法画一个单独的轮廓
cnt = contours[0]
cv2.drawContours(img, [cnt], 0, (255,0,0), 2)               #蓝色轮廓
cv_show(res,'res')

运行结果:
【OpenCV-图像处理】图像轮廓1(寻找、绘制轮廓)——OpenCV官方教程翻译(全网最详细)_第2张图片
主要参考于OpenCV官方网站:http://www.opencv.org.cn/

目前博主已更新OpenCV平滑处理函数、形态学操作函数的详细介绍,链接如下:
【OpenCV-图像处理】图像平滑处理函数

【OpenCV-图像处理】形态学变换函数

【OpenCV-图像处理】图像阈值处理

【OpenCV-图像处理】如何计算图像梯度,以及如何使用梯度来检测边缘

【OpenCV-图像处理】Canny 边缘检测

【OpenCV-图像处理】图像金字塔

<后续还会继续翻译和整理【OpenCV-图像处理】相关内容,如果需要,可持续关注我哦~>

<翻译和整理不易,留个赞或评论支持一下我吧^^>

如有疑问,欢迎批评指正^^

你可能感兴趣的:(OpenCV图像处理,python,opencv,计算机视觉,图像处理)