私は最近これに対処しなければなりませんでした.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 つの行に対してどのように機能するかの例です。
画像マトリックスの各要素に番号を付け、トレーニングマトリックスの対応する行に配置する必要があります。たとえば、それが 3 番目の画像である場合、これはトレーニング マトリックスの 3 番目の行になります。
各画像をループして、それに応じて出力行列に値を設定する必要があります。複数の画像の例を次に示します。
コードでこれを行う方法については、 を使用できますが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)。または、一度に複数の画像をテストする場合は、前に定義したトレーニング マトリックスと同じ形式のマトリックスを作成し、それを引数として渡すことができます。ただし、戻り値は異なります。
幸運を!