这篇文章上次修改于 194 天前,可能其部分内容已经发生变化,如有疑问可询问作者。

轮廓检测

轮廓检测使用cv2.findContours(img,mode,method)函数

mode:轮廓检索模式

  • RETR_EXTERNAL :只检索最外面的轮廓;
  • RETR_LIST:检索所有的轮廓,并将其保存到一条链表当中;
  • RETR_CCOMP:检索所有的轮廓,并将他们组织为两层:顶层是各部分的外部边界,第二层是空洞的边界;
  • RETR_TREE:检索所有的轮廓,并重构嵌套轮廓的整个层次;

method:轮廓逼近方法

  • CHAIN_APPROX_NONE:以Freeman链码的方式输出轮廓,所有其他方法输出多边形(顶点的序列)。
  • CHAIN_APPROX_SIMPLE:压缩水平的、垂直的和斜的部分,也就是,函数只保留他们的终点部分。

在进行轮廓检测的时候,为了更高的准确率,需要对图像进行二值化,对于如何二值化参考:这里

现在载入一张需要进行轮廓检测的图,对其进行灰度化和二值化:

img = cv2.imread('contours.png')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)#二值图像,突出对比度,使边缘更加明显
cv_show('thresh',thresh)

image.png

进行轮廓检测:

contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
#传入绘制图像,轮廓,轮廓索引,颜色模式,线条厚度
# 注意需要copy,要不原图会变
draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, -1, (0, 0, 255), 2)
cv_show(res,'res')

可以看到检测效果:
image.png

对单个形状进行轮廓检测:

draw_img = img.copy()
res = cv2.drawContours(draw_img, contours, 8, (0, 0, 255), 2)
cv_show(res,'res')

image.png

轮廓特征

对于上述的代码,检测其五角星的轮廓特征

cnt = contours[8]
#面积
cv2.contourArea(cnt)

#周长,True表示闭合的
cv2.arcLength(cnt,True)

image.png

轮廓近似

首先选取一张图片进行正常灰度化、二值化、与轮廓检测

img = cv2.imread('contours2.png')

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[0]

draw_img = img.copy()
res = cv2.drawContours(draw_img, cnt, -1, (0, 0, 255), 2)
cv_show(res,'res')

进行轮廓近似处理

epsilon = 0.1*cv2.arcLength(cnt,True) 
approx = cv2.approxPolyDP(cnt,epsilon,True)

draw_img = img.copy()
res = cv2.drawContours(draw_img, [approx], -1, (0, 0, 255), 2)
cv_show(res,'res')

结果:
image.png

轮廓近似会将一个轮廓形状近似为一个顶点数量更少的形状,假设我们试图在轮廓中寻找到一个正方形,但是检测出来的形状是一个不规则的多边形,这时候就可以通过轮廓近似进行处理。epsilon代表从轮廓到近似轮廓的最大距离(0.1和0.01不同),第三个参数则指定了曲线是关闭的还是开放的,ture代表关闭,false代表开放。
cv2.approxPolyDP为近似函数,返回近似后的轮廓。

边界矩形

边界矩形的含义是在对指定图形进行轮廓检测后,在其外表画一个最小的矩形。

img = cv2.imread('contours.png')

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
cnt = contours[4]

x,y,w,h = cv2.boundingRect(cnt)
img = cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
cv_show(img,'img')

image.png

前期操作与前面类似,灰度化,二值化,寻找轮廓
cv2.boundingRect(cnt)该函数返回四个值,分别是x,y,w,h,其中,x和y是边界矩形左顶点的位置,w和h是边界矩形的宽和高。
cv2.rectangle()通过该函数绘制矩形:
第一个参数:img是原图

第二个参数:(x,y)是矩阵的左上点坐标

第三个参数:(x+w,y+h)是矩阵的右下点坐标

第四个参数:(0,255,0)是画线对应的BGR颜色

第五个参数:2是所画的线的宽度

边界外接圆

边界外接圆与边界矩形类似,但绘制的是圆形:

(x,y),radius = cv2.minEnclosingCircle(cnt) 
center = (int(x),int(y)) 
radius = int(radius) 
img = cv2.circle(img,center,radius,(0,255,0),2)
cv_show(img,'img')

image.png

(x,y),radius = cv2.minEnclosingCircle(cnt) :获取轮廓的圆心坐标和半径
cv2.circle(img,center,radius,(0,255,0),2):绘制圆形,图片,圆心,半径,颜色,线条粗细