OpenCV学习之路(十)轮廓的一些操作/contours返回值详解/轮廓类似详解

在findContours()函数中,我们一共返回了三个参数:image,contours,hierarchy。其中image代表的是修改之后的原图,contours代表的是轮廓,hierarchy代表的是轮廓的层次结构。我们主要来讨论一下第二个返回值:contours。以及轮廓可以进行的一些操作。

contours

contours代表的是找到的轮廓,它是一个numpy中的列表结构,那么接下来就让我们探究一下这个列表究竟是怎么存储轮廓的。

import numpy as np
import cv2
img=cv2.imread('D://zopencv//contours.png')
imgcopy=img.copy()
imgray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,img_thre=cv2.threshold(imgray,127,255,cv2.THRESH_BINARY)
image,contours,hierarchy=cv2.findContours(img_thre,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
mask1=cv2.drawContours(imgcopy,contours,-1,(0,0,255),2)
cv2.imshow('mask1',mask1)
cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV学习之路(十)轮廓的一些操作/contours返回值详解/轮廓类似详解_第1张图片
之前我们已经讨论过了,drawContours()函数的第三个参数是轮廓的索引,如果我们定为-1就会把所有轮廓画出。那你有没有想过,他既然是索引,我们是不是可以一个一个轮廓的画出来。
我们将索引定为0:

mask1=cv2.drawContours(imgcopy,contours,0,(0,0,255),2)

OpenCV学习之路(十)轮廓的一些操作/contours返回值详解/轮廓类似详解_第2张图片
只有正方形的轮廓被画了出来,也就是说,正方形的轮廓在轮廓列表contours中的索引是0.
同理,我们可以把索引分别设置成1,2。箭头和圆的轮廓分别被画出来了。从这我们也可以看出,contours列表中的大致情况。
有了这些理解,我们下面理解轮廓的操作就会顺利许多。

一些操作

图像面积

简言之就是计算一个图像的轮廓包起来的面积。
构造函数如下:

cv2.contourArea()

一定要把contours列表按索引单独计算,容易理解。

image,contours,hierarchy=cv2.findContours(img_thre,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt=contours[0]
area=cv2.contourArea(cnt)
print(area)
#3080.0
轮廓周长

同理,图像的轮廓周长
构造函数:

 cv2.arcLength(cnt,True) 
  • 第二个参数用来指定图像时闭合的(True),还是不闭合。
image,contours,hierarchy=cv2.findContours(img_thre,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt=contours[0]
length=cv2.arcLength(cnt,True)
#222.0
轮廓近似

我们在实际应用中,有时候图像会长的不尽人意,轮廓也因此奇形怪状,但是我们想让图像的轮廓能变得“整齐”一些,我们就需要用到轮廓近似的方法。
其原理就是:我们先设置一个值thre=x,然后在图像中找到两个带你A,B,两点间做辅助线,得到距离AB实际边缘最远距离d,只要d小于thre,那么AB之间的实际轮廓就可以近似为AB直接做的辅助线(直线)。
OpenCV学习之路(十)轮廓的一些操作/contours返回值详解/轮廓类似详解_第3张图片
但是如果d>thre,那么我们就在AC、BC之间再连线,重复AB之间的做法,如果d小于thre,就可近似为直线,否则继续重复操作。有点像二分操作的思想。
OpenCV学习之路(十)轮廓的一些操作/contours返回值详解/轮廓类似详解_第4张图片
道理就是这样,OpenCV中提供给我们现成的函数:

approx = cv2.approxPolyDP(cnt,epsilon,True)
  • cnt:轮廓
  • epsilon:我们自己定义的thre,也就是那个分界值。
  • True:设定轮廓是否闭合
import numpy as np
import cv2
img=cv2.imread('D://zopencv//lunkuojinsi.png')
imgcopy=img.copy()
imgray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,img_thre=cv2.threshold(imgray,127,255,cv2.THRESH_BINARY)
image,contours,hierarchy=cv2.findContours(img_thre,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt=contours[0]
epsilon=0.1*cv2.arcLength(cnt,True)
mask2=cv2.approxPolyDP(cnt,epsilon,True)
mask1=cv2.drawContours(imgcopy,[mask2],-1,(0,0,255),2)
cv2.imshow('mask1',mask1)
cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV学习之路(十)轮廓的一些操作/contours返回值详解/轮廓类似详解_第5张图片
我们取周长的十分之一作为界限,得到如上图像。很显然,轮廓变得整齐了起来。

边界矩形

我们在物体识别追踪之类的项目中常常需要把识别到的物体框起来,这时候就需要用到边界矩形。
两个函数一起调用:

x,y,w,h = cv2.boundingRect(cnt) 
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
  • (x,y)是矩形左上角的坐标
  • w,h是矩形的宽和高
import numpy as np
import cv2
img=cv2.imread('D://zopencv//contours.png')
imgcopy=img.copy()
imgray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,img_thre=cv2.threshold(imgray,127,255,cv2.THRESH_BINARY)
image,contours,hierarchy=cv2.findContours(img_thre,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt=contours[1]
x,y,w,h=cv2.boundingRect(cnt)
cv2.rectangle(img,(x,y),(x+w,y+h),(255,255,0),thickness=2)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV学习之路(十)轮廓的一些操作/contours返回值详解/轮廓类似详解_第6张图片

外接圆

函数:

(x,y),radious=cv2.minEnclosingCircle(cnt)

这个函数返回轮廓最小外接圆的圆心坐标和半径,但要注意返回值不是int型。

import numpy as np
import cv2
img=cv2.imread('D://zopencv//contours.png')
imgcopy=img.copy()
imgray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret,img_thre=cv2.threshold(imgray,127,255,cv2.THRESH_BINARY)
image,contours,hierarchy=cv2.findContours(img_thre,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
cnt=contours[1]
(x,y),radious=cv2.minEnclosingCircle(cnt)
img=cv2.circle(img,(int(x),int(y)),int(radious),(255,255,0),2)
cv2.imshow('img',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV学习之路(十)轮廓的一些操作/contours返回值详解/轮廓类似详解_第7张图片

你可能感兴趣的:(OpenCV学习之路)