OpenCVでSVMを使用して画像の読み取り、トレーニング用の特徴抽出、新しい画像のテストを行うのに苦労しています。誰か良いリンクを教えてもらえませんか?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} は曲線に属しますが、残りは属しません。
ベストアンサー1
最近、この問題に対処する必要があり、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);
したがって、このマトリックスの 3 番目の要素labels
が -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)。または、一度に複数の画像をテストする場合は、前に定義したトレーニング マトリックスと同じ形式のマトリックスを作成し、それを引数として渡すことができます。ただし、戻り値は異なります。
幸運を!