OpenCV/Visual Studio試用記
OpenCVをVisual Studio 2013/Windows 7でC++によって使用してみた。標準C++によるもの(コンソールアプリケーション)と、C++/CLRによるもの(Windows フォームアプリケーション)の2通りを試みた。以下は、その備忘録である。
まず、OpenCVをウェブサイト
http://opencv.org/downloads.html
からダウンロードした。バージョンは、OpenCV for Windows Version 2.4.10である。
これを使用するために、以下の3つの作業を行った。
(1) プログラムのコンパイル時に探索されるOpenCVの関数用ヘッダーファイルのディレクトリの設定
(3) プログラムの実行時に探索されるDLLの存在するディレクトリの環境変数Pathへの設定
なお、Windowsフォームアプリケーションのときは、フォームのヘッダーファイルにおける宣言・定義に注意が必要であるが、それらについては当該の説明箇所で述べる。
(1) と(2)はプログラム(プロジェクト)ごとに行うが、(3)の設定はシステム環境変数の設定なので、1回だけ設定すればよい。
まず、この(3)「システム環境変数Pathの設定」について説明する。
上のOpenCVのサイトからダウンロードしたファイルを実行解凍すると、フォルダopencvが作成され、その中に作成されたフォルダbuild内に必要なファイルがある。
図1
環境変数Pathに設定するのは、フォルダopencv内のbinフォルダである。すなわち
opencv\build\x86\vc12\bin
である。解凍後のフォルダ内のbinフォルダを設定してもよいが、他の設定も分かり易くするために、ドライブCにフォルダ\opencv2410を作成して、このフォルダに解凍後のフォルダおよびファイルをコピーした(図2)。
図2
したがって、Pathに設定するディレクトリは
C:\opencv2410\build\x86\vc12\bin
となる(図3)。
図3
環境変数Pathの設定手順は以下のようである(Windows 7の場合; Windows 8.1の場合も同様である)。
「コントロールパネル|システムとセキュリティ|システム」を選んで表示されるウィンドウにおいて「システムの詳細設定」を選ぶ(図4)。
図4
表示された「システムのプロパティ」ウィンドウにおいて、「環境変数」ボタンをクリックする(図5)。
図5
「環境変数」ウィンドウが表示される(図6)。
図6
「システム環境変数」ボックス内の「Path」をクリックして選び、「編集」ボタンをクリックすると、「システム変数の編集」ウィンドウが表示される(図7)。
図7
変数値のエディタボックス内の文字列に、セミコロン ; を挟んでOpenCVのDLLの格納されているディレクトリ名「C:\opencv2410\build\x86\vc12\bin」を追加する。
「OK」ボタンをクリックする。「OK」ボタンのクリックの繰り返して、図5の「OK」ボタンのクリックまで行い、環境変数Pathの設定を終了する。Pathの終了後、PCを再起動する。
再起動後、Pathに設定した値が有効になっているので、プログラムの実行時にOpenCVのDLLが設定したディレクトリ(図7の場合は、「C:\opencv2410\build\x86\vc12\bin」)から呼び出せるようになる。
次に、プログラムのインクルードファイルのディレクトリ、およびライブラリのプロジェクトへの追加の手続きを行うが、これはプロジェクトごとに行う。
まず、標準C++準拠プログラムの場合について説明するが、これは.NetFramework用のC++/CLR(あるいは、C++/CLI)の場合も同じである。VC++/CLRのウィンドウフォームアプリケーションについての追加事項は、標準C++の場合の説明の後で取り上げる。
まず、図8のように新規にプログラムが作成されたとする(図8)。
図8
プログラムの新規作成は、ウェブサイト
http://y-okamoto-psy1949.la.coocan.jp/VCpp/StdCppVS/
で説明している。
インクルードされるヘッダーファイル「opencv2/highgui/highgui_c.h」の格納されているディレクトリ(フォルダ)の設定を行う。
ソリューションエクスプローラ内のプロジェクト名をクリックしてマークしておく(図9)。
図9
メニュ「プロジェクト|プロパティ」を選ぶ(図10)。
図10
「構成プロパティ」の左の横向き白三角をクリックする(図11)。
図11
項目「C/C++」を選び、右のペインに表示される「追加のインクルードディレクトリ」欄の空白セルをクリックする(図12)。
図12
空白セルの右端に表示される黒の下向き三角印のボタンをクリックする(図13)。
図13
表示される「<編集...>」をクリックする(図14)。
図14
表示された「追加のインクルードディレクトリ」ウィンドウ内のフォルダアイコンの付いたボタンをクリックする(図15)。
図15
「...」印のボタンをクリックする(図16)。
図16
「ディレクトリの選択」ウィンドウが表示される(図17)。
図17
設定したいディレクトリを選ぶ(図15)。
図18
図18で選ばれている「C:\opencv2410\build\include」には、2つのディレクトリ「opencv」と「opencv2」が存在している(図19)。
図19
図18でディレクトリ(フォルダー)の選択後、「フォルダーの選択」ボタンをクリックする。
図20
プロパティウィンドウが表示され、追加したディレクトリが「追加のインクルードディレクトリ」欄に表示されている(図20)。
「適用」ボタンのクリックで、追加したディレクトリが設定される。「OK」ボタンをクリックして設定終了である。
図21
インクルードディレクトリが設定されたので、ヘッダーファイル「highgui_c.h」がエディタに読み込まれ、図9では表示されていた赤色の波線の下線が消えている(図21)。
OpenCVの関数がどのヘッダーファイルにあるのかは、ウィンドウの検索機能を利用すればわかる。例えば、「cvLoadImage関数」がどのヘッダーファイルに宣言されているかは以下のようにして調べることができる。
まず、フォルダ「C:\opencv2410\build\include」を開く(図22)。
図22
検索語として「cvLoadImage」を設定して、フォルダ「include」内を検索する(図23)。
図23
文字列「cvLoadImage」を含むファイルが表示される(図24)。
1番目の「core.hpp」をダブルクリックすると、core.hppが表示される(図24)。
図24
メニュ「編集|検索と置換」を選んで、検索する文字列に「cvLoadImage」を設定して「次を検索」ボタンをクリックする。
文字列「cvLoadImage」がコメント内にあるので、このファイルは関係ないと推測される。
図25
図23において、「highgui_c.h」を選んでダブルクリックして表示し、文字列「cvLoadImage」で検索すると、cvLoadImage関数が宣言されていることがわかる(図26)。
図26
図20において、追加のインクルードファイルのディレクトリとして「include」までが設定されているので、図23から「opencv2/highgui/highgui_c.h」を < と > で挟んで#includeすればよいことがわかる(図21)。
リンク時のライブラリは、メニュ「プロジェクト|既存項目の追加」によって行う。
ライブラリは、図2のファイル構成の場合は、「C:\opencv2410\build\x86\vc12\lib」にあるもの(図A1)を使用するが、デバッグ用プログラムの場合とリリース版プログラムの場合とで、リンクするライブラリが異なる。
図A1
ファイル名が「*d.lib」と d で終わっているものがデバッグ版プログラム用であり、名前の最後に d が付いていないものはリリース版用である。プログラムを作成するときは、普通は「Debug」としてデバッグ版用である(図A2)。
図A2
リリース版を作成するときは、「Debug」とあるのを「Release」にする(図A3)。
図A3
(1) のインクルードディレクトリの設定や、以下に説明するプロジェクトのプロパティの設定は、必要ならば「Debug」版と「Release」版、それぞれに対して行う必要がある。ここでは、「Debug」版の場合のみを扱うので、「Release」版に対する設定は行わない。
デバッグ版用のライブラリだけを集めたフォルダ「\libd」を作成しておくと便利である(図A4)。
図A4
リンク用ライブラリのプロジェクトへの追加は以下のようになる。
ソリューションエクスプローラ内のプロジェクト名「Sample1」をクリックしてマークする(図A5)。
図A5
メニュ「プロジェクト|既存項目の追加」を選ぶ(図A6)。
図A6
表示された「既存項目の追加」ウィンドウにおいて、デバッグ用ライブラリを集めた「C:\opencv2410\build\x86\vc12\libd」を開く(図A7)。
図A7
フォルダ「\libd」内のライブラリファイルを全て選び、「追加」ボタンをクリックする(図A8)。
図A8
ソリューションエクスプローラ内に追加したライブラリファイルが表示される(図A9)。
図A9
これで、プログラムのビルド・実行の準備ができたことになるが、図21のプログラム
#include <opencv2/highgui/highgui_c.h>
int main(){
IplImage * img = cvLoadImage("TestImg.bmp");
cvNamedWindow("TestImage", CV_WINDOW_AUTOSIZE);
cvShowImage("TestImage", img);
cvMoveWindow("TestImage", 100, 100);
cvWaitKey(0);
cvReleaseImage(&img);
cvDestroyWindow("TestImage");
return 0;
}
では、画像ファイル「TestImg.bmp」が読み込まれている。このファイルは、上のプログラムでは、プログラムのソースコードファイルSource.cppと同じフォルダ、すなわちプロジェクトフォルダ内にあると想定されている(図A10)。
図A10
プロジェクトフォルダ内に画像ファイル「TestImg.bmp」を用意して、プログラムのビルド・実行すると、図A11のように画像ファイルが表示される。
図A11
画像の表示されているウィンドウの右上のX印ボタンのクリックで、プログラムは終了する。
プログラムファイルは圧縮ファイルWin32Console.zipとしてまとめた。このファイルをダウンロード解凍すれば、Visual Studio 2013で開くことができる。画像ファイルTestImg.bmpも含まれている。
ただし、このプログラムでは、OpenCV2のフォルダはC:\opencv2410の下にあるとして、インクルードファイルのフォルダおよびライブラリファイルの追加が行われている。使用するPCでのOpenCVのフォルダが他の名前、例えばC:\opencvであれば、それに合わせて設定し直す必要がある。ライブラリファイルは、ソリューションエクスプローラにはファイル名しか表示されていないが、これらを一度プロジェクトから除いてから「Project|Exclude From Project」、新たに使用するPCに合わせたフォルダからライブラリをプロジェクトに追加する。
プロジェクトを開いたとき、エラーがでることがあるが、これは無視できる。詳しくは、ウェブサイト
http://y-okamoto-psy1949.la.coocan.jp/booksetc/introvcpp/vs2012FormApp/#BM1
で説明した。
プログラムは、デバッグ用の構成とリリース版の構成の区別があり、それぞれリンクされるライブラリが異なるので、上で用意したデバッグ用の構成からリリース版へ変更するときは、リンク時のライブラリをリリース版用に変更する必要がある。この変更は、以下のようにできる。
Visual StudioをRelease用に設定し、ソリューションエクスプローラ内のデバッグ用リンクファイルを全て選ぶ(図A12)。
図A12
全てを選んでマークした青色の領域内をマウスの右ボタンでクリックすると、メニュが表示される(図A13)。
図A13
「プロジェクトから除外」を選ぶと、選んだライブラリは全て除かれる(図A14)。
図A14
Release版用のライブラリを追加する前に、Debug用のライブラリは全て除いておかないと、ビルドのときエラーになることがある。
次に、ソリューションエクスプローラ内のプロジェクト名Sample1をクリックして選ぶ(図A15)。
図A15
メニュ「プロジェクト|既存項目の追加」を選んで、「既存項目の追加」ウィンドウを表示させる(図A16)。
図A16
先に用意しておいたRelease版用ライブラリを集めたフォルダ(この場合は、「C:\opencv2410\build\x86\vc12\libnd」)内のすべてのファイルを選び、「追加」ボタンをクリックする。
「追加のインクルードディレクトリ」はDebug用構成のときと同じように設定する。
インクルードディレクトリとリンク時ライブラリの設定後、ビルド・実行できる。
.NetFrameworkのフォームアプリケーションにおけるOpenCVの使用
.NetFrameworkの利用が加わることを除いて、上の標準C++によるプログラミングと同じ要領である。
まず、PictureBoxコンポーネントpictureBox1をフォームに貼り付けたVC++/CLRプロジェクトを用意する(図B1)。CLRとCLIの違いは、CLIは仕様であり、その仕様の実装がCLRである。ここでは、基本的にCLRの用語を用いる。
図B1
.NetFramworkのウィンドウフォームアプリケーションの作成方法は、ウェブサイト
http://y-okamoto-psy1949.la.coocan.jp/booksetc/introvcpp/vs2012FormApp/
で説明した。また、初心者用解説書として
<岡本安晴「大学生のための心理学VC++プログラミング入門」勁草書房>
を上梓した。
このプログラムのインクルードディレクトリの設定とリンク時のライブラリの追加は、上で説明した方法ですでに済んでいるものとする。
フォームのソースコードは、以下のようになっている。
#pragma once
#include <stdlib.h> // 乱数の関数 rand() などの使用のため
#include "common.h" // グローバル変数 cv_img の設定のため
namespace CLRSample {
・
・
・
#pragma endregion
private: System::Void MyForm_Load(System::Object^ sender, System::EventArgs^ e) {
cv_img = cvLoadImage("TestImg.bmp", CV_LOAD_IMAGE_COLOR); // 画像ファイルを読み込んでOpenCVのcv_imgに設定
if (cv_img == NULL){
MessageBox::Show("cvLoadImage error !");
return;
}
//
// cv_imgの画像をBitmapのbmに設定
//
Bitmap ^ bm = gcnew Bitmap(cv_img->width, cv_img->height, cv_img->widthStep, Imaging::PixelFormat::Format24bppRgb, IntPtr(cv_img->imageData));
pictureBox1->Left = 0;
pictureBox1->Top = 0;
pictureBox1->Width = bm->Width;
pictureBox1->Height = bm->Height;
pictureBox1->Image = bm; // bmの画像をpictureBox1に設定して表示
this->AutoSize = true; // フォームのサイズをpictureBox1のサイズに自動的に合わせる。
srand(0); // 乱数の初期化
}
double urand(){
return rand() / double(RAND_MAX); // 一様乱数の作成
}
private: System::Void MyForm_FormClosing(System::Object^ sender, System::Windows::Forms::FormClosingEventArgs^ e) {
if (cv_img != NULL)
cvReleaseImage(&cv_img);
}
//
// マウスの画像(pictureBox1)上でのクリックで呼び出されるメソッド
//
private: System::Void pictureBox1_MouseClick(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) {
int r = int(50.0 + 100.0 * urand());
int cr = int(255.0 * urand()), cg = int(255.0 * urand()), cb = int(255.0 * urand());
cvCircle(cv_img, cvPoint(e->X, e->Y), r, CV_RGB(cr, cg, cb), CV_FILLED, 8); // ランダムな円盤の描画
Bitmap ^ bm = gcnew Bitmap(cv_img->width, cv_img->height, cv_img->widthStep, Imaging::PixelFormat::Format24bppRgb, IntPtr(cv_img->imageData));
pictureBox1->Image = bm;
}
};
}
プログラムファイルなどは、圧縮ファイルCLRSample.zipとしてまとめてある。ダウンロードして解凍すれば、Visual Studio 2013で開くことができる。開くときエラーがでることがあるが、無視できる。このエラーについて、ウェブサイト
http://y-okamoto-psy1949.la.coocan.jp/booksetc/introvcpp/vs2012FormApp/#BM1
で説明した。
ただし、プログラムCLRSampleでは、OpenCV2のフォルダはC:\opencv2410の下にあるとして、インクルードファイルのフォルダおよびライブラリファイルの追加が行われている。使用するPCでのOpenCVのフォルダが他の名前、例えばC:\opencvであれば、それに合わせて設定し直す必要がある。ライブラリファイルは、ソリューションエクスプローラにはファイル名しか表示されていないが、これらを一度プロジェクトから除いてから「Project|Exclude From Project」、新たに使用するPCに合わせたフォルダからライブラリをプロジェクトに追加する。
ユーザーインターフェースのプログラミングを簡単にするために、Visual C++/CLRによる .NetFrameworkでのウィンドウズ・フォーム・アプリケーションのプログラミングを行っているが、OpenCVの画像はPictureBox型のオブジェクトによって表示する。
OpenCVの画像はIplImage型の構造体に設定されるが、
IplImage * cv_img
と定義している。変数などの定義・宣言は、フォームの参照クラス型が宣言されているファイルにおいて、参照クラス型の宣言より前に置くとトラブルが生じるので、別のファイルに定義・宣言する。プログラムでは、2つのファイルcommon.hとcommon.cppを、
=========== common.hファイル =============
#ifndef COMMON_CK
#define COMMON_CK
#include <opencv2/opencv.hpp>
extern IplImage * cv_img;
#endif
==================================
および
========== common.cppファイル ============
#include "common.h"
IplImage * cv_img;
==================================
と用意して、common.hファイルをフォームの参照クラス型が宣言されているファイルに#includeしている。
OpenCVの画像データは、cv_imgのメンバーimageDataにあるので、それをBimap型オブジェクトに
Bitmap ^ bm = gcnew Bitmap(cv_img->width, cv_img->height, cv_img->widthStep, Imaging::PixelFormat::Format24bppRgb, IntPtr(cv_img->imageData));
と設定した後、このBitmap型オブジェクトに設定された画像をPictureBox型オブジェクトのImageに
pictureBox1->Image = bm;
と設定して表示している。プログラムを実行すると、図B2のように表示される。
図B2
画像の上でマウスでクリックすると、図B3のようにランダムな大きさと色でクリックしたところに円盤が描かれる。
図B3
これは、PictureBox上のマウスクリックイベントで呼び出されるメソッドによって、以下のように描かれている。
private: System::Void pictureBox1_MouseClick(System::Object^ sender, System::Windows::Forms::MouseEventArgs^ e) {
int r = int(50.0 + 100.0 * urand());
int cr = int(255.0 * urand()), cg = int(255.0 * urand()), cb = int(255.0 * urand());
cvCircle(cv_img, cvPoint(e->X, e->Y), r, CV_RGB(cr, cg, cb), CV_FILLED, 8);
Bitmap ^ bm = gcnew Bitmap(cv_img->width, cv_img->height, cv_img->widthStep, Imaging::PixelFormat::Format24bppRgb, IntPtr(cv_img->imageData));
pictureBox1->Image = bm;
}
OpenCVによってcv_img上に円が描かれた後、描画画像がpictureBox1に設定されて表示される。
イベントに対応するメソッドの用意の仕方などは、<岡本安晴「大学生のための心理学VC++プログラミング入門」勁草書房>で説明している。