hu不变矩--python

本文探讨如何使用Python实现Hu矩提取,并与OpenCV自带函数进行比较。通过实验发现,虽然自编代码耗时较长,但OpenCV的效率更高且结果更可靠。Hu矩的值普遍较小,对图片对比的度量方法提出疑问。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于网上关于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矩的值都比较小,进行不同图片的对比时如何进行距离的度量是个问题。

由于最近比较忙,这篇博客写的不够严谨,故仅供参考。


以上,欢迎交流,禁止转载。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值