Как настроить CvSVM для классификации изображений в OpenCV и C++

Я разрабатываю систему распознавания рукописных символов с использованием OpenCV LibSVM. я извлек 14 признаков для вектора признаков, включая моменты Ху, аффинно-инвариантные моменты, количество углов и т. д. Для каждого символа я использую 5 образцов (для буквы «А», существует 5 типов А). Я знаю, что 5 сэмплов недостаточно, но на данный момент у меня есть только 5 сэмплов для каждого персонажа.

Я использую базовый пример LINEAR SVM из документации opencv. Моя проблема в том, могу ли я использовать этот пример документации как есть для своей цели. Я читал о системах OCR, которые используют многоклассовые SVM. Нужен ли мне такой многоклассовый SVM для моего приложения. Я не понимаю об этом. Пожалуйста, может кто-нибудь объяснить? Вот мой код.

у меня 180 образцов цифр и английских заглавных букв и на один образец приходится 14 признаков.

float labels[180][1] = {1.0, 2.0, 3.0, 4.0, 5.0, ,,,,, -> 180.0};
Mat matlabesls(180,1, CV_32FC1, labels);

Mat mattrainingDataMat(180, 14, CV_32FC1, ifarr_readtrainingdata);
CvSVMParams params;

params.svm_type    = CvSVM::C_SVC;
params.kernel_type = CvSVM::LINEAR;
params.term_crit   = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);

CvSVM SVM;
SVM.train(mattrainingDataMat,matlabesls,Mat(),Mat(),params);

Mat matinput(1,14,CV_32FC1,ifarr_testarray);
is_recognizedcharacter= SVM.predict(matinput);

return is_recognizedcharacter;

person Heshan Sandeepa    schedule 26.05.2013    source источник


Ответы (1)


Неправильно настроены ваши ярлыки. Вы определили 180 уникальных ярлыков, но у вас есть только 26 классов данных. Метки должны иметь длину 180, но они должны содержать только значения 1..26 (подойдут любые 26 различных значений) в порядке, соответствующем порядку символов в mattrainingDataMat.

Вам понадобится больше, например, 5000 образцов каждой буквы, а не только 5. Вы можете начать с набора данных рукописных цифр MNIST, пока не получите правильные данные.

Ваш код, кажется, обучает svm просто распознавать 1 символ. Вы не должны делать это так, потому что обучение svm может занять много времени. Вы должны обучить svm отдельно и сохранить модель, чтобы ее можно было повторно использовать без необходимости каждый раз переобучать.

Насколько я понимаю, код svm в OpenCV основан на старой версии Libsvm. Поэтому я просто использую последнюю версию libsvm напрямую, а не версию OpenCV.

Кроме того, для вашего случая вы почти наверняка получите гораздо лучшую точность с ядром RBF, чем с линейным ядром (хотя линейное легче обучать). Кажется, у вас есть 26 классов, поэтому, конечно, вам нужна мультиклассовая SVM (на самом деле это просто много двоичных SVM) - Libsvm решает проблему мультикласса за вас.

person Bull    schedule 26.05.2013
comment
привет большое спасибо за рассмотрение моего вопроса. я изменяю код следующим образом. у меня 36 классов (26 букв, 10 цифр). На данный момент я использую только 5 семплов (пока не получу четкое представление). для одного класса 5 образцов и для одного образца 14 признаков. тогда для одного класса есть 70 признаков (5 * 14). это то, что вы имели ввиду ?? помогите пожалуйста.. 'float labels[36][1] = {1.0, 2.0, ... -> 36.0}; Mat matlabesls(36,1, CV_32FC1, labels) Mat mattrainingDataMat(36, 70, CV_32FC1, ifarr_readtrainingdata);' - person Heshan Sandeepa; 26.05.2013
comment
Если ваши данные состоят из функций для 3 примеров «A», 2 из «C» и 3 из «5» (в таком порядке), то ваши метки будут «плавающие метки [7] [1] = {11.0, 11.0, 11.0, 13.0,13,0, 5.0, 5.0, 5.0} при условии, что 0.0..9.0 используются для маркировки от «0» до «9», а 11.0..35.0 используются для маркировки «A»... «Z». Если бы порядок ваших данных был перепутан, метки нужно было бы переставить, чтобы они совпадали. Метки сообщают SVM, какой образец представляет собой каждый элемент данных. - person Bull; 26.05.2013
comment
Большое спасибо, я понимаю о маркировке. не могли бы вы рассказать мне о том, где здесь мультиклассовый SVM. я чувствую, как вы сказали, есть 3 11.0, 2 13.0 ... и т. д. это называется MultiClass SVM ?? - person Heshan Sandeepa; 26.05.2013
comment
Если бы у вас было только 2 метки, скажем, 0 и 1 или -1 и 1, то это был бы бинарный svm. Если вы указываете более двух разных значений, то linsvm (который использует opencv) автоматически обучает множество бинарных svms и объединяет результаты, чтобы у вас был многоклассовый классификатор. Фактический алгоритм svm является бинарным по своей природе, он просто ищет гиперплоскость, которая разделит ваши данные на два набора (в идеале, чтобы все метки в каждом наборе были одинаковыми). Если бы ваши данные состояли всего из двух «А» и трех «С», у вас были бы «плавающие метки» [5] [1] = {11.0, 11.0, 13.0, 13.0 13.0}, и это даст вам двоичный файл svm. - person Bull; 26.05.2013
comment
@ user2151446-k, тогда я настрою свой код и посмотрю результат. Большое спасибо за вашу помощь и ваши усилия в моем вопросе.HND - person Heshan Sandeepa; 26.05.2013