OpenGL de プログラミング - OpenCV::逆離散フーリエ変換
現在地 >> メニュー >> サンプルコード::OpenCV >> 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);



/********** ここからメイン関数 ************/
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, dft_MAT->rows); //離散フーリエ変換
cvDFT (dft_MAT, dft_MAT, CV_DXT_INVERSE_SCALE, dft_MAT->rows); //離散逆フーリエ


/*実部と虚部の分解*/
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);
cvReleaseImage(&image_Im);


/** 出力できるようにchar*型に変換 **/
IplImage *after = cvCreateImage (cvGetSize(imgA), IPL_DEPTH_8U, 1);

cvSetImageROI(image_Re,cvRect(0,0,after->width,after->height)); //roiを設定
cvConvertScale(image_Re,after); //変換
cvResetImageROI(image_Re); //roiの解放
cvReleaseImage(&image_Re); //画像の開放



/**** ウィンドウに表示 *****/
cvNamedWindow ("after", CV_WINDOW_AUTOSIZE);
cvShowImage ("after", after);


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


cvWaitKey(0);


cvReleaseImage( &imgA );
cvReleaseImage(&after);

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);

}

メモ


DFT用の最適行列サイズと、もともとの画像のサイズが異なる場合があるので、
ROIを用いる必要がある。