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.