OpenCVで顔検出


ここからは、これまでの知識を踏まえ、顔認識を行うコードを書き始めていく。
ただし、「画像処理」とは違い、基本的に顔検出に対する流れを紹介するのみで、解説そのものはあまり行わない。

1.静止画からの検出

まずは、読み込んだ静止画から顔の位置情報を検出し、そこに矩形描画を行うプログラムを作成する。

以下のソースコードはこれまでの基本的な流れの中に「検出器の読み込み」「検出」「検出位置に描画」のプロセスを加えたものである。
また、今回も解説都合上、エラー処理などは一切省いているので、そこは了承願いたい。

静止画からの顔認識プログラム

#include "cv.h"
#include "highgui.h"
// 顔検出(静止画)
int main(int argc, char* argv[]) {
	// 顔検出対象の画像データ用
	IplImage* tarImg;

	// 検出対象の画像ファイルパス
	char tarFilePath[] = "lena.jpg";

	// 画像データの読み込み
	tarImg = cvLoadImage(tarFilePath, CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);

	// 正面顔検出器の読み込み
	CvHaarClassifierCascade* cvHCC = (CvHaarClassifierCascade*)cvLoad("haarcascade_frontalface_default.xml");

	// 検出に必要なメモリストレージを用意する
	CvMemStorage* cvMStr = cvCreateMemStorage(0);

	// 検出情報を受け取るためのシーケンスを用意する
	CvSeq* face;

	// 画像中から検出対象の情報を取得する
	face = cvHaarDetectObjects(tarImg, cvHCC, cvMStr);

	for (int i = 0; i < face->total; i++) {
		検出情報から顔の位置情報を取得
		CvRect* faceRect = (CvRect*)cvGetSeqElem(face, i);

		// 取得した顔の位置情報に基づき、矩形描画を行う
		cvRectangle(tarImg,
			cvPoint(faceRect->x, faceRect->y),
			cvPoint(faceRect->x + faceRect->width, faceRect->y + faceRect->height),
			CV_RGB(255, 0 ,0),
			3, CV_AA);
	}

	// 顔位置に矩形描画を施した画像を表示
	cvNamedWindow("face_detect");
	cvShowImage("face_detect", tarImg);

	// キー入力待ち
	cvWaitKey(0);

	// ウィンドウの破棄
	cvDestroyWindow("face_detect");

	// 用意したメモリストレージを解放
	cvReleaseMemStorage(&cvMStr);

	// カスケード識別器の解放
	cvReleaseHaarClassifierCascade(&cvHCC);
	
	// イメージの解放
	cvReleaseImage(&tarImg);

	return 0;
}

実行結果

顔検出の実行結果

今回も対象はおなじみの「lena」を利用した。顔の位置に赤い矩形描画が行われていることが確認できる。

まず、顔認識をして検出させるための前準備として、検出器の読み込みが必要となる。

オブジェクト検出について - リファレンス

オブジェクト検出を行う方法は様々なものが存在するが、このOpenCVにおいては「Haar-like 特徴」を用いた物体検出を利用する。

ここで基本的な、オブジェクト検出について話をする。オブジェクトを認識するには、まず「検出対象はどのようなものなのか」という情報が必要となる。そもそもコンピュータにとって、画像データは所詮データの羅列に過ぎず、それが何を構成しているかということは知る由もない。我々は、その画像データが「どうのような構成になっているか」ということを脳内で構築し「それがいったい何であるか」という判断を下す。つまり画像データを見ることで「車」という記憶と一致すれば、その画像が「車」であると認識する、という具合である。

このことをコンピュータに、よく似たプロセルを踏ませることで「この画像内で検出すべきものはどれか」ということを認識させる必要がある。つまり、事前にしろ動的にしろ「検出するものは何か」という学習とその学習情報の蓄積が必要となるわけだ。その学習情報が詳しければ詳しいほど、検出精度は向上していく。例えば、学習程度が弱ければ、検出したいオブジェクトどころか似たようなものまで検出対象としてしまうが、精度が高ければ似通ったオブジェクトでも正しく切り分けが可能で、少し何か違うオブジェクトの影に隠れたりしたとしても、そこに「対象オブジェクト」が存在している、と認識することができるようになる。

ここで今回のHaar-like 特徴を用いた物体検出について話を戻す。
Haar-like 特徴の細かな解説はリファレンスを参照願いたいが、「Haar-like 特徴」を利用したオブジェクト検出を行う際には、対象範囲(今回で言えばlena.jpg)から、どのようなオブジェクトを検出するかを計算するために必要な「分類器」が必要である。「分類器」は言わば「検出対象について学習した情報」から、対象が「正であるか否であるか」を見極めるためのもので、その分類器情報を集めたものが「検出器」であり、サンプルなどでも利用してきたXMLファイルである。今回のサンプルコードでいうところの「haarcascade_frontalface_default.xml」がそれにあたる。
つまり、これらが今回のHaar-like特徴を使った検知に必要な「事前に用意された学習情報の蓄積」にあたる。

cvLoad() - リファレンス

検出器を読み込むには、OpenCVで扱われているデータを読み込むのに最適な「cvLoad()」を利用することができる。

void* cvLoad( const char* filename, CvMemStorage* memstorage = NULL, const char* name = NULL, const char* real_name = NULL );

cvLoadは、「対象ファイルパス」「動的構造体のためのメモリストレージ」「オブジェクト名」「読み込まれたオブジェクトの名前が代入される出力パラメータ」を引数に取る。
ただし、検出器の読み込みに必要なのは対象ファイルパスの引数だけなので、ここで第2〜第4の引数については説明を割愛する。

「対象ファイルパス」は、顔認識のサンプルでも取り扱った「haarcascade_frontalface_default.xml」である。このファイルを読み込み、その戻り値を「CvHaarClassifierCascade」でキャストすることで、正面顔を学習させたカスケード検出器とそのパラメータを受け取ることができる。

cvHaarDetectObjects() - リファレンス

画像中のオブジェクトを検出するには「cvHaarDetectObjects()」を使用する。

CvSeq* cvHaarDetectObjects( const CvArr* image, CvHaarClassifierCascade* cascade, CvMemStorage* storage, double scale_factor = 1.1, int min_neighbors = 3, int flags = 0, CvSize min_size = cvSize(0,0) );

cvHaarDetectObjectsは、「対象画像」「使用する検出器」「オブジェクト候補の矩形情報を出力するためのメモリストレージ」「スキャン毎に探索ウィンドウがスケーリングされる際のスケールファクタ」「オブジェクトを構成する近傍矩形の最小数」「処理モード」「最小ウィンドウサイズ」を引数に取る。
ただし、今回の検出では前三つの引数のみを扱い、ここで第4〜第7の引数については説明を割愛する。

「対象ファイルパス」は、今回もOpenCVのサンプルフォルダにある「lena.jpg」である。

「使用する検出器」は先に読み込んでおいた「CvHaarClassifierCascade」を指定する。

「オブジェクト候補の矩形情報を出力するためのメモリストレージ」は、動的構造体のデータ「CvMemStorage」のポインタを引数にとる。今回のデータは動的構造体のデータなので、先に「CvMemStorage」を「cvCreateMemStorage()」で生成しておき、そのポインタを渡している。このようなシーケンスや輪郭、グラフなどの動的構造体を読み込む場合は、今回と同様に事前にCvMemStorageを生成しておき、出力先メモリストレージとして指定する。

「スキャン毎に探索ウィンドウがスケーリングされる際のスケールファクタ」「オブジェクトを構成する近傍矩形の最小数」「処理モード」「最小ウィンドウサイズ」に関しては、今回検出対象となるデータとその入力方法、そして出力方法を加味した上で値を決定する。それぞれリファレンスを良く読むほか、別のサイトなどで情報を集めることをお奨めする。
例えば今回のサンプルコードでは静止画に対して行うため、リアルタイムな処理速度を必要とせず、どちらかといえば一度の検出精度を高めたい為、第4〜第7引数を指定していない。これにより設定は「デフォルト」で動作することになる。

検出結果として、cvHaarDetectObjects()は、検出したオブジェクトの矩形領域情報をシーケンス(列情報)として返す。
そのシーケンスを使うことで、検出されたオブジェクトの矩形情報に対し、ループで一つ一つ処理していくことができる。

cvGetSeqElem() - リファレンス

取得した矩形情報のシーケンスから、1つの要素を取得するために「cvGetSeqElem()」を利用することができる。

char* cvGetSeqElem( const CvSeq* seq, int index );

cvGetSeqElemは、「対象シーケンス」「インデックス値」を引数に取る。

「対象シーケンス」は、先に検出したオブジェクトの矩形情報であるシーケンスを指定する。

「インデックス値」に関しては、全てのシーケンス要素を取り出して処理する(検出された顔に対して全て処理する)ので、ループのカウンタを指定している。

cvGetSeqElemから取り出した要素のポインタを「CvRect」で受け取ることで、顔の位置情報を扱うことができるようになる。CvRectには検出元の画像に対しての「x座標」「y座標」「高さ」「幅」の情報が存在している。

その後、この取得した矩形情報を用いて、対象画像に対して矩形描画を行うことができる「cvRectangle()」を使い、実際に赤い矩形描画を施したデータを作成している。

cvReleaseMemStorage() - リファレンス

生成したメモリストレージを解放する場合には「cvReleaseMemStorage()」を使用する。

void cvReleaseMemStorage( CvMemStorage** storage );

cvReleaseMemStorageは「解放対象のメモリストレージ」を引数に取る。

cvReleaseHaarClassifierCascade() - リファレンス

読み込んだ検出器を解放する場合には「cvReleaseHaarClassifierCascade()」を使用する。

void cvReleaseHaarClassifierCascade( CvHaarClassifierCascade** storage );

cvReleaseHaarClassifierCascadeは「解放対象の検出器」を引数に取る。

2.カメラ映像からの検出

カメラ映像からの検出、というといろいろと面倒なことがありそうだが、最終的にはカメラからのキャプチャに対して、顔検出を実行することになるため、顔検出の処理自体は先ほどの「静止画からの顔認識プログラム」とほぼ同内容である。
どちらかといえば、ここではOpenCV単独でのカメラキャプチャの方法についてのサンプルコードと言えるので、カメラキャプチャの利用方法のみを紹介してゆくこととする。

カメラ映像からの顔認識プログラム

#include "cv.h"
#include "highgui.h"
// 顔検出(動画)
int main(int argc, char* argv[]) {

	// ビデオキャプチャ構造体
	CvCapture *capture = 0;
	// フレーム単位データ
	IplImage *frame = 0;
	// 縦横サイズ
	double height = 240;
	double width = 320;
	// 入力キー受け付け用
	int c;
	
	// 正面顔検出器の読み込み
	CvHaarClassifierCascade* cvHCC = (CvHaarClassifierCascade*)cvLoad("haarcascade_frontalface_default.xml");

	// 検出に必要なメモリストレージを用意する
	CvMemStorage* cvMStr = cvCreateMemStorage(0);

	// 検出情報を受け取るためのシーケンスを用意する
	CvSeq* face;
	
	// 0番号のカメラに対するキャプチャ構造体を生成するる
	capture = cvCreateCameraCapture (0);
	
	// キャプチャのサイズを設定する。ただし、この設定はキャプチャを行うカメラに依存するので注意る
	cvSetCaptureProperty (capture, CV_CAP_PROP_FRAME_WIDTH, width);
	cvSetCaptureProperty (capture, CV_CAP_PROP_FRAME_HEIGHT, height);
	cvNamedWindow ("capture_face_detect", CV_WINDOW_AUTOSIZE);
	
	// 停止キーが押されるまでカメラキャプチャを続ける
	while (1) {
		frame = cvQueryFrame (capture);

		// 画像中から検出対象の情報を取得する
		face = cvHaarDetectObjects(frame, cvHCC, cvMStr);

		for (int i = 0; i < face->total; i++) {
			// 検出情報から顔の位置情報を取得
			CvRect* faceRect = (CvRect*)cvGetSeqElem(face, i);

			// 取得した顔の位置情報に基づき、矩形描画を行う
			cvRectangle(frame,
				cvPoint(faceRect->x, faceRect->y),
				cvPoint(faceRect->x + faceRect->width, faceRect->y + faceRect->height),
				CV_RGB(255, 0 ,0),
				3, CV_AA);
		}

		// 顔位置に矩形描画を施した画像を表示
		cvShowImage ("capture_face_detect", frame);

		// 終了キー入力待ち(タイムアウト付き)
		c = cvWaitKey (10);
		if (c == 'e') {
			break;
		}
	}

	// 生成したメモリストレージを解放
	cvReleaseMemStorage(&cvMStr);

	// キャプチャの解放
	cvReleaseCapture (&capture);
	
	// ウィンドウの破棄
	cvDestroyWindow("capture_face_detect");

	// カスケード識別器の解放
	cvReleaseHaarClassifierCascade(&cvHCC);
	
	return 0;
}

カメラキャプチャだけに焦点を当てると「CvCapture」「cvCreateCameraCapture()」「cvSetCaptureProperty()」「cvQueryFrame()」「cvReleaseCapture()」が新しく登場したものである。

処理の流れとして「キャプチャを扱うための構造体」を生成し、それに設定を行い、実際にキャプチャフレームを取得する。処理を終了する際に、生成したキャプチャを扱うための構造体を解放する、という具合である。
ソースを見てみると、前回の「静止画からの認識」の画像取得部分が、そのままキャプチャ処理に入れ替わっているだけであることが分かる。異なる点は、キャプチャは連続した静止画解析とみなして、ループ処理の内側で検出処理が行われるところぐらいである。

しかしながら、上記のサンプルコードを実行しても、あまりに処理が重かったり、うまく認識できない人が多いであろうと予測される。先に行ったとおり、これはあくまで静止画での認識をそのままキャプチャ用に流用しただけのため、リアルタイム処理を扱わせるにはコストが高いのである。

つまるところ動画用に「検出処理をもっと効率よく行う」必要がある。
そこで基本的で且つ簡単な対処方法を2つ紹介する。それが「グレースケール+ダウンスケール」と「cvHaarDetectObjects()へのパラメータ調整」である。

「グレースケール+ダウンスケール」は、検出の対象となる画像データから極力余分なデータを無くし、且つ少ない手順で済むように、検出対象の画像に手を加える方法である。もともと、この顔検出の検知器にとって「色情報」は重要な情報ではなく、グレースケールであれば問題なく特徴情報を取得できる。また、学習を行う際には、入力される画像よりももっと小さなスケールでの学習が行われているため、あまり大きな画像データも必要としない。よって、カメラからキャプチャした画像データをグレースケール化し、サイズを縮小することで、検知速度を向上させることができるのだ。これを行うだけでも、目に見えて処理速度が向上を実感できる上に、認識精度にも影響を見ることができる。

次に有効なのが「cvHaarDetectObjects()へのパラメータ調整」である。むしろ極端に処理が遅い場合などは、こちらのパラメータを調整することで、劇的な効果を得ることができることがある。特に注目してもらいたいのが、後半4つのパラメータ「スキャン毎に探索ウィンドウがスケーリングされる際のスケールファクタ」「オブジェクトを構成する近傍矩形の最小数」「処理モード」「最小ウィンドウサイズ」で、中でも認識精度なら「オブジェクトを構成する近傍矩形の最小数」、処理速度なら「最小ウィンドウサイズ」を見直すと良い。無論、他の2つの影響も大きいので、そこは適当な調整が必要となる。

そして、上記の速度向上を行ったソースコードが以下である。

カメラ映像からの顔認識プログラム(速度向上版)

#include "cv.h"
#include "highgui.h"

#define SCALE 1.3

// 顔検出(動画)
int main(int argc, char* argv[]) {

	// ビデオキャプチャ構造体
	CvCapture *capture = 0;
	// フレーム単位データ
	IplImage *frame = 0;
	// フレーム単位データコピー用
	IplImage *frame_copy = 0;
	// 縦横サイズ
	double height = 240;
	double width = 320;
	// 入力キー受け付け用
	int c;
	
	// 正面顔検出器の読み込み
	CvHaarClassifierCascade* cvHCC = (CvHaarClassifierCascade*)cvLoad("haarcascade_frontalface_default.xml");

	// 検出に必要なメモリストレージを用意する
	CvMemStorage* cvMStr = cvCreateMemStorage(0);

	// 検出情報を受け取るためのシーケンスを用意する
	CvSeq* face;
	
	// 0番号のカメラに対するキャプチャ構造体を生成するる
	capture = cvCreateCameraCapture (0);
	
	// キャプチャのサイズを設定する。ただし、この設定はキャプチャを行うカメラに依存するので注意る
	cvSetCaptureProperty (capture, CV_CAP_PROP_FRAME_WIDTH, width);
	cvSetCaptureProperty (capture, CV_CAP_PROP_FRAME_HEIGHT, height);
	cvNamedWindow ("capture_face_detect", CV_WINDOW_AUTOSIZE);
	
	// 停止キーが押されるまでカメラキャプチャを続ける
	while (1) {
		frame = cvQueryFrame (capture);

		// フレームコピー用イメージ生成
		frame_copy = cvCreateImage(cvSize(frame->width, frame->height), IPL_DEPTH_8U, frame->nChannels);
		if(frame->origin == IPL_ORIGIN_TL) {
			cvCopy(frame, frame_copy);
		} else {
			cvFlip(frame, frame_copy);
		}

		// 読み込んだ画像のグレースケール化、及びヒストグラムの均一化を行う
		IplImage* gray = cvCreateImage(cvSize(frame_copy->width, frame_copy->height), IPL_DEPTH_8U, 1);
		IplImage* detect_frame = cvCreateImage(cvSize((frame_copy->width / SCALE), (frame_copy->height / SCALE)), IPL_DEPTH_8U, 1);
		cvCvtColor(frame_copy, gray, CV_BGR2GRAY);
		cvResize(gray, detect_frame, CV_INTER_LINEAR);
		cvEqualizeHist(detect_frame, detect_frame);

		// 画像中から検出対象の情報を取得する
		face = cvHaarDetectObjects(detect_frame, cvHCC, cvMStr, 1.1, 2, CV_HAAR_DO_CANNY_PRUNING, cvSize(30, 30) );

		for (int i = 0; i < face->total; i++) {
			// 検出情報から顔の位置情報を取得
			CvRect* faceRect = (CvRect*)cvGetSeqElem(face, i);

			// 取得した顔の位置情報に基づき、矩形描画を行う
			cvRectangle(frame_copy,
				cvPoint(faceRect->x * SCALE, faceRect->y * SCALE),
				cvPoint((faceRect->x + faceRect->width) * SCALE, (faceRect->y + faceRect->height) * SCALE),
				CV_RGB(255, 0 ,0),
				3, CV_AA);
		}

		// 顔位置に矩形描画を施した画像を表示
		cvShowImage ("capture_face_detect", frame_copy);

		// 終了キー入力待ち(タイムアウト付き)
		c = cvWaitKey (10);
		if (c == 'e') {
			break;
		}
	}

	// 生成したメモリストレージを解放
	cvReleaseMemStorage(&cvMStr);

	// キャプチャの解放
	cvReleaseCapture (&capture);
	
	// ウィンドウの破棄
	cvDestroyWindow("capture_face_detect");

	// カスケード識別器の解放
	cvReleaseHaarClassifierCascade(&cvHCC);
	
	return 0;
}

ずいぶんと速度は改善されたであろうと思う。認識精度に関しては、実のところパラメータを弄るよりも、より学習練度の高い「検出器」を利用することが、もっとも効果的だと思われる。これまでは「haarcascade_frontalface_default.xml」を利用してきたが、顔認識のサンプルのときにも紹介したほかの検出器のXMLファイルを使ってみると、また違った結果を得られるだろう。

まとめ

以上が顔認識についてのサンプルコードである。もちろん、これらは「正面顔の検出器」を利用しているので「顔認識」になっていることは、理解していただけていると思う。例えば「全身の検出器」を使用すれば、ある程度のパラメータ調整は必要になっても、処理自体はまったく同じもので「全身認識」へと変更することが可能だ。

ここまで紹介してきた今回のオブジェクト認識のコード自体も、先の画像処理のコードを多く流用している。これは、もっとも基本的な流れさえ把握しておけば、様々な別の処理へと移行、変更していくことができることを証明している。

さらには、高機能でないにしてもOpenCV自体でカメラキャプチャを手軽に行えるところにも注目したい。カメラキャプチャは、OpenCVでなくとも問題ないが、先のコードにあったように、少ない手順ですぐに実現できる点が、敷居が低く有用だ。

このようにOpenCVは、ほとんど画像処理や動画処理・コンピュータヴィジョンに対しての知識がなくとも、色々な可能性を見出すことのできるライブラリであり、見出すだけでなく実際にコードを書き、実行可能なものを作成することのできる非常に「実感のしやすい楽しいもの」だと感じていただけると思う。

OpenCVで実現可能なことはまだまだ多様にある。また、ここでは紹介しきず、OpenCVそのものではないが、オブジェクト認識でも使用した「検出器」を自身で作成することもできる。OpenCVにはすでに「学習サンプルを多量に作るツール」「機械学習を行うツール」「検出器のパフォーマンスを測定するツール」などが付いてきており、例えば何かの「ロゴ」を認識するような検出器であれば、割と簡単に作成できるのだ。(ただし、学習や素材集めに時間はかかる)

また時間があれば、その点をまとめた情報をここに追加したいと思うが、今回はこれにてOpenCVの紹介を終える。
これらの情報が、これをご覧になった方のOpenCVへのさらなる興味への導入となることを願ってやまない。


参考資料

検出器の自作

オブジェクト認識に使用する「検出器」は自作することができる。その為に必要なツール群が、既定であれば以下に格納されている。

C:\Program Files\OpenCV\bin\
createsamples.exe ... 「学習サンプルを多量に作るツール」
haartraining.exe ... 「機械学習を行うツール」
performance.exe ... 「検出器のパフォーマンスを測定するツール」

学習方法については、また気が向いたときに書く予定だが、もう十分に他のサイトで有用な情報が見つかるので、それを参照すると良い。
ただし文中にも書いたが、少し精度の高い検出器を作ろうとするとかなりの労力と時間を要する点には注意。
例えば、筆者が実際に「とあるロゴ(h50 x w248)」を学習に使用したデータとコマンドを以下に記すので、何かの足しにして頂きたい。
表中の「正画」がポジティブイメージ、「否画」がネガティブイメージである。全て同じ「ロゴ」の学習によるものである。
今思えば、少々ネガティブイメージに使った画像データが良くなかったと思える。

学習データとコマンド
正画否画学習検出器の出来(抽象)使用コマンドサンプル
400014944時間ほどなかなかの精度 createsamples.exe -vec logo.vec -img logo.bmp -num 4000 -bgcolor 255 -h 25 -w 62 -show
haartraining.exe -data logo_3 -vec logo.vec -bg NGList_extFonts.txt -npos 4000 -nneg 1494 -mem 1024 -mode BASIC -h 25 -w 62
400014947時間かなり精度が低い createsamples.exe -vec logo.vec -img logo.bmp -num 4000 -bgcolor 255 -bgthresh 5 -h 25 -w 62 -randinv -show
haartraining.exe -data logo_40_15_1 -vec logo.vec -bg NGList_extFonts.txt -npos 4000 -nneg 1494 -mem 1024 -mode ALL -h 25 -w 62
10014941時間半ほどまあまあの精度 createsamples.exe -vec logo.vec -img logo.bmp -num 100 -bgcolor 255 -h 25 -w 62 -show
haartraining.exe -data logo_1_15_1 -vec logo.vec -bg NGList_extFonts.txt -npos 100 -nneg 1494 -mem 1024 -mode ALL -h 25 -w 62
400014942時間ほどほぼ使い物にならない createsamples.exe -vec logo.vec -img logo.bmp -num 4000 -bgcolor 255 -h 24 -w 24 -show
haartraining.exe -data logo_40_15_2424_ALL_1 -vec logo.vec -bg NGList_extFonts.txt -npos 4000 -nneg 1494 -mem 1024 -mode ALL -h 24 -w 24
400014941時間45分ほどほぼ使い物にならない createsamples.exe -vec logo.vec -img logo.bmp -num 4000 -bgcolor 255 -h 12 -w 31 -show
haartraining.exe -data link_logo_40_15_1231_ALL_1 -vec logo.vec -bg NGList_extFonts.txt -npos 4000 -nneg 1494 -mem 1024 -mode ALL -h 12 -w 31
101応答なし- createsamples.exe -vec logo.vec -img logo.bmp -num 10 -bgcolor 255 -h 25 -w 62 -show
haartraining.exe -data link_logo_01_001_2562_ALL_1 -vec logo.vec -bg NGList_small.txt -npos 10 -nneg 1 -mem 1024 -mode ALL -h 25 -w 62
1001992error(NGデータが悪い) createsamples.exe -vec sellalogo.vec -img logo.bmp -num 100 -bgcolor 255 -h 25 -w 62 -show
haartraining.exe -data serralink_logo_1_20_1 -vec sellalogo.vec -bg NGList_Full.txt -npos 100 -nneg 1992 -mem 1024 -mode ALL -h 25 -w 62
10016332時間ほど意味がないほど検知できない createsamples.exe -vec sellalogo.vec -img logo.bmp -num 100 -bgcolor 255 -h 25 -w 62 -show
haartraining.exe -data serralink_logo_1_16_1 -vec sellalogo.vec -bg NGList_Full.txt -npos 100 -nneg 1633 -mem 1024 -mode ALL -h 25 -w 62