Hu 矩是归一化中心矩的线性组合。Hu 矩在图像旋转、缩放、平移等操作后,仍能保持矩 的不变性,所以经常会使用 Hu 距来识别图像的特征。
1. Hu矩函数
函数 cv2.HuMoments()的语法格式为:
hu = cv2.HuMoments( m )
式中返回值 hu,表示返回的 Hu 矩值;参数 m,是由函数 cv2.moments()计算得到矩特征值。
【例 12.8】计算图像的 Hu 矩,对其中第 0 个矩的关系进行演示。
import cv2
img = cv2.imread("/Users/zhaofeier/Desktop/源代码及图像/chapter12/cs1.bmp")
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
HuM1 = cv2.HuMoments(cv2.moments(gray)).flatten()
print("cv2.moments(gray)=\n",cv2.moments(gray))
print("\nHuM1=",HuM1)
print("HuM1=",HuM1[0])
【例 12.9】计算三幅不同图像的 Hu 矩,并进行比较。
#! 图像img1的Hu矩
img1 = cv2.imread("/Users/zhaofeier/Desktop/源代码及图像/chapter12/cs1.bmp")
gray1 = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
HuM1 = cv2.HuMoments(cv2.moments(gray1)).flatten()
#! 图像img2的Hu矩
img2 = cv2.imread("/Users/zhaofeier/Desktop/源代码及图像/chapter12/cs3.bmp")
gray2 = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
HuM2 = cv2.HuMoments(cv2.moments(gray2)).flatten()
#! 图像img3的Hu矩
img3 = cv2.imread("/Users/zhaofeier/Desktop/源代码及图像/chapter12/lena.bmp")
gray3 = cv2.cvtColor(img3,cv2.COLOR_BGR2GRAY)
HuM3 = cv2.HuMoments(cv2.moments(gray3)).flatten()
#! 打印图像img1,img2,img3的特征值
print("img1.shape=",img1.shape)
print("img2.shape=",img2.shape)
print("img3.shape=",img3.shape)
print("cv2.moments(gray1)=\n",cv2.moments(gray1))
print("cv2.moments(gray2)=\n",cv2.moments(gray2))
print("cv2.moments(gray3)=\n",cv2.moments(gray3))
print("\nHuM1=\n",HuM1)
print("\nHuM2=\n",HuM2)
print("\nHuM3=\n",HuM3)
#! 图像img1与img2,图像img1与img3的Hu矩之差
print("\nHuM1-HuM2=\n",HuM1-HuM2)
print("\nHuM1-HuM3=\n",HuM1-HuM3)
#! 显示图像
cv2.imshow("original1",img1)
cv2.imshow("original2",img2)
cv2.imshow("original3",img3)
cv2.waitKey()
cv2.destroyAllWindows()
2. 形状匹配
为了更直观方便地比较Hu矩值,OpenCV提供了函数cv2.matchShapes(), 对两个对象的 Hu 矩进行比较。
函数cv2.matchShapes()
允许我们提供两个对象,对二者的 Hu 矩进行比较。这两个对象可 以是轮廓,也可以是灰度图。不管是什么,cv2.matchShapes()都会提前计算好对象的 Hu 矩值。
函数 cv2.matchShapes()的语法格式为:
retval = cv2.matchShapes( contour1, contour2, method, parameter )
式中 retval 是返回值。
该函数有如下 4 个参数:
- contour1:第 1 个轮廓或者灰度图像。
- contour2:第 2 个轮廓或者灰度图像。
- method:比较两个对象的 Hu 矩的方法
- parameter:应用于 method 的特定参数,该参数为扩展参数,目前(截至 OpenCV 4.1.0版本)暂不支持该参数,因此将该值设置为 0。
【例 12.10】使用函数 cv2.matchShapes()计算三幅不同图像的匹配度。
img1 = cv2.imread("/Users/zhaofeier/Desktop/源代码及图像/chapter12/cs1.bmp")
img2 = cv2.imread("/Users/zhaofeier/Desktop/源代码及图像/chapter12/cs2.bmp")
img3 = cv2.imread("/Users/zhaofeier/Desktop/源代码及图像/chapter12/cc.bmp")
gray1 = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
gray2 = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)
gray3 = cv2.cvtColor(img3,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)
contour1,hierarchy = cv2.findContours(binary1,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
contour2,hierarchy = cv2.findContours(binary2,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
contour3,hierarchy = cv2.findContours(binary3,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
cnt1 = contour1[0]
cnt2 = contour2[0]
cnt3 = contour3[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)
- 同一幅图像的 Hu 矩是不变的,二者差值为 0。
- 相似的图像即使发生了平移、旋转和缩放后,函数 cv2.matchShapes()的返回值仍然比较接近。例如,图像 o1 和图像 o2,o2 是对 o1 经过缩放、旋转和平移后得到的,但是对二者应用 cv2.matchShapes()函数后,返回值的差较小。
- 不相似图像 cv2.matchShapes()函数返回值的差较大。例如,图像 o1 和图像 o3 的差别较大,因此对二者应用 cv2.matchShapes()函数后,返回值的差也较大。