リード開発メモ

大阪のソフトウェア会社です。 技術的な事柄についてのメモとしてブログを始めます。

OpenCV

OpenCV3を使う (その5)

今回はエッジ検出を試してみる。

OpenCV のエッジ検出には、Sobel、Laplacian、Canny の3種類がある。

main.cpp を以下のように書き換える。


int main(int argc, char* argv[])
{
	// オリジナル画像の読み込み
	cv::Mat img_org = cv::imread("test1.JPG");
	cv::namedWindow("original");
	imshow("original", img_org);

	// グレースケール
	cv::Mat img_gray;
	cv::cvtColor(img_org, img_gray, CV_BGR2GRAY);
	cv::namedWindow("grayscale");
	imshow("grayscale", img_gray);

	// Sobelフィルタ
	cv::Mat img_sobel_x;
	cv::Sobel(img_gray, img_sobel_x, CV_32F, 1, 0);
	cv::convertScaleAbs(img_sobel_x, img_sobel_x);
	cv::Mat img_sobel_y;
	cv::Sobel(img_gray, img_sobel_y, CV_32F, 0, 1);
	cv::convertScaleAbs(img_sobel_y, img_sobel_y);
	cv::Mat img_sobel = (img_sobel_x + img_sobel_y) / 2;
	cv::namedWindow("sobel");
	imshow("sobel", img_sobel);

	// Laplacian
	cv::Mat img_laplacian;
	cv::Laplacian(img_gray, img_laplacian, CV_32F);
	cv::convertScaleAbs(img_laplacian, img_laplacian);
	cv::namedWindow("laplacian");
	imshow("laplacian", img_laplacian);

	// Cannyアルゴリズム
	cv::Mat img_canny;
	cv::Canny(img_gray, img_canny, 50, 200);
	cv::namedWindow("canny");
	imshow("canny", img_canny);

	cv::waitKey(0);
	cv::destroyAllWindows();
	return 0;
}


実行すると、ダイアログが4つ表示される。これは元画像。
opencv9

こちらはSobelフィルターによるエッジ検出。これは一次微分を用いてエッジ検出を行うもの。 方向を指定する必要があり、横方向を指定すると、横向きの線などが検出されない。 そのため横と縦と別々に処理し、結果を合成するなどの考慮が必要になる。 上のサンプルコードでもそのようにしている。
速度は一番速い。
opencv16

次にLaplacian。 Laplacianは二次微分を用いてエッジ検出を行う。 方向を指定する必要がないため処理がシンプルになる。
opencv17

最後にCanny。 Cannyは閾値を指定する必要がある。この閾値は自動で設定されないため、閾値がまずいと線が消えてしまう。次の画像でもいくつかの線が消えてしまっている。
opencv18

以上です。

OpenCV3を使う (その4)

今回も画像を2値化を行う。前回は画像全体で閾値を決めるグローバルな閾値を使ったが、今回は局所的に閾値を決定する適応型を使用する。

適応的には2通りのアルゴリズムがあり、adaptiveThreshold に渡すパラメータ CV_ADAPTIVE_THRESH_MEAN_C または CV_ADAPTIVE_THRESH_GAUSSIAN_C で決定する。

両方とも BlockSize x BlockSize の近傍領域で判定するため、画像全体で最適な閾値がないような場合にはこちらのほうが適していると思われる。

main.cpp を以下のように書き換える。

int g_MeanBlockSize = 0;
int g_MeanOffset = 0;
int g_GaussianBlockSize = 0;
int g_GaussianOffset = 0;

void onTrackbarMean(int, void* pimg_gray)
{
	try {
		cv::Mat img_gray = *(cv::Mat*)pimg_gray;
		cv::Mat img_threshold;
		cv::adaptiveThreshold(img_gray, img_threshold, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, g_MeanBlockSize, g_MeanOffset);
		imshow("threshold_mean", img_threshold);
	}
	catch (...) {
		cv::Mat img_gray = *(cv::Mat*)pimg_gray;
		cv::Mat img(img_gray.size(), CV_8UC3, cv::Scalar(0, 0, 0));
		imshow("threshold_mean", img);
	}
}

void onTrackbarGaussian(int, void* pimg_gray)
{
	try {
		cv::Mat img_gray = *(cv::Mat*)pimg_gray;
		cv::Mat img_threshold;
		cv::adaptiveThreshold(img_gray, img_threshold, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C, CV_THRESH_BINARY, g_GaussianBlockSize, g_GaussianOffset);
		imshow("threshold_gaussian", img_threshold);
	}
	catch (...) {
		cv::Mat img_gray = *(cv::Mat*)pimg_gray;
		cv::Mat img(img_gray.size(), CV_8UC3, cv::Scalar(0, 0, 0));
		imshow("threshold_gaussian", img);
	}
}

int main(int argc, char* argv[])
{
	// オリジナル画像の読み込み
	cv::Mat img_org = cv::imread("hp-business-card.JPG");
	cv::namedWindow("original");
	imshow("original", img_org);

	// グレースケール
	cv::Mat img_gray;
	cv::cvtColor(img_org, img_gray, CV_BGR2GRAY);
	cv::namedWindow("grayscale");
	imshow("grayscale", img_gray);

	// 画像の適応的閾値処理(MEAN)
	cv::namedWindow("threshold_mean");
	cv::createTrackbar("blockSize", "threshold_mean", &g_MeanBlockSize, 255, onTrackbarMean, &img_gray);
	cv::createTrackbar("offset", "threshold_mean", &g_MeanBlockSize, 255, onTrackbarMean, &img_gray);
	cv::setTrackbarPos("blockSize", "threshold_mean", 41);
	cv::setTrackbarPos("offset", "threshold_mean", 5);

	// 画像の適応的閾値処理(GAUSSIAN)
	cv::namedWindow("threshold_gaussian");
	cv::createTrackbar("blockSize", "threshold_gaussian", &g_GaussianBlockSize, 255, onTrackbarGaussian, &img_gray);
	cv::createTrackbar("offset", "threshold_gaussian", &g_GaussianOffset, 255, onTrackbarGaussian, &img_gray);
	cv::setTrackbarPos("blockSize", "threshold_gaussian", 41);
	cv::setTrackbarPos("offset", "threshold_gaussian", 5);

	cv::waitKey(0);
	cv::destroyAllWindows();
	return 0;
}


実行すると、ダイアログが3つ表示される。これは元画像。
opencv9

こちらは CV_ADAPTIVE_THRESH_MEAN_C。「Harry Potter」も「Graphic Designer」も判定できる。
opencv14

こちらはCV_ADAPTIVE_THRESH_GAUSSIAN_C。こちらも「Graphic Designer」も「Harry Potter」も読むことができる。
opencv15

以上です。

OpenCV3を使う (その3)

今回は画像を2値化を行う。

2値化とは、濃淡のある画像をある閾値で白か黒に置き換える処理のことで、閾値の決定方法はいくつか存在する。

今回は大津のアルゴリズムを用いて最適な閾値を自動的に決定する方法と、手動で閾値を決定する方法を示す。

手動で閾値を決定する方法では、ウィンドウにスライダーを付け、スライダーを動かすことによって画像が動的に変更される。このスライダーはOpenCVが提供するコントロールである。

main.cpp を以下のように書き換える。

void onTrackbar(int thresh, void* pimg_gray)
{
	cv::Mat img_gray = *(cv::Mat*)pimg_gray;
	cv::Mat img_threshold;
	cv::threshold(img_gray, img_threshold, thresh, 255, CV_THRESH_BINARY);
	imshow("threshold_manual", img_threshold);
}

int main(int argc, char* argv[])
{
	// オリジナル画像の読み込み
	cv::Mat img_org = cv::imread("test1.JPG");
	cv::namedWindow("original");
	imshow("original", img_org);

	// グレースケール
	cv::Mat img_gray;
	cv::cvtColor(img_org, img_gray, CV_BGR2GRAY);
	cv::namedWindow("grayscale");
	imshow("grayscale", img_gray);

	// 画像の二値化(大津)
	cv::Mat img_threshold;
	cv::threshold(img_gray, img_threshold, 0, 255, CV_THRESH_OTSU | CV_THRESH_BINARY);
	cv::namedWindow("threshold_otsu");
	imshow("threshold_otsu", img_threshold);

	// 画像の二値化(手動)
	cv::namedWindow("threshold_manual");
	int value = 0;
	cv::createTrackbar("threshold", "threshold_manual", &value, 255, onTrackbar, &img_gray);
	cv::setTrackbarPos("threshold", "threshold_manual", 60);

	cv::waitKey(0);
	cv::destroyAllWindows();
	return 0;
}


実行すると、ダイアログが3つ表示される。これは元画像。
opencv9

threshold_otsu が大津のアルゴリズムを使ったもの。この例では閾値は140くらいだと思うが、「Harry Potter」の文字が若干読みにくい。「Graphic Designer」に至っては判別できない。
opencv11

こちらはスライダーを用いた手動で閾値を設定するもの。初期値を60にしたところ。「Graphic Designer」は読めるが、「Harry Potter」の文字が白く飛んでしまった。
opencv12

閾値をいくらにしても「Harry Potter」、「Graphic Designer」のどちらかが読めなくなってしまう。 opencv13

以上です。

OpenCV3を使う (その2)

今回は画像を読み込み、グレースケールをかける。

プロジェクトの設定を少し変え、デバッグ実行したとき相対パスで画像ファイルを指定できるようにしておく。

作成したプロジェクトのプロパティを開き、以下の設定を行う。
1. 構成プロパティ - デバッグ - 全般 - 作業ディレクトリに、「$(OutputPath)」を指定する。構成の Debug / Release ともこのようにしておく。

以上で設定は完了。

main.cpp を以下のように書き換える。


int main(int argc, char* argv[])
{
	// オリジナル画像の読み込み
	cv::Mat img_org = cv::imread("test1.JPG");
	cv::namedWindow("original");
	imshow("original", img_org);

	// グレースケール
	cv::Mat img_gray;
	cv::cvtColor(img_org, img_gray, CV_BGR2GRAY);
	cv::namedWindow("grayscale");
	imshow("grayscale", img_gray);

	cv::waitKey(0);
	cv::destroyAllWindows();
	return 0;
}


実行すると、次のようなダイアログが2つ表示される。こちらは元画像。
opencv9

こちらはグレースケール。
opencv10


以上です。

OpenCV3を使う (その1)

OpenCV3 を使ってみる。今回はVisual Studio 2013 で OpenCV3 の環境を作る。

OpenCVは以下からダウンロードする。
http://opencv.org/downloads.html

最新は「VERSION 3.0」なので、これの「OpenCV for Windows」をクリックし、opencv-3.0.0.exeをダウンロードする。

これは圧縮ファイルとなっているので、解凍したら、includeとx86を適当なフォルダに配置する。
今回は32bitアプリケーションを作成する予定のためx86を使った。64bitアプリケーションを作る場合はx64を使う必要がある。

次にVisual Studio 2013でC++のプロジェクトを作成する。
プロジェクトは、「Visual C++」の「Win32 コンソールアプリケーション」で、「空のプロジェクト」として作成する。

作成したプロジェクトのプロパティを開き、以下の設定を行う。
1. 構成プロパティ - C/C++ - 全般 - 追加のインクルードディレクトリに、上で解凍したincludeフォルダを指定する。
2. 構成プロパティ - リンカー - 全般 - 追加のライブラリディレクトリに、上で解凍したx86フォルダ内のvc12/staticlibフォルダを指定する。これは静的リンクをする設定なので、動的リンクをする場合はvc12/libを指定すること。
3. 構成プロパティ - C/C++ - コード生成 - ランタイムライブラリの設定を変更する。設定は Debug / Release で違う。Debug は「マルチスレッド デバッグ (/MTd)」を設定、Release では「マルチスレッド (/MT)」を設定する。
以上で設定は完了。

プロジェクトに以下の内容で main.cpp を追加する。

#include <opencv2/opencv.hpp>

#ifdef _DEBUG        
#pragma comment(lib,"opencv_core300d.lib")
#pragma comment(lib,"opencv_imgproc300d.lib")
#pragma comment(lib,"opencv_highgui300d.lib")
#pragma comment(lib,"opencv_hal300d.lib")
#pragma comment(lib,"opencv_imgcodecs300d.lib")
#pragma comment(lib,"ippicvmt.lib")
#pragma comment(lib,"IlmImfd.lib")
#pragma comment(lib,"libjasperd.lib")
#pragma comment(lib,"libjpegd.lib")
#pragma comment(lib,"libpngd.lib")
#pragma comment(lib,"libtiffd.lib")
#pragma comment(lib,"libwebpd.lib")
#pragma comment(lib,"zlibd.lib")
#else    
#pragma comment(lib,"opencv_core300.lib")
#pragma comment(lib,"opencv_imgproc300.lib")
#pragma comment(lib,"opencv_highgui300.lib")
#pragma comment(lib,"opencv_hal300.lib")
#pragma comment(lib,"opencv_imgcodecs300.lib")
#pragma comment(lib,"ippicvmt.lib")
#pragma comment(lib,"IlmImf.lib")
#pragma comment(lib,"libjasper.lib")
#pragma comment(lib,"libjpeg.lib")
#pragma comment(lib,"libpng.lib")
#pragma comment(lib,"libtiff.lib")
#pragma comment(lib,"libwebp.lib")
#pragma comment(lib,"zlib.lib")  
#endif

int main(int argc, char* argv[])
{
	cv::Mat img(cv::Size(320, 240), CV_8UC3, cv::Scalar(0, 0, 0));
	cv::circle(img, cv::Point(80, 80), 60, cv::Scalar(0, 255, 0), 1);
	imshow("opencvtest", img);
	cv::waitKey(0);
	cv::destroyAllWindows();
	return 0;
}

実行すると、次のようなダイアログが表示されれば成功。
opencv8

以上です。

アクセスカウンター
  • 今日:
  • 昨日:
  • 累計:

livedoor 天気