1. 程式人生 > >hu不變矩--python

hu不變矩--python

由於網上關於Hu矩的定義的內容較多,程式碼實現部分又多為matlab、C++或者opencv等,因此本文將主要介紹如何用python實現Hu矩的提取。後續可能會利用Hu矩進行圖片分類以及平移、旋轉不變性的實驗,有時間做的話到時候會放上來結果。
本篇部落格內容參考影象的七個不變矩 可用於影象的匹配中的matlab程式碼,在其基礎上進行修改而成。

#-*-coding:utf-8-*-
import cv2
from datetime import datetime
import numpy as np
np.set_printoptions(suppress=True)

def humoments
(img_gray):
''' 由於7個不變矩的變化範圍很大,為了便於比較,可利用取對數的方法進行資料壓縮;同時考慮到不變矩有可能出現負值的情況,因此,在取對數之前先取絕對值 經修正後的不變矩特徵具有平移 、旋轉和比例不變性 ''' # 標準矩定義為m_pq = sumsum(x^p * y^q * 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() 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] inv_m7 = np.log(np.abs(inv_m7)) return inv_m7 if __name__ == '__main__': t1 = datetime.now() fp = '/home/mamq/images/3.jpg' img = cv2.imread(fp) img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) print humoments(img_gray) print datetime.now() - t1

結果:

[‘0.004757610794121051’, ‘1.0751006208352332e-05’, ‘5.069206342794947e-08’, ‘1.3770952298167658e-07’, ‘1.7004668315871364e-15’, ‘4.163184056113891e-10’, ‘1.1379424976439726e-14’]

這是之前為取對數時的結果,取對數後七個矩之間差距較小,便於後續計算。

執行耗時:3.79秒,相比zernike矩耗時較長。
目前看來Hu矩提取出來的值都比較小,最小的甚至到了小數點後14位,看到網上也有人提出這個問題,不確定是否是程式碼的問題。

寫完這篇部落格後,又嘗試了下opencv自帶的函式,程式碼與結果如下:

#-*-coding:utf-8-*-
import cv2
from datetime import datetime
import numpy as np

def test(img):
    moments = cv2.moments(img)
    humoments = cv2.HuMoments(moments)
    # humoments = no.log(np.abs(humoments)) # 同樣建議取對數
    print(humoments)

if __name__ == '__main__':
    t1 = datetime.now()    
    fp = '/home/mamq/images/3.jpg'
    img = cv2.imread(fp)
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    test(img_gray)
    print datetime.now() - t1

結果:

[[1.58880283e-03]
[1.30795119e-07]
[6.01877793e-11]
[7.45476806e-11]
[4.34518625e-21]
[1.69631118e-14]
[2.46057599e-21]]

執行耗時:0.13秒.
對比:

可以看出,opencv自帶函式效率更高,耗時非常短,但兩段程式碼使用的都是同一張圖片,但結果相差較大,還是相信opencv吧,畢竟更權威,第一段程式碼僅供學習參考。但從結果中可以看出來,Hu矩的值都比較小,進行不同圖片的對比時如何進行距離的度量是個問題。

由於最近比較忙,這篇部落格寫的不夠嚴謹,故僅供參考。