opencv中的矩

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Jacky_Ponder/article/details/66969416

在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; }空间矩的公式为:

可以知道,对于01二值化的图像,m00即为轮廓的面积。中心矩的公式为:

其中:

归一化的中心矩公式为:

在OpenCV中,还可以很方便的得到Hu不变距,Hu不变矩在图像旋转、缩放、平移等操作后,仍能保持矩的不变性,所以有时候用Hu不变距更能识别图像的特征。Hu不变矩的基本概念请参考paper:Hu. Visual Pattern Recognitionby Moment Invariants, IRE Transactions on Information Theory, 8:2, pp. 179-187,1962, 或者参考中文介绍:http://www.cnblogs.com/skyseraph/archive/2011/07/19/2110183.html

OpenCV中计算矩的函数为:Moments moments(InputArray array, bool binaryImage=false )

1.1几何矩

几何矩是由Hu(Visual pattern recognition by moment invariants)在1962年提出的,具有平移、旋转和尺度不变性。定义如下:

① (p+q)阶不变矩定义:

② 对于数字图像,离散化,定义为:

 

③ 归一化中心矩定义:

 ④Hu矩定义



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

OpenCV中计算Hu矩的公式为:

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


1.1.1 实现(源码)

①自编函数模块

//#################################################################################//
double M[7] = {0};        //HU不变矩
bool HuMoment(IplImage* img)
{
int bmpWidth = img->width;
int bmpHeight = img->height;
int bmpStep = img->widthStep;
int bmpChannels = img->nChannels;
   uchar*pBmpBuf = (uchar*)img->imageData;
 
doublem00=0,m11=0,m20=0,m02=0,m30=0,m03=0,m12=0,m21=0;  //中心矩
double x0=0,y0=0;    //计算中心距时所使用的临时变量(x-x')
doubleu20=0,u02=0,u11=0,u30=0,u03=0,u12=0,u21=0;//规范化后的中心矩
//double M[7];    //HU不变矩
double t1=0,t2=0,t3=0,t4=0,t5=0;//临时变量,
//double Center_x=0,Center_y=0;//重心
int Center_x=0,Center_y=0;//重心
int i,j;            //循环变量
 
//  获得图像的区域重心(普通矩)
double s10=0,s01=0,s00=0;  //0阶矩和1阶矩 
for(j=0;j<bmpHeight;j++)//y
    {
for(i=0;i<bmpWidth;i++)//x
       {
           s10+=i*pBmpBuf[j*bmpStep+i];
           s01+=j*pBmpBuf[j*bmpStep+i];
           s00+=pBmpBuf[j*bmpStep+i];
       }
    }
   Center_x=(int)(s10/s00+0.5);
   Center_y=(int)(s01/s00+0.5);
 
//  计算二阶、三阶矩(中心矩)
   m00=s00;
for(j=0;j<bmpHeight;j++)
    {
for(i=0;i<bmpWidth;i++)//x
       {
           x0=(i-Center_x);
           y0=(j-Center_y);
           m11+=x0*y0*pBmpBuf[j*bmpStep+i];
           m20+=x0*x0*pBmpBuf[j*bmpStep+i];
           m02+=y0*y0*pBmpBuf[j*bmpStep+i];
           m03+=y0*y0*y0*pBmpBuf[j*bmpStep+i];
           m30+=x0*x0*x0*pBmpBuf[j*bmpStep+i];
           m12+=x0*y0*y0*pBmpBuf[j*bmpStep+i];
           m21+=x0*x0*y0*pBmpBuf[j*bmpStep+i];
       }
    }
 
//  计算规范化后的中心矩: mij/pow(m00,((i+j+2)/2)
   u20=m20/pow(m00,2);
   u02=m02/pow(m00,2);
   u11=m11/pow(m00,2);
   u30=m30/pow(m00,2.5);
   u03=m03/pow(m00,2.5);
   u12=m12/pow(m00,2.5);
   u21=m21/pow(m00,2.5);
 
//  计算中间变量
   t1=(u20-u02);
   t2=(u30-3*u12);
   t3=(3*u21-u03);
   t4=(u30+u12);
   t5=(u21+u03);
 
//  计算不变矩
   M[0]=u20+u02;
   M[1]=t1*t1+4*u11*u11;
   M[2]=t2*t2+t3*t3;
   M[3]=t4*t4+t5*t5;
   M[4]=t2*t4*(t4*t4-3*t5*t5)+t3*t5*(3*t4*t4-t5*t5);
   M[5]=t1*(t4*t4-t5*t5)+4*u11*t4*t5;
   M[6]=t3*t4*(t4*t4-3*t5*t5)-t2*t5*(3*t4*t4-t5*t5);
 
returntrue;
}

1.1.2调用OpenCV方法

//  利用OpenCV函数求7个Hu矩
   CvMoments moments;
   CvHuMoments hu;
   cvMoments(bkImgEdge,&moments,0);
   cvGetHuMoments(&moments, &hu);
   cout<<hu.hu1<<"/"<<hu.hu2<<"/"<<hu.hu3<<"/"<<hu.hu4<<"/"<<hu.hu5<<"/"<<hu.hu6<<"/"<<hu.hu7<<"/"<<"/"<<endl;
   cvMoments(testImgEdge,&moments,0);
   cvGetHuMoments(&moments, &hu);
   cout<<hu.hu1<<"/"<<hu.hu2<<"/"<<hu.hu3<<"/"<<hu.hu4<<"/"<<hu.hu5<<"/"<<hu.hu6<<"/"<<hu.hu7<<"/"<<"/"<<endl;

1.1.3三相似性准则

 ①法一

//  计算相似度1

double dbR =0; //相似度
double dSigmaST =0;
   double dSigmaS =0;
   double dSigmaT =0;
   double temp =0; 
   {for(int i=0;i<7;i++)
    {
       temp = fabs(Sa[i]*Ta[i]);
       dSigmaST+=temp;
       dSigmaS+=pow(Sa[i],2);
       dSigmaT+=pow(Ta[i],2);
   }}
dbR =dSigmaST/(sqrt(dSigmaS)*sqrt(dSigmaT));

②法二

//  计算相似度2

double dbR2 =0; //相似度
double temp2 =0;
double temp3 =0; 
   {for(int i=0;i<7;i++)
    {
       temp2 += fabs(Sa[i]-Ta[i]);
       temp3 += fabs(Sa[i]+Ta[i]);
   }}
dbR2 =1-(temp2*1.0)/(temp3);

1.2范例1

下面的代码计算轮廓的矩,并根据1阶中心矩得到轮廓的质心,代码如下:

src = imread( "../star1.jpg" ,1 );

/// Convert image to gray and blur it
cvtColor( src, src_gray, CV_BGR2GRAY );
blur( src_gray, src_gray, Size(3,3) );

namedWindow( "image", CV_WINDOW_AUTOSIZE );
imshow( "image", src );

Mat canny_output;
vector<vector<Point> > contours;
vector<Vec4i> hierarchy;

//利用canny算法检测边缘
Canny( src_gray, canny_output, thresh, thresh*2, 3 );
namedWindow( "canny", CV_WINDOW_AUTOSIZE );
imshow( "canny", canny_output );
//查找轮廓
findContours( canny_output, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );

//计算轮廓矩
vector<Moments> mu(contours.size() );
for( int i = 0; i < contours.size(); i++ )
    { mu[i] = moments( contours[i], false ); }

//计算轮廓的质心
vector<Point2f> mc( contours.size() );
for( int i = 0; i < contours.size(); i++ )
    { mc[i] = Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 ); }

//画轮廓及其质心
Mat drawing = Mat::zeros( canny_output.size(), CV_8UC3 );
for( int i = 0; i< contours.size(); i++ )
    {
    Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
    drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() );
    circle( drawing, mc[i], 4, color, -1, 8, 0 );
    }

namedWindow( "Contours", CV_WINDOW_AUTOSIZE );
imshow( "Contours", drawing );

//打印轮廓面积和轮廓长度
printf("\t Info: Area and Contour Length \n");
for( int i = 0; i< contours.size(); i++ )
    {
    printf(" * Contour[%d] - Area (M_00) = %.2f - Area OpenCV: %.2f - Length: %.2f \n", i, mu[i].m00, contourArea(contours[i]), arcLength( contours[i], true ) );
    Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
    drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point() );
    circle( drawing, mc[i], 4, color, -1, 8, 0 );
    }


猜你喜欢

转载自blog.csdn.net/Jacky_Ponder/article/details/66969416
今日推荐