How to choose index in getDecisionFunction for multiclass SVM
The objective is to train an SVM to classify up to 10 digits handwritten. So the SVM is a muticlass classifier.
As a result of the training, I have got a yml file which indicates the SVM has a total of 1009 support vectors, a class_count of 10 (because there are 10 digits in the training dataset). It all works very fine. But now I would like to use cv::ml::HOGDescripctor::detectMiltiscale(), in order to detect the digits in any other image or video. My problem arrises when I try to use the HOG::setSVMDetector function, since the SVM model I have just created is not compatible (I tried and it returned errors). So I search on the Internet the way to process the SVM support vectors so as to load it in the setSVMDetector function.
I have found loads of forums pointing to this function:
void get_svm_detector(const Ptr<SVM>& svm, vector< float > & hog_detector ){
// get the support vectors
Mat sv = svm->getSupportVectors();
const int sv_total = sv.rows;
// get the decision function
Mat alpha, svidx;
double rho = svm->getDecisionFunction(0, alpha, svidx);
CV_Assert( alpha.total() == 1 && svidx.total() == 1 && sv_total == 1 );
CV_Assert( (alpha.type() == CV_64F && alpha.at<double>(0) == 1.) ||
(alpha.type() == CV_32F && alpha.at<float>(0) == 1.f) );
CV_Assert( sv.type() == CV_32F );
hog_detector.clear();
hog_detector.resize(sv.cols + 1);
memcpy(&hog_detector[0], sv.ptr(), sv.cols*sizeof(hog_detector[0]));
hog_detector[sv.cols] = (float)-rho;
}
But I have analize it, and the ASSERT this code have will launch an exception in runtime since the sv_total is not equal to 1 for my SVM model (it is equal to 1009). So I have to get rid of the ASSERTS, but now, the problem I with which index I should ue in the getDecisionFunction(0, alpha, svidx) since according to documentation, 0 is just for one or two-class models, but mine is 10-class model. I tried using 45, since there will be 45 different equations to solve, but it launches and error, I tried with 1, 2, and with 10, but I never finds the correct digits on my test image.
The code I implemented is the following (I try to use my variable names in Spanish, I love my language jejeje):
cv::Mat sv = svm->getSupportVectors();
const int sv_total = sv.rows;
cv::Mat alpha, svidx;
double rho = svm->getDecisionFunction(10, alpha, svidx);
vector<float> svmDetector;
svmDetector.clear();
svmDetector.resize(sv.cols + 1);
memcpy(&svmDetector[0], sv.ptr(), sv.cols * sizeof(svmDetector[0]));
svmDetector[sv.cols] = (float)-rho;
And I use the result, svmDetector, in this way with the rest:
hog.setSVMDetector(svmDetector);
hog.detectMultiScale(imagenPrueba, encontrados, 2);
cout << encontrados.size() << endl;
cv::Mat resultadoImagen;
vector<cv::Mat> grises;
grises.push_back(imagenPrueba);
grises.push_back(imagenPrueba);
grises.push_back(imagenPrueba);
cv::merge(grises, resultadoImagen);
for(int i=0;i<encontrados.size();i++)
cv::rectangle(resultadoImagen, encontrados[i], cv::Scalar(0, 0, 255));
cv::imshow("RESULTADO", resultadoImagen);
cv::waitKey(0);
I have read a lot about it, but still cannot figure out how to ...