The Support Vector Machine (SVM) classifier finds a discriminant function by maximizing the geometrical margin between the classes. Thus, the space is mapped in such a way that the classes are as widely separated as possible. SVM minimizes both the training error and the geometrical margin. Nowadays, this classifier is one of the best classifiers available and has been applied to many real-world problems. The following SVMClassifier
sample code performs a classification using the SVM classifier and a dataset of 66 image objects. The dataset is divided into four classes: a training shoe (class 1), a cuddly toy (class 2), a plastic cup (class 3), and a bow (class 4). The following screenshot shows the examples of the four classes. A total of 56 images and 10 images were used for the training and the test sets, respectively. Images in the training set take the following name structure: [1-14].png
corresponds to class 1, [15-28].png
to class 2, [29-42].png
to class 3, and [43-56].png
to class 4. On the other hand, images in the test set are characterized by the word unknown followed by a number, for example, unknown1.png
.
The images of the four classes have been extracted from the Amsterdam Library of Object Images (ALOI) available at http://aloi.science.uva.nl/.
The SVMClassifier
sample code is as follows:
//… (omitted for simplicity) #include <opencv2/features2d/features2d.hpp> #include <opencv2/nonfree/features2d.hpp> using namespace std; using namespace cv; int main(int argc, char *argv[]){ Mat groups; Mat samples; vector<KeyPoint> keypoints1; //ORB feature detector with 15 interest points OrbFeatureDetector detector(15, 1.2f, 2, 31,0, 2, ORB::HARRIS_SCORE, 31); Mat descriptors, descriptors2; //SURF feature descriptor SurfDescriptorExtractor extractor; //Training samples for(int i=1; i<=56; i++){ stringstream nn; nn <<i<<".png"; //Read the image to be trained Mat img=imread(nn.str()); cvtColor(img, img, COLOR_BGR2GRAY); //Detect interest points detector.detect(img, keypoints1); //Compute SURF descriptors extractor.compute(img, keypoints1, descriptors); //Organize and save information in one row samples.push_back(descriptors.reshape(1,1)); keypoints1.clear(); } //Set the labels of each sample for(int j=1; j<=56; j++){ if(j<=14) groups.push_back(1); else if(j>14 && j<=28) groups.push_back(2); else if(j>28 && j<=42) groups.push_back(3); else groups.push_back(4); } //Indicate SVM parameters CvSVMParams params=CvSVMParams(CvSVM::C_SVC, CvSVM::LINEAR, 0, 1, 0, 1, 0, 0, 0, cvTermCriteria(CV_TERMCRIT_ITER+CV_TERMCRIT_EPS, 100, FLT_EPSILON)); //Create SVM classifier CvSVM classifierSVM; //Train classifier classifierSVM.train(samples, groups, Mat(), Mat(), params ); //Test samples for(int i=1; i<=10; i++){ stringstream nn; nn <<"unknown"<<i<<".png"; //Read the image to be tested Mat unknown=imread(nn.str()); cvtColor(unknown, unknown, COLOR_BGR2GRAY); //Detect interest points detector.detect(unknown, keypoints1); //Compute descriptors extractor.compute(unknown, keypoints1, descriptors2); //Test sample float result=classifierSVM.predict(descriptors2.reshape(1,1)); //Print result cout<<nn.str()<<": class "<<result<<endl; } return 0; }
The explanation of the code is given as follows. In this example, images are represented by their descriptors (see Chapter 5, Focusing on the Interesting 2D Features). For each image in the training set, its interest points are detected using an Oriented FAST and Rotated BRIEF (ORB) detector (OrbFeatureDetector
) and its descriptors are computed using the Speeded Up Robust Features (SURF) descriptor (SurfDescriptorExtractor
).
An SVM classifier is created using the CvSVM
class and its parameters are set using the CvSVMParams::CvSVMParams(int svm_type, int kernel_type, double degree, double gamma, double coef0, double Cvalue, double nu, double p, CvMat* class_weights, CvTermCriteria term_crit)
constructor. The interesting parameters in this constructor are the type of SVM (svm_type
) and the type of kernel (kernel_type
). The first specified parameter takes, in our case, the CvSVM::C_SVC
value because an n-classification (n 2) with an imperfect separation of the classes is needed. It also uses a C penalty value for atypical values. C acts, therefore, as a regularizer. The kernel_type
parameter indicates the type of SVM kernel. The kernel represents the basis function required to separate the cases. For the SVM classifier, OpenCV includes the following kernels:
CvSVM::LINEAR
: The linear kernelCvSVM::POLY
: The polynomial kernelCvSVM::RBF
: The radial basis functionCvSVM::SIGMOID
: The sigmoid kernelThen, the classifier builds an optimal linear discriminating function using the training set (with the train
function). Now, it is prepared to classify new unlabeled samples. The test set is used for this purpose. Note that we also have to calculate the ORB detector and the SURF descriptors for each image in the test set. The result is as shown in the following screenshot, where all the classes have been classified correctly: