目錄
- 轉載本文請注明詳細位址
- 本文介紹了矩和圖像矩的含義
- 本文介紹了不變矩的計算、應用
- 本文介紹了如何計算圖像相似度
一、思維導圖
二、普通矩的定義
1、零階矩
2、二階矩
3、二階以上矩
4、怎麼判斷是幾階矩
三、什麼是圖像矩?
四、hu不變矩(cv2.humoments())
1、幾何矩
幾何矩前幾階的意義
2、中心矩(決定了平移不變性)
3、歸一化中心矩(決定了尺度不變性)
4、hu不變矩計算(決定了旋轉不變性)
5、hu不變矩的性質
6、hu不變矩的應用與意義
7、适用條件
五、Python+opencv實作不變矩計算
1、自帶函數cv2.moments()和cv2.humoments()
2、自定義函數
3、結果
4、 網絡上的典型例子
六、形狀相似度計算(cv2.matchshapes())
參數解析:
距離計算方法
自定義距離計算方法
一、思維導圖

二、普通矩的定義
1、零階矩
2、二階矩
3、二階以上矩
對于三階或三階以上矩,使用圖像在軸或軸上的投影比使用圖像本身的描述更友善。
三階矩:投影扭曲,描述了圖像投影的扭曲程度。扭曲是一個經典統計量,用來衡量關于均值對稱分布的偏差程度。
四階矩:投影峰度,峰度是一個用來測量分布峰度的經典統計量。可以計算峰度系數。當峰度系數為0時,表示高斯分布;當峰度系數小于0時,表示平坦的少峰分布;當峰度系數大于0時,表示狹窄的多峰分布。
4、怎麼判斷是幾階矩
在計算矩的表達式中,将x,y的指數進行相加,得到的值就是圖像矩的階數
三、什麼是圖像矩?
最初接觸的矩的概念就是力矩的概念,力與距離的乘積叫做力矩。圖像矩因為涉及到兩個距離x,y,是以是和兩個距離、一個像素強度(灰階值有關),具體定義如下:
其中:M、N分别是圖像的長寬,f是對應像素點的灰階值
四、hu不變矩(cv2.humoments())
1、幾何矩
幾何矩前幾階的意義
2、中心矩(決定了平移不變性)
3、歸一化中心矩(決定了尺度不變性)
比較大的争議是在r的求值上,是否加上1,一般情況下加上1會結果準确些
4、hu不變矩計算(決定了旋轉不變性)
5、hu不變矩的性質
圖像形狀平移不變性
圖像形狀尺度不變性
圖像形狀旋轉不變性
6、hu不變矩的應用與意義
圖像形狀比對
圖像形狀區分
圖像形狀相似度計算
7、适用條件
适用于紋理不複雜的圖像
五、Python+opencv實作不變矩計算
1、自帶函數cv2.moments()和cv2.humoments()
前者輸入的是灰階值圖像,後者輸入的是由幾何矩、中心矩、歸一化的中心矩組成的一個字典
import cv2
import numpy as np
np.set_printoptions(suppress=True)#定義輸出的精度
def sys_moments(img):
'''
opencv_python自帶求矩以及不變矩的函數
:param img: 灰階圖像,對于二值圖像來說就隻有兩個灰階0和255
:return: 傳回以10為底對數化後的hu不變矩
'''
moments = cv2.moments(img)#傳回的是一個字典,三階及以下的幾何矩(mpq)、中心矩(mupq)和歸一化的矩(nupq)
humoments = cv2.HuMoments(moments)#根據幾何矩(mpq)、中心矩(mupq)和歸一化的矩(nupq)計算出hu不變矩
# 因為直接計算出來的矩可能很小或者很大,是以取對數好比較,這裡的對數底數為e,通過對數除法的性質将其轉換為以10為底的對數,一般是負值,是以加一個負号将其變為正的
humoment = -(np.log(np.abs(humoments)))/np.log(10)
return humoment
2、自定義函數
有兩個前面這個是在求(p+q)階中心矩的時候采用了一些推導公式,後面那個是嚴格按照公式來的,建議看後面那個
def def_moments(img_gray):
'''
自定義求矩函數,主要是根據公式将一個個參數求出
:param img_gray: 灰階圖像,對于二值圖像來說就隻有兩個灰階0和255
:return: 傳回以10為底對數化後的hu不變矩
'''
'''
由于7個不變矩的變化範圍很大,為了便于比較,可利用取對數的方法進行資料壓縮;
同時考慮到不變矩有可能出現負值的情況,是以,在取對數之前先取絕對值
經修正後的不變矩特征具有平移 、旋轉和比例不變性
'''
# 标準矩定義為m_pq = sumsum(x^p * y^q * f(x, y))其中f(x,y)為像素點處的灰階值
row, col = img_gray.shape
# 計算圖像的0階幾何矩
m00 = img_gray.sum()
##初始化一到三階幾何矩
#計算一階矩陣
m10 = m01 = 0
# 計算圖像的二階、三階幾何矩
m11 = m20 = m02 = m12 = m21 = m30 = m03 = 0
for i in range(row):
m10 += (i * img_gray[i]).sum()#sum表示将一行的灰階值進行相加
m20 += (i ** 2 * img_gray[i]).sum()
m30 += (i ** 3 * img_gray[i]).sum()
for j in range(col):
m11 += i * j * img_gray[i][j]
m12 += i * j ** 2 * img_gray[i][j]
m21 += i ** 2 * j * img_gray[i][j]
for j in range(col):
m01 += (j * img_gray[:, j]).sum()
m02 += (j ** 2 * img_gray[:, j]).sum()
m30 += (j ** 3 * img_gray[:, j]).sum()
# 由标準矩我們可以得到圖像的"重心"
u10 = m10 / m00
u01 = m01 / m00
# 計算圖像的二階中心矩、三階中心矩
y00 = m00
y10 = y01 = 0
y11 = m11 - u01 * m10
y20 = m20 - u10 * m10
y02 = m02 - u01 * m01
y30 = m30 - 3 * u10 * m20 + 2 * u10 ** 2 * m10
y12 = m12 - 2 * u01 * m11 - u10 * m02 + 2 * u01 ** 2 * m10
y21 = m21 - 2 * u10 * m11 - u01 * m20 + 2 * u10 ** 2 * m01
y03 = m03 - 3 * u01 * m02 + 2 * u01 ** 2 * m01
# 計算圖像的歸一化中心矩
n20 = y20 / m00 ** 2
n02 = y02 / m00 ** 2
n11 = y11 / m00 ** 2
n30 = y30 / m00 ** 2.5
n03 = y03 / m00 ** 2.5
n12 = y12 / m00 ** 2.5
n21 = y21 / m00 ** 2.5
# 計算圖像的七個不變矩
h1 = n20 + n02
h2 = (n20 - n02) ** 2 + 4 * n11 ** 2
h3 = (n30 - 3 * n12) ** 2 + (3 * n21 - n03) ** 2
h4 = (n30 + n12) ** 2 + (n21 + n03) ** 2
h5 = (n30 - 3 * n12) * (n30 + n12) * ((n30 + n12) ** 2 - 3 * (n21 + n03) ** 2) + (3 * n21 - n03) * (n21 + n03) \
* (3 * (n30 + n12) ** 2 - (
n21 + n03) ** 2)
h6 = (n20 - n02) * ((n30 + n12) ** 2 - (n21 + n03) ** 2) + 4 * n11 * (n30 + n12) * (n21 + n03)
h7 = (3 * n21 - n03) * (n30 + n12) * ((n30 + n12) ** 2 - 3 * (n21 + n03) ** 2) + (3 * n12 - n30) * (n21 + n03) \
* (3 * (n30 + n12) ** 2 - (
n21 + n03) ** 2)
inv_m7 = [h1, h2, h3, h4, h5, h6, h7]
humoments = np.log(np.abs(inv_m7))
return humoments
def main():
img = cv2.imread('roi.png',0)
sys_humoments = sys_moments(img)
def_humoments = def_moments(img)
print('自帶函數:\n',sys_humoments)
print('自定義函數:\n',def_humoments)
if __name__ == '__main__':
main()
def def_moments(img_gray):
'''
自定義求矩函數,主要是根據公式将一個個參數求出
:param img_gray: 灰階圖像,對于二值圖像來說就隻有兩個灰階0和255
:return: 傳回以10為底對數化後的hu不變矩
'''
'''
由于7個不變矩的變化範圍很大,為了便于比較,可利用取對數的方法進行資料壓縮;
同時考慮到不變矩有可能出現負值的情況,是以,在取對數之前先取絕對值
經修正後的不變矩特征具有平移 、旋轉和比例不變性
'''
# 标準矩定義為m_pq = sumsum(x^p * y^q * f(x, y))其中f(x,y)為像素點處的灰階值
row, col = img_gray.shape
# 計算圖像的0階幾何矩
m00 = 0.0
##初始化一到三階幾何矩
# 計算一階矩陣
m10 = m01 = 0.0
# 計算圖像的二階、三階幾何矩
m11 = m20 = m02 = m12 = m21 = m30 = m03 = 0.0
for i in range(row):
for j in range(col):
m00 += img_gray[i][j]
m10 += i*img_gray[i][j]
m20 += i**2*img_gray[i][j]
m30 += i**3*img_gray[i][j]
m11 += i * j * img_gray[i][j]
m12 += i * j ** 2 * img_gray[i][j]
m21 += i ** 2 * j * img_gray[i][j]
for j in range(col):
for i in range(row):
m01 += (j * img_gray[i, j])
m02 += (j ** 2 * img_gray[i, j])
m03 += (j ** 3 * img_gray[i, j])
# 由标準矩我們可以得到圖像的"重心"
u10 = m10 / m00
u01 = m01 / m00
# 計算圖像的二階中心矩、三階中心矩
y00 = y10 = y01 = y11 = y20 = y02 = y30 = y12 = y21 = y03 = 0.0
for x in range(row):
for y in range(col):
x_ = x - u10
y_ = y - u01
y00 += img_gray[x][y]
y10 += x_*img_gray[x][y]
y01 += y_*img_gray[x][y]
y11 += x_*y_*img_gray[x][y]
y02 += y_**2*img_gray[x][y]
y20 += x_**2*img_gray[x][y]
y03 += y_**3*img_gray[x][y]
y30 += x_**3*img_gray[x][y]
y12 += x_*y_**2*img_gray[x][y]
y21 += x_**2*y_*img_gray[x][y]
# 計算圖像的歸一化中心矩
n20 = y20 / (y00 ** 2)
n02 = y02 / (y00 ** 2)
n11 = y11 / (y00 ** 2)
n30 = y30 / (y00 ** 2.5)
n03 = y03 / (y00 ** 2.5)
n12 = y12 / (y00 ** 2.5)
n21 = y21 / (y00 ** 2.5)
# 計算圖像的七個不變矩
h1 = n20 + n02
h2 = (n20 - n02) ** 2 + 4 * (n11 ** 2)
h3 = (n30 - 3 * n12) ** 2 + (3 * n21 - n03) ** 2
h4 = (n30 + n12) ** 2 + (n21 + n03) ** 2
h5 = (n30 - 3 * n12) * (n30 + n12) * ((n30 + n12) ** 2 - 3 * (n21 + n03) ** 2) + (3 * n21 - n03) * (n21 + n03) \
* (3 * (n30 + n12) ** 2 - (
n21 + n03) ** 2)
h6 = (n20 - n02) * ((n30 + n12) ** 2 - (n21 + n03) ** 2) + 4 * n11 * (n30 + n12) * (n21 + n03)
h7 = (3 * n21 - n03) * (n30 + n12) * ((n30 + n12) ** 2 - 3 * (n21 + n03) ** 2) + (3 * n12 - n30) * (n21 + n03) \
* (3 * (n30 + n12) ** 2 - (
n21 + n03) ** 2)
inv_m7 = [h1, h2, h3, h4, h5, h6, h7]
humoments = np.log(np.abs(inv_m7))
return humoments
3、結果
結果不是很理想,可能在編寫計算中心矩和不變矩的公式的時候出現了錯誤,可以自行糾正
4、 網絡上的典型例子
可以看到,圖像K0.png就是字母K,而S0.png就是字母S。接下來,我們将字母S移到S1中。在s2。png中移動+縮放。我們添加了一些旋轉使S3.png,并進一步翻轉圖像使S4.png。
注意,S0、S1、S2、S3和S4的所有Hu矩的值都很接近,除了S4的最後Hu矩的符号被翻轉了。另外,注意它們都與K0非常不同。
六、形狀相似度計算(cv2.matchshapes())
我們将學習如何使用Hu矩來找出兩個圖形之間的距離。如果距離小,形狀的外觀接近,如果距離大,形狀的外觀較遠。
OpenCV提供了一個名為matchShapes的實用程式函數,它可以擷取兩幅圖像(或輪廓),并使用Hu矩查找它們之間的距離。是以,你不需要明确地計算Hu力矩。簡單地對圖像進行二值化并使用matchShapes。
dist = matchShapes(contour1, contour2, method, parameter)
這裡是利用兩個圖像的不變矩來進行距離的計算
參數解析:
前兩個參數是兩個圖像
method:進行距離計算的方法即公式,分别有以下三種方法
parameter:一般設定為0即可
距離計算方法
注意:以下的計算方法的hu不變矩陣都是經過log函數變換的
兩個圖像(im1和im2)是相似的,如果上面的距離很小。你可以使用任何距離測量。它們通常産生相似的結果。我個人更喜歡d2。
自定義距離計算方法
七、參考文獻
https://zhuanlan.zhihu.com/p/117344473(中文版)
https://www.learnopencv.com/shape-matching-using-hu-moments-c-python/(英文版)
hu不變矩的原理:https://www.researchgate.net/publication/224146066_Analysis_of_Hu's_moment_invariants_on_image_scaling_and_rotation
https://blog.csdn.net/qq_37207090/article/details/83986950
https://blog.csdn.net/qq_23541329/article/details/60963456