在连续情况下,图像函数为 ,那么图像的p+q阶几何矩(标准矩)定义为:
p+q阶中心距定义为:
其中 和
代表图像的重心,
对于离散的数字图像,采用求和号代替积分:
和
分别是图像的高度和宽度;
归一化的中心距定义为:
;其中
利用二阶和三阶归一化中心矩构造了7个不变矩 :
这7个不变矩构成一组特征量,Hu.M.K在1962年证明了他们具有旋转,缩放和平移不变性。
实际上,在对图片中物体的识别过程中,只有 和
不变性保持的比较好,其他的几个不变矩带来的误差比较大,有学者认为只有基于二阶矩的不变矩对二维物体的描述才是真正的具有旋转、缩放和平移不变性(
和
刚好都是由二阶矩组成的)。不过我没有证明是否是真的事这样的。
由Hu矩组成的特征量对图片进行识别,优点就是速度很快,缺点是识别率比较低,我做过手势识别,对于已经分割好的手势轮廓图,识别率也就30%左右,对于纹理比较丰富的图片,识别率更是不堪入眼,只有10%左右。这一部分原因是由于Hu不变矩只用到低阶矩(最多也就用到三阶矩),对于图像的细节未能很好的描述出来,导致对图像的描述不够完整。
Hu不变矩一般用来识别图像中大的物体,对于物体的形状描述得比较好,图像的纹理特征不能太复杂,像识别水果的形状,或者对于车牌中的简单字符的识别效果会相对好一些。
// Hu不变矩.cpp : 定义控制台应用程序的入口点。
#include "stdafx.h"
#include "cv.h"
#include "highgui.h"
#include <iostream>
using namespace std;
IplImage* oriImg;
IplImage* grayImg;
int Img2Gray(void)
{
if((oriImg = cvLoadImage("lena.jpg", 1)) != 0 )
{ grayImg = cvCreateImage(cvSize(oriImg->width,oriImg->height),IPL_DEPTH_8U,1);
cvCvtColor(oriImg,grayImg,CV_BGR2GRAY);
return 1;}
return 0;
}
int main( int argc, char** argv )
{
int succees = 0;
succees = Img2Gray();
if(succees)
{
CvMoments moments;
CvHuMoments hu;
cvMoments(grayImg,&moments,0);
cvGetHuMoments(&moments, &hu);
cvNamedWindow( "Image", 1 );
cvShowImage( "Image", grayImg );
printf("hu1=%e\nhu2=%e\nhu3=%e\nhu4=%e\nhu5=%e\nhu6=%e\nhu7=%e\n",hu.hu1,hu.hu2,hu.hu3,hu.hu4,hu.hu5,hu.hu6,hu.hu7);
cvWaitKey(0);
cvReleaseImage( &oriImg );
cvReleaseImage( &grayImg );
cvDestroyWindow( "Image" );
}
return 0;
}
由OPENCV提供计算中心距、归一化中心距和hu矩的函数为:
其中cvMoments和上面的cvContourMoments是同一个函数。
同时OPENCV还提供了输入图像直接进行hu矩匹配的函数是
double cvMatchShapes(const void*object1,const void*object2,int method,double parameter=0); 因此可以帮助省掉中间的步骤。
HU矩的效果并不是很好,字母旋转后的hu矩变化还是很大的