什么是图形轮廓
图像轮廓是具有相同颜色或灰度的连续点的曲线,轮廓在形状分析和物体检测与识别中很有用处
轮廓的作用:
查找轮廓
注意:
- 为了保证检测的准确性,需要先对图像进行
二值化 或Canny边缘检测 操作 - 画轮廓时会修改输入的图像,如果之后想继续使用原始图像,应该将原始图像存储一份到其他变量中(备份)——
img_copy = img.copy()
关键API:cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]])
利用该函数可以获取轮廓的信息
其中:
-
mode :查找轮廓的模式 (写模式名或数字都可以)
-
cv2.RETR_EXTERNAL / 0 :表示只检测外围轮廓 -
cv2.RETR_LIST / 1 :检测的轮廓不建立等级关系(属于同一轮廓线上即为同一级,),即检测所有的轮廓,从右到左,从里到外画轮廓(一般不会出现这么复杂的索引) -
cv2.RETR_CCOMP / 2 : 每层最多两级,从小到大,最里到外 -
cv2.RETR_TREE / 3 :按照树型存储轮廓,从大到小,从右到左 ——> 先从外到内把右边的算完,再算左边的,!最常用! -
method :轮廓近似方法,也叫ApproximationMode。总的来说就是如何去保存你的轮廓
cv2.CHAIN_APPROX_NONE :保存所有轮廓上的点,会把轮廓上所有像素点的坐标都保存下来,存储信息较大cv2.CHAIN_APPROX_SIMPLE :只保存角点,比如四边形,只保存四边形的四个角,存储信息较少,比较常用 -
返回值-> contours, hierarchy :需要用变量去接受
contours :轮廓的集合,可以通过contours[i](i = 0,1,2...) 来调用某一个轮廓hierarchy :层级
import cv2
import numpy as np
img = cv2.imread('./contours.jpeg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv2.imshow('img',img)
cv2.imshow('gray',gray)
thresh,temp = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours,hierarchy = cv2.findContours(temp,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
print(type(contours))
print(contours)
cv2.waitKey(0)
cv2.destroyAllWindows()
绘制轮廓
关键API:drawContours(image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]]]]) 其中:
image :操作的图像,由于我们可以设置轮廓的颜色color ,所以就不太适合用二值化或灰度化后的图片进行操作,应该用三通道的彩图进行绘画(原图)contours :轮廓点,由查找轮廓的函数cv2.findContours() 的返回值可得contourIdx :要绘制的轮廓编号,-1 表示绘制所有轮廓,此处是索引!因此不能写成contours[] 的形式color :轮廓的颜色,如(0,0,255)表示红色thickness :线宽,-1 表示全部填充
import cv2
import numpy as np
img = cv2.imread('./contours.jpeg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv2.imshow('img',img)
cv2.imshow('gray',gray)
thresh,temp = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours,hierarchy = cv2.findContours(temp,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
img_copy = img.copy()
cv2.drawContours(img_copy,contours,-1,(0,0,255),2)
cv2.imshow('img',img)
cv2.imshow('img_copy',img_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:
如果我们想只画一个轮廓,那么可以根据目标轮廓的层级来绘制(我们使用的是cv2.RETR_TREE :从左到右、从外到内)
例如把参数中的-1 改成0
cv2.drawContours(img_copy,contours,0,(0,0,255),2)
结果:
计算轮廓的面积和周长
轮廓面积
轮廓面积是指每个轮廓中所有的像素点围成区域的面积,单位为像素
轮廓面积是轮廓重要的统计特性之一,通过轮廓面积的大小可以进一步分析每个轮廓隐含的信息,例如通过轮廓面积区分物体大小、识别不同的物体
在查找到轮廓后,可能会有很多细小的轮廓,我们可以通过轮廓的面积进行过滤(比如小于某一个阈值,就把这个轮廓过滤掉)
关键API:cv2.contourArea(contour[, oriented])
- 参数是
countour (不加s ,加了s(countours) 后表示轮廓的集合)
轮廓周长
关键API:cv2.arcLength(curve, closed)
curve :轮廓closed :是否是闭合的轮廓,为布尔类型,一般设置为closed = True
import cv2
import numpy as np
img = cv2.imread('./contours.jpeg')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv2.imshow('img',img)
cv2.imshow('gray',gray)
thresh,temp = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours,hierarchy = cv2.findContours(temp,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
img_copy = img.copy()
cv2.drawContours(img_copy,contours,0,(0,0,255),2)
area = cv2.contourArea(contours[1])
print('area:',area)
length = cv2.arcLength(contours[1],closed = True)
print('length:',length)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:
area: 115239.5
length: 1355.0710676908493
多边形逼近
cv2.findContours() 后的轮廓信息contours 可能过于复杂不平滑,可以用cv2.approxPolyDP() 函数来对该多边形曲线做适当近似,这就是轮廓的多边形逼近
cv2.approxPolyDP() 就是以多边形去逼近轮廓,采用的是Douglas_Peucker算法(方法名中的DP)
DP算法 的原理比较简单,核心就是不断找多边形最远的点加入形成新的多边形,直到最短距离小于指定的精度
关键API:cv2.approxPolyDP(curve, epsilon, closed[, approxCurve]) 其中:
curve :要近似逼近的轮廓epsilon :DP算法的阈值,阈值越小,近似轮廓越贴合真是轮廓,蕴含的像素点也就越多,占用内存越大closed :轮廓是否闭合
import cv2
import numpy as np
img = cv2.imread('./hand.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
thresh,temp = cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours,hierarchy = cv2.findContours(temp,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
img_copy = img.copy()
cv2.drawContours(img_copy,contours,0,(0,0,255),2)
approx = cv2.approxPolyDP(contours[0],20,closed = True)
cv2.drawContours(img_copy,[approx],0,(0,255,0),2)
cv2.imshow('img',img)
cv2.imshow('img_copy',img_copy)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果:
|