轮廓是连接具有相同颜色或强度的所有连续点(沿边界)的曲线,轮廓是用于形状分析以及对象及检测和识别的有用工具。
为了获取更高的准确性,会先进行二值化处理,在得到二进制图像后,寻找轮廓就是从黑色背景中找到白色物体,因此我们要找的对象应是白色,背景应该是黑色。
通过分析出物体对象后,找出物体的轮廓点位并绘制出来。
实现效果:
执行后会把找到的所有轮廓点位都绘制出来,如上图所示。
import cv2
img=cv2.imread('test.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, img2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
binary,contours, hierarchy = cv2.findContours(img2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
img3 = cv2.drawContours(img, contours, -1, (0,255,255), 3)
cv2.imshow("BINARY", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
特征矩代表了一个轮廓、一幅图像的全局特征,矩信息包含了对应对象不同类型的几何特征,特征矩分为三种:空间矩、中心矩和归一化中心矩。
1)空间矩:也叫几何矩,是图像的大小面积及周长等。包括零阶矩:m00,一阶矩:m10,m01,二阶矩:m20,m11,m02,三阶矩:m30,m21,m12,m03。
2)中心矩:对于高阶图像,特征矩会随着位置的变化而变化,为了解决这个问题中心矩就应运而生,它通过减去均值而获取平移的不变性,因而能比较不同位置的两个对象是否一致,即中心矩具有平移不变性特征。包括二阶中心矩:mu20,mu11,mu02,三阶中心矩:mu30,mu21,mu12,mu03。
3)归一化中心矩:除平移之外,有些图像我们还会碰到缩放的情况,即在缩放后也能判断其特征,归一化中心矩通过除以物体总尺寸而获得缩放不变性。
包括二阶Hu矩:nu20,nu11,nu02,三阶Hu距:nu30,nu21,nu12,nu03。接下来通过分析出的轮廓,计算出轮廓的特征矩,面积和周长。
实现效果:
面积和周长的单位为像素,这里计算的是图像最外围的轮廓。
import cv2
img=cv2.imread('test.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, img2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
binary,contours, hierarchy = cv2.findContours(img2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnt=contours[0]
m=cv2.moments(cnt)
area=cv2.contourArea(cnt)
perimeter=cv2.arcLength(cnt,True)
print("特证矩:",m)
print("面积:",area)
print("周长:",perimeter)
寻找后的轮廓信息“contours”可能过于复杂不平滑,可以用approxPolyDP函数对该多边形曲线做适当近似,这就是轮廓的多边形逼近。
该函数是以多边形去逼近轮廓,采用的是Douglas-Peucker算法(方法名中的
DP),DP算法原理比较简单,核心就是不断找多边形最远的点加入形成新的多边形,直到最短距离小于指定的精度。
接下来通过多边形逼近来分析出物体的轮廓。
实现效果:
多边形逼近后的轮廓会尽量贴合图形。
import cv2
img=cv2.imread('test.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, img2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
binary,contours, hierarchy = cv2.findContours(img2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnt=contours[1]
approxl=cv2.approxPolyDP(cnt,20,True)
img3 = cv2.drawContours(img, [approxl], -1, (255,0,0), 3)
cv2.imshow("BINARY", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
凸包跟逼近多边形很像,只不过它是物体最外层的凸多边形。凸包指的是完全包含原有轮廓,并且仅由轮廓上的点所构成的多边形。凸包的每一处都是凸的,即在凸包内连接任意两点的直线都在凸包的内部。在凸包内,任意连续三个点的内角小于180°。
接下来通过轮廓凸包来分析出物体的轮廓。
轮廓凸包会连接轮廓的顶点部分。
import cv2
img=cv2.imread('test.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, img2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
binary,contours, hierarchy = cv2.findContours(img2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnt=contours[1]
hull=cv2.convexHull(cnt,True)
img3 = cv2.drawContours(img, [hull], -1, (255,0,0), 3)
cv2.imshow("BINARY", img)
cv2.waitKey(0)
cv2.destroyAllWindows()
外接矩形分为带旋转角度的最小外接矩形和常规外接矩形。
最小外接矩形:按照物体的角度以最小的面积进行衔接,可以知道物体有没有旋转。
常规外接矩形:把物体扩在里面但是面积最大。
接下来会分布绘制物体的常规和最小外接矩形。
import cv2
import numpy as np
img=cv2.imread('test.jpg')
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, img2 = cv2.threshold(img_gray, 127, 255, cv2.THRESH_BINARY)
binary,contours, hierarchy = cv2.findContours(img2, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cnt=contours[1]
RotatedRect=cv2.minAreaRect(cnt)
x,y,w,h=cv2.boundingRect(cnt)
box=cv2.boxPoints(RotatedRect)
box=np.int0(box)
img3 = cv2.drawContours(img, [box], -1, (255,0,0), 3)
img4=cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),3)
cv2.imshow("BINARY", img)
cv2.waitKey(0)
cv2.destroyAllWindows()