web-dev-qa-db-ja.com

OpenCVとSVMを画像とともに使用する

SVMを使用してOpenCVで画像を読み取り、トレーニング用の機能を抽出し、新しい画像をテストするのが困難です。誰かが私に素晴らしいリンクを教えてくれますか? OpenCVイントロダクションサポートベクターマシン を見ました。しかし、それは画像を読むのに役立ちません、そして、私はそれをどのように組み込むのかわかりません。


私の目標は、画像内のピクセルを分類することです。これらのピクセルは曲線に属します。トレーニングマトリックスの形成を理解しています(たとえば、イメージA 1,1 1,2 1,3 1,4 1,5 2,1 2,2 2,3 2,4 2,5 3,1 3,2 3 3 3,4 3,5

トレーニング行列を[3] [2] = {{1,1} {1,2} {1,3} {1,4} {1,5} {2,1} .. {}として形成します}

しかし、私はラベルについて少し混乱しています。私の理解から、トレーニング行列のどの行(画像)が対応するかを指定する必要があります。これは曲線または非曲線に対応します。しかし、曲線に属するピクセルと曲線に属さないピクセルがある場合、どのようにトレーニング行列の行(画像)にラベルを付けることができますか?たとえば、私のトレーニングマトリックスは[3] [2] = {{1,1} {1,2} {1,3} {1,4} {1,5} {2,1} .. {}} 、ピクセル{1,1}および{1,4}は曲線に属しますが、残りは属しません。

63
Carnez Davis

私は最近これに対処しなければなりませんでしたが、これがSVMを画像で動作させるためにやったことです。

画像セットでSVMをトレーニングするには、まずSVMのトレーニングマトリックスを作成する必要があります。このマトリックスは次のように指定されます:マトリックスの各行は1つの画像に対応し、その行の各要素はクラスの1つの機能(この場合は特定のポイントでのピクセルの色)に対応します。画像は2Dであるため、1Dマトリックスに変換する必要があります。各行の長さは、画像の面積になります(画像は同じサイズでなければなりません)。

5つの異なる画像でSVMをトレーニングしたいとしましょう。各画像は4x3ピクセルでした。まず、トレーニングマトリックスを初期化する必要があります。マトリックスの行数は5、列数は画像の面積、4 * 3 = 12です。

_int num_files = 5;
int img_area = 4*3;
Mat training_mat(num_files,img_area,CV_32FC1);
_

理想的には、_num_files_と_img_area_はハードコードされず、ディレクトリをループして画像の数をカウントし、画像の実際の領域を取得することで取得されます。

次のステップでは、_training_mat_の行に各画像のデータを「入力」します。以下は、このマッピングが1つの行に対してどのように機能するかの例です。

Convert 2D image matrix to 1D matrix

トレーニングマトリックスの対応する行のどこに画像マトリックスの各要素を番号付けしました。たとえば、それが3番目の画像である場合、これはトレーニングマトリックスの3番目の行になります。

各画像をループし、それに応じて出力マトリックスに値を設定する必要があります。複数の画像の例を次に示します。

Training matrix with multiple images

コードでこれを行う方法については、 reshape() を使用できますが、行列が連続していないために問題が発生しました。私の経験では、次のようなことをしました。

_Mat img_mat = imread(imgname,0); // I used 0 for greyscale
int ii = 0; // Current column in training_mat
for (int i = 0; i<img_mat.rows; i++) {
    for (int j = 0; j < img_mat.cols; j++) {
        training_mat.at<float>(file_num,ii++) = img_mat.at<uchar>(i,j);
    }
}
_

すべてのトレーニングイメージに対してこれを行います(_file_num_をインクリメントすることを忘れないでください)。この後、トレーニングマトリックスを適切に設定して、SVM関数に渡す必要があります。残りの手順は、オンラインの例と非常によく似ているはずです。

これを行う間、トレーニング画像ごとにラベルを設定する必要があることに注意してください。たとえば、画像に基づいて目と目を分類する場合、トレーニングマトリックスのどの行が目と目以外に対応するかを指定する必要があります。これは1Dマトリックスとして指定され、1Dマトリックスの各要素は2Dマトリックスの各行に対応します。各クラスの値を選択し(例:目以外の場合は-1、目については1)、ラベルマトリックスに設定します。

_Mat labels(num_files,1,CV_32FC1);
_

したがって、このlabelsマトリックスの3番目の要素が-1だった場合、トレーニングマトリックスの3番目の行が「非目」クラスにあることを意味します。これらの値は、各画像を評価するループで設定できます。できることの1つは、トレーニングデータをクラスごとに個別のディレクトリに並べ替え、各ディレクトリ内の画像をループし、ディレクトリに基づいてラベルを設定することです。

次に行うことは、SVMパラメータを設定することです。これらの値はプロジェクトによって異なりますが、基本的にはCvSVMParamsオブジェクトを宣言して値を設定します。

_CvSVMParams params;
params.svm_type = CvSVM::C_SVC;
params.kernel_type = CvSVM::POLY;
params.gamma = 3;
// ...etc
_

質問で投稿したリンクのように、これらのパラメーターを設定する方法に関するオンラインの例がいくつかあります。

次に、CvSVMオブジェクトを作成し、データに基づいてトレーニングします!

_CvSVM svm;
svm.train(training_mat, labels, Mat(), Mat(), params);
_

持っているデータの量によっては、これには長い時間がかかる場合があります。ただし、トレーニングが完了したら、トレーニング済みのSVMを保存して、毎回再トレーニングする必要がなくなります。

_svm.save("svm_filename"); // saving
svm.load("svm_filename"); // loading
_

トレーニング済みのSVMを使用して画像をテストするには、画像を読み取って1Dマトリックスに変換し、svm.predict()に渡します。

_svm.predict(img_mat_1d);
_

ラベルとして設定したものに基づいて値を返します(上記の私の目/目以外の例に基づいて-1または1)。または、一度に複数の画像をテストする場合は、前に定義したトレーニングマトリックスと同じ形式のマトリックスを作成し、それを引数として渡すことができます。ただし、戻り値は異なります。

幸運を!

216
Walfie