株式会社インデペンデンスシステムズ横浜

システム開発エンジニアの西田五郎が運営しております。Raspberry Pi や Arduino その他新規開発案件のご依頼をお待ちしております。

OpenCV

OpenCVをWin32ベースで利用する(その2)OpenCVの組み込み

投稿日:2014年11月1日 更新日:

OpenCVをWin32ベースで利用するの2回目です。前回はベースになるダイアログベースのアプリケーションを作成しました。今回はこのアプリケーションにOpenCVを組み込んで実際に動かしてみます。

(※2014.11.16追記)
以下でOpenCVを組み込む前の画面上の入出力用のコントロールを追加したバージョンを作成しました。
OpenCVをWin32ベースで利用する(その5)GUIコントロールの追加

今回のソース一式は以下からダウンロード出来ます。(※必要な場合は用途に限らずご利用頂いて問題ありませんが、一切無保証です。弊社は一切の責任を負いません。)
今回のソース一式(※OpenCVを取り込んでいるため72M程度のサイズになっています。)

まずOpenCVの組み込みはここではNuGetを使います。以下のページに書きました。より詳細はこちらを参照して下さい。
NuGetでOpenCVを導入する

前回のプロジェクトの状態から、ツールメニュー → NuGetパッケージマネージャー → ソリューションのNuGetパッケージの管理 から管理画面を起動します。
0002

検索エリアからOpenCVで検索をして見つかったOpenCVを選択してインストールをします。これでOpenCVの組み込みは完了です。現状では、OpenCV 2.4.8が導入出来ます。

次にソースファイルの上に以下のインクルードファイルを追加します。C言語、C++の両方を使えるようにインクルードします。

#include <opencv\cv.h>
#include <opencv\highgui.h>

#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>

これでビルドを実行するとエラーになります。これについては以下で書きました。
Visual C++ CRT(Cランタイムライブラリ)のビルドエラー

ここでは対処法だけ書きます。stdafx.hの#pragma onceの下に以下の行を挿入します。これでエラーは出なくなります。(文字コードのワーニングは気にしないことにします。)以上でOpenCVの組み込みは完了です。
#define _CRT_SECURE_NO_WARNINGS 1

ここからですが、以下のような処理の流れを想定してプログラムを作成しました。

1. 読み込みボタンで画像を読み込んでメインダイアログに表示する。(読み込み方は必ず3チャンネルカラー画像)

2. ボタンを押した際に何かしらの画像処理を行う。(ボタンは5個あり各ボタンクリック時の関数を用意)

3. 画像処理の結果を表示する(結果の表示はOpenCVのGUIを利用)

4. 画像処理の結果を保存用の変数にセットする(必要な場合のみ)

5. 画像処理の結果を保存する(必要な場合のみ)

ここで大事なのは、2.と3.です。ここでやりたいOpenCVの処理を書きます。実際に例として簡単ですが読み込んだ画像をグレースケールに変換して表示するというプログラムを作りました。(※ページ先頭のソース一式です。)

以下のような動きをします。
起動時
0001

読み込みボタンから画像を読み込みます。普通のファイルダイアログです。
0003

読み込んだ画像が表示されます。画像が大きい場合は縮小して表示します。
0005

処理1ボタンでグレースケール画像を作成して表示します。(※元々が曇りの天候の時の画像のようであまり変わっていないようですが。)
0008

保存ボタンでグレースケールの画像が保存出来ます。普通のファイルダイアログです。
0013

保存した画像をブラウザ上で表示しました。
0015

以上のような流れです。OpenCVの処理はグレースケール画像の作成の処理です。その部分のソースコードについて書きます。ソースは以下です。処理1ボタンがクリックされると実行されます。

/*------------------------------------------------
 処理1
-------------------------------------------------*/
void func1(HWND hWnd)
{
	if (imgMatRead.rows == 0){
		MessageBox(hWnd, "画像が無効です", "エラー", MB_OK);
		return;
	}

	//読み込んだ画像をグレースケースに変換して表示する
	cv::Mat grImg;
	cv::cvtColor(imgMatRead, grImg, CV_BGR2GRAY);
	cv::imshow("gray", grImg);

	//保存用の画像に設定する
	imgMatWrite = grImg;
}

関数内に定義のない変数についてです。以下の定義がソースファイルの上部にあります。

//入力画像、出力画像
cv::Mat imgMatRead; //読み込み用(読み込んだ画像はここに保持される)
cv::Mat imgMatWrite; //書き込み用(保存する際はここに対象画像を設定すること)

imgMatReadがファイルダイアログから読み込んだ画像が保持される変数です。無条件に3チャンネルカラー画像で読み込んでいるので必要な場合は変換して使います。(今回ではグレースケールに変換しています。)imgMatWriteが保存用の画像を設定する変数です。読み込み、保存は別の処理があるので、ボタンがクリックされた時の処理はOpenCVの処理に集中すればいいです。結果の表示はWin32APIを使わなくてもOpenCVのGUIでいいかなと思いました。

それから、ここではC++を使っていますが、C言語で処理する場合は、cv::MatとIplImageを相互変換すればいいです。

imgMatReadをIplImageに変換する場合は、以下のように代入で変換出来ます。
IplImage img = imgMatRead;
あとは、OpenCVのC言語の関数でimgを使って画像処理を行えばいいです。

IplImageをimgMatWriteに変換するには以下のように変換出来ます。
IplImage imgの場合です。
imgMatWrite = cv::cvarrToMat(&img);

IplImage* imgの場合です。
imgMatWrite = cv::cvarrToMat(img);

こうすれば読み込み、保存はそのまま使えます。

以上のようにボタンをクリックした時の処理に集中すればいいので分かるやすくプログラムが書けるかなと思って作ってみましたがいかかでしょうか。

あと、OpenCVの処理としては画像が大きい場合にピクチャーコントロールに入るように縮小する際に、cv::resize()を使っています。補間手法はデフォルトのバイリニア補間を指定しています。他の補間方法もcv::resize()の最後の引数で指定出来ます。

ここでの補間という意味は画像の拡大、縮小の際のピクセル間のデータの再計算のことです。画像を拡大、縮小するとピクセルの数が当然変化するので拡大、縮小後の各ピクセルのデータを元画像からどう計算して処理するかということです。(※画像処理関連としては基本かもしれないですが、その補間手法が何種類もあって、このOpenCVのresize()で指定出来るというのが何かすごいなと思ったので書きました。)

その他の内部的な処理は、Win32APIになりますのでここでは取り上げないことにします。必要な場合はソースを読んでみて下さいということでご了承頂ければと思います。ソースはページ始めのリンクからダウンロード出来ます。

今回はここまでです。次回はカメラからの画像を入力にして処理をするプログラムを書きます。

関連書籍
(※APIで学ぶWindows徹底理解は中古でしか手に入らないようですが私も持っています。)

(※OpenCV 2 プログラミングブックは私も持っています。)

(※ここからはKindle版で英語ですが最新の情報もあるようです。また価格的にはいいかもしれないです。)


AdSense

AdSense

-OpenCV

執筆者:

関連記事

OpenCV2 cv::Matクラスの基礎

OpenCV2のcv::Matクラスの基礎についてです。OpenCV 2.0からはC++のインターフェースが追加されました。cv::MatクラスはそのC++インターフェースで画像を扱うクラスです。まず …

Tesseract-OCRの導入(その3)OpenCVの出力を認識する

2019/07/20追記 この記事を書いてから随分と経過しました。完全に情報が古くなっています。外部のサイトですが必要な場合は以下等を参照して下さい。 PythonとTesseract OCRで文字認 …

Visual Studio Community 2013のVisual C++でOpenCVを使う

Visual Studio Community 2013のVisual C++でOpenCVを使う方法についてです。Visual Studio Community 2013については前回書きましたが、 …

OpenCVで輪郭抽出から隣接領域の切り出し(その3)凸包の取得

OpenCVで画像内の輪郭抽出からその輪郭の隣接領域(四角形)を求めてその領域を切り出すという処理を作ってみました。前回までのプログラムとほぼ同じですが、前回までは輪郭抽出 → 直線近似 → 隣接領域 …

OpenCVをWin32ベースで利用する(その4)カメラ入力からの動画処理

OpenCVをWin32ベースで利用するの4回目です。前回はカメラ入力からの画像処理(静止画)を扱いましたが、今回は動画を処理します。動画と言っても特に変わることはなくキャプチャしたフレームごとに処理 …