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

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

OpenCVでフーリエ変換(dft)2 表示編

こんにちは、よりです。
今日は下記の記事で紹介したフーリエ変換をした後の画像の表示方法を紹介したいと思います。
yori1029.hatenablog.com

とはいえ手探りで頑張ってるので私のメモ程度のレベルです。
今回はさくさく行きましょう、表示するだけやし。

前回の記事を参照してもらうとわかるんですけど dft 後のデータって2チャンネルになってるし虚部があるから扱いにくいよなーって感じです。
それを何とかして、よく見るフーリエ変換後の画像にしていきたいと思います。


全体の流れとしては

  1. フーリエ変換したデータを実部と虚部に分ける
  2. すべて実数にする(二乗して平方根
  3. 表示用に対数に変換する
  4. 表示位置を変更する(よく見るフーリエ変換後の画像にする)

って感じです。

今回フーリエ変換する画像はこちら。
f:id:yori1029:20160705105925j:plain



正直全然大したことないので参考にしたサイトのURLとコードを載せます。
下記のサイトの関数 create_fourier_magnitude_image_from_complex を参考に書きました。

opencv_sample_list_jp/main.cpp at master · YusukeSuzuki/opencv_sample_list_jp · GitHub


それでは私のわかりにくいコードも載せます。

#include <iostream> 
#include <cmath>
#include <string>
#include <sstream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <ctype.h>

using namespace cv;
using namespace std;

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

	//表示用
	Mat divdisplay[2];

	//フーリエ後を実部と虚部に分ける
	split(furimg, divdisplay);

	//表示用にすべて実数に
	Mat display;
	magnitude(divdisplay[0], divdisplay[1], display);

	//対数に変換する(そのため各ピクセルに1を加算)
	display += Scalar::all(1);
	log(display, display);

	//表示用に正規化
	Mat outdisplay;
	normalize(display, outdisplay, 0, 1, CV_MINMAX);

	namedWindow("aftdft");
	imshow("aftdft", outdisplay);

	waitKey(-1);

	return 0;

}


実行すると下図が出てきます。


f:id:yori1029:20160705093146p:plain


これは画像をフーリエ変換し、それを可視化したものです。
しかし普段みるフーリエ変換後の画像とは異なってますよね?
普段見るのは白い部分が中心にきてると思いますが、それは見やすいように変換している画像です。
では変換してみましょう。

追加した部分がわかるように書いたのでそこだけ見てもらえれば大丈夫です。

#include <iostream> 
#include <cmath>
#include <string>
#include <sstream>
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <ctype.h>

using namespace cv;
using namespace std;

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

	//表示用
	Mat divdisplay[2];

	//フーリエ後を実部と虚部に分ける
	split(furimg, divdisplay);

	//表示用にすべて実数に
	Mat display;
	magnitude(divdisplay[0], divdisplay[1], display);

	//対数に変換する(そのため各ピクセルに1を加算)
	display += Scalar::all(1);
	log(display, display);

	//ここから下を追加
	//___________________________________________

	const int halfW = display.cols / 2;
	const int halfH = display.rows / 2;

	Mat tmp;

	Mat q0(display,
		Rect(0, 0, halfW, halfH));
	Mat q1(display,
		Rect(halfW, 0, halfW, halfH));
	Mat q2(display,
		Rect(0, halfH, halfW, halfH));
	Mat q3(display,
		Rect(halfW, halfH, halfW, halfH));

	q0.copyTo(tmp);
	q3.copyTo(q0);
	tmp.copyTo(q3);
	q1.copyTo(tmp);
	q2.copyTo(q1);
	tmp.copyTo(q2);

	//____________________________________________
	//ここから上を追加

	//表示用に正規化
	Mat outdisplay;
	normalize(display, outdisplay, 0, 1, CV_MINMAX);

	namedWindow("aftdft");
	imshow("aftdft", outdisplay);

	waitKey(-1);

	return 0;

}

上記のものを実行すると下図がでてきます。
f:id:yori1029:20160705094156p:plain


これで画像のフーリエ変換を可視化することができました!!