完全に実力不足な理系大学生からの成長ブログ

プログラミング能力皆無、でも頑張ります。

OpenCVでのフーリエ変換(dft)


はじめまして、よりです。
今回ブログを書く決意をしたのはやったことを忘れないようにメモしようと思ったからです。


OpenCVでは離散フーリエ変換用の関数 dft が用意されています。
これをつかってフーリエ変換したいと思います。
下記のサイトに dft の解説がありますが基本的には dft(Mat(入力),Mat(出力)) って感じです。
配列操作 — opencv 2.2 documentation


さっそくフーリエ変換するぞー!!

int main(int argc, char **argv)
{
        //入力
	Mat image = cv::imread("lena.jpg", cv::IMREAD_GRAYSCALE); 

    //出力配列の用意
	Mat imgout;

    //フーリエ変換
	dft(image, imgout);

	return 0;

}

はい、エラー出ました。
出力結果
OpenCV Error: Assertion failed (type == CV_32FC1 || type == CV_32FC2 || type == CV_64FC1 || type == CV_64FC2) in cv::dft, file ..\..\..\modules\core\src\dxt.cpp, line 2506

英語が読めないのでよくわからないんですけど dft に入れるMatのtypeがよくないんですかね。
というわけで現在入力している画像の詳細を見てみます。

void checkMat(Mat m1) {
	// 行数
	std::cout << "rows:" << m1.rows << std::endl;
	// 列数
	std::cout << "cols:" << m1.cols << std::endl;
	// 次元数
	std::cout << "dims:" << m1.dims << std::endl;
	// サイズ(2次元の場合)
	std::cout << "size[]:" << m1.size().width << "," << m1.size().height << std::endl;
	// ビット深度ID
	std::cout << "depth (ID):" << m1.depth() << "(=" << CV_64F << ")" << std::endl;
	// チャンネル数
	std::cout << "channels:" << m1.channels() << std::endl;
	// (複数チャンネルから成る)1要素のサイズ [バイト単位]
	std::cout << "elemSize:" << m1.elemSize() << "[byte]" << std::endl;
	// 1要素内の1チャンネル分のサイズ [バイト単位]
	std::cout << "elemSize1 (elemSize/channels):" << m1.elemSize1() << "[byte]" << std::endl;
	// 要素の総数
	std::cout << "total:" << m1.total() << std::endl;
	// ステップ数 [バイト単位]
	std::cout << "step:" << m1.step << "[byte]" << std::endl;
	// 1ステップ内のチャンネル総数
	std::cout << "step1 (step/elemSize1):" << m1.step1() << std::endl;
	// データは連続か?
	std::cout << "isContinuous:" << (m1.isContinuous() ? "true" : "false") << std::endl;
	// 部分行列か?
	std::cout << "isSubmatrix:" << (m1.isSubmatrix() ? "true" : "false") << std::endl;
	// データは空か?
	std::cout << "empty:" << (m1.empty() ? "true" : "false") << std::endl;

	cout << endl;
}

この関数を使えば中身がだいたい分かりそうですね。
下記のサイトのcv::Matの様々なプロパティに載ってます。
cv::Matの基本処理 — OpenCV-CookBook

出力結果
rows:512
cols:512
dims:2
size[]:512,512
depth (ID):0(=6)
channels:1
elemSize:1[byte]
elemSize1 (elemSize/channels):1[byte]
total:262144
step:512[byte]
step1 (step/elemSize1):512
isContinuous:true
isSubmatrix:false
empty:false

いろいろ調べた結果、フーリエ変換をした時に出てくる複素数を扱うためにはMatのチャンネルを2にする必要があるそうです。
今回imageに画像を入れましたがこのままだと1チャンネルしかないようなので2チャンネルにします。
mergeという関数が適しているようなのでこれを用いましょう。
mergeさせるのはimageと同じ大きさの複素数のMatです。

int main(int argc, char **argv)
{
	//入力
	Mat image = cv::imread("lena.jpg", cv::IMREAD_GRAYSCALE);
	
	//フーリエ変換用Mat
	Mat furimg;

	//実部のみのimageと虚部を0で初期化したMatをRealImaginary配列に入れる
	Mat RealIamginary[] = { Mat_<float>(image), Mat::zeros(image.size(), CV_32F) };
	
	//配列を合成
	merge(RealIamginary, 2, furimg);

	//フーリエ変換
	dft(furimg, furimg);

	return 0;

}

今回はエラーが出ませんでした!
おそらくfurimgにフーリエ変換後の値が入っていると思います。

今日はこれからバイトなのでここまで。