現在地 >> メニュー >> サンプルコード::OpenCV >> OpenCV::離散フーリエ変換(改)

関連OpenCV::離散フーリエ変換の仕方OpenCV::離散フーリエ変換の仕方::詳細

問題


以下の画像を読み込んで、離散フーリエ変換を行い、スペクトルを表示せよ。

画像

その他条件:
  • ウィンドウ中心部ほど高周波のままでよい(cvShiftDFTは不要)
  • OpenCV::離散フーリエ変換3のプログラムを整理して処理を関数化する


OpenCV::離散フーリエ変換::フィルタ?

答え


#include <iostream>
#include <cv.h>
#include <highgui.h>


/********** 各種プロトタイプ宣言 **************/
CvMat* GET_MAT_FOR_DFT(IplImage *imgA);
void CONVERT_AND_COPY_TO_MAT(IplImage *imgA,CvMat *dft_A);
IplImage* CALC_SPECTRAL(IplImage *image_Re,IplImage *image_Im);
void CHANGE_SCALE_SPECTRAL(IplImage *spectral);


/********** ここからメイン関数 ************/
int main( int argc, char **argv)
{

IplImage *imgA = cvLoadImage( "test.jpg", CV_LOAD_IMAGE_GRAYSCALE);
if(imgA ==NULL)
{
std::cout<<"Can't Load Image .\n";
return (-1);
}


CvMat *dft_MAT;
dft_MAT = GET_MAT_FOR_DFT(imgA); //画像からDFTに最適な行列を作成

CONVERT_AND_COPY_TO_MAT(imgA,dft_MAT); //データのスケール変換と行列にデータのコピー


/************* ここから、DFT *****************/
cvDFT (dft_MAT, dft_MAT, CV_DXT_FORWARD, imgA->height); //離散フーリエ変換


/*実部と虚部の分解*/
IplImage *image_Re = cvCreateImage (cvGetSize(dft_MAT), IPL_DEPTH_64F, 1);
IplImage *image_Im = cvCreateImage (cvGetSize(dft_MAT), IPL_DEPTH_64F, 1);
cvSplit (dft_MAT, image_Re, image_Im, 0, 0);
cvReleaseMat(&dft_MAT);




/*********** ここから、各種計算 **************/
IplImage *spectral = CALC_SPECTRAL(image_Re,image_Im);
cvReleaseImage(&image_Re);
cvReleaseImage(&image_Im);




/******** 出力できるようにスケール変換 *********/
CHANGE_SCALE_SPECTRAL(spectral);
cvNamedWindow ("magnitude", CV_WINDOW_AUTOSIZE);
cvShowImage ("magnitude", spectral);



cvNamedWindow("window",CV_WINDOW_AUTOSIZE);
cvShowImage("window",imgA);

cvWaitKey(0);

cvReleaseImage( &imgA );
cvReleaseImage( &spectral);
cvDestroyAllWindows();


return 0;
}


/******************* ここから各種関数 *******************************/
/******** 画像からDFTに最適な行列を作り、そのアドレスを返す ********/
CvMat* GET_MAT_FOR_DFT(IplImage *imgA)
{

int dft_M = cvGetOptimalDFTSize (imgA->height - 1); //CPU=>0,1,2
int dft_N = cvGetOptimalDFTSize (imgA->width - 1); //画像=>1,2,3 より「−1」引く

CvMat *dftM = cvCreateMat (dft_M, dft_N, CV_64FC2); //2チャネル
cvSetZero(dftM); //要素を0で初期化

return dftM;

}



/*********** 画像データスケール変換し,行列にコピー ********************/
void CONVERT_AND_COPY_TO_MAT(IplImage *imgA,CvMat *dft_A)
{

/* IplImage を2つ用意 */
IplImage *realInput = cvCreateImage (cvGetSize (imgA), IPL_DEPTH_64F, 1); //実部
IplImage *imaginaryInput = cvCreateImage (cvGetSize (imgA), IPL_DEPTH_64F, 1);//虚部

cvScale (imgA, realInput, 1.0, 0.0);// 実部に画像データ(double型で)
cvZero (imaginaryInput);//虚部はゼロクリア

/* 2つのIplImageをマージする */
IplImage *complexInput = cvCreateImage (cvGetSize (imgA), IPL_DEPTH_64F, 2);
cvMerge (realInput, imaginaryInput, NULL, NULL, complexInput);

cvReleaseImage(&realInput);
cvReleaseImage(&imaginaryInput);


CvMat tmp;
cvGetSubRect (dft_A, &tmp, cvRect (0, 0, imgA->width, imgA->height));
cvCopy (complexInput, &tmp, NULL); //画像データを行列にコピー

cvReleaseImage(&complexInput);

}



/********** スペクトルを計算し、そのIplImageのアドレスを返す ***************/
IplImage* CALC_SPECTRAL(IplImage *image_Re,IplImage *image_Im)
{

IplImage *Re = cvCloneImage(image_Re);
IplImage *Im = cvCloneImage(image_Im);

/* |a + bi|=√(a + bi)(a - bi)= √(a^2 + b^2) の計算*/
cvPow (Re, Re, 2.0); //各データを2乗
cvPow (Im, Im, 2.0);
cvAdd (Re, Im, Re, NULL); //2乗結果をたす (a^2 + b^2)
cvPow (Re, Re, 0.5); //√(a^2 + b^2)

cvReleaseImage(&Im);//以後はimage_Reのみ

cvAddS (Re, cvScalarAll (1.0), Re, NULL); //各要素に1を足す
cvLog (Re, Re); // log(1 + |a + bi|)

return Re;

}

/*********** ウィンドウに出力できるようにスケール変換 ***************/
void CHANGE_SCALE_SPECTRAL(IplImage *spectral)
{

double m, M;
cvMinMaxLoc (spectral, &m, &M, NULL, NULL, NULL);
cvScale (spectral, spectral, 1.0 / (M - m), 1.0 * (-m) / (M - m));

}

目次

― その他 ―

Wiki内検索

計測中...(07.10.8〜)

Save The World






▲よろしければ広告のクリックもお願いします


▲ランキングに参加しました

管理人/副管理人のみ編集できます