ラベル Cpp の投稿を表示しています。 すべての投稿を表示
ラベル Cpp の投稿を表示しています。 すべての投稿を表示

2014年4月26日土曜日

OpenCVを使って一般物体認識エンジンを作成する

画像中の物体のクラスを認識する処理を、一般物体認識という。

一方、同インスタンスを認識する処理を特定物体認識という。

画像の feature や 機械学習手法をある程度勉強すれば、OpenCVを用いてどちらの識別器をつくることも可能だ。

今回は、一般物体認識の識別器をつくる方法をまとめる。

以下の準備が必要だ。

1.画像の収集
2.環境の準備
3.訓練
4.検証

順に、はまった点なども含めて記載していこうと思う。

1.画像の収集

認識したいクラスの画像(正事例)を少なくとも 3000 枚程度集める。
(例えば車を横からとらえた画像であれば、様々な種類の車、撮影角度、明るい、暗い、などの条件で収集する。)

これは Microsoft のBING APIを使うと、無料で5000回のリクエストを投げることが出来るので、便利だ。

画像を集めたら、画像中からクラスを表す部分を出来るだけ正確に抜き出す。
出来るだけ認識したい部分だけを、欠けること無く切りだすと良い。

また、認識したクラス以外の画像(負事例)もたくさんあつめる。少なくとも正事例画像の半分は集めること。
また、正事例として切り出した画像の倍程度の解像度で使用することを前提に切り出すと良い。


画像を切り出したら、学習に必要なファイルを作成する。
正事例と負事例では、異なるフォーマットのファイルが必要だ。

正事例

以下のフォーマットでsamplesファイルを作成しておく。

[画像ファイルへのパス] [N(画像中の物体の個数)] [クラスを囲む矩形の左上座標x] [クラスを囲む矩形の左上座標y] [width] [height] …N回繰り返し

(画像枚数分の行)

ex)
./positive/img.jpg 2 110 150 45 45  40 30 20 20

これは画像が切り出せていれば簡単なプログラムで出力すれば良いだろう。

負事例

正事例と違い、クラスを囲む矩形の矩形の情報はいらない。以下のフォーマットとなる。

[画像ファイルへのパス]
ex)
./negative/img.jpg

以上で、訓練画像の実体とそれらを示す samples ファイルが出来た。



2.環境の準備


OpenCV環境を使用する。

Androidで動作させたい場合は、OpenCV 2.4.1 までを使用すれば、OpenCV Manager をインストールする必要はない。(その変わりアプリサイズは大きくなる)
用途に合わせてバージョンを選択すれば良いだろう。

今回は、OpenCV Managerを使わずに、iPhone、Android端末上で動作させたかったので、
OpenCV 2.4.1 を使用した。

Windows環境を前提とする。

OpenCVの公式サイトからダウンロードする。

訓練環境はWindowsで作成する。
・Windows
以下から、2.4.1を選ぼう。

http://opencv.org/downloads.html


Androidに搭載したいので、以下をダウンロードしておく。
(Android開発環境ADTは構築済みとする)
・Android
http://sourceforge.net/projects/opencvlibrary/files/opencv-android/2.4.1/


OpenCVをビルドする

まずは、OpenCVをビルドする。RAMを贅沢に使える環境が増えているので、32bit版を使用していても 1 GB制限を外したいことが主な理由だが、ソースコードを書き換えて使う場合、ビルドは必須だ。

CMakeのダウンロードと使い方。

CMakeをダウンロードする。
http://www.cmake.org/

CMakeを使って、OpenCVのコードをvisualstudioのプロジェクトファイルを作成する。

以下が詳しくてありがたい。(3つ)
  • http://cvwww.ee.ous.ac.jp/oc20inst.html
  • http://ameblo.jp/banquet-of-merry-widow/entry-11105368931.html
  • http://blogs.yahoo.co.jp/nobuyuki_tsukasa/2803954.html
visualstudioのプロジェクトファイルが出来たら、開けばソースからビルド出来る。
(割りと時間がかかる。)

x32のOpenCVを使った方がはまりづらいが、RAM使用量の制限がうざい。
解除するには以下のサイトが参考になる。
http://d.hatena.ne.jp/manji602/20111214/1323834770


次に、学習用のプロジェクトをビルド使用。moduleに含まれている。

visualstudioを使ったが、インクルードするディレクトリなどは、mkファイルを参照しながら
追加した。
※以下は、opencv241_winにOpenCV2.4.1のソースを展開した前提。

○haartraining opencv visual studio(VC++)
○createsamples opencv visual studio(VC++)

・インクルードディレクトリ
C:\opencv241_win\build\include;C:\opencv241_win\build\include\opencv;C:\opencv241_win\build\include\opencv2;

・ライブラリディレクトリ
C:\opencv241_win\build\x86\vc10\lib;C:\opencv241_win\build\common\tbb\intel64\vc10;

opencv_imgproc241.lib;opencv_highgui241.lib;opencv_features2d241.lib;opencv_objdetect241.lib;opencv_calib3d241.lib;opencv_core241.lib;


○traincascade opencv visual studio(VC++)
・インクルードディレクトリ
C:\opencv241_win\build\include;C:\opencv241_win\build\include\opencv;C:\opencv241_win\build\include\opencv2;

・ライブラリディレクトリ
C:\opencv241_win\build\common\tbb\ia32\vc10;C:\opencv241_win\build\x86\vc10\lib;

opencv_core opencv_ml opencv_imgproc opencv_objdetect opencv_highgui opencv_calib3d opencv_video opencv_features2d opencv_flann opencv_legacy

・ライブラリ
opencv_imgproc241.lib;opencv_highgui241.lib;opencv_features2d241.lib;opencv_objdetect241.lib;opencv_calib3d241.lib;opencv_core241.lib;opencv_flann241.lib;opencv_contrib241.lib;opencv_ml241.lib;opencv_video241.lib;opencv_legacy241.lib


VC++のうざい警告が出るので、以下でやめさせる。

指定した警告を無視するで以下を指定。
4290;4996

また、デバッグビルドだとうまく動作せず、以下のエラーが出た。
http://grayhole.blogspot.jp/2012/04/isctypec-expression-unsignedc-1-256.html

リリースビルドだと動作したのでとりあえず放置。


学習用正事例サンプルの作成


正事例データを作成するために、createsampleプロジェクトを使用する。

createsamplesの使い方


> createsamples.exe -info samples.txt -vec ./positives/vec/positive_samples.vec -num 2 -h 10 -w 10

samples.txtは1の②で作成したファイルを使用する。


・h, wは 10~50 が良いらしい


作成されたsamplesの確認方法


> createsamples.exe -vec ./positives/vec/positive_samples.vec -w 10 -h 10

・h, wは 作成時の値を指定する


学習

createsamplesの出力したvecファイルを正事例用に使用する。

①haartrainingを使用する。
1世代前の学習。Haar-like特徴のみ使用できる。
②traincascadeを使用する。
最新の学習プログラム。以下のアルゴリズムを指定できる。
Haar-like
HOG
LBP

②のほうが新しく書き直されたもので、①も含むので基本②を使えば良い。
というか、②しか使ったことが無い。

traincascade

重要なパラメータは以下。


  • data:出力先ディレクトリ(つくってくれないので、事前につくっておくこと)
  • vec:positiveサンプルのvecファイル
  • bg:negativeサンプルのリストファイル
  • numPos:採用するポジティブサンプルの数
  • numNeg:採用するネガティブサンプルの数
  • numStages:AdaBoostステージ数
  • w:横(positive vecに合わせる)
  • h:縦(positive vecに合わせる)
  • min_hit_rate:各ステージの最少ヒット率
  • maxFalseAlarmRate:半分を超えない識別機は意味がないので排除する
  • bgcolor:認識したい物体の背景に多い輝度を指定(または認識したい物体と遠い輝度)



訓練が成功すると学習結果が出来上がる。
辞書がうまく成長しない場合、以下をチェックする。


  • 正事例数
  • 負事例数
  • 正事例と負事例の解像度比
  • 特徴量
  • ステージ数


AndroidでOpenCVを使う

CDTは入れておこう!
EclipseのNew Software Instoreから入れる。
nativeのソースをコンパイルしたいので、windows用OpenCVのlibsにあるlibとdllを指定する。
デフォルトだと以下、OpenCVをローカルでビルドした場合、build先のディレクトリにする。
各種lib → [OpenCV展開ディレクトリ]\build\x86\vc10\lib
各種dll → [OpenCV展開ディレクトリ]\build\x86\vc10\bin


NDKもダウンロードしておこう!
ダウンロードして、好きな場所に展開したら、
NDKの場所をEclipseに設定出来るので、ディレクトリを設定する。
さらに、ndkのビルドをwindows用のコマンドに変更する。

SurfaceViewは理解しておこう!
http://qiita.com/croquette0212/items/24dc2b6de3730e831aab


CDTでインクルードに成功し、追加ライブライを追加できたら、Android.mkファイルを手直しする必要があるかもしれない。
必要であれば、mkファイルでインクルードするOpenCVのライブラリの場所を、ローカルのOpenCVのパスに変更する。

2014年3月29日土曜日

Android NDK でSTLを使用する

Android NDKで cpp のコードを使用する際、そのままだと <string>などが使用できない。
STLを使用できるよう、設定を変更する。

行うことは簡単で、jniディレクトリにApplication.xmlを作成したら、以下の行を追加する。

APP_STL         := stlport_static

以上でOK。

2014年2月21日金曜日

OpenCV Win32 のメモリ制限を解除する

OpenCV の Win32 API は、メモリ制限がかかってる。

64bit OS で動作させる場合は、もっとたくさんめもりを使って、早く処理を終わらせたい。

OpenCVの以下を編集してビルドさせれば、制限を解除できます。

編集するファイル

coreに含まれる、internal.hpp を以下のように編集する。

//#define  CV_MAX_ALLOC_SIZE    (((size_t)1 << (sizeof(size_t)*8-2)))
#define CV_MAX_ALLOC_SIZE ULLONG_MAX

OpenCVをビルドしなおせばOK。



2014年2月15日土曜日

Eclipse CDT Cygwin

EclipseでC++コンパイル&ビルド環境をつくる。

VC++ならvisual studioでいいけど、JavaでEclipse使っているのでどうせなら一つで、ということで方法。

最も整理されていたサイトは以下。

http://www3.ntu.edu.sg/home/ehchua/programming/howto/EclipseCpp_HowTo.html


たぶん、CygwinやEclipse CDTを入れる順番によって、必要のあることが変わってくんだと思う。

ADTの環境にCDT、そのあと、Cygwinを入れたので、割と面倒だったのかもしれない。


Cygwinをインストール

以下からCygwinのbinを持ってきてインストール。


  • インストールディレクトリ C\:cygwin64
  • パッケージディレクトリ C\:cygwin64\package


http://cygwin.com/install.html

インストールするパッケージを選択するとき、Develの"gcc"と"libmpfr4"を選択する。


インストールが完了したら、EclipseのCDTにCygwinの設定を行う。


メインメニューの設定

Window > Preference > C/C++ > Debug > Source Lookup Path > Path Mappings

以下を設定。

Name: cygdrive
Compilation path: /cygdrive/c
Local file system path: C:\


プロジェクトの設定

C/C++ Builder > Tool Chain Editor


Cygwin GCC、Gnu Make Builder を選択。


C/C++ General > Path and Symbols

以下を追加。

<language name="C Source File">
<includepath>C:\cygwin64\usr\include</includepath>
<includepath>C:\cygwin64\usr\include\w32api</includepath>
<includepath>C:\cygwin64\lib\gcc\i686-pc-cygwin\4.8.2\include</includepath>
<includepath>C:\cygwin64\lib\gcc\i686-pc-cygwin\4.8.2\include-fixed</includepath>

<language name="C++ Source File">
<includepath>C:\cygwin64\usr\include\w32api</includepath>
<includepath>C:\cygwin64\usr\include</includepath>
<includepath>C:\cygwin64\lib\gcc\i686-pc-cygwin\4.8.2\include</includepath>
<includepath>C:\cygwin64\lib\gcc\i686-pc-cygwin\4.8.2\include-fixed</includepath>
<includepath>C:\cygwin64\lib\gcc\i686-pc-cygwin\4.8.2\include\c++</includepath>
<includepath>C:\cygwin64\lib\gcc\i686-pc-cygwin\4.8.2\include\c++\i686-pc-cygwin</includepath>
<includepath>C:\cygwin64\lib\gcc\i686-pc-cygwin\4.8.2\include\c++\backward</includepath>

コンパイル

プロジェクトのビルドをすると、コンパイルが出来る。


実行形式ファイルの作成

プロジェクトのプロパティ > Make Targets

から、好きな名前でターゲットを作成する。


以下でビルド可能。

Make Targets > Build



2014年1月26日日曜日

画像のラベリング

画像のラベリングのサンプル。

画像のラベリングのスタンダードな手法は 2 つある。

1. 再帰処理


2. 接続表


1. は注目画素から探索範囲を膨張して、背景画素や探索範囲の境界に到達したら収束させる処理を、全ての画素に対して行う。
背景画素が少ない場合の探索では、画素×画素程度の計算量が必要になりそう。


2. は探索は全画素数の2~3倍程度で良さそう。1回目は、注目画素が抽出した物体画素だった場合に、4または8近傍を探索して、ラベル付けされていなければ ラベル番号n +1を振り、ラベル付けされていれば ラベル番号nを振る処理をラスター処理する。
2回目は、各画素の4または8近傍に対し、自分自身のラベルnよりも小さいラベルmが降られているか、振られていれば、nをすべて、小さいラベルmに置き換える。この処理をラスター処理する。
最後は、ラベルを小さい方から順に詰める処理をラベルの中で行う。


以下、コード。

2013年8月13日火曜日

2013年8月4日日曜日

Kinect 距離による表示フィルター RGBと距離カメラの位置補正を含む

距離カメラの情報が1次元データなので、RGBカメラ座標に変換するときに少し工夫する。


Kinectアプリケーションビルド時の注意点

Kinectアプリケーションは、x86アプリなのか、x64アプリなのか、明確にした上で環境設定を行うこと。

そうしないと、以下のエラーでビルドに失敗する。

fatal error LNK1112: モジュールのコンピューターの種類 ‘X64′ は対象コンピューターの種類 ‘x86′ と競合しています。

これは、x86のアプリで、x64のライブラリを使おうとする場合におこる。
逆の場合もありえる。
C++のWin32コンソールアプリを選んだ場合、KinectとOpenCVのライブラリを x86 で統一しておくと安全。

Kinect Basic Sample 01 RGB Camera View

Kinectを使って身体の研究をするプロジェクトの第一弾。 最も簡単なSample。 RGBカメラの表示。

2013年7月3日水曜日

EXEファイルの仕組み

EXEファイルの構造

MZヘッダー、PEヘッダー、セクションヘッダー からなる。

  1. MZヘッダー:DOSヘッダー
  2. MZヘッダー:MS-DOS用スタブ
  3. PEヘッダー:シグネチャ
  4. PEヘッダー:ファイルヘッダー
  5. PEヘッダー:オプションヘッダー
  6. セクションデータ:セクションヘッダー1
  7. セクションデータ:セクションヘッダー2
  8. セクションデータ:…
  9. セクションデータ:セクション1
  10. セクションデータ:セクション2
  11. セクションデータ:…

DOSヘッダー

先頭はMZ。


MS-DOS用スタブ

This program cannot be run in DOS mode. を表示するプログラム


PEヘッダー

PEという2文字と2byte分の0からなるシグネチャが先頭。


セクションデータ

Windowsプログラム本体。いくつかのコード(命令)やデータのまとまり(セクション)に分けられている。
各セクションヘッダーの並びの後に、セクション本体が並ぶ。



EXEファイルの内容をダンプする


ダンプツール:dumpbin.exe → MZヘッダーを読み飛ばす。

以下のダンプ出力コードで、exeを作成すれば、すべて閲覧できる。



%02Xは16進数を表す%xに02: 最低2文字出力し、足りなければ 0 で埋める。と X: 大文字で表記を追加した書き方。
%08Xであれば、最低8文字で足りなければ0で、大文字表記。


上記をコンパイル&リンクすれば、良い。

cl dump.c
上記で作成した dump.exe でMZ(4D 5A)ヘッダも確認できる。 50 45 00 00 はPEヘッダー。


このダンププログラムは exe だけに使えるわけではなく、txt ファイルなどにももちろん使える。

たとえばある文字列が exe のヘッダに含まれていることを確認したければ、txt ファイルに文字列を
記述して dump した文字列が、exe のdump結果に含まれているか見ればよい。


PEヘッダーとセクションデータの内容

dumpbin /[オプション] EXEファイル名

FILE HEADER VALUES の number of sections の個数分、section ヘッダー があることを確認できる。

プログラム中に分散したコードやデータは、コードのセクションとデータのセクションにまとめれていることも確認できる。


セクションの内容を見る

dumpbin /rawdata EXEファイル名
RAW DATAのナンバーが、セクションナンバーの数だけある。


逆アセンブル

コマンド: dissm

dumpbin /disasm EXEファイル名

push や mov、call などから、callが関数、pushがそれに渡す引数のように使われていることがわかる。


簡単なプログラムを書いて、コンパイラがどのようにコードを整理するのか確認してみると
おもしろい

次は メモリーロード。






2013年6月30日日曜日

CPPを本格的に始める

データ型を重視した言語。

基本データ型



  1. int 整数型 4byte
  2. float 単精度浮動小数点型 4byte
  3. double 倍精度浮動小数点型 8byte
  4. char 文字型 1byte

コンパイルツール:cl


ex)
cl /c HelloWorld.c

/cはコンパイルのみ行うオプション。自動リンクを行わない。

リンカー:link 


書式:link オブジェクトファイル1 2 … N /OUT:EXEファイル名

プログラムの実行に必要なオブジェクトファイルが指定されていないと、以下のようにエラーとなる。

ex)
HelloWorld.obj : error LNK2019: 未解決の外部シンボル _printf が関数 _main で参照
されました。
LINK : error LNK2001: 外部シンボル "_mainCRTStartup" は未解決です。
HelloWorld.exe : fatal error LNK1120: 2 件の未解決の外部参照


objのシンボルテーブルを確認すると、何が足りないのか発見できる。


オブジェクトファイルの内容確認:dumpbin


ex)
dumpbin HelloWorld.obj /SYMBOLS

COFF SYMBOL TABLE
000 00CEEB9B ABS    notype       Static       | @comp.id
001 80000191 ABS    notype       Static       | @feat.00
002 00000000 SECT1  notype       Static       | .drectve
    Section length   2F, #relocs    0, #linenums    0, checksum
004 00000000 SECT2  notype       Static       | .debug$S
    Section length   68, #relocs    0, #linenums    0, checksum
006 00000000 SECT3  notype       Static       | .data
    Section length    D, #relocs    0, #linenums    0, checksum 9806FD4
008 00000000 SECT3  notype       Static       | $SG2940
009 00000000 SECT4  notype       Static       | .text
    Section length   14, #relocs    2, #linenums    0, checksum F829D91
00B 00000000 UNDEF  notype ()    External     | _printf
00C 00000000 SECT4  notype ()    External     | _main

上の_printfがUNDEFになっている。これが発見できなかったシンボル。


EXEファイルのスタートアップルーチン

スタートアップルーチン:_mainCRTStartup
EXEファイルの実行開始位置。main関数の呼び出し元。

以下で内容を確認できる。

C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\crt\src\crt0.c

この中で、_mainCRTStartupが__mainCRTStartupを呼び出し、_tmainを呼び出していることがわかる。引数は、mainの引数と同じ、引数の個数、コマンドライン引数の配列、環境変数の配列


規定のライブラリリンク

C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\lib\libcmt.lib
安全のために、上記libを任意のディレクトリにコピーしたあと、下記を実行すると、temp.txtにデフォルトオブジェクトの一覧を記述できる。

lib libcmt.lib /LIST:temp.txt
この中に、printf.objなどの普段何気なく使用するシンボルが並んでいる。

このようにlinkし、エラーとなったオブジェクトをlinkに加えと繰り返すことでリンクを完了させることができる。


次はEXEファイルの構成。


2013年5月11日土曜日

JNI JavaからCppを実行する


JNI Javaからcppを呼び出してみる。

■まずはJavaでコード書きます
https://gist.github.com/masazdream/5560075


■対応するCppファイルを書きます
https://gist.github.com/masazdream/5560082


※Javaのコードとの名称対応は大切です。


■JavaとCppのコードから必要なヘッダファイルとSharedObjectを作成します
そのために今回はantを使用しますので、antからgccコンパイルする環境を作成します。

・ant-contribのバイナリをantのlibに配置
http://sourceforge.net/projects/ant-contrib/files/

・ant-xercesのバイナリを取得して、antoのlibに配置

http://xerces.apache.org/mirrors.cgi

・ant-cpptasksを作成する。
http://sourceforge.net/projects/ant-contrib/files/ant-contrib/cpptasks-1.0-beta5/


デフォルトでついてくるbuild.xmlに以下の対策を施して、実行するとjarが作成出来ます。
■対策
①javacタグにincludeAntRuntime="true"を設定します。
②ソースをコンパイルするJavaのバージョンに注意しないと警告が
うるさいので処理します。
A. java.sourceとjavac.targetには、コンパイルするJavaのバージョンを
設定しましょう。
B. jt.jarのパスを表すpathを作成して、javacのbootclasspathに指定します。
<path id="compile.boot.path">
  <fileset dir="${java.home}/lib">
    <include name="rt.jar" />
  </fileset>
</path>
<javac ・・・
  <bootclasspath refid="compile.boot.path" />
</javac>

■必要なパスを通す
③xercesのライブラリをクラスパスに追加する
<path id="compile.path">
  <fileset dir="[最初のステップでjarを置いたディレクトリ]">
    <include name="*.jar" />
  </fileset>
</path>
<javac ・・・
  <classpath refid="compile.path" />
</javac>

これでコンパイル出来ます。
target/lib/cpptasks.jarがあるので、ant本体のlibディレクトリに
コピーします。

> echo $ANT_HOME

でhomeを確認が出来たら、配下のlibにコピーします。

■antの記述を整えます。
javahでヘッダーファイル作成を記述します。
ccタスクでcppファイルをコンパイルします。

<taskdef resource="cpptasks.tasks">でccタスクを使用する準備が出来ますので、
以下のようにccタスクを記述します。

<cc link="shared" outfile="[soを出力するディレクトリ名]/[クラス名]" obj="[ヘッダーファイルを出力したディレクトリ]">
  <includepath location="${env.JAVA_HOME}/include}" />
  <includepath location="${env.JAVA_HOME}/include/linux" />
  <fileset dir="[ヘッダーファイルを出力したディレクトリ]" includes="HelloWorldJNI.cpp" />
  <libset libs="stdc++">  ←cppの場合は指定。CとCPPが混じっている場合には、cppファイルのみにantで実行出来ます。
</cc>

※outfileに指定したパスのファイル名をつかって、libhello.soなどの名前が決定されます。

最終的に以下の様なファイルになる。https://gist.github.com/masazdream/5560085


■Javaの実行
soファイルの入ったディレクトリを環境変数「LD_LIBRARY_PATH」に指定してから実行します。

実行結果は、Hello World。
せっかくなのでcやcppで記述したファイルをドンドンJavaで実行していましょう。