0
$\begingroup$

I have implemented SVM by openCV. However, I have a problem about SVM with openCV. For example, I have six categories, but I just use "five" of them to train my SVM. When testing, I want my system which can find out the sixth category is not belong to any category in the system. I think that I can use a threshold to decide whether the result is belong to this category, namely whether the distance is short enough. But, I have no idea to implement my thought by openCV. Is there anyone who can help me? Thank you very much.


I have implemented the One_Class for SVM by openCV. I implemented this part in Bag of Word. The following is my code.

cv::Mat dictionary; 
cv::FileStorage fs("D:\\photo\\dictionary.yml", cv::FileStorage::READ);
fs["vocabulary"] >> dictionary;  //load vocabulary into dictionary
fs.release();  

cv::Ptr<cv::DescriptorMatcher> matcher = cv::DescriptorMatcher::create("FlannBased");
cv::Ptr<cv::DescriptorExtractor> extractor = new cv::SiftDescriptorExtractor();
cv::BOWImgDescriptorExtractor bowDE(extractor, matcher); 
//dextractor – Descriptor extractor that is used to compute descriptors for an input image and its keypoints.
//dmatcher – Descriptor matcher that is used to find the nearest word of the trained vocabulary for each keypoint descriptor of the image.
//int dictionarySize=100;

bowDE.setVocabulary(dictionary); 

Then I extract the feature of each image in my file and find theirs representation about BoW. I only extract one object's image for different view angle.

cout<<"extracting histograms in the form of BOW for each image "<<endl;
cv::Mat labels(0, 1, CV_32FC1);
cv::Mat trainingData(0, dictionarySize, CV_32FC1);
vector<cv::KeyPoint> keypoint1;
cv::Mat bowDescriptor1;
std::vector<cv::KeyPoint> keypoints;
cv::Mat sifts;
//start training
cv::Mat trainImage;
long double angleNum[8]={-7, -14, -21, -28, 7, 14, 21, 28};

long double f=1 //only extract one object's  
    for(int i=0;i<8;i++)
    {        
        //create the file name of an image
        std::string fileNum=std::to_string(f);
        std::string fileNum1=std::to_string(angleNum[i]);
        //open the file
        trainImage=cv::imread("D:\\BoW\\"+fileNum+"_"+fileNum1+".bmp", CV_LOAD_IMAGE_GRAYSCALE); //Load as grayscale

        //detect feature points
        cv::SIFT siftDetectorExtractor;
        siftDetectorExtractor(trainImage,cv::Mat(), keypoints, sifts); 
        bowDE.compute(trainImage , keypoints, bowDescriptor1);
        trainingData.push_back(bowDescriptor1);
        labels.push_back((float) f);

    }

Finally, I want to use One_class SVM by openCV to identify whether the image is belong to the same training object.

cv::SVMParams params;
cv::SVM svm;
params.kernel_type = cv::SVM::LINEAR ;
params.svm_type = cv::SVM::ONE_CLASS;
params.nu=0.0001;
params.term_crit= cv::TermCriteria(CV_TERMCRIT_ITER, 500, 1e-6);

bool ForSVM=svm.train(trainingData, labels, cv::Mat(),cv::Mat(), params);

cout<<"Processing evaluation data..."<<endl;
cv::Mat groundTruth(0, 1, CV_32FC1);
cv::Mat evalData(0, dictionarySize, CV_32FC1);
k=0;
std::vector<cv::KeyPoint> keypoints2; //save keypoint extract from input image
cv::Mat bowDescriptor2; //save BoWdescriptor for inputimage
cv::Mat results(0, 1, CV_32FC1);;
cv::Mat testingimg; 
float response;
long double f=1;
for(int i=0;i<8;i++)
{
    //create the file name of an image
    std::string fileNum=std::to_string(f);
    std::string fileNum1=std::to_string(angleNum[i]);
    //open the file
    testingimg=cv::imread("D:\\BoW\\"+fileNum+"_"+fileNum1+".bmp", CV_LOAD_IMAGE_GRAYSCALE); //Load as grayscale

    cv::SIFT siftDetectorExtractor;
    siftDetectorExtractor(testingimg,cv::Mat(), keypoints2, sifts);
    //detector.detect(img2, keypoint2);
    bowDE.compute(testingimg, keypoints2, bowDescriptor2);
    evalData.push_back(bowDescriptor2);
    //groundTruth.push_back((float) i);

    response = svm.predict(bowDescriptor2); // predict a class of a new input image
    cout<<"result"<<(int)i<<" = "<<response<<endl;
}

This is the final version that identify whether the image is belong to the same training object. And the result is correct.

$\endgroup$
2
$\begingroup$

This is called novelty detection. One-Class SVM is used, where the test data is classified only with regard to membership to the training data. The separating hyperplane lies around the training data and thereby implicitly divides the training data from the rejection class. The advantage is that the rejection class is not defined explicitly, which is difficult to do in certain applications like texture classification or as in your case. The resulting support vectors are all lying at the border.

OpenCV has one-class implemented and it is in the documentation here. Use the option SVM::ONE_CLASS.

There are also other SVM libraries you can use. LibSVM is a very good one and has a far better documentation.

$\endgroup$
  • $\begingroup$ Oh~!!! maybe I miss One-Class SVM for openCV. And now, I don't real understand how to utilize One-Class SVM for openCV. I will read the relative document carefully. Thank you very much for you reply. $\endgroup$ – Kuo Dec 25 '14 at 15:54
  • $\begingroup$ No problems. Updated my reply. Please check again. $\endgroup$ – Tolga Birdal Dec 25 '14 at 16:03
  • $\begingroup$ Hi @tbirdal , I have complemented the code about ONE_CLASS SVM by openCV. Besides, I have updated the code in my original question. Thank you. $\endgroup$ – Kuo Jan 5 '15 at 13:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.