Store in hard disk a CvSVM object - c++

I have create a SVM detector for faces in opencv. I want to separate the process of train and predict. Thus, I want to find a way to store in my hard disk CvSVM SVM object in order to access it whenever I want without train again a new model. In this way, I could use predict method by just loading SVM object from hard disk. This is pretty straight forward in Matlab, but how can I succeed it in opencv c++?
Using load and save functions in order to load and save SVM model it leads to munmap_chunk()::invalid pointer message(glibc detected) message.
CvSVM SVM = detect.SVMtrain("dbpath/");
SVM.save("svmTrain.xml", 0);
cout <<"Detection system in progress progress...\n";
string pathFile = databasePath+ imageFilename;
vector<float> confidence;
detections = detect.detection(pathFile);
CvSVM SVM;
SVM.load("svmTrain.xml",0);
confidence = detect.SVMpredict(detections.at(0), SVM);
//cout << "confidence is: " << confidence.at(0) << endl;
When I ran the above code I received the above message. The problem stands in svmpredict function. And SVMpredict function:
vector<float> Detection::SVMpredict(Mat image, CvSVM SVM){
vector<float> res;
//Mat image = imread(fileName,0); //Read as a gray image
//cvtColor(sampleMat, sampleMat, CV_BGR2GRAY);
image = eigenfacesExtraction(image);
image.convertTo(image, CV_32FC1); // <-- Convert to CV_32F for matrix mult
float response = SVM.predict(image); res.push_back(response);
float val = SVM.predict(image,true); res.push_back(val);
cout << "svm result: "<< response <<" val: "<< val << endl;
return res;
}

Straightforward too. It's a CvStatModel, so it comes with save and load methods.

Related

how to code one vs rest multi class SVM for action recognition project

I'm new to SVM. I want to use Multiclass svm for classification in my action recognition project. My data set have 15 class like running jogging walking biking etc. I understand binary SVM and seen lot of examples. I'm getting confusion in one vs one multiclass svm and one vs rest multiclass svm.
My question is: Should I have to create and train a svm for each class like svm1 for running, svm2 for jogging.....etc what should be class lebels for each created svm either (0,1,2,.......14) or (0,1). how to determine the model for multiclass classification.how the result will be predicted ?
I was trying some thing like this:
Mat trainData, trainLabels;
for (int i = 0; i < 15; i++ )
{
sprintf_s(filename, "VocabularyHOG/Dictionary%d.yml", i);
Mat feature;
FileStorage fs(filename, FileStorage::READ);
fs["vocabulary"] >> feature;
feature.convertTo(feature, CV_32F); // make sure we got float data
trainData.push_back(feature.reshape(1, 1)); // as a flat column
trainLabels.push_back(i); // the classlabel
}
// Train the SVM
Ptr<SVM> svm = SVM::create();
svm->setType(SVM::C_SVC);
svm->setKernel(SVM::LINEAR);
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));
svm->train(trainData, ROW_SAMPLE, trainLabels);
Mat testData;
FileStorage fs("DictionaryrunningHOG.yml", FileStorage::READ);
fs["vocabulary"] >> testData;
int response = svm->predict(testData.reshape(1, 1));
if (response == 1)
cout << "boxing";
else
cout << "negative result";
waitKey(27);
return 0;
but getting error. what is wrong here?? how to code one vs rest multiclass svm properly.What is the label for each svm? Thanks

opencv Normbal bayes predict probability output zero

I have some training data that consists of a number of features extracted from images and different class labels. I have managed to train Normal Bayes classifiers using OpenCV3 in C++. And I am able to pass new test data into the classifiers to obtain the predicted class labels using predict() function.
However, I don't want to simply get the predicted class label, I also wish to know the probabilities for each class label per test data using predictProb() function of class NormalBayesClassifier.
There is a predictProb() function that seems to be able to return the probabilities per class label:
virtual float cv::ml::NormalBayesClassifier::predictProb
( InputArray inputs,
OutputArray outputs,
OutputArray outputProbs,
int flags = 0
) const
However, when i tested the code, I always get a vector of 0s or a mixture of 0s and Inf for different test images as the predict probabilities even though I do get a correct prediction. I tried adding RAW_OUTPUT to the flags and the result is the same.
int N=4;
vector<string> loc;
loc.push_back("1.jpg");
loc.push_back("2.jpg");
loc.push_back("3.jpg");
loc.push_back("4.jpg");
loc.push_back("5.jpg");
loc.push_back("6.jpg");
Ptr<ml::NormalBayesClassifier> rt = cv::ml::NormalBayesClassifier::create();
Mat img,features,dictionary;
vector<cv::KeyPoint> keyPoints;
Mat X;
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("FlannBased");
Ptr<SURF> detector = SURF::create(400,4,2,1,1);
Ptr<DescriptorExtractor> extractor = detector;
FileStorage fs("Bag-Of-Features.yml", FileStorage::READ);
fs["dictionary"] >> dictionary;
fs.release();
Ptr<BOWImgDescriptorExtractor> bowDE=makePtr<BOWImgDescriptorExtractor>(extractor, matcher);
bowDE->setVocabulary(dictionary);
for(int i=0;i<4;i++)
{
img=imread(loc[i]);
detector->detect(img,keyPoints);
bowDE->compute(img,keyPoints,features);
int rows = features.rows;
int cols = features.cols;
//cout << "r"<< rows << "c "<< cols ;
X.push_back(features);
}
Mat_<int> Y(N,1);
Y << 0,0, 1,1 ;
rt->train(X, ml::ROW_SAMPLE, Y);
rt->save("classifier.yml");
/////////prediction/////////////
Mat features1;
vector<cv::KeyPoint> keyPoints1;
Mat r,p;
Mat inp;
Mat R1,P1;
for (int i=0;i<2;i++)
{
inp=imread(loc[4+i]);
//inp.convertTo(inp,CV_8U);
detector->detect(inp, keyPoints1);
bowDE->compute(inp, keyPoints1, features1);
//features1.convertTo(features1,CV_32F);
rt->predictProb(features1,r,p);
R1.push_back(r);
P1.push_back(p);
}
cout << "Probability"<<P1 <<endl ;
return 0;
}
Ouput:
Probability[0, 0;inf, 0]
There are two conditions that need to be met for the Bayes Classifier to be able to output probabilities:
1) You must train it with multiple samples that pair to the same response value.
2) The training samples should be normalized.
I had this same question, and after scouring the internet for answers finally this link helped me conclude the above statement:
Opencv3 Bayes Classifier predictProb giving strange results

C++/OpenCV: How to use BOWImgDescriptorExtractor to determine which clusters relate to which images in the vocabulary?

My goal is to take an image as a query and find its best match in a library of images. I am using SURF features, in openCV 3.0.0, and the Bag of Words approach to find a match. I need a way to find out if the query image has a match in the library. If it does, I want to know the index of the image that is the nearest match.
Here is my code for reading in all the images (300 total in the library of images) and extracting and clustering the features:
Mat training_descriptors(1, extractor->descriptorSize(), extractor->descriptorType());
//read in all images and set to binary
char filepath[1000];
for (int i = 1; i < trainingSetSize; i++){
cout << "in for loop, iteration: " << i << endl;
_snprintf_s(filepath, 100, "C:/Users/Randal/Desktop/TestCase1Training/%d.bmp", i);
Mat temp = imread(filepath, CV_LOAD_IMAGE_GRAYSCALE);
Mat tempBW;
adaptiveThreshold(temp, tempBW, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 11, 2);
detector->detect(tempBW, keypoints1);
extractor->compute(tempBW, keypoints1, descriptors1);
training_descriptors.push_back(descriptors1);
cout << "descriptors added" << endl;
}
cout << "Total descriptors: " << training_descriptors.rows << endl;
trainer.add(training_descriptors);
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("FlannBased");
BOWImgDescriptorExtractor BOW(extractor, matcher);
Mat library = trainer.cluster();
BOW.setVocabulary(library);
I wrote the following code in an attempt to find a match. The problem is that BOW.compute only returns the indices of clusters (words) that exist in both the image and the library of images. imgQ is the query image.
Mat output;
Mat imgQBW;
adaptiveThreshold(imgQ, imgQBW, 255, ADAPTIVE_THRESH_GAUSSIAN_C, THRESH_BINARY, 11, 2);
imshow("query image", imgQBW);
detector->detect(imgQBW, keypoints2);
extractor->compute(imgQBW, keypoints2, descriptors2);
BOW.compute(imgQBW, keypoints1, output);
cout << output.row(0) << endl;
I need to know which clusters in the BoW correspond to which images. My output right now--output.row(0)--is just an array with all the the indices of clusters found in the library. Am I misunderstanding this output? Is there a way to determine which image has the most matching clusters?
I also did something similar based on this code:
https://github.com/royshil/FoodcamClassifier/blob/master/training_common.cpp
But the above part is after the clustering has finished.
What you have to do is to train using your ML(I used SVM) and your cluster centers, the visual bag of words that you have.
More, you need to find all the "closest" points to your clustered points and train them using histograms. Next, you will have a histogram of frequencies(bag of key points) that you need to train.
Ptr<ifstream> ifs(new ifstream("training.txt"));
int total_samples_in_file = 0;
vector<string> classes_names;
vector<string> lines;
//read from the file - ifs and put into a vector
for(int i=0;i<lines.size();i++) {
vector<KeyPoint> keypoints;
Mat response_hist;
Mat img;
string filepath;
string line(lines[i]);
istringstream iss(line);
iss >> filepath;
string class_to_train;
iss >> class_to_train;
class_ml = "class_" + class_to_train;
if(class_ml.size() == 0) continue;
img = imread(filepath);
detector->detect(img,keypoints);
bowide.compute(img, keypoints, response_hist);
cout << "."; cout.flush();
//here create the logic for the class to train(class_0, e.g) and the data you need to train.
}
More you can find at this git project:
https://github.com/royshil/FoodcamClassifier
Documentation here:
http://www.morethantechnical.com/2011/08/25/a-simple-object-classifier-with-bag-of-words-using-opencv-2-3-w-code/

How to form data for SVM training OpenCV3

I am trying to write utility for training svm classifier for image classification in OpenCV3. But I have Floating point exception (core dumped) error during training process.
My main problem is that I don't know, I'm not sure exactly how to form training data to feed svm.train method.
This is code which is forming training data.
TrainingDataType SVMTrainer::prepareDataForTraining() {
cv::Mat trainingData(m_numOfAllImages, 28*28, CV_32FC1);
cv::Mat trainingLabels(m_numOfAllImages, 1, CV_32FC1);
int rowNum = 0;
// Item is pair of classId (int) and vector of images.
for(auto item : m_data){
int classId = item.first;
for(auto item1 : item.second){
Mat temp = item1.reshape(1,1);
temp.copyTo(trainingData.row(rowNum));
trainingLabels.at<float>(rowNum) = item.first;
++rowNum;
}
}
return cv::ml::TrainData::create(trainingData,
cv::ml::SampleTypes::ROW_SAMPLE,
trainingLabels) ;
}
void SVMTrainer::train(std::string& configPath){
// Read and store images in memory.
formClassifierData(configPath);
m_classifier = cv::ml::SVM::create();
// Training parameters:
m_classifier->setType(cv::ml::SVM::C_SVC);
m_classifier->setKernel(cv::ml::SVM::POLY);
m_classifier->setGamma(3);
m_classifier->setDegree(3);
TrainingDataType trainData = prepareDataForTraining();
m_classifier->trainAuto(trainData);
}
All images are already prepared with dimensions 28*28, black&white.
And actual train call is in this method
Can somebody tell me what I am doing wrong.
Thanks,
Its simple. Change the label format to CV_32SC1. It will definitely resolve your issue in opencv 3.0 ml.

SVM classifier based on HOG features for "object detection" in OpenCV

I have a project, which I want to detect objects in the images; my aim is to use HOG features. By using OpenCV SVM implementation , I could find the code for detecting people, and I read some papers about tuning the parameters in order to detect object instead of people. Unfortunately, I couldn't do that for a few reasons; first of all, I am probably tuning the parameters incorrectly, second of all, I am not a good programmer in C++ but I have to do it with C++/OpenCV... here you can find the code for detecting HOG features for people by using C++/OpenCV.
Let's say that I want to detect the object in this image. Now, I will show you what I have tried to change in the code but it didn't work out with me.
The code that I tried to change:
HOGDescriptor hog;
hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());
I tried to change getDefaultPeopleDetector() with the following parameters, but it didn't work:
(Size(64, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9, 0,-1, 0, 0.2, true, cv::HOGDescriptor::DEFAULT_NLEVELS)
I then tried to make a vector, but when I wanted to print the results, it seems to be empty.
vector<float> detector;
HOGDescriptor hog(Size(64, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9, 0,-1, 0, 0.2, true, cv::HOGDescriptor::DEFAULT_NLEVELS);
hog.setSVMDetector(detector);
Please, I need help solving this problem.
In order to detect arbitrary objects with using opencv HOG descriptors and SVM classifier, you need to first train the classifier. Playing with the parameters will not help here, sorry :( .
In broad terms, you will need to complete the following steps:
Step 1) Prepare some training images of the objects you want to detect (positive samples). Also you will need to prepare some images with no objects of interest (negative samples).
Step 2) Detect HOG features of the training sample and use this features to train an SVM classifier (also provided in OpenCV).
Step 3) Use the coefficients of the trained SVM classifier in HOGDescriptor::setSVMDetector() method.
Only then, you can use the peopledetector.cpp sample code, to detect the objects you want to detect.
I've been dealing with the same problem and surprised with the lack of some clean C++ solutions I have create ~> this wrapper of SVMLight <~, which is a static library that provides classes SVMTrainer and SVMClassifier that simplify the training to something like:
// we are going to use HOG to obtain feature vectors:
HOGDescriptor hog;
hog.winSize = Size(32,48);
// and feed SVM with them:
SVMLight::SVMTrainer svm("features.dat");
then for each training sample:
// obtain feature vector describing sample image:
vector<float> featureVector;
hog.compute(img, featureVector, Size(8, 8), Size(0, 0));
// and write feature vector to the file:
svm.writeFeatureVectorToFile(featureVector, true); // true = positive sample
till the features.dat file contains feature vectors for all samples and at the end you just call:
std::string modelName("classifier.dat");
svm.trainAndSaveModel(modelName);
Once you have a file with model (or features.dat that you can just train the classifier with):
SVMLight::SVMClassifier c(classifierModelName);
vector<float> descriptorVector = c.getDescriptorVector();
hog.setSVMDetector(descriptorVector);
...
vector<Rect> found;
Size padding(Size(0, 0));
Size winStride(Size(8, 8));
hog.detectMultiScale(segment, found, 0.0, winStride, padding, 1.01, 0.1);
just check the documentation of HOGDescriptor for more info :)
I have done similar things as you did: collect samples of positive and negative images using HOG to extract features of car, train the feature set using linear SVM (I use SVM light), then use the model to detect car using HOG multidetect function.
I get lot of false positives, then I retrain the data using positive samples and false positive+negative samples. The resulting model is then tested again. The resulting detection improves (less false positives) but the result is not satisfying (average 50% hit rate and 50% false positives). Tuning up multidetect parameters improve the result but not much (10% less false positives and increase in hit rate).
Edit
I can share you the source code if you'd like, and I am very open for discussion as I have not get satisfactory results using HOG. Anyway, I think the code can be good starting point on using HOG for training and detection
Edit: adding code
static void calculateFeaturesFromInput(const string& imageFilename, vector<float>& featureVector, HOGDescriptor& hog)
{
Mat imageData = imread(imageFilename, 1);
if (imageData.empty()) {
featureVector.clear();
printf("Error: HOG image '%s' is empty, features calculation skipped!\n", imageFilename.c_str());
return;
}
// Check for mismatching dimensions
if (imageData.cols != hog.winSize.width || imageData.rows != hog.winSize.height) {
featureVector.clear();
printf("Error: Image '%s' dimensions (%u x %u) do not match HOG window size (%u x %u)!\n", imageFilename.c_str(), imageData.cols, imageData.rows, hog.winSize.width, hog.winSize.height);
return;
}
vector<Point> locations;
hog.compute(imageData, featureVector, winStride, trainingPadding, locations);
imageData.release(); // Release the image again after features are extracted
}
...
int main(int argc, char** argv) {
// <editor-fold defaultstate="collapsed" desc="Init">
HOGDescriptor hog; // Use standard parameters here
hog.winSize.height = 128;
hog.winSize.width = 64;
// Get the files to train from somewhere
static vector<string> tesImages;
static vector<string> positiveTrainingImages;
static vector<string> negativeTrainingImages;
static vector<string> validExtensions;
validExtensions.push_back("jpg");
validExtensions.push_back("png");
validExtensions.push_back("ppm");
validExtensions.push_back("pgm");
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Read image files">
getFilesInDirectory(posSamplesDir, positiveTrainingImages, validExtensions);
getFilesInDirectory(negSamplesDir, negativeTrainingImages, validExtensions);
/// Retrieve the descriptor vectors from the samples
unsigned long overallSamples = positiveTrainingImages.size() + negativeTrainingImages.size();
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Calculate HOG features and save to file">
// Make sure there are actually samples to train
if (overallSamples == 0) {
printf("No training sample files found, nothing to do!\n");
return EXIT_SUCCESS;
}
/// #WARNING: This is really important, some libraries (e.g. ROS) seems to set the system locale which takes decimal commata instead of points which causes the file input parsing to fail
setlocale(LC_ALL, "C"); // Do not use the system locale
setlocale(LC_NUMERIC,"C");
setlocale(LC_ALL, "POSIX");
printf("Reading files, generating HOG features and save them to file '%s':\n", featuresFile.c_str());
float percent;
/**
* Save the calculated descriptor vectors to a file in a format that can be used by SVMlight for training
* #NOTE: If you split these steps into separate steps:
* 1. calculating features into memory (e.g. into a cv::Mat or vector< vector<float> >),
* 2. saving features to file / directly inject from memory to machine learning algorithm,
* the program may consume a considerable amount of main memory
*/
fstream File;
File.open(featuresFile.c_str(), ios::out);
if (File.good() && File.is_open()) {
File << "# Use this file to train, e.g. SVMlight by issuing $ svm_learn -i 1 -a weights.txt " << featuresFile.c_str() << endl; // Remove this line for libsvm which does not support comments
// Iterate over sample images
for (unsigned long currentFile = 0; currentFile < overallSamples; ++currentFile) {
storeCursor();
vector<float> featureVector;
// Get positive or negative sample image file path
const string currentImageFile = (currentFile < positiveTrainingImages.size() ? positiveTrainingImages.at(currentFile) : negativeTrainingImages.at(currentFile - positiveTrainingImages.size()));
// Output progress
if ( (currentFile+1) % 10 == 0 || (currentFile+1) == overallSamples ) {
percent = ((currentFile+1) * 100 / overallSamples);
printf("%5lu (%3.0f%%):\tFile '%s'", (currentFile+1), percent, currentImageFile.c_str());
fflush(stdout);
resetCursor();
}
// Calculate feature vector from current image file
calculateFeaturesFromInput(currentImageFile, featureVector, hog);
if (!featureVector.empty()) {
/* Put positive or negative sample class to file,
* true=positive, false=negative,
* and convert positive class to +1 and negative class to -1 for SVMlight
*/
File << ((currentFile < positiveTrainingImages.size()) ? "+1" : "-1");
// Save feature vector components
for (unsigned int feature = 0; feature < featureVector.size(); ++feature) {
File << " " << (feature + 1) << ":" << featureVector.at(feature);
}
File << endl;
}
}
printf("\n");
File.flush();
File.close();
} else {
printf("Error opening file '%s'!\n", featuresFile.c_str());
return EXIT_FAILURE;
}
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Pass features to machine learning algorithm">
/// Read in and train the calculated feature vectors
printf("Calling SVMlight\n");
SVMlight::getInstance()->read_problem(const_cast<char*> (featuresFile.c_str()));
SVMlight::getInstance()->train(); // Call the core libsvm training procedure
printf("Training done, saving model file!\n");
SVMlight::getInstance()->saveModelToFile(svmModelFile);
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Generate single detecting feature vector from calculated SVM support vectors and SVM model">
printf("Generating representative single HOG feature vector using svmlight!\n");
vector<float> descriptorVector;
vector<unsigned int> descriptorVectorIndices;
// Generate a single detecting feature vector (v1 | b) from the trained support vectors, for use e.g. with the HOG algorithm
SVMlight::getInstance()->getSingleDetectingVector(descriptorVector, descriptorVectorIndices);
// And save the precious to file system
saveDescriptorVectorToFile(descriptorVector, descriptorVectorIndices, descriptorVectorFile);
// </editor-fold>
// <editor-fold defaultstate="collapsed" desc="Test detecting vector">
cout << "Test Detecting Vector" << endl;
hog.setSVMDetector(descriptorVector); // Set our custom detecting vector
cout << "descriptorVector size: " << sizeof(descriptorVector) << endl;
getFilesInDirectory(tesSamplesDir, tesImages, validExtensions);
namedWindow("Test Detector", 1);
for( size_t it = 0; it < tesImages.size(); it++ )
{
cout << "Process image " << tesImages[it] << endl;
Mat image = imread( tesImages[it], 1 );
detectAndDrawObjects(image, hog);
for(;;)
{
int c = waitKey();
if( (char)c == 'n')
break;
else if( (char)c == '\x1b' )
exit(0);
}
}
// </editor-fold>
return EXIT_SUCCESS;
}