什么叫图像或轮廓的空间矩、中心矩、归一化中心矩?并利用OpenCV的类Moments计算轮廓的这几个矩和质心位置

矩(moments)是描述图像特征的算子,被广泛应用于图像检索和识别,以及图像匹配、图像重建、图像压缩及运动图像分析等领域。

接下来介绍图像矩的原理。

在物理上,有个概念叫“力矩”,相信大家都有印象。力F对点O的矩,不仅决定于力的大小,同时与矩心的位置有关,矩心的位置不同,力矩随之不同。

借助于物理学上的这个概念,我们可以定义图像的矩。图像的矩有很多种,接下来介绍几个常用的图像矩并利用OpenCV的类Moments计算轮廓的这几个矩和质心位置。

一、图像空间矩【spatial moments】

我们先来看图像空间矩【spatial moments】的概念
这里插一句题外话,有些资料把空间矩也称为叫几何矩,博主觉得叫几何矩不准确,因为几何矩是几何图形的矩,而几何图形是不考虑每一点的像素值大小的。

图像空间矩【spatial moments】的计算公式如下:
在这里插入图片描述
其中, a r r a y ( x , y ) array(x,y) array(x,y)是像素(x,y)处的像素值。
注意:x代表的是像素的列号,而不是行号;y代表的是像素的行号,而不是列号。这一点可以在下面的示例代码的运行结果中看出。这也是为什么上面m的下标不是“ i j ij ij”而是“ j i ji ji”的原因。

从这个计算式我们可以看出,图像的空间矩不仅与像素值大小有关,还与像素的位置有关,这一点和物理学中力矩的概念是一致的。

j = i = 0 j=i=0 j=i=0时,有 m 00 = ∑ x , y a r r a y ( x , y ) x 0 y 0 = ∑ x , y a r r a y ( x , y ) m_{00}=\sum_{x,y}array(x,y)x^{0}y^{0}=\sum_{x,y}array(x,y) m00=x,yarray(x,y)x0y0=x,yarray(x,y)

此时 m 00 m_{00} m00称为叫图像的零阶空间矩,从这个计算式我们可以看出,图像的零阶空间矩实际上就是所有像素值的累加,零阶矩的值与像素的位置无关。

j = 0 , i = 1 j=0,i=1 j=0,i=1 j = 1 , i = 0 j=1,i=0 j=1,i=0时, m 01 m_{01} m01 m 10 m_{10} m10称为图像的一阶空间矩,很明显,图像的一阶空间矩在空间位置上只与像素的行号或列号有关。以此类推,可以有图像的二阶空间矩,三阶空间矩等。比如以下三种情况都是图像的二阶空间矩:
① j=0,i=2,即 m 02 m_{02} m02
② j=1,i=1,即 m 11 m_{11} m11
③ j=2,i=0,即 m 20 m_{20} m20

根据图像的零阶空间矩和一阶空间矩,我们可以定义出图像的质心的坐标计算式:

x ˉ = m 10 m 00 \bar{x}=\frac{m_{10}}{m_{00} } xˉ=m00m10 y ˉ = m 01 m 00 \bar{y}=\frac{m_{01}}{m_{00}} yˉ=m00m01 注意, x ˉ \bar{x} xˉ是列号, y ˉ \bar{y} yˉ是行号。

二、图像的中心矩【central moments】

图像的中心矩的计算式如下:
在这里插入图片描述
式中的 x ˉ \bar{x} xˉ y ˉ \bar{y} yˉ就是图像的质心位置坐标(上边已经介绍过了),即:

x ˉ = m 10 m 00 \bar{x}=\frac{m_{10}}{m_{00} } xˉ=m00m10 y ˉ = m 01 m 00 \bar{y}=\frac{m_{01}}{m_{00}} yˉ=m00m01 注意, x ˉ \bar{x} xˉ是列号, y ˉ \bar{y} yˉ是行号。

根据上面的计算式,容易得到:
在这里插入图片描述  在这里插入图片描述

三、图像归一化的中心矩【normalized central moments】

图像归一化的中心矩的计算式如下:
在这里插入图片描述
根据上面的计算式容易得到:
n u 00 = 1 nu_{00}=1 nu00=1   n u 10 = n u 01 = 0 nu_{10}=nu_{01}=0 nu10=nu01=0

四、利用OpenCV的类Moments计算图像或点集(轮廓)的空间矩、中心矩和归一化的中心矩

OpenCV提供了类Moments来计算图像或点集(轮廓)的空间矩、中心矩和归一化的中心矩。
下面介绍这个类Moments。
先说类Moments的成员函数moments(),这个成员函数的原型如下:

Moments cv::moments	(	InputArray 	array,
						bool 	binaryImage = false 
					)	

成员函数moments()用于计算多边形或像素图像的三阶(包含三阶)以下的空间矩、中心矩和归一化的中心矩。官方文档原话如下:
Calculates all of the moments up to the third order of a polygon or rasterized shape.
其参数意义如下:
array—Raster image (single-channel, 8-bit or floating-point 2D array) or an array ( 1×N or N×1 ) of 2D points (Point or Point2f )。
binaryImage—If it is true, all non-zero image pixels are treated as 1’s. The parameter is used for images only.
以上英文很简单,就不翻译了,不明白的再加博主的微信/QQ 2487872782交流吧。
再说类Moments的成员变量,它的成员变量和表示的意义分别如下:
在这里插入图片描述
在这里插入图片描述
注意:由于
在这里插入图片描述在这里插入图片描述
所以上面的中心矩没有 m u 00 mu_{00} mu00 m u 01 mu_{01} mu01 m u 10 mu_{10} mu10这几个。
在这里插入图片描述
注意:由于 n u 00 = 1 nu_{00}=1 nu00=1   n u 10 = n u 01 = 0 nu_{10}=nu_{01}=0 nu10=nu01=0

所以上面的归一化中心矩没有 n u 00 nu_{00} nu00 n u 10 nu_{10} nu10 n u 01 nu_{01} nu01这几个。

接下来是使用类Moments计算图像轮廓的空间矩、质心位置、中心矩、归一化中心矩的示例代码。
代码中用到的图像下载链接:https://pan.baidu.com/s/1ZfOReFRyeMDLhk3PjJXGwA?pwd=aes8

//博主微信/QQ 2487872782
//有问题可以联系博主交流
//有图像处理需求也可联系博主
//图像处理技术交流QQ群 271891601

//OpenCV版本:3.0
//VS版本:2013

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include<opencv2/imgcodecs/imgcodecs.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include <iostream>

using namespace cv;
using namespace std;

int main()
{
    
    
	Mat srcGary = imread("F:/material/images/P0045-ellipse-02.jpg", 0);
	imshow("srcGary", srcGary);

	// 阈值化操作
	Mat threMat;
	int thresh = 128;
	threshold(srcGary, threMat, thresh, 255, THRESH_BINARY);


	vector<vector<Point>> contours;

	// find Contours
	findContours(threMat, contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_NONE);
	cout << "检测到的轮廓个数为:" << (int)contours.size() << endl << endl;

	// draw Contours
	Mat contours_img(srcGary.size(), CV_8U, Scalar(0));
	drawContours(contours_img, contours, -1, Scalar(255), 1);
	imshow("contours_img", contours_img);

	//计算质心位置
	Moments moments_1 = moments(contours[0]);
	double moments_1_m00 = moments_1.m00;
	cout << "空间矩m00的值为:" << moments_1_m00 << endl << endl;
	double moments_1_m10 = moments_1.m10;
	cout << "空间矩m10的值为:" << moments_1_m10 << endl << endl;
	double moments_1_m01 = moments_1.m01;
	cout << "空间矩m01的值为:" << moments_1_m01 << endl << endl;

	int cx = moments_1_m10 / moments_1_m00;
	cout << "质心的列号为(横坐标-x坐标):" << cx << endl << endl;
	int cy = moments_1_m01 / moments_1_m00;
	cout << "质心的行号为(列坐标-y坐标)::" << cy << endl << endl;

	//用绿色的实心圆把质心绘制出来
	Point center_point = Point(cx, cy);
	Mat result_img = srcGary.clone();
	cvtColor(result_img, result_img, CV_GRAY2BGR);
	circle(result_img, center_point, 5, Scalar(0, 220, 0), CV_FILLED, CV_AA, 0);
	imshow("result_img", result_img);

	double moments_1_mu11 = moments_1.mu11;
	cout << "中心矩mu11的值为:" << moments_1_mu11 << endl << endl;

	double moments_1_nu11 = moments_1.nu11;
	cout << "归一化的中心矩nu11的值为:" << moments_1_nu11 << endl << endl;

	waitKey();
	return(0);
}

运行结果如下图所示:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
下一篇博文,介绍下Hu矩,Hu矩是由二阶和三阶中心距计算得到七个不变矩,Hu矩具有旋转、平移和缩放不变性,因此在图像具有旋转和放缩的情况下Hu矩具有更广泛的应用领域。
关于Hu矩,等写好后再把链接放到这里吧。
博主2022-05-12 18:29:35注:已经写好了介绍Hu矩的博文,链接如下:
图像或轮廓的Hu矩的定义、优缺点、适用范围,并利用OpenCV的函数HuMoments()和matchShapes()实现Hu矩的计算和轮廓匹配

猜你喜欢

转载自blog.csdn.net/wenhao_ir/article/details/124728035#comments_22101051