1.1什么是轮廓
轮廓能够简单认为成连续的点(连着边界)连在一块儿的曲线,具备相同的颜色或者灰度。轮廓在形状分析和物体的检测和识别中颇有用。python

  • 为了准确,要使用二值化图像。须要进行阀值化处理或者Canny边界检测。
  • 查找轮廓的函数会修改原始图像。若是以后想继续使用原始图像,应该将原始图像储存到其余变量中。
  • 在OpenCV中,查找轮廓就像在黑色背景中超白色物体。你应该记住,要找的物体应该是白色而背景应该是黑色。
    如何在一个二值图像中查找轮廓。
    函数cv2.findContours()有三个参数,第一个是输入图像,第二个是轮廓检索模式,第三个是轮廓近似方法。返回值有三个,第一个是图像,第二个是轮廓,第三个是(轮廓的)层析结构。轮廓(第二个返回值)是一个Python列表,其中储存这图像中全部轮廓。每个轮廓都是一个Numpy数组,包含对象边界点(x,y)的坐标。
    1.2怎样绘制轮廓
    函数cv2.drawContours()能够被用来绘制轮廓。它能够根据你提供的边界点绘制任何形状。它的第一个参数是原始图像,第二个参数是轮廓,一个python列表,第三个参数是轮廓的索引(在绘制独立轮廓是颇有用,当设置为-1时绘制全部轮廓)。接下来的参数是轮廓的颜色和厚度。
    在一幅图像上绘制全部的轮廓:
import numpy as np
import cv2

img = cv2.imread('1024.jpg') imgray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) ret,thresh = cv2.threshold(imgray,127,255,0) image ,contours,hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) #绘制独立轮廓,如第四个轮廓 #imag = cv2.drawContour(img,contours,-1,(0,255,0),3) #可是大多数时候,下面方法更有用 imag = cv2.drawContours(img,contours,3,(0,255,0),3) while(1): cv2.imshow('img',img) cv2.imshow('imgray',imgray) cv2.imshow('image',image) cv2.imshow('imag',imag) if cv2.waitKey(1) == ord('q'): break cv2.destroyAllWindows() 

1.3轮廓的近似方法
以前提到轮廓是一个形状具备相同灰度值的边界,它会存储形状边界上全部的(x,y)坐标。实际上咱们不须要全部的点,当须要直线时,找到两个端点便可。cv2.CHAIN_APPROX_SIMPLE能够实现。它会将轮廓上的冗余点去掉,压缩轮廓,从而节省内存开支。
下面用矩阵来演示,在轮廓列表中的每个坐标上画一个蓝色圆圈。第一个显示使用cv2.CHAIN_APPROX_NONE的效果,一共734个点,第二个图是使用cv2.CHAIN_APPROX_SIMPLE的结果,只有4个点。
算法

2.轮廓特征
2.1矩
图像的矩能够帮助咱们计算图像的质心,面积等。
函数cv2.moments()会将计算获得的矩以一个字典的形式返回。数组

import numpy as np
import cv2

img = cv2.imread('1024.jpg',0) ret,thresh = cv2.threshold(img,127,255,0) image,contours,hierarchy=cv2.findContours(thresh,1,2) cnt=contours[0] M=cv2.moments(cnt) print(M) 

根据这些矩的值,咱们能够计算出对象的重心:app

cx=int(M['m10']/M['m00']) cy=int(M['m01']/M['m00']) 

2.2轮廓面积
可使用函数cv2.contourArea()计算获得,也能够用矩(0阶矩),M['m00']。函数

area=cv2.contourArea(cnt) 

2.3轮廓周长
也被称为弧长。可使用函数cv2.arcLength()计算获得。这个函数的第二参数能够用来指定对象的形状是闭合的(True),仍是打开的(一条曲线)。ui

perimeter = cv2.arcLength(cnt,True) 

2.4轮廓近似
将轮廓形状近似到另一种由更少点组成的轮廓形状,新轮廓的点的数目由咱们设定的准确度来决定,使用的Douglas-Peucker算法,能够本身Google。
假设咱们要在一幅图像中查找一个矩形,可是因为图像的种种缘由咱们不能获得一个完美的矩形,而是一个“坏形状”,如今就可使用这个函数来近似这个形状,第二个参数是epsilon,它是从原始轮廓到近似轮廓的最大距离,它是一个准确度参数。spa

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

2.5凸包
凸包与轮廓近似类似,但不一样,虽然有些状况下它们给出的结果是同样的。函数cv2.convexHull()能够用来检测一个曲线是否具备凸性缺陷,并能纠正缺陷。通常来讲,凸性曲线老是凸出来的,至少是平的。若是有地方凹进去了就被叫作凸性缺陷。例以下图中的手,红色曲线显示了手的凸包,凸性缺陷被双箭头标出来了。
3d

hull = cv2.convexHull(points,hull,clockwise,returnPoints) 

参数:code

  • points咱们要传入的轮廓
  • hull输出,一般不须要
  • clockwise方向标志,若是设置为True,输出的凸包是顺时针方向的,不然为逆时针方向。
  • returnPoints默认值为True。它会返回凸包上点的坐标,若是设置为False,就会返回与凸包点对应的轮廓上的点。
    要得到上图的凸包,能够用下面命令:
hull=cv2.convexHull(cnt) 

可是若是你想得到凸性缺陷,须要把returnPoints设置为False。以上面矩形为例,首先咱们找到他的轮廓从cnt。如今把returnPoints设置为True查找凸包,获得的就是矩形的四个角点。把returnPoints设置为False,获得的是轮廓点的索引。
2.6凸性检测
函数cv2.isContourConvex()能够检测一个曲线是否是凸的。它只能返回True或者False。对象

k=cv2.isContourConvex(cnt) 

2.7边界矩形
直边界矩形,一个直矩形,没有旋转。不会考虑对象是否旋转。因此边界矩形的面积不是最小的。可使用函数cv2.boundingRect()查找获得

#(x,y)为矩形左上角的坐标,(w,h)是矩形的宽和高 x,y,w,h=cv2.boundingRect(cnt) img=cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2) 

旋转的边界矩形,这个边界矩形是面积最小的,由于它考虑了对象的旋转。用函数cv2.minAreaRect()。返回的是一个Box2D结构,其中包含矩形最上角角点坐标(x,y)矩形的宽和高(w,h)以及旋转角度。可是要绘制这个矩形须要矩形的4个角点,能够经过函数cv2.boxPoints()得到。
其中绿色的为直矩形,红色为旋转矩形。

2.8最小外接圆
函数cv2.minEnclosingCircle()能够帮咱们找到一个对象的外接圆。它是全部可以包括对象的圆中面积最小的一个。

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

2.9椭圆拟合
使用函数cv2.ellipse(),返回值其实就是旋转边界矩形的内切圆。

ellipse = cv2.fitEllipse(cnt) img = cv2.ellipse(img,ellipse,(0,255,0),2) 

2.10直线拟合
能够根据一组点拟合出一条直线,一样咱们也能够为图像中的白色点拟合出一条直线。

rows,cols = img.shape[:2] [vx,vy,x,y]=cv2.fitLine(cnt,cv2.DIST_L2,0,0.01,0.01) lefty=int((x*vy/vx)+y) righty=int(((cols-x)*vy/vx)+y) img = cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)