目录

1 什么是图像矩?

2 如何计算图像矩

2.1 质心获取

2.2 中心矩

2.3 Hu矩

3 基于Hu矩实现形状匹配

3.1 Hu矩的计算

3.2 基于matchShapes函数计算两个图形之间的距离

4 代码

4.1 Hu矩计算

4.2 形状匹配

5 参考


在这篇文章中,我们将展示如何使用Hu Moments进行形状匹配。您将学习以下内容

  • 什么是图像矩?
  • 如何计算图像矩?
  • 什么是图像矩不变量(或胡时刻)?
  • 如何使用OpenCV计算图像的Hu图像矩?
  • 如何使用Hu图像矩来找到两个形状之间的相似性。

1 什么是图像矩?

图像矩是图像像素强度的加权平均值。让我们选择一个简单的例子来理解。

为简单起见,我们考虑单通道二进制图像I。位置处的像素强度(X,Y)为I(X,Y)。二进制图像的I(X,Y)可以取值0或255。

最简单的图像矩可以这样计算:

我们在上面的等式中所做的就是计算所有像素值的总和。换句话说,所有图像矩仅基于它们的值加权,而不是基于它们在图像中的位置。

对于二进制图像,可以以几种不同的方式解释上述矩:

  1. 它是值白色像素的数量(即强度=255)。
  2. 它是代表图像中白色区域的面积。

到目前为止,您可能不会对图像矩留下深刻印象,但这里有一些有趣的东西。图1包含三个二进制图像S(S0.png),旋转S(S5.png)和K(K0.png)

S图像和旋转S图像的图像矩非常接近,K的矩就大大不同。

对于两个相同的形状,上面的图像矩必然是相同的,但它不是一个充分的条件。我们可以很容易地构建两个图像,其中图像矩相同的,但它们看起来非常不同。

2 如何计算图像矩

2.1 质心获取

让我们看看一些更复杂的矩。

i和j是整数。这种矩通常被称为图像几何矩,以区别于本文后面提到的中心矩。请注意,上述矩取决于像素的强度及其在图像中的位置。如此直观地说,这些矩正在捕捉一些形状的信息。

我们可以通过图像矩计算质心。使用以下公式计算质心:

其他信息查看:

https://blog.csdn.net/LuohenYJ/article/details/88599334

2.2 中心矩

中心矩非常类似于我们之前看到的几何矩,在几何矩的基础上我们需要减去质心坐标。

请注意,上述中心矩是具有平移不变性的。换句话说,无论图像中的blob在哪里,如果形状相同,则中心矩是不变的。

如果我们还能让这个矩具有不变性,那会不会很酷?那么为此我们需要在中心矩添加标准化,得到中心归一化矩。如下所示。

中心矩是平移不变的,中心归一化矩是平移和尺度不变的。三种矩总结如下:

2.3 Hu矩

中心矩具有很不错的特性,但是不足以用于特征匹配。我们想要计算对平移,缩放和旋转不变的矩,幸运的是,我们实际上可以计算出这样的矩,他们被称为Hu矩的7个不变量。如下图所示。

Hu矩(或者更确切地说是Hu矩不变量)是使用对图像变换不变的中心矩计算的一组7个变量。事实证明,前6个矩不变量对于平移,缩放,旋转和映射都是不变的。而第7个矩会因为图像映射而改变。

Hu矩的理论你可参考论文:

https://www.researchgate.net/publication/224146066_Analysis_of_Hu's_moment_invariants_on_image_scaling_and_rotation

3 基于Hu矩实现形状匹配

3.1 Hu矩的计算

幸运的是,我们不需要在OpenCV中进行所有计算,因为我们有计算Hu矩的函数。在OpenCV中,我们HuMoments()用来计算输入图像中的Hu矩。

(1)我们先读取原图并将其转换为灰度图像

C++:

// Read image as grayscale image

Mat im = imread(filename,IMREAD_GRAYSCALE);

Python:

# Threshold image

_,im = cv2.threshold(im, 128, 255, cv2.THRESH_BINARY)

(2)使用阈值处理对图像进行二值化:

C++:

// Threshold image 阈值分割

threshold(im, im, 0, 255, THRESH_OTSU);

Python:

# Threshold image

_,im = cv2.threshold(im, 128, 255, cv2.THRESH_BINARY)

(3)基于OpenCV先计算图像中心矩,再计算图像Hu矩

C++:

// Calculate Moments

Moments moments = moments(im, false);

// Calculate Hu Moments

double huMoments[7];

HuMoments(moments, huMoments);

Python:

# Calculate Moments

moments = cv2.moments(im)

# Calculate Hu Moments

huMoments = cv2.HuMoments(moments)

(4)在前一步骤中获得的Hu矩变化过大。例如k图像的Hu矩为:

h[0] = 0.00162663

h[1] = 3.11619e-07

h[2] = 3.61005e-10

h[3] = 1.44485e-10

h[4] = -2.55279e-20

h[5] = -7.57625 e-14

h[6] = 2.09098e-20

请注意,hu [0]的大小与hu [6]不具有可比性。我们可以使用下面给出的对数转换将它们放在相同的范围内

转换后的结果如下:

H[0] = 2.78871

H[1] = 6.50638

H[2] = 9.44249

H[3] = 9.84018

H[4] = -19.593

H[5] = -13.1205

H[6] = 19.6797

转换代码为:

C++:

// Log scale hu moments

for(int i = 0; i < 7; i++)

{

  huMoments[i] = -1 * copysign(1.0, huMoments[i]) * log10(abs(huMoments[i])); 

}

Python:

# Log scale hu moments

for i in range(0,7):

  huMoments[i] = -1* copysign(1.0, huMoments[i]) * log10(abs(huMoments[i])))

其中copysign函数的意思是将函数第一个变量的符号设置成第二个变量的正负数符号,然后输出第一个变量。例如若第二个变量为负数,则上式1变为负数-1,输出-1。

3.2 基于matchShapes函数计算两个图形之间的距离

如前所述,所有7个Hu矩不变量不管图像缩放和旋转都是不变的。只有映射时比如图像翻转,那么第七个Hu矩正负符号就会变化。那不是很漂亮吗?

我们来看一个例子。在下表中我们有6张图片和他们的Hu矩。

如您所见,我们在S1.png中移动字母S,并在S2.png中移动+缩放它。我们添加了一些旋转来制作S3.png并进一步翻转图像以制作S4.png。注意,S0,S1,S2,S3和S4的所有Hu矩在值上彼此接近,除了翻转S4的第七个Hu矩的符号。另外,请注意它们与K非常不同。

在本节中,我们将学习如何使用Hu Moments来找到两个形状之间的距离。如果距离小,则两个图形在外观上接近。

OpenCV提供了一个易于使用的名为matchShapes函数,它接收两个图像(或轮廓)并使用Hu矩找到它们之间的距离。所以,你只需将图像二值化并使用matchShapes即可。

用法如下所示

C++:

double d1 = matchShapes(im1, im2, CONTOURS_MATCH_I1, 0);

double d2 = matchShapes(im1, im2, CONTOURS_MATCH_I2, 0);

double d3 = matchShapes(im1, im2, CONTOURS_MATCH_I3, 0);

Python:

d1 = cv2.matchShapes(im1,im2,cv2.CONTOURS_MATCH_I1,0)

d2 = cv2.matchShapes(im1,im2,cv2.CONTOURS_MATCH_I2,0)

d3 = cv2.matchShapes(im1,im2,cv2.CONTOURS_MATCH_I3,0)

请注意,您可以通过第三个参数(CONTOURS_MATCH_I1,CONTOURS_MATCH_I2或CONTOURS_MATCH_I3)使用三种b不同的距离。如果上述距离很小,则两个图像(im1和im2)相似。您可以使用任何距离测量。它们通常产生类似的结果。个人喜欢第二种,因为好计算。

三种距离具体计算如下:

1 CONTOURS_MATCH_I1

2 CONTOURS_MATCH_I2

3 CONTOURS_MATCH_I3

是图像A和B之间的距离, 是图像A和B第i个Hu矩对数转换后的值。

当我们在图像上使用形状匹配时,如S0与S0,K0和S4,我们得到以下输出:

S0和S0:0.0

S0和K0:0.10783054664091285

S0和S4:0.008484870268973932

如果您想在两个形状之间自定义距离。例如,您可能希望使用由给定的Hu Moments之间的欧几里德距离。首先,如前一节所述,计算对数变换的Hu矩,然后自己计算距离,而不是使用matchShapes。

4 代码

代码地址:

https://github.com/luohenyueji/OpenCV-Practical-Exercise

https://download.csdn.net/download/luohenyj/11026231

如果没有积分(系统自动设定资源分数)看看参考链接。我搬运过来的,大修改没有。

4.1 Hu矩计算

C++:

#include "pch.h"
#include <iostream>
#include "opencv2/opencv.hpp" using namespace cv;
using namespace std; int main()
{
//是否进行log转换
bool showLogTransformedHuMoments = true; // Obtain filename 图像地址
string filename("./image/s0.png"); // Read Image 读图
Mat im = imread(filename, IMREAD_GRAYSCALE); // Threshold image 阈值分割
threshold(im, im, 0, 255, THRESH_OTSU); // Calculate Moments 计算矩
//第二个参数True表示非零的像素都会按值1对待,也就是说相当于对图像进行了二值化处理,阈值为1
Moments moment = moments(im, false); // Calculate Hu Moments 计算Hu矩
double huMoments[7];
HuMoments(moment, huMoments); // Print Hu Moments
cout << filename << ": "; for (int i = 0; i < 7; i++)
{
if (showLogTransformedHuMoments)
{
// Log transform Hu Moments to make squash the range
cout << -1 * copysign(1.0, huMoments[i]) * log10(abs(huMoments[i])) << " ";
}
else
{
// Hu Moments without log transform.
cout << huMoments[i] << " ";
}
}
// One row per file
cout << endl;
}

Python:

from math import copysign, log10

def main():
showLogTransformedHuMoments = True # Obtain filename from command line argument
filename = './image/s0.png' # Read image
im = cv2.imread(filename,cv2.IMREAD_GRAYSCALE) # Threshold image
_,im = cv2.threshold(im, 128, 255, cv2.THRESH_BINARY) # Calculate Moments
moment = cv2.moments(im) # Calculate Hu Moments
huMoments = cv2.HuMoments(moment) # Print Hu Moments
print("{}: ".format(filename),end='') for i in range(0,7):
if showLogTransformedHuMoments:
# Log transform Hu Moments to make
# squash the range
print("{:.5f}".format(-1*copysign(1.0,\
huMoments[i])*log10(abs(huMoments[i]))),\
end=' ')
else:
# Hu Moments without log transform
print("{:.5f}".format(huMoments[i]),end=' ')
print() if __name__ == "__main__":
main()

4.2 形状匹配

C++:

#include "pch.h"
#include "opencv2/opencv.hpp" using namespace cv;
using namespace std; int main()
{
Mat im1 = imread("./image/S0.png",IMREAD_GRAYSCALE);
Mat im2 = imread("./image/K0.png",IMREAD_GRAYSCALE);
Mat im3 = imread("./image/S4.png",IMREAD_GRAYSCALE); double m1 = matchShapes(im1, im1, CONTOURS_MATCH_I2, 0);
double m2 = matchShapes(im1, im2, CONTOURS_MATCH_I2, 0);
double m3 = matchShapes(im1, im3, CONTOURS_MATCH_I2, 0); cout << "Shape Distances Between " << endl << "-------------------------" << endl;
cout << "S0.png and S0.png : " << m1 << endl;
cout << "S0.png and K0.png : " << m2 << endl;
cout << "S0.png and S4.png : " << m3 << endl;
}

Python:

import cv2

def main():

    im1 = cv2.imread("./image/S0.png",cv2.IMREAD_GRAYSCALE)
im2 = cv2.imread("./image/K0.png",cv2.IMREAD_GRAYSCALE)
im3 = cv2.imread("./images/S4.png",cv2.IMREAD_GRAYSCALE) m1 = cv2.matchShapes(im1,im1,cv2.CONTOURS_MATCH_I2,0)
m2 = cv2.matchShapes(im1,im2,cv2.CONTOURS_MATCH_I2,0)
m3 = cv2.matchShapes(im1,im3,cv2.CONTOURS_MATCH_I2,0) print("Shape Distances Between \n-------------------------") print("S0.png and S0.png : {}".format(m1))
print("S0.png and K0.png : {}".format(m2))
print("S0.png and S4.png : {}".format(m3)) if __name__ == "__main__":
main()

5 参考

https://www.learnopencv.com/shape-matching-using-hu-moments-c-python/

[OpenCV实战]10 使用Hu矩进行形状匹配的更多相关文章

  1. [OpenCV实战]49 对极几何与立体视觉初探

    本文主要介绍对极几何(Epipolar Geometry)与立体视觉(Stereo Vision)的相关知识.对极几何简单点来说,其目的就是描述是两幅视图之间的内部对应关系,用来对立体视觉进行建模,实 ...

  2. Hu矩SVM训练及检测-----OpenCV

    关键词:Hu矩,SVM,OpenCV 在图像中进行目标物识别,涉及到特定区域内是否存在目标物,SVM可在样本量较少情况下对正负样本(图片中前景背景)做出良好区分,图片基本特征包括诸如HOG.LBP.H ...

  3. opencv计算两个轮廓之间hu矩相似程度,MatchShapes

    https://blog.csdn.net/jiake_yang/article/details/52589063 [OpenCV3.3]通过透视变换矫正变形图像 https://blog.csdn. ...

  4. 【图像算法OpenCV】几何不变矩--Hu矩

    原文地址  http://blog.csdn.NET/daijucug/article/details/7535370 [图像算法OpenCV]几何不变矩--Hu矩 一 原理 几何矩是由Hu(Visu ...

  5. opencv —— moments 矩的计算(空间矩/几何矩、中心距、归一化中心距、Hu矩)

    计算矩的目的 从一幅图像计算出来的矩集,不仅可以描述图像形状的全局特征,而且可以提供大量关于该图像不同的几何特征信息,如大小,位置.方向和形状等.这种描述能力广泛应用于各种图像处理.计算机视觉和机器人 ...

  6. opencv中的图像矩(空间矩,中心矩,归一化中心矩,Hu矩)

    严格来讲矩是概率与统计中的一个概念,是随机变量的一种数字特征.设 x 为随机变量,C为常数,则量E[(x−c)^k]称为X关于C点的k阶矩.比较重要的两种情况如下: 1.c=0,这时a_k=E(X^k ...

  7. OpenCV实战:人脸关键点检测(FaceMark)

    Summary:利用OpenCV中的LBF算法进行人脸关键点检测(Facial Landmark Detection) Author:    Amusi Date:       2018-03-20 ...

  8. 几何不变矩--Hu矩

    [图像算法]图像特征: ---------------------------------------------------------------------------------------- ...

  9. 【OpenCV】轮廓的特征矩Moment

    opencv中的矩主要包括以下几种:空间矩,中心矩和中心归一化矩. class Moments { public: ...... // 空间矩 double m00, m10, m01, m20, m ...

随机推荐

  1. Linux文本相关命令

    Linux文本相关命令 目录 Linux文本相关命令 文本排序命令 文本去重命令 基础命令cut 文本三剑客 sed awk grep 文本排序命令 sort 常用参数: -n:以数值大小进行排序 - ...

  2. 通过linux-PAM实现禁止root用户登陆的方法

    前言 在linux系统中,root账户是有全部管理权限的,一旦root账户密码外泄,对于服务器而言将是致命的威胁:出于安全考虑,通常会限制root账户的登陆,改为配置普通用户登陆服务器后su切换到ro ...

  3. 原生JavaScript

    原生JavaScript 为了方便查看. 所有的js和css代码都是嵌入式直接写在html代码中 1.js的引入方式 <!DOCTYPE html> <html lang=" ...

  4. 知识图谱-生物信息学-医学顶刊论文(Bioinformatics-2021)-SumGNN:通过有效的KG聚集进行多类型DDI预测

    3.(2021.3.26)Bioinformatics-SumGNN:通过有效的KG聚集进行多类型DDI预测 论文标题: SumGNN: multi-typed drug interaction pr ...

  5. PX01关于手机屏IIC触摸调试学习笔记

    相关文件下载: 上位机工具:http://www.xk-image.com/download/blog/0002_TP调试/LcdTools20210605.rar 调试案例:http://www.x ...

  6. JS逆向实战8——某网实战(基于golang-colly)

    其实本章算不上逆向教程 只是介绍golang的colly框架而已 列表页分析 根据关键字搜索 通过抓包分析可知 下一页所请求的参数如下 上图标红的代表所需参数 所以其实我们真正需要的也就是Search ...

  7. xss学习笔记(萌新版)

    xss简介 xss攻击者构造恶意信息然后在用户的浏览器上执行,主要分为反射性xss,这种主要是某个页面存在有漏洞的参数,然后填上恶意参数把整个链接发给用户或者管理员,他们点击了带有恶意参数的链接就会执 ...

  8. linux系统配置文件或shell脚本批量注释

    1. 配置文件批量注释 1.1 批量注释 ① 进入命令行模式,按ctrl + v进入 visual block模式,键盘上下箭头选中多行,把需要注释的行标记起来 ② 按大写字母I,再输入注释符:# ③ ...

  9. 嵌入式-C语言基础:实现字符串拷贝函数

    自己实现一个字符串的拷贝函数 #include<stdio.h> #include<stdlib.h> #include <string.h> char * mys ...

  10. 直播CDN调度技术关键挑战与架构设计

    作者:胡济麟 1.背景介绍 1.1 直播业务特点 互联网视频直播是一种消息媒介形态,提供时产时消的内容,经过多年,已经发展出秀场.游戏.电商.体育等多种业务形态.主要特点是:内容实时产生实时消费,对时 ...