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

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

OpenCV

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

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

OpenCVをWin32ベースで利用するの3回目です。前回は画像ファイルを入力にしてその画像に対してOpenCVで画像処理を行うというプログラムでした。今回は大きくは変わらないですが、カメラからの画像を入力にして画像処理を行います。今回のプログラムで重要になってくるのはWin32APIでのスレッド処理です。しかしながら、スレッド処理はOpenCVとは関係ないのでポイントだけということで書いていきたいと思います。

(※2017年2月8日 いまさらですが、ソースが中途半端で動作しないというご指摘を頂きましたので修正しました。読み込みボタンでカメラの起動処理を実行して、キャプチャやグレースケールスケール変換が出来ると思います。何かありましたら、フィードバックページ等をご利用下さい。)

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

それではまずは今回のプログラムの動作からです。以下のような流れを想定しました。当然ですがカメラが接続(または内蔵)されていて利用出来ることが前提です。前回から変わっているのは入力がカメラになったということです。

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

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

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

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

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

ここで大事なのは前回と同様に、2.と3.です。ここでやりたいOpenCVの処理を書きます。ここではまずはビデオ画像をキャプチャして表示するという処理と、キャプチャした画像をグレースケールに変換して表示するというプログラムを作りました。(※ページ先頭のソース一式です。)

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

読み込みボタンでキャプチャ開始
0002

キャプチャーボタンでキャプチャーして別画面表示
0005

グレースケールボタンでキャプチャーしてグレースケールに変換後に別画面で表示
0008

すいません、夜の時間帯に室内から窓の外を撮ったものであまり違いがはっきりしないですがご了承ください。
あと、保存処理は前回と同様です。保存用の画像変数に設定した画像が保存出来ます。

次に今回のプログラムの要点のスレッド処理についてです。(理解されている方は当然理解されていると思いますが)スレッドとはプログラム内(Windowsの場合はプロセスという表現が出来ると思いますが)で別々の独立した処理の流れのことです。C言語の場合は独立した処理というのは関数単位です。最新の様々なプログラミング言語仕様では非同期という処理が可能なので今回のような処理も非同期を使えば比較的に簡単に出来るかと思いますがやはりスレッドは重要なプログラミングの要素です。

しかしながらですが、最初に書いたように、スレッド処理は、OpenCVとは関係ないのでポイントだけ書きます。以下がポイントになるかと思います。

・カメラ入力の処理はリアルタイムに動いているのでこれを別スレッドとして実行する。
(メインダイアログでの処理とは別にしてメインダイアログは常に処理を受け付けている状態とする。)

・Win32APIのスレッド起動は、_beginthreadex()を使う。
(最も安全に利用できる関数(API)である。)

・カメラ入力の別スレッドではGUIを操作しない。
(C言語(Win32API)の場合は、おそらく問題なく動作する場合もあると思うが基本的には別スレッドからはGUIは操作しない。)

以下がスレッドの関数です。スレッドの形式は、ここではこういった決まった形式で実装するということにしておきます。OpenCVの処理としては、最初に見つかったビデオ入力(カメラと想定しています)をオープンして終了のフラグがセットされるまで入力用の画像に取り込んでWin32APIでメインダイアログに表示し続けています。

/*------------------------------------------------
 カメラキャプチャー
-------------------------------------------------*/
unsigned int __stdcall CameraCaptureThread(PVOID pv)  {

	cv::VideoCapture cap(0);
	if (!cap.isOpened()){
		return -1;
	}

	while (1){

		if (endFlag){
			break;
		}

		cap >> imgMatRead;

		img = imgMatRead;
		imgFromOpenCV = &img;

		//メモリを確保
		if (bmpData != NULL){
			HeapFree(GetProcessHeap(), 0, bmpData);
		}

		bmpData = (LPDWORD)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, imgFromOpenCV->width * imgFromOpenCV->height * 4);

		//iplImageからDIBへ変換
		iplTobmp(imgFromOpenCV, bmpInfo, bmpData);

		//ここで描画
		StretchDIBits(hDC,
			0, 0, imgFromOpenCV->width, imgFromOpenCV->height,
			0, 0, imgFromOpenCV->width, imgFromOpenCV->height,
			bmpData, &bmpInfo, DIB_RGB_COLORS, SRCCOPY);
	}

	return 0;
}

このスレッドを起動する処理が以下です。該当部分のみです。

case ID_READ:
	//カメラキャプチャー開始
	if (threadHandle != NULL)
	{
		break;
	}
		
	//スレッド起動
	threadHandle = (HANDLE)_beginthreadex(
		NULL,          
		0,              
		CameraCaptureThread,  
		NULL,
		0,               
		(unsigned int*)&dwThread);

	if (!threadHandle) {
		MessageBox(hDlg, "スレッド起動エラー", "debug", MB_OK);
	}

	break;

プログラム全体はページ先頭のリンクからダウンロード出来ます。全体が必要な場合はお手数ですがダウンロードをして下さい。

今回はここまでです。次回はカメラ入力は同じですがリアルタイムに画像処理を行って画像処理を動画として保存出来るようなプログラムに変更してみます。

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

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

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


AdSense

AdSense

-OpenCV

執筆者:

関連記事

Raspberry Pi 4にOpenCVをインストールしてPythonで動作確認

Raspberry Pi 4にOpenCVをインストールして動作確認をしました。Pythonでのプログラミングを想定して動作確認はPythonで行いました。

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

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

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

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

OpenCVでのORBによる特徴点抽出とマッチング(その2)GUIの利用

OpenCVでのORBアルゴリズムによる特徴点抽出とマッチングの処理についての2回目です。前回はVisual Studio Community 2013のVisual C++コンソールアプリでORBに …

OpenCVで輪郭抽出から隣接領域の切り出し(その2)輪郭の直線近似と切り出し

OpenCVで画像内の輪郭抽出からその輪郭の隣接領域(四角形)を求めてその領域を切り出すという処理を作ってみました。以下の画像がその結果の例です。(※実画像サイズは大きめです。) 今回はその2回目です …