矩的概念介绍

       矩函数在图像分析中有着广泛的应用,如模式识别、目标分类、目标识别与方位估计、图像的编码与重构等。从一幅图像计算出来的矩集,不仅可以描述图像形状的全局特征,而且可以提供大量关于该图像不同的几何特征信息,如大小,位置、方向和形状等。图像矩这种描述能力广泛应用于各种图像处理、计算机视觉和机器人技术领域的目标识别与方位估计中。

一阶矩:与形状有关;

二阶矩:显示曲线围绕直线平均值的扩展程度;

三阶矩:关于平均值的对称性测量;由二阶矩和三阶矩可以导出7个不变矩。而不变矩是图像的统计特性,满足平移、伸缩、旋转均不变的不变性、在图像识别领域得到广泛的应用。

       在OpenCV中,可以很方便的计算多边形区域的3阶特征矩,opencv中的矩主要包括以下几种:空间矩,中心矩和中心归一化矩。

       class Moments { public: ...... // 空间矩 double m00, m10, m01, m20, m11, m02, m30, m21, m12, m03; 

                                                    // 中心矩 double mu20, mu11, mu02, mu30, mu21, mu12, mu03;

                                                    // 中心归一化矩 double nu20, nu11, nu02, nu30, nu21, nu12, nu03; }

函数原型:

Moments moments( InputArray array, bool binaryImage=false );

 moments 计算生成数据:

                          

1 、空间矩/几何矩

空间矩的实质为面积或者质量。可以通过一阶矩计算质心/重心。

                                                  

可以知道,对于01二值化的图像,m00即为轮廓的面积。

2、中心矩

        中心矩体现的是图像强度的最大和最小方向(中心矩可以构建图像的协方差矩阵),其只具有平移不变性,所以用中心矩做匹配效果不会很好。

                                                    

   其中:                         

假设array(x,y)只有0,1是二值图像,则m00表示非0像素总数,即面积。可以这膜理解:先求出所有非零像素的x,y坐标的和,然后除以非零像素的总数,得到的均值作为中心。

3、归一化的中心矩

      归一化后具有尺度不变性。

                                                              

在OpenCV中,还可以很方便的得到Hu不变距,Hu不变矩在图像旋转、缩放、平移等操作后,仍能保持矩的不变性,所以有时候用Hu不变距更能识别图像的特征。

Hu不变矩的基本概念请参考 http://www.cnblogs.com/skyseraph/archive/2011/07/19/2110183.html

Hu不变矩主要是利用归一化中心矩构造了7个不变特征矩:

 函数原型:‘

void HuMoments( const Moments& moments, double hu[7] );
void HuMoments( const Moments& m, CV_OUT OutputArray hu );

实例:

//图像矩:(Image Moments)
//步骤:提取图像边缘
//发现轮廓
//计算每个轮廓对象的矩
//计算每个对象的中心、弧长、面积
 
#include"stdafx.h"
#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
 
using namespace cv;
using namespace std;
 
Mat src, dst, drawImage;
const char*result = "moments_demo";
int threshold_value = 120;
int threshold_max = 255;
RNG rng(12345);
void Moments_demo(int, void*);
int main(int argc, char*argv)
{
	src = imread("111.png");
	if (!src.data)
	{
		printf("could not load image...\n");
		return -1;
	}
	char input[] = "gray image";
	namedWindow(input, CV_WINDOW_AUTOSIZE);
	namedWindow(result, CV_WINDOW_AUTOSIZE);
	//输入图像转为灰度图像
	cvtColor(src, dst, CV_BGR2GRAY);
	GaussianBlur(dst, dst, Size(3, 3), 0, 0);
	imshow(input, dst);
 
	const char*thresh = "threshold value";
	createTrackbar(thresh, result, &threshold_value, threshold_max, Moments_demo);
	Moments_demo(0, 0);
 
	waitKey(0);
	return 0;
}
 
void Moments_demo(int, void*)
{
	//提取图像边缘
	Mat canny_out;
	Canny(dst, canny_out, threshold_value, threshold_value * 2, 3, false);
	//imshow("canny image", canny_out);
 
	//发现轮廓,找到图像轮廓
	vector<vector<Point>> contours;
	vector<Vec4i> hierachy;
	findContours(canny_out, contours, hierachy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0));
 
	//计算每个轮廓对象的矩
	vector<	Moments> contours_moments(contours.size());
	vector<Point2f> centers(contours.size());
	for (size_t i = 0; i < contours.size(); i++)
	{
		//计算矩
		contours_moments[i] = moments(contours[i]);
		//moments(InputArray  array,//输入数据
		//bool   binaryImage = false // 是否为二值图像
		centers[i] = Point(static_cast<float>(contours_moments[i].m10 / contours_moments[i].m00), static_cast<float>(contours_moments[i].m01 / contours_moments[i].m00));
		//图像中心Center(x0, y0)=(m10/m00,m01/m00)
	}
 
	src.copyTo(drawImage);
	for (size_t i = 0; i < contours.size(); i++)
	{
		printf("centers point x:%.2f,y:%.2f\n", centers[i].x, centers[i].y);
		printf("contours %d Area:%.2f Arc length:%.2f \n", i, contourArea(contours[i]), arcLength(contours[i], true));
		//contourArea(InputArray  contour,//输入轮廓数据
		//bool   oriented// 默认false、返回绝对值)
		//arcLength(InputArray  curve,//输入曲线数据
		//bool   closed// 是否是封闭曲线)
 
		//考虑如何把数据显示在原图像上
		//double A;
		//A=contourArea(contours[i]);
		//ostringstream os;
		//os << A;
		//putText(drawImage,os.str,centers[i], CV_FONT_BLACK, 2.0, Scalar(0,0,255), 2, 8);
		//依次含义:原图,输入字的内容,起始位置,字体,字的大小,颜色,线条大小粗 细,连接域
 
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		drawContours(drawImage, contours, i, color, 2, LINE_AA, hierachy, 0, Point(0, 0));//绘制轮廓
		circle(drawImage, centers[i], 2, color, 2, LINE_AA);//绘制图形中心
	}
	imshow(result, drawImage);
	return;
}

程序执行后效果图:

  

from:https://blog.csdn.net/zhu_hongji/article/details/81699736

matchShape函数

   最后我们利用matchShape函数比较两个轮廓,如果结果为0,表示两个轮廓完全相似,结果值越大,越不相似,但这个最大值好像并没有归一化。函数原型:

 double matchShapes( InputArray contour1, InputArray contour2,
                                 int method, double parameter );

//调用方法
double comres = matchShapes(contours[0], contours[1],CV_CONTOURS_MATCH_I1, 0.0); 

前两个参数输入“灰度图像”时,并不是想当然的那样,其内容包含待匹配轮廓图案的灰度图;而是使用一行或一列双通道灰度图或者两列灰度图,该图中的每个像素不是什么图片,而是代表多边形轮廓上各节点的X,Y坐标。????
输入轮廓时每个参数只能是一个轮廓。

官方文档:https://docs.opencv.org/2.4/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=matchshapes#cv2.matchShapes

matchShapes函数其实比较的是两个轮廓的Hu不变矩,第三个参数决定比较的方式,即三种不同的判定物体相似的方法

                 CV_CONTOURS_MATCH_I1
                 CV_CONTOURS_MATCH_I2
                 CV_CONTOURS_MATCH_I3

            

double comres;
	comres = matchShapes(contours[0], contours[1], CV_CONTOURS_MATCH_I1, 0.0);
	cout<<contours.size()<<"CV_CONTOURS_MATCH_I1 比较结果是"<< comres<<endl;

结果:

                          

Hu矩特性:具有旋转,缩放和平移不变性。

由Hu矩组成的特征量对图片进行识别,优点就是速度很快,缺点是识别率比较低。 因此Hu不变矩一般用来识别图像中大的物体,对于物体的形状描述得比较好,图像的纹理特征不能太复杂。

from:https://www.cnblogs.com/mikewolf2002/p/3427564.html

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐