OpenCV 图像轮廓

边缘检测虽然能够检测出边缘,但边缘是不连续的,检测到的边缘并不是一个整体。图像轮廓是指将边缘连接起来形成的一个整体,用于后续的计算。

图像轮廓是图像中非常重要的一个特征信息,通过对图像轮廓的操作,我们能够获取目标图像的大小、位置、方向等信息。

案例来源于傅老师。

1.查找轮廓

寻找轮廓的操作一般用于二值化图,所以通常会使用阈值分割或Canny边缘检测先得到二值图。

函数cv2.findContours()的语法格式为:

contours,hierarchy=cv2.findContours(image,mode,method)

contours:返回的轮廓。例如contours[i]表示第i个轮廓。

hierarchy:图像的拓扑信息(轮廓层次)。

image:输入的图像。

mode:轮廓搜索模式:决定了轮廓的提取方式。

method:轮廓近似方法:决定了如何表达轮廓。

import cv2
import numpy as np
img = cv2.imread('shape.jpg')    #读取图像
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转为灰度值图
ret, binary = cv2.threshold(gray,220,255,cv2.THRESH_BINARY) #转为二值图
contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE) #寻找轮廓
n=len(contours)       #轮廓个数
print(n)
print(len(contours[0]))       #轮廓0像素数目
print(len(contours[1]))       #轮廓1像素数目
print(len(contours[2]))       #轮廓2像素数目
print(len(contours[3]))       #轮廓3像素数目

2.绘制轮廓

函数cv2.drawContours的语法格式为:

image=cv2.drawContours(image, contours, contourIdx, color, thickness=None, lineType=None, hierarchy=None, maxLevel=None, offset=None)

cv2.imshow("img",img) #显示原图像
img2 = cv2.drawContours(img,contours,1,(0,165,255),-1)  #绘制轮廓,1表示绘制第几个轮廓
cv2.imshow("contours",img2)   #显示轮廓
cv2.waitKey()
cv2.destroyAllWindows()

OpenCV 图像轮廓_第1张图片

OpenCV 图像轮廓_第2张图片

3.矩特征

矩的计算:

比较两个轮廓最简单的方法是比较二者的轮廓矩。轮廓矩代表了一个轮廓、一幅图像、一组点集的全局特征。矩信息包含了对应对象不同类型的几何特征,例如大小、位置、角度、形状等。矩特征被广泛地应用在模式识别、图像识别等方面。

函数cv2.moments()的语法格式为:

retval=cv2.moments(array[,binaryImage])

array:可以是点集,也可以是灰度图像或者二值图像。

binaryImage:当为True时,array内所有的非零值都会被处理为1。

import cv2
import numpy as np
img = cv2.imread('shape.jpg')    #读取图像
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转为灰度值图
ret, binary = cv2.threshold(gray,220,255,cv2.THRESH_BINARY) #转为二值图
contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,\
                                       cv2.CHAIN_APPROX_NONE) #寻找轮廓
n=len(contours)       #轮廓个数
contoursImg=[]
for i in range(n):
    temp=np.zeros(img.shape,np.uint8) #生成黑背景
    contoursImg.append(temp)
    contoursImg[i]=cv2.drawContours(contoursImg[i],contours,i,(255,255,255), 3)  #绘制轮廓
    cv2.imshow("contours[" + str(i)+"]",contoursImg[i])   #显示轮廓
print("计算图像的矩特征:")
for i in range(n):
    moment=cv2.moments(contours[i])
    print(f"轮廓{i}的矩:\n{moment}")
cv2.waitKey()
cv2.destroyAllWindows()
for i in range(n):
    area=cv2.moments(contours[i])["m00"]
    print(f"轮廓{i}的面积:\n{area}")

计算轮廓的面积:

函数cv2.contourArea()的语法格式为:

area=cv2.contourArea(contour [, oriented])

contour:轮廓。

oriented:布尔值,当为True时,表示顺时针或逆时针计算。

import cv2
import numpy as np
img = cv2.imread('shape.jpg')    #读取图像
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #转为灰度值图
ret, binary = cv2.threshold(gray,220,255,cv2.THRESH_BINARY) #转为二值图
contours, hierarchy = cv2.findContours(binary,cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE) #寻找轮廓
n=len(contours)       #轮廓个数
contoursImg=[]
for i in range(n):
    area = cv2.contourArea(contours[i])
    print(f"轮廓{i}的面积:\n{area}")

计算轮廓的长度:

函数cv2.arcLength()的语法格式为:

length=cv2.arcLength(curve,closed)

curve:轮廓。

closed:布尔值,当为True时,表示闭合。

n=len(contours)       #轮廓个数
contoursImg=[]
for i in range(n):
    length = cv2.arcLength(contours[i], True)  #获取轮廓长度
    print(f"轮廓{i}的长度:\n{length}")

4.Hu矩函数

Hu矩是归一化中心矩的线性组合,Hu矩再图像旋转,缩放,平移等操作后,仍能保持矩的不变性,经常使用 Hu 矩来识别图像的特征。

形状匹配:

通过Hu 矩可以来判断两个对象的一致性。但是结果比较抽象,OpenCV 提供了 cv2.matchShapes() 对两个对象的Hu矩进行比较。

函数cv2.matchShapes()的语法格式为:

retval = cv2.matchShapes(contour1, contour2, method, 0.0)

retval:矩形边界左上角顶点的坐标值及矩形边界的宽度和高度。

contour1:第一个轮廓或灰度图像。

contour2:第二个灰度或轮廓图像。

method:比较两个对象的Hu 矩的方法,写1吧。

import cv2
o1 = cv2.imread('m1.png')
o2 = cv2.imread('m2.png')
o3 = cv2.imread('m3.png') 
gray1 = cv2.cvtColor(o1,cv2.COLOR_BGR2GRAY) 
gray2 = cv2.cvtColor(o2,cv2.COLOR_BGR2GRAY) 
gray3 = cv2.cvtColor(o3,cv2.COLOR_BGR2GRAY) 
ret, binary1 = cv2.threshold(gray1,127,255,cv2.THRESH_BINARY) 
ret, binary2 = cv2.threshold(gray2,127,255,cv2.THRESH_BINARY) 
ret, binary3 = cv2.threshold(gray3,127,255,cv2.THRESH_BINARY) 
contours1, hierarchy = cv2.findContours(binary1,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE) 
contours2, hierarchy = cv2.findContours(binary2,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE) 
contours3, hierarchy = cv2.findContours(binary3,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE) 
cnt1 = contours1[0]
cnt2 = contours2[0]
cnt3 = contours3[0]
ret0 = cv2.matchShapes(cnt1,cnt1,1,0.0)
ret1 = cv2.matchShapes(cnt1,cnt2,1,0.0)
ret2 = cv2.matchShapes(cnt1,cnt3,1,0.0)
print("相同图像的 matchShape=",ret0)
print("相似图像的 matchShape=",ret1)
print("不相似图像的 matchShape=",ret2)

5.轮廓拟合

最小包围矩形框:

函数cv2.minAreaRect()的语法格式为:

retval =cv2.minAreaRect( points )

retval:返回的矩阵特征信息,结构是(最小外接矩形的中心(x,y),(宽度,高度),旋转角度)。

points:轮廓。

import cv2
o=cv2.imread('shape.jpg')
cv2.imshow("original",o)
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY)
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY) 
contours, hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE) 
rect = cv2.minAreaRect(contours[1])
print("返回值 rect:\n",rect)
points = cv2.boxPoints(rect)
print("\n 转换后的 points:\n",points)
points = np.int64(points)                 #取整,np.int64=np.int0
image=cv2.drawContours(o,[points],0,(0,0,0),2)
cv2.imshow("result",o)
cv2.waitKey()
cv2.destroyAllWindows()

OpenCV 图像轮廓_第3张图片

最优拟合椭圆:

函数cv2.fitEllipse()的语法格式为:

retval = cv2.fitEllipse( points )

import cv2
o=cv2.imread('shape.jpg')
cv2.imshow("original",o)
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY) 
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY) 
contours, hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)

ellipse = cv2.fitEllipse(contours[1])
print("ellipse=",ellipse)
cv2.ellipse(o,ellipse,(0,255,0),3)
cv2.imshow("result",o)
cv2.waitKey()
cv2.destroyAllWindows()

OpenCV 图像轮廓_第4张图片

最优拟合直线:

函数cv2.fitLine()的语法格式为:

line = cv2.fitLine( points, distType, param, reps, aeps )

import cv2
o=cv2.imread('shape.jpg')
cv2.imshow("original",o)
gray = cv2.cvtColor(o,cv2.COLOR_BGR2GRAY) 
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY) 
contours, hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)

rows,cols = o.shape[:2]
[vx,vy,x,y] = cv2.fitLine(contours[1], cv2.DIST_L2,0,0.01,0.01) # 返回值是共线的归一化向量,和线上一点
lefty = int((-x*vy/vx) + y)                   # 说白了就是一个方向和一个点,点斜式嘛,还啥vec4f,,讲究
righty = int(((cols-x)*vy/vx)+y)                # 计算两个点,代值计算就行
cv2.line(o,(cols-1,righty),(0,lefty),(0,255,0),2)   
cv2.imshow("result",o)
cv2.waitKey()
cv2.destroyAllWindows()

OpenCV 图像轮廓_第5张图片

逼近多边形:

函数cv2.approxPolyDP()用来构造指定精度的逼近多边形曲线,语法格式为:

approx = cv2.approxPolyDP(contour[0],epsilon,True)

import cv2
import numpy as np

# 多边形逼近
# 1.先找到轮廓
img = cv2.imread('contours3.png')
cv2.imshow("original",img)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) 
ret, binary = cv2.threshold(gray,127,255,cv2.THRESH_BINARY) 
contours, hierarchy = cv2.findContours(binary,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
cnt = contours[0]

# 2.进行多边形逼近,得到多边形的角点
approx1 = cv2.approxPolyDP(cnt, 3, True)
approx2 = cv2.approxPolyDP(cnt, 15, True)
approx3 = cv2.approxPolyDP(cnt, 75, True)

# 3.画出多边形
adp=img.copy()
img1=cv2.polylines(adp, [approx1], True, (255, 0, 0), 2)
cv2.imshow('approxPloyDP1', img1)
####
adp=img.copy()
img2=cv2.polylines(adp, [approx2], True, (0, 255, 0), 2)
cv2.imshow('approxPloyDP2', img2)
#####
adp=img.copy()
img3=cv2.polylines(adp, [approx3], True, (0, 0, 255), 2)
cv2.imshow('approxPloyDP3', img3)

print(len(approx1),len(approx2),len(approx3))  # 角点的个数
cv2.waitKey(0)
cv2.destroyAllWindows()

OpenCV 图像轮廓_第6张图片

OpenCV 图像轮廓_第7张图片

OpenCV 图像轮廓_第8张图片

OpenCV 图像轮廓_第9张图片

你可能感兴趣的:(OpenCV,opencv)