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

問題


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

画像

答え


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

using namespace std;


void cvShiftDFT (CvArr * src_arr, CvArr * dst_arr);


int main( int argc, char **argv)
{
IplImage *imgA = cvLoadImage( "test2.jpg", CV_LOAD_IMAGE_GRAYSCALE);
if(imgA ==NULL)
{
cout<<"Can't Load Image ." << endl;
std::exit(0);
}


/* 2チャネルのIplImage 作成 */
IplImage *realInput = cvCreateImage (cvGetSize (imgA), IPL_DEPTH_64F, 1);
IplImage *imaginaryInput = cvCreateImage (cvGetSize (imgA), IPL_DEPTH_64F, 1);
IplImage *complexInput = cvCreateImage (cvGetSize (imgA), IPL_DEPTH_64F, 2);

cvScale (imgA, realInput, 1.0, 0.0); //64ビットにスケール変換
cvZero (imaginaryInput);
cvMerge (realInput, imaginaryInput, NULL, NULL, complexInput);

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



/* DFT計算用に行列作成 */
int dft_M, dft_N;
CvMat *dft_A;

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


IplImage *image_Re;
IplImage *image_Im;
image_Re = cvCreateImage (cvSize (dft_N, dft_M), IPL_DEPTH_64F, 1);
image_Im = cvCreateImage (cvSize (dft_N, dft_M), IPL_DEPTH_64F, 1);


/* 行列の初期設定 */
CvMat tmp;
cvGetSubRect (dft_A, &tmp, cvRect (0, 0, imgA->width, imgA->height));
cvCopy (complexInput, &tmp, NULL);

/* あまった部分はゼロで埋める */
if (dft_A->cols > imgA->width)
{
cvGetSubRect (dft_A, &tmp, cvRect (imgA->width, 0, dft_A->cols - imgA->width, imgA->height));
cvZero (&tmp);
}


/* DFT */
cvDFT (dft_A, dft_A, CV_DXT_FORWARD, complexInput->height);
cvSplit (dft_A, image_Re, image_Im, 0, 0);
cvReleaseMat(&dft_A);


/*スペクトル計算*/
cvPow (image_Re, image_Re, 2.0);
cvPow (image_Im, image_Im, 2.0);
cvAdd (image_Re, image_Im, image_Re, NULL);
cvPow (image_Re, image_Re, 0.5);


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

cvAddS (image_Re, cvScalarAll (1.0), image_Re, NULL);
cvLog (image_Re, image_Re);


cvShiftDFT (image_Re, image_Re);


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


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

cvNamedWindow ("magnitude", CV_WINDOW_AUTOSIZE);
cvShowImage ("magnitude", image_Re);


cvWaitKey(0); // 0秒待つ => ずっと入力待ち



IplImage *output = cvCreateImage (cvGetSize (image_Re), IPL_DEPTH_8U, 1);
cvConvertScale(image_Re, output,255);
cvSaveImage("out.jpg",output);



cvReleaseImage( &output );


cvReleaseImage( &imgA );
cvDestroyWindow("window");

cvReleaseImage( &image_Re );
cvDestroyWindow("magnitude");

return 0;
}


/******原点(直流成分)が画像の中心にくるように,画像の象限を入れ替える関数*********/
void cvShiftDFT (CvArr * src_arr, CvArr * dst_arr)
{
CvMat *tmp = 0;
CvMat q1stub, q2stub;
CvMat q3stub, q4stub;
CvMat d1stub, d2stub;
CvMat d3stub, d4stub;
CvMat *q1, *q2, *q3, *q4;
CvMat *d1, *d2, *d3, *d4;

CvSize size = cvGetSize (src_arr);
CvSize dst_size = cvGetSize (dst_arr);
int cx, cy;

if (dst_size.width != size.width || dst_size.height != size.height) {
cvError (CV_StsUnmatchedSizes, "cvShiftDFT", "Source and Destination arrays must have equal sizes", __FILE__, __LINE__);
}
if (src_arr == dst_arr) {
tmp = cvCreateMat (size.height / 2, size.width / 2, cvGetElemType (src_arr));
}
cx = size.width / 2; /* 画像中心 */
cy = size.height / 2;

q1 = cvGetSubRect (src_arr, &q1stub, cvRect (0, 0, cx, cy));
q2 = cvGetSubRect (src_arr, &q2stub, cvRect (cx, 0, cx, cy));
q3 = cvGetSubRect (src_arr, &q3stub, cvRect (cx, cy, cx, cy));
q4 = cvGetSubRect (src_arr, &q4stub, cvRect (0, cy, cx, cy));
d1 = cvGetSubRect (src_arr, &d1stub, cvRect (0, 0, cx, cy));
d2 = cvGetSubRect (src_arr, &d2stub, cvRect (cx, 0, cx, cy));
d3 = cvGetSubRect (src_arr, &d3stub, cvRect (cx, cy, cx, cy));
d4 = cvGetSubRect (src_arr, &d4stub, cvRect (0, cy, cx, cy));

if (src_arr != dst_arr) {
if (!CV_ARE_TYPES_EQ (q1, d1)) {
cvError (CV_StsUnmatchedFormats, "cvShiftDFT", "Source and Destination arrays must have the same format", __FILE__, __LINE__);
}
cvCopy (q3, d1, 0);
cvCopy (q4, d2, 0);
cvCopy (q1, d3, 0);
cvCopy (q2, d4, 0);
}
else { /* インプレースモード */
cvCopy (q3, tmp, 0);
cvCopy (q1, q3, 0);
cvCopy (tmp, q1, 0);
cvCopy (q4, tmp, 0);
cvCopy (q2, q4, 0);
cvCopy (tmp, q2, 0);
}
}

メモ


ほぼサンプルのまんま。

cvShiftDFT()関数


「OpenCV」で「離散フーリエ変換」を行ったあと、画像を4分割し

12
43

という番号をつけ、これを
34
21

となるようにすると、「原点」が「画像の中心」にくる。


(※何もしなければ、画面中央ほど、高周波成分であるという画像)

目次

― その他 ―

Wiki内検索

計測中...(07.10.8〜)

Save The World






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


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

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