日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Zernike矩

發布時間:2025/3/21 编程问答 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Zernike矩 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Zernike在1934年引入了一組定義在單位圓?上的復值函數集{?},{?}具有完備性和正交性,使得它可以表示定義在單位圓盤內的任何平方可積函數。其定義為:

?表示原點到點?的矢量長度;?表示矢量?與?軸逆時針方向的夾角。

?是實值徑向多項式:

稱為Zernike多項式。

Zernike多項式滿足正交性:

其中

?為克羅內克符號,?

?是?的共軛多項式。

由于Zernike多項式的正交完備性,所以在單位圓內的任何圖像?都可以唯一的用下面式子來展開:

式子中?就是Zernike矩,其定義為:

注意式子中?和?采用的是不同的坐標系(?采用直角坐標,而?采用的極坐標系,在計算的時候要進行坐標轉換)

對于離散的數字圖像,可將積分形式改為累加形式:

?

我們在計算一副圖像的Zernike矩時,必須將圖像的中心移到坐標的原點,將圖像的像素點映射到單位圓內,由于Zernike矩具有旋轉不變性,我們可以將?作為圖像的不變特征,其中圖像的低頻特征有p值小的提取,高頻特征由p值高的?提取。從上面可以看出,Zernike矩可以構造任意高階矩。

由于Zernike矩只具有旋轉不變性,不具有平移和尺度不變性,所以要提前對圖像進行歸一化,我們采用標準矩的方法來歸一化一副圖像,標準矩定義為:

?,

由標準矩我們可以得到圖像的"重心",

我們將圖像的"重心"移動到單位圓的圓心(即坐標的原點),便解決了平移問題。

我們知道?表征了圖像的"面積",歸一圖像的尺度無非就是把他們的大小變為一致的,(這里的大小指的是圖像目標物的大小,不是整幅圖像的大小,"面積"也是目標物的"面積")。

所以,對圖像進行變換?就可以達到圖像尺寸一致的目的。

綜合上面結果,對圖像進行?變換,最終圖像?的Zernike矩就是平移,尺寸和旋轉不變的。


? ? ?Zernike?不變矩相比?Hu?不變矩識別效果會好一些,因為他描述了圖像更多的細節內容,特別是高階矩,但是由于Zernike?不變矩計算時間比較長,所以出現了很多快速的算法,大家可以?google?一下。

? ? 用?Zernike?不變矩來識別手勢輪廓,識別率大約在?40%~50%?之間,跟?Hu?不變矩一樣,?Zernike?不變矩一般用來描述目標物形狀占優勢的圖像,不適合用來描述紋理豐富的圖像,對于紋理圖像,識別率一般在?20%~30%?左右,很不占優勢。


ZernikeMoment.h文件代碼:

#pragma once
#include <iostream> ?
#include "opencv2/opencv.hpp" ?
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"




using namespace cv;
using namespace std;


#define MaxP(x,y) (float)(x>y?x:y)
#define MinP(x,y) (float)(x<y?x:y)
#define PI ?3.14






typedef struct?
{
float ? ?rou;
float ? ?sigma;
}
RS_POINT;


typedef struct?
{
float ? ?x;
float ? ?y;
}CARTESIAN_POINT;




typedef struct?
{
float ? ?r;
float ? ?t;
}POLAR_POINT;




typedef struct?
{
float ? ?Cnm;
float ? ?Snm;
}ZERNIKE;




class ZernikeMoment{


? ? private:
? IplImage* ? ?oriImg;?
? ? ? ?IplImage* ? ?grayImg;
? float ? ? ? ?Cnm,Snm;
? ? ? ?float ? ? ? ?Z_mode;




public:

ZernikeMoment();
~ZernikeMoment();


? ? ? ? float ? ? ? ? ? ? ? getRpqr(float p,float q,float r);
? ?RS_POINT* ? ? ? ? ? get_rou_sigma(float x,float y);
CARTESIAN_POINT* ? ?get_x_y(float r,float s,int N);
? ? ? ??
int ? ? ? ? ? ? ? ? Img2Gray(void);
void ? ? ? ? ? ? ? ? ClearOpenCV(void);


float ? ? ? ? ? ? ? get_8_XYValue(int x,int y);
float ? ? ? ? ? ? ? get_32_XYValue(int x,int y);


? ? ? ? float ? ? ? ? ? ? ? getZernike(int n,int m);
? ? ? ??

void Caculate_8_Zernike(int n,int m);
void Caculate_32_Zernike(int n,int m);


};


Zernike矩.cpp文件中的代碼:

// ZernikeTest.cpp : 定義控制臺應用程序的入口點。
/************************************************************
讀入圖像是在RGB2GRAY函數中,自己修改對應圖像的路徑
*************************************************************/
#include "stdafx.h"
#include <math.h>
#include "ZernikeMoment.h"
//#include "cv.h"
//#include "highgui.h"?
//#include <opencv2/opencv.hpp>
#include <iostream> ?
using namespace std;
//using namespace cv;


double factorial(long n)//
{
if(n < 0)
return(0.0) ;
if(n == 0)
return(1.0) ;
else
return(n * factorial(n-1)) ;
}


float zernikeR(int n, int l, float r)/
{
? int m ;
? float sum = 0.0 ;
??
? if( ((n-l) % 2) != 0 )
? ? {
? ? ? cout <<"zernikeR(): improper values of n,l\n" ;
? ? ? return(0) ;
? ? }
??
? for(m = 0; m <= (n-l)/2; m++)
? ? {
? ? ? sum += (pow((float)-1.0,(float)m)) * ( factorial(n-m) ) /?
( factorial(m) * (factorial((n - 2*m + l) / 2)) *
?(factorial((n - 2*m - l) / 2)) ) *
( pow((float)r, (float)(n - 2*m)) );
? ? }
??
? return(sum) ;
}




ZernikeMoment::ZernikeMoment()
{


oriImg ? ?= NULL;


grayImg ? = NULL;


Z_mode ? ?= 0;


}






ZernikeMoment::~ZernikeMoment()
{


}






//Fast Compute ?Zernike Polynomials Rpq(r)
float ZernikeMoment::getRpqr(float p,float q,float r)//
{
? ?/**** ?verify that p-q is even ?***




**********************************/
? ? ?float Rpqr = 0;




float Bppp=1;




int times ? = (p-q)/2;
? ? ?int numbers = times+1;




? ? ?float ?Bpqp ?= ? pow((p+q)/(p-q+2),times); ??
? ? ?float* Bpqk = new float[numbers];
? ? ?
? ? ?Bpqk[0] = Bpqp;


? ? ? int k=(int)p;
?int t=(int)p;
? ? ??


//Bpqk[0] is Bpqp , Bpqk[1] is Bpq(p-2) ... Bpqk[numbers-1] is Bpqq respectively


?for(int i=0;i<(numbers-1);i++)
?{
? ? ? ? ? float ?coeff = ((k+q)*(k-q)) ?/ ?((k+p)*(p-k+2));
?Bpqk[i+1] ? = ?(-1)*(Bpqk[i])*coeff;
?k=k-2;
?}
? ? ??




?int temp = numbers-1;
? ? ?
?
?//Compute Rpqr
?for(k=(int)q;k<=t;k=k+2)
?{
? ? ? ? ??
?Rpqr = Rpqr + (Bpqk[temp])*(pow(r,k));


? ? ? ? ? temp--;
?}




?delete[] ?Bpqk;
? ??
? ? ? float ?a = Rpqr;
? ? ? float ?b = Rpqr;


?return Rpqr;


}




//Ordinary Compute Rpqr






//convert to ?rou, sigma coordinate,this function was never used.
RS_POINT* ZernikeMoment::get_rou_sigma(float x,float y)
{
? ??
? ? RS_POINT ? *rs_p = new RS_POINT();


? ? float ?rou ? = MaxP(abs(x),abs(y));

float ?sigma;




? ? if(abs(x)==rou)
? ? ?
sigma = (2*(rou-x)*y)/abs(y)+x*y/rou;


? ? if(abs(y)==rou)
? ? ? ? ?
sigma = 2*y -x*y/rou;
??
? ? rs_p->rou ? = rou;
? ? rs_p->sigma = sigma;
??


return ?rs_p;


}




//Convert rou-sigma to x-y coordinate,also never used.
CARTESIAN_POINT* ZernikeMoment::get_x_y(float rou,float sigma,int N)
{
? ? ?



float r ?= ?2*rou/N;
? ? float t ?= ?(PI*sigma)/4*rou;
? ? ?
CARTESIAN_POINT *xy_point = new CARTESIAN_POINT();


xy_point->x = r*cos(t);
xy_point->y = r*sin(t);


? ? ? return ?xy_point;
}










//Get the x,y pixel value of Image ,8 depths
float ZernikeMoment::get_8_XYValue(int x,int y)//
{
int height ? ? ?= grayImg->height;
? ? int widthStep ? = grayImg->widthStep;
char* ?Data ? ? = grayImg->imageData;


? ? uchar ?c_value = ?((uchar *)(Data+x*widthStep))[y];

float ?value = (float)c_value;


? ? return value;




}
//Get the x,y pixel value of Image ,32 depths
float ZernikeMoment::get_32_XYValue(int x,int y)/
{
int height ? ? ?= grayImg->height;
? ? int widthStep ? = grayImg->widthStep;
char* ?Data ? ? = grayImg->imageData;


? ? float ?value = ?((float *)(Data+x*widthStep))[y];


? ? return value;




}










//RGB to Gray
//本函數部分代碼被注釋了,因為改為直接讀入灰度圖了
int ?ZernikeMoment::Img2Gray(void)/
{
? ??




int a =1;
?//if((oriImg = cvLoadImage("E:\\XH.jpg", 1)) != 0 ? )
? ? if((grayImg = cvLoadImage("lena.jpg", 0)) != 0 ? )//讀入一張灰度圖
//if((grayImg = cvLoadImage("C:\\Users\\dell\\Desktop\\測試用圖\\T5.bmp", 1)) != 0 ? )
? ? ??
{ //grayImg ?= cvCreateImage(cvSize(oriImg->width,oriImg->height),IPL_DEPTH_8U,1);




? ? ? ? ?//cvCvtColor(oriImg,grayImg,CV_BGR2GRAY);


? ? ? ? ?return 1;}

return 0;


}




//Cleanning Work,release memory,etc
void ZernikeMoment::ClearOpenCV(void)///
{


if(oriImg!=NULL){


? ? ? ? cvReleaseImage( &oriImg ?);
oriImg = NULL;


}



if(grayImg!=NULL){


? ? ? ? cvReleaseImage( &grayImg );


grayImg = NULL;


}
? ? ? ? ? ? ? ?





}




//Function to caculate Zernike_8_(n,m), a very important function.
void ZernikeMoment::Caculate_8_Zernike(int n,int m)
{
??


? ? int height ? ? ?= ?grayImg->height;
? ? int widthStep ? = ?grayImg->widthStep;


float N ? ? ? ? = ?MinP(height,widthStep);
? ??
float N2 ? ? ? ?= ?N/2;






float Rpqr_C =0;
float Rpqr_S =0;
? ??







for(float r=1;r<N2;r++)
{


? ? ? ? float temp_C = 0;
float temp_S = 0;
? ? ??


for(float s=1;s<=8*r;s++)
{
? ??
float xy_v = get_8_XYValue(r,s);
?
? ? ? ? ? ? ?temp_C = temp_C + cos((PI*m*s)/(4*r))*xy_v;
? ? ? ? ? ? ?temp_S = temp_S + sin((PI*m*s)/(4*r))*xy_v;


}
? ??
? ? //float Rpqr ? = ? ?getRpqr(n,m,(2*r)/N);
float Rpqr = ? ? zernikeR(n,m,(2*r)/N);
Rpqr_C = Rpqr_C ?+ ? ?temp_C* Rpqr;
? ? Rpqr_S = Rpqr_S ?+ ? ?temp_S* Rpqr;
?
}


? ??


Cnm = Rpqr_C*(2*n+2)/pow(N,2);
? ? Snm = Rpqr_S*(2*n+2)/pow(N,2);

float l_c = pow(Cnm,2);
float l_s = pow(Cnm,2);
float l_p = l_c + l_s;


? ? Z_mode = pow((float)l_p,(float)0.5);



}






//Function to caculate Zernike_32_(n,m), a very important function.


void ZernikeMoment::Caculate_32_Zernike(int n,int m)
{
? ? int height ? ? ?= ?grayImg->height;
? ? int widthStep ? = ?grayImg->widthStep;


float N ? ? ? ? = ?MinP(height,widthStep);
? ??
float N2 ? ? ? ?= ?N/2;






float Rpqr_C =0;
float Rpqr_S =0;
? ??







for(float r=1;r<N2;r++)
{


? ? ? ? float temp_C = 0;
float temp_S = 0;
? ? ??


for(float s=1;s<=8*r;s++)
{
? ?
float xy_v = get_32_XYValue(r,s);
?
? ? ? ? ? ? ?temp_C+= cos((PI*m*s)/(4*r))*xy_v;
? ? ? ? ? ? ?temp_S+= sin((PI*m*s)/(4*r))*xy_v;




}
? ? ??
? ? float ? ? Rpqr ? = ? ?getRpqr(n,m,(2*r)/N);
Rpqr_C = Rpqr_C ?+ ? ?temp_C* Rpqr;
? ? Rpqr_S = Rpqr_S ?+ ? ?temp_S* Rpqr;
?
}


? ??


Cnm = Rpqr_C*(2*n+2)/pow(N,2);
? ? Snm = Rpqr_S*(2*n+2)/pow(N,2);


? ? Z_mode = pow((float)pow(Cnm,2)+pow(Cnm,2),(float)0.5);
}






float ZernikeMoment::getZernike(int n,int m)//
{


? int pass = Img2Gray();


? if(!pass)
?
return -1;
? ??


? ?
? ?int depth ? ? ?= 0;
? ?int nChannels ?= 0;
? ?nChannels ? ? ?= grayImg->nChannels;


// ? ?if(nChannels!=1)
// ? return -1;




? ?depth = grayImg->depth;


??
? switch(depth)
? {
? ? ?
? ? ? ? ? case ? IPL_DEPTH_8U: ? Caculate_8_Zernike(n,m); ? ?break; ??
? ? ? ? ? case ? IPL_DEPTH_32F: ?Caculate_32_Zernike(n,m); ? break; ??
? ? ? ? ? default: ? ? break; ??
? }




? ClearOpenCV();


??
? return ?Z_mode;




}








int main( int argc, char** argv )
{ ??

? ?int succees = 0;
? ? ??
? ? ? ? ?//Compute zernike modes ,for n = 4;


? ? ? ? ?float *z_modes = new float[9];


ZernikeMoment *z_m = new ZernikeMoment();
? ? ? ? ??
int index = 0;

?
z_modes[index++] = z_m->getZernike(0,0);


z_modes[index++] = z_m->getZernike(1,1);


? ? ? ? ? ? ?z_modes[index++] = z_m->getZernike(2,0);


z_modes[index++] = z_m->getZernike(2,2);


z_modes[index++] = z_m->getZernike(3,1);


? ? ? ? ? ? ?z_modes[index++] = z_m->getZernike(3,3);


? ? ? ? ? ? ?z_modes[index++] = z_m->getZernike(4,0);


? ? ? ? ? ? ?z_modes[index++] = z_m->getZernike(4,2);


z_modes[index++] = z_m->getZernike(4,4);


if(z_m!=NULL)
delete z_m;


? ? ? ? ? ? cout<<"zernike modes sequence: "<<endl;






? ? ? ? ?for(int i=0;i<9;i++)
cout<<z_modes[i]<<",\n";//
? ? ? ? ?cout<<endl;


return 0;
? ? ??
}

總結

以上是生活随笔為你收集整理的Zernike矩的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。