# OpenGL de プログラミング

### 問題

#### 答え

#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)
{
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); //ＣＰＵ=>０,１,２
dft_N = cvGetOptimalDFTSize (imgA->width - 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); // ０秒待つ => ずっと入力待ち

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」で「離散フーリエ変換」を行ったあと、画像を４分割し

 1 2 4 3

という番号をつけ、これを
 3 4 2 1

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

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

この広告は60日間更新がないwikiに表示されております。

― その他 ―

## Save The World

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

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