У меня возникают трудности с чтением изображения, извлечением функций для обучения и тестированием новых изображений в OpenCV с использованием SVM. Может кто-нибудь, пожалуйста, укажите мне отличную ссылку? Я посмотрел на OpenCV Введение в опорные векторные машины. Но это не помогает с чтением в изображениях, и я не уверен, как включить это.
Мои цели — классифицировать пиксели в изображении. Эти пиксели будут принадлежать кривым. Я понимаю формирование тренировочной матрицы (например,
изображение А
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} принадлежат кривой, а остальные нет.
Мне пришлось столкнуться с этим недавно, и вот что я в итоге сделал, чтобы заставить SVM работать с изображениями.
Чтобы обучить свой SVM на наборе изображений, сначала вы должны построить матрицу обучения для SVM. Эта матрица указывается следующим образом: каждая строка матрицы соответствует одному изображению, а каждый элемент в этой строке соответствует одному признаку класса — в этом случае цвет пикселя в определенной точке. Поскольку ваши изображения 2D, вам нужно будет преобразовать их в 1D матрицу. Длина каждой строки будет соответствовать площади изображений (обратите внимание, что изображения должны быть одинакового размера).
Допустим, вы хотели обучить SVM на 5 разных изображениях, и каждое изображение было размером 4х3 пикселя. Сначала вам нужно будет инициализировать тренировочную матрицу. Количество строк в матрице будет 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
с данными из каждого изображения. Ниже приведен пример того, как это отображение будет работать для одной строки.
Я пронумеровал каждый элемент матрицы изображения, указав, куда он должен идти в соответствующей строке в обучающей матрице. Например, если бы это было третье изображение, это была бы третья строка в обучающей матрице.
Вы должны были бы пройтись по каждому изображению и соответственно установить значение в выходной матрице. Вот пример для нескольких изображений:
Что касается того, как вы будете делать это в коде, вы можете использовать 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-я строка в обучающей матрице находится в классе «без глаз». Вы можете установить эти значения в цикле, где вы оцениваете каждое изображение. Одна вещь, которую вы могли бы сделать, это отсортировать обучающие данные в отдельные каталоги для каждого класса, пройтись по изображениям в каждом каталоге и установить метки на основе каталога.
Следующее, что нужно сделать, это настроить параметры 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, на основе приведенного выше примера для моего глаза / глаза). В качестве альтернативы, если вы хотите проверить более одного изображения за раз, вы можете создать матрицу, которая имеет тот же формат, что и обучающая матрица, определенная ранее, и передать ее в качестве аргумента. Однако возвращаемое значение будет другим.
Удачи!
Других решений пока нет …