I am using opencv-2.4 (CvSVM
) for classification. For each test data it is predicting one class as predicted output. But I need to find the next class which is more
Unfortunately, you can not do it directly with the current interface. One solution would be to use the library libsvm instead.
You may do it in opencv, but it will require a little bit of work.
First, you must know that OpenCV uses a "1-against-1" strategy for multi-class classification. For a N-class problem, it will train N*(N-1)/2 binary classifier (one for each couple of classes), and then uses a majority vote to choose the most probable class.
You will have to apply each classifier, and do the majority yourself to get what you want.
The code below show you how to do that with OpenCV 3 (warning: it is untested, probably contains errors, but it gives you a good starting point).
Ptr<SVM> svm;
int N; //number of classes
Mat data; //input data to classify
Mat sv=svm->getSupportVectors();
Ptr<Kernel> kernel=svm->getKernel();
Mat buffer(1,sv.rows,CV_32F);
kernel->calc(sv.rows, sv.cols , sv.ptr<float>(), data.ptr<float>(), buffer.ptr<float>()); // apply kernel on data (CV_32F vector) and support vectors
Mat alpha, svidx;
vector<int> votes(N, 0); // results of majority vote will be stored here
int i, j, dfi;
for( i = dfi = 0; i < N; i++ )
{
for( j = i+1; j < N; j++, dfi++ )
{
// compute score for each binary svm
double rho=svm->getDecisionFunction(dfi, alpha, svidx);
double sum = -rho;
for( k = 0; k < sv.rows; k++ )
sum += alpha.at<float>(k)*buffer.at<float>(svidx.at<int>(k));
// majority vote
votes[sum > 0 ? i : j]++;
}
}
Edit: This code is adapted from the internal code of Opencv here. It is incorrect, as pointed out by David Doria in the comments, since there is no getKernel function defined in the SVM class. I still leave it here, since it should'nt be too difficult to modify the internal OpenCV code to add it, and there is apparently no other way to do it.