1. 程式人生 > >影象的七個不變矩 可用於影象的匹配

影象的七個不變矩 可用於影象的匹配

影象的幾何不變矩 

矩特徵主要表徵了影象區域的幾何特徵,又稱為幾何矩, 由於其具有旋轉、平移、尺度等特性的不變特徵,所以又稱其為不變矩。在影象處理中,幾何不變矩可以作為一個重要的特徵來表示物體,可以據此特徵來對影象進行分類等操作。

1.     HU矩

幾何矩是由Hu(Visual pattern recognition by moment invariants)在1962年提出的,影象f(x,y)的(p+q)階幾何矩定義為

        Mpq =∫∫(x^p)*(y^q)f(x,y)dxdy(p,q = 0,1,……∞)

        矩在統計學中被用來反映隨機變數的分佈情況,推廣到力學中,它被用作刻畫空間物體的質量分佈。同樣的道理,如果我們將影象的灰度值看作是一個二維或三維的密度分佈函式,那麼矩方法即可用於影象分析領域並用作影象特徵的提取。最常用的,物體的零階矩表示了影象的“質量”:

                  Moo= ∫∫f(x,y )dxdy

        一階矩(M01,M10)用於確定影象質心( Xc,Yc):

              Xc = M10/M00;Yc = M01/M00;

         若將座標原點移至 Xc和 Yc處,就得到了對於影象位移不變的中心矩。如

            Upq =∫∫[(x-Xc)^p]*[(y-Yc)^q]f(x,y)dxdy。

Hu在文中提出了7個幾何矩的不變數,這些不變數滿足於影象平移、伸縮和旋轉不變。如果定義

Zpq=Upq/(U20 + U02)^(p+q+2),

Hu 的7種矩為:

                   H1=Z20+Z02;H1=(Z20+Z02)^2+4Z11^2;......

矩是描述影象特徵的運算元,它在模式識別與影象分析領域中有重要的應用.迄今為止,常見的矩描述子可以分為以下幾種:幾何矩、正交矩、複數矩和旋轉矩.其中幾何矩提出的時間最早且形式簡單,對它的研究最為充分。幾何矩對簡單影象有一定的描述能力,他雖然在區分度上不如其他三種矩,但與其他幾種運算元比較起來,他極其的簡單,一般只需用一個數字就可表達。所以,一般我們是用來做大粒度的區分,用來過濾顯然不相關的文件。

比如在圖形庫中,可能有100萬幅圖,也許只有200幅圖是我們想要的。使用一維的幾何矩的話,就可以對幾何矩進行排序,建立索引,然後選出與目標圖的幾何矩最近的2000幅圖作比較就好了。而對於其他的矩來說,由於一般是多維的關係,一般不好排序,只能順序查詢,自然速度有巨大的差別.所以。雖然幾何矩不太能選出最像的,但可以快速排除不像的,提高搜尋效率。

MATLAB程式碼:

img=

invariable_moment(imread('lena.jpg'));
function inv_m7 = invariable_moment(in_image)
% 功能:計算影象的Hu的七個不變矩
% 輸入:in_image-RGB影象
% 輸出:inv_m7-七個不變矩

% 將輸入的RGB影象轉換為灰度影象   
image=rgb2gray(in_image);     
%將影象矩陣的資料型別轉換成雙精度型
image=double(image);      
%%%=================計算 、 、 =========================
%計算灰度影象的零階幾何矩 
m00=sum(sum(image));     
m10=0;
m01=0;
[row,col]=size(image);
for i=1:row
    for j=1:col
        m10=m10+i*image(i,j);
        m01=m01+j*image(i,j);
    end
end
%%%=================計算 、 ================================
u10=m10/m00;
u01=m01/m00;
%%%=================計算影象的二階幾何矩、三階幾何矩============
m20 = 0;m02 = 0;m11 = 0;m30 = 0;m12 = 0;m21 = 0;m03 = 0;
for i=1:row
    for j=1:col
        m20=m20+i^2*image(i,j);
        m02=m02+j^2*image(i,j);
        m11=m11+i*j*image(i,j);
        m30=m30+i^3*image(i,j);
        m03=m03+j^3*image(i,j);
        m12=m12+i*j^2*image(i,j);
        m21=m21+i^2*j*image(i,j);
    end
end
%%%=================計算影象的二階中心矩、三階中心矩============
y00=m00;
y10=0;
y01=0;
y11=m11-u01*m10;
y20=m20-u10*m10;
y02=m02-u01*m01;
y30=m30-3*u10*m20+2*u10^2*m10;
y12=m12-2*u01*m11-u10*m02+2*u01^2*m10;
y21=m21-2*u10*m11-u01*m20+2*u10^2*m01;
y03=m03-3*u01*m02+2*u01^2*m01;
%%%=================計算影象的歸格化中心矩====================
        n20=y20/m00^2;
        n02=y02/m00^2;
        n11=y11/m00^2;
        n30=y30/m00^2.5;
        n03=y03/m00^2.5;
        n12=y12/m00^2.5;
        n21=y21/m00^2.5;
%%%=================計算影象的七個不變矩======================
h1 = n20 + n02;                      
h2 = (n20-n02)^2 + 4*(n11)^2;
h3 = (n30-3*n12)^2 + (3*n21-n03)^2;  
h4 = (n30+n12)^2 + (n21+n03)^2;
h5 = (n30-3*n12)*(n30+n12)*((n30+n12)^2-3*(n21+n03)^2)+(3*n21-n03)*(n21+n03)*(3*(n30+n12)^2-(n21+n03)^2);
h6 = (n20-n02)*((n30+n12)^2-(n21+n03)^2)+4*n11*(n30+n12)*(n21+n03);
  h7 = (3*n21-n03)*(n30+n12)*((n30+n12)^2-3*(n21+n03)^2)+(3*n12-n30)*(n21+n03)*(3*(n30+n12)^2-(n21+n03)^2);
 
inv_m7= [h1 h2 h3 h4 h5 h6 h7];   
c++程式碼:
/*===============================================//
功能:不變矩匹配
時間:3/28/2011 SkySeraph HQU
參考:
//===============================================*/
#include "iostream"
 usingnamespace std;

#include "cv.h"
#include "highgui.h"

#include "math.h"

#pragma comment(lib,"highgui.lib")
#pragma comment(lib,"cv.lib")
#pragma comment(lib,"cvaux.lib")
#pragma comment(lib,"cxcore.lib")

constchar* filename ="D:\\My Documents\\My Pictures\\Images\\1.bmp";
constchar* filename2 ="D:\\My Documents\\My Pictures\\Images\\2.bmp";

/*=============================================*/
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;

double m00=0,m11=0,m20=0,m02=0,m30=0,m03=0,m12=0,m21=0; //中心矩
double x0=0,y0=0; //計算中心距時所使用的臨時變數(x-x')
double u20=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階矩 //注:二值影象的0階矩表示面積
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];
}
} 

// 計算規範化後的中心矩
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);


/*cout<<M[0]<<endl;//<<二"<<M[0]<<"三"<<M[0]<<"四"<<M[0]<<"五"<<M[0]<<"六"<<M[0]<<"七"<<M[0]<<endl;
cout<<M[1]<<endl;
cout<<M[2]<<endl;
cout<<M[3]<<endl;
cout<<M[4]<<endl;
cout<<M[5]<<endl;
cout<<M[6]<<endl;
cout<<endl;*/
returntrue;
}


int main(char argc,char** argv)
{
int i;
double Sa[7] = {0},Ta[7] ={0};

///*源影象
IplImage*img = cvLoadImage(filename,0);//灰度
HuMoment(img);
for(i=0;i<7;i++)
{
Sa[i] = M[i];
M[i] =0;
}
cout<<Sa[0]<<endl;
cout<<Sa[1]<<endl;
cout<<Sa[2]<<endl;
cout<<Sa[3]<<endl;
cout<<Sa[4]<<endl;
cout<<Sa[5]<<endl;
cout<<Sa[6]<<endl;
cout<<endl;
//*/


///*模板圖
IplImage*tpl = cvLoadImage(filename2,0);//灰度
HuMoment(tpl);
for(i=0;i<7;i++)
{
Ta[i] = M[i];
M[i] =0;
}
cout<<Ta[0]<<endl;
cout<<Ta[1]<<endl;
cout<<Ta[2]<<endl;
cout<<Ta[3]<<endl;
cout<<Ta[4]<<endl;
cout<<Ta[5]<<endl;
cout<<Ta[6]<<endl;
cout<<endl;


// 計算相似度
double dbR =0; //相似度
double dSigmaST =0;
double dSigmaS =0;
double dSigmaT =0;
double temp =0; 

for(i=0;i<7;i++)
{
temp = Sa[i]*Ta[i];
dSigmaST+=temp;
dSigmaS+=pow(Sa[i],2);
dSigmaT+=pow(Ta[i],2);
}
dbR = dSigmaST/(sqrt(dSigmaS)*sqrt(dSigmaT));
printf("%lf\n",dbR);
//cout<<dbR<<endl;

cvReleaseImage(&img);
cvReleaseImage(&tpl);

return0;
}

其他幾種矩的比較可以參考這篇文章: