首发于OpenCV实战

使用Hu矩进行形状匹配

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

  1. 什么是图像矩?
  2. 如何计算图像矩?
  3. 胡矩不变量(或胡矩)是什么?
  4. 如何使用OpenCV计算图像的Hu矩?
  5. 胡矩如何用于寻找两个形状之间的相似性。

1. 什么是图像矩?

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

为简单起见,我们考虑单通道二值图像I。位置(x,y)的像素强度由I(x,y)给出。注意,对于二进制图像,I(x,y)可以取0或1的值。

下面给出了我们能定义的最简单的力矩

我们在上面的方程中所做的就是计算所有像素强度的总和。换句话说,所有像素强度的权重只基于它们的强度,而不基于它们在图像中的位置。

对于二值图像,上面的矩可以用几种不同的方式来解释

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

到目前为止,你可能不会对图像时刻印象深刻,但这里有一些有趣的事情。图1包含三个二进制图像—S (S0.png)、旋转S (S5.png)和K (K0.png)。

这个S和旋转S的图像的力矩会非常接近,而K的力矩会不同。

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

2. 如何计算图像矩?

让我们看一些更复杂的时刻。

其中i和j是整数(例如0、1、2…)。这些时刻通常被称为原始时刻,以便与本文后面提到的中心时刻区分开来。

注意上述时刻取决于像素的强度和它们在图像中的位置。所以这些瞬间直观地捕捉到了一些形状的概念。

使用图像矩的质心

2.1 Central Moments

中心矩与我们之前看到的原始图像矩非常相似,只是我们从矩公式中的x和y中减去了形心。

注意,上面的中心矩是平移不变的。换句话说,无论斑点在图像的什么地方,如果形状是一样的,力矩是一样的。

如果我们也能使矩不随比例变化不是很酷吗?我们需要如下图所示的标准化中心矩。

3.什么是胡矩?

中心矩是平移不变的,这很好。但这对于形状匹配来说还不够。我们想要计算的矩是不变的平移,规模,和旋转如下图所示。

幸运的是,我们可以计算这样的时刻,它们被称为Hu矩。

如果你有兴趣了解胡矩的理论基础,请参阅这篇论文。

4. 如何计算OpenCV中的Hu矩?

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

让我们讨论一下计算OpenCV中Hu矩的分步方法。

  1. Read in image as Grayscale
// Read image as grayscale image
Mat im = imread(filename,IMREAD_GRAYSCALE);

2.Binarize the image using thresholding

// Threshold image
threshold(im, im, 128, 255, THRESH_BINARY);

3.Calculate Hu Moments

OpenCV有一个计算Hu矩的内置函数。毫不奇怪,它被称为HuMoments。将图像的中心矩作为输入,利用函数矩计算中心矩

// Calculate Moments
Moments moments = moments(im, false);
// Calculate Hu Moments
double huMoments[7];
HuMoments(moments, huMoments)

4.Log Transform

在前一步中得到的Hu矩有很大的范围。例如上图所示的K (K0.png)的7 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.57625e-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
// Log scale hu moments
for(int i = 0; i < 7; i++)
{
  huMoments[i] = -1 * copysign(1.0, huMoments[i]) * log10(abs(huMoments[i])); 
}

5. Shape Matching using Hu Moments

如前所述,在平移(x或y方向移动)、缩放和旋转下,所有7个Hu矩都是不变的。如果一个图形是另一个图形的镜像,那么第7个Hu时刻在符号上翻转。

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

可以看到,图像K0.png就是字母K,而S0.png就是字母S。接下来,我们将字母S移到S1中。在s2。png中移动+缩放。我们添加了一些旋转使S3.png,并进一步翻转图像使S4.png。

注意,S0、S1、S2、S3和S4的所有Hu矩的值都很接近,除了S4的最后Hu矩的符号被翻转了。另外,注意它们都与K0非常不同。

5.1 Distance between two shapes using matchShapes

在本节中,我们将学习如何使用Hu矩来找出两个图形之间的距离。如果距离小,形状的外观接近,如果距离大,形状的外观较远。

OpenCV提供了一个名为matchShapes的实用程序函数,它可以获取两幅图像(或轮廓),并使用Hu矩查找它们之间的距离。所以,你不需要明确地计算Hu力矩。简单地对图像进行二值化并使用matchShapes。

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);

注意,您可以通过第三个参数(CONTOURS_MATCH_I1、CONTOURS_MATCH_I2或CONTOURS_MATCH_I3)使用三种类型的距离。

两个图像(im1和im2)是相似的,如果上面的距离很小。你可以使用任何距离测量。它们通常产生相似的结果。我个人更喜欢d2。

我们来看看这三个距离是如何定义的。

设D(A, B)为形状A和B之间的距离,H^A_i和H^B_i为形状A和B的i^{th} log变换Hu矩。三种情况下对应的距离定义为

  1. CONTOURS_MATCH_I1


  1. CONTOURS_MATCH_I2


  1. CONTOURS_MATCH_I3

当我们对图像S0, K0, S4 (S0的变换和翻转版本)进行形状匹配时,得到如下输出:

Shape Distances Between ————————-
S0.png and S0.png : 0.0
S0.png and K0.png : 0.10783054664091285
S0.png and S4.png : 0.008484870268973932

5.2 Custom distance measure

如果您想定义两个形状之间的自定义距离度量,您可以轻松地这样做。例如,你可能想使用胡矩之间的欧几里德距离

首先,您计算前一节中提到的对数转换Hu矩,然后自己计算距离,而不是使用matchShapes。

参考

Shape Matching using Hu Moments (C++ / Python)

发布于 03-26

文章被以下专栏收录