Train SVM and save it with OpenCV 3.0 - c++

I am using Visual Studio 2010, with OpenCV 3.0. I'm trying to train a SVM and to save it into a file, but I am having problems.
My purpose is to extract the HOG features of some images and train a SVM with them. All seems to be right, but when I try to save the model in a xml file I obtain the following error:
Unhandled exception in 0x000007fefd9bb16d (KernelBase.dll) in TrainSVM.exe: Exception de MICROSOFT C++: cv::Exception at memory location 0x0026e1b0.
And then this is showed in console:
OpenCV Error: Parsing error (SVM model data is invalid, check sv_count, var_* an
d class_count tags) in cv::ml::SVMImpl::write, file C:\builds\master_PackSlave-w
in64-vc12-shared\opencv\modules\ml\src\svm.cpp, line 2027
The error seems to appear when the SVM has not been trained properly, but I don't understand where I have failed, because the line
svm->train(auxResult)
has "true" as result.
I have checked the images and they are loaded properly, anybody could help me?
Thanks in advance.
Here is the code:
String imagesPathPos = "Positivas/*.jpg"; // it has filters, too !
vector<String> fp;
glob(imagesPathPos, fp);
int tamaƱo = fp.size();
std::vector<cv::Point> positions;
positions.push_back(cv::Point(0,0));
std::vector<float> descriptor;
Ptr<TrainData> auxResult;
for (size_t i=0; i<fp.size(); ++i)
{
string nameFile = fp[i];
Mat img = imread(fp[i]);
cv::Mat grayImg;
cvtColor( img, grayImg, COLOR_BGR2GRAY );
hog.compute(grayImg,descriptor,winStride,trainingPadding,positions);
Mat auxDescriptor = cv::Mat(descriptor);
Mat descriptorMat(1,auxDescriptor.rows,CV_32FC1);
transpose(auxDescriptor, descriptorMat);
trainingData.push_back(descriptorMat);
trainingLabels.push_back(labelPositive);
}
String imagesPathNeg = "Negativas/*.jpg";
vector<String> fn;
glob(imagesPathNeg, fn, true);
for (size_t i=0; i<fn.size(); i++)
{
Mat img = imread(fn[i]);
cv::Mat grayImg;
cvtColor( img, grayImg, COLOR_BGR2GRAY );
hog.compute(grayImg,descriptor,Size(),Size(),positions);
Mat auxDescriptor = cv::Mat(descriptor);
Mat descriptorMat(1,auxDescriptor.rows,CV_32FC1);
transpose(auxDescriptor, descriptorMat);
trainingData.push_back(descriptorMat);
trainingLabels.push_back(labelPositive);
}
auxResult = TrainData::create(trainingData, type, trainingLabels);
svm->train(auxResult);
svm->save("output.xml");

You are defining "labelPositive" even when the images are negative. Possibly the error is there, within the loop through the vector fn:
trainingLabels.push_back(labelPositive);
You should use a parameter named "labelNegative" defined as -1.

Related

Access violation reading location when push_back Mat in another Mat

I want write simple code to extract HOG features and then train SVM. but this exception occur, i try different OpenCV versions like 3.4.5 and 4.0 but not differ.
cv::HOGDescriptor hogDetector = cv::HOGDescriptor();
hogDetector.winSize = cv::Size(256, 256);
hogDetector.blockSize = cv::Size(64, 64);
hogDetector.blockStride = cv::Size(192, 192);
hogDetector.cellSize = cv::Size(32, 32);
and function return HOG features :
cv::Mat computeHOG(cv::Mat img)
{
std::vector<float> descriptors;
std::vector<cv::Point> locations;
hogDetector.compute(img, descriptors, cv::Size(8, 8), cv::Size(0, 0), locations);
cv::Mat row = cv::Mat(descriptors);
return row;
}
and main code for extract features :
cv::Mat trainFeatures;
cv::Mat trainLables;
while (!PFile.eof())
{
std::string name; std::getline(PFile, name);
std::vector<std::string> parts = splitString(name, ' ');
cv::Mat img = cv::imread(basePath + parts[0]);
cv::cvtColor(img, img, cv::COLOR_BGR2GRAY);
cv::resize(img, img,cv::Size(1250, 320));
cv::Mat f = computeHOG(img);
trainFeatures.push_back(f);
trainLables.push_back(std::stoi(parts[1]));
}
exception occur in line : trainFeatures.push_back(f);, and f shape is 1 * 1 * 162000
full exception :
Exception thrown at 0x00007FFF5A9C17E5 (opencv_world345d.dll) in vehicleRecognition.exe: 0xC0000005: Access violation reading location 0x000002A830658140.
in debugging i found f Mat (HOG features) is FLOAT32 but trainFeatures is UINT8, first i change cv::Mat trainFeatures; to cv::Mat trainFeatures = cv::Mat1f(); but not differ and again change it to cv::Mat trainFeatures = cv::Mat(1, 162000,CV_32FC1); and work, fixed issue.
and also change row with : row = row.reshape(1, 1);
I don't know why fixed issue and it's weird why OpenCV automatically can't detect its. if you have better solution please write it.

SIFT detects 0 keypoints?

I'm creating the visual histograms (following the Bag of Visual Words model) of a dataset of n images using OpenCV.
This is the code:
std::vector<std::string> fileList;
std::unique_ptr<cv::BOWImgDescriptorExtractor> bowDE;
cv::Mat vocabulary;//will be filled through KMeans
...
bowDE->setVocabulary(vocabulary);
cv::Ptr<cv::Feature2D> featureDetectorDescriptor = cv::xfeatures2d::SIFT::create(0,3,0.04,10,1.6);;
for(size_t i=0;i<n;i++) {
cv::UMat img;
cv::Mat word;
imread(fileList[i], cv::IMREAD_GRAYSCALE).copyTo(img);
std::vector<cv::KeyPoint> keyPoints;
featureDetectorDescriptor->detect(img, keyPoints);
bowDE->compute(img, keyPoints, word);
histograms.push_back(word);
assert(histograms.rows==(i+1));//this is for testing
}
The problem is that after 4625 images have been inserted, the assert condition is false. I tested keypoints.size() and it results 0, no keypoints are detected!
I tried to remove the image which created the error, but another one creates the same error (so the error seems not to depend from the image).
Why this happens?
Update: actually I found out that the error was image dependent. It seems that with the default parameters cv::SIFT detects 0 keypoints with this image from Caltech101:

Error with SVM training (assertion failed for sample type)

I am trying to use SVM to match a query image with its appropriate class. Right now the classes are just 1 or 0. I extract the class from a .txt file and store it into a Mat. I use BoW to compute a histogram for each image in the training set, and also store it into a Mat.
Mat response_hist;
Mat histograms;
Mat classes;
ifstream ifs("train.txt");
int total_samples_in_file = 0;
vector<string> classes_names;
vector<string> lines;
for (int i = 1; i <= trainingSetSize; i++){
cout << "in for loop iteration"<< i << endl;
_snprintf_s(filepath, 100, "C:/Users/Randal/Desktop/TestCase1Training/train/%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);
BOW.compute(tempBW, keypoints1, response_hist);
response_hist.convertTo(response_hist, CV_32F);
histograms.push_back(response_hist);
}
//read from the file - ifs and put into a vector
std::string line;
float class_num;
string imgfilepath;
for (int j = 1; getline(ifs, line); j++)
{
istringstream ss(line);
ss >> imgfilepath >> class_num;
classes.push_back(class_num);
}
The Mats class_num and histograms are used in training the SVM. Each row in "histograms" represents a sample (a histogram of an image in the training set). "class_num" is one row with each column being the class (1 or 0) of a corresponding image in the training set.
Ptr<ml::SVM> svm = ml::SVM::create();
svm->setType(ml::SVM::C_SVC);
svm->setKernel(ml::SVM::POLY);
svm->setGamma(3);
Mat trainingDataMat(histograms);
Mat trainingDataClass(classes);
trainingDataMat.convertTo(trainingDataMat, CV_32F);
trainingDataMat = trainingDataMat.reshape(trainingDataMat.cols, 1);
trainingDataClass.convertTo(classes, CV_32F);
svm->train(trainingDataMat, ml::ROW_SAMPLE, trainingDataClass); //incorrect types? I think it is a problem with ROW_SAMPLE
Mat res; // output
svm->predict(output, res);
When I run this I get the error "Assertion failed (samples.type() == CV_32F || samples.type() == CV_32S) in cv::ml::TrainDataImpl::setData". However, I have placed lines of code in to convert both my class Mat and my histogram Mat to type CV_32F. Is the issue with my inputs or does it have something to do with ROW_SAMPLE in svm->train? Any help is greatly appreciated.
Thanks
The error was caused by my input being incorrect. I changed the type of Mat classesMat to CV_32S in its declaration. I also changed
trainingDataMat_32.reshape(trainingDataMat_32.cols, 1);
to have the correct number of channels and rows.
trainingDataMat_32.reshape(1, trainingDataMat_32.rows);
TrainingDataMat.cols was not the correct value at all. It needed 1 channel (first parameter) and the same number of rows as my histogram input.
This caused a new error regarding the kernel I am using (SVM parameter "POLY"). I had to add another line right below the kernel parameter:
svm->setDegree(3);
This fixed the error. My output is not correct, but this solved the assertion failure.

Debug assertion failed with Open CV SIFT

I hope someone can help. I have been trying to work with SIFT and even the simplest program like this will cause a debug assertion failed.
int DoSift()
{
string image2 ="G:/SIFT Test/Foods/f1.jpg";
string image1 ="G:/SIFT Test/Foods/f2.jpg";
Mat input = imread(image1, IMREAD_GRAYSCALE );
Mat img_2 = imread( image2, IMREAD_GRAYSCALE );
// const cv::Mat input = cv::imread("input.jpg", 0); //Load as grayscale
cv::SiftFeatureDetector detector;
std::vector<cv::KeyPoint> keypoints;
detector.detect(input, keypoints);
// Add results to image and save.
cv::Mat output;
cv::drawKeypoints(input, keypoints, output);`enter code here`
cv::imwrite("sift_result.jpg", output);
return Exit_Success(); //<- it happens here
}
I think it's in the cleanup somewhere here:
void _Tidy()
{ // free all storage
if (this->_Myfirst != pointer())
{ // something to free, destroy and deallocate it
this->_Orphan_all();
_Destroy(this->_Myfirst, this->_Mylast);
this->_Getal().deallocate(this->_Myfirst,
this->_Myend - this->_Myfirst);**//--->......Here.....**
this->_Myfirst = pointer();
this->_Mylast = pointer();
this->_Myend = pointer();
}
The exception details says:
**Debug assertion failed.
Program:...
File: f:\dd\vctools\ctr_bld\self_x86\crt\src\dbgheap.c
Line: 1322
Expression: _CrtIsValidHeapPointers(pUserData)**
The problem is with visual studio 2012. Switching to 2010 ran smoothly. I believe that the 2012 doesn't quite like openCV.

(Adaptive) thresholding in opencv error (Bad argument (Unknown array type) in cvarrToMat)

I'm trying to use thresholding on my video stream but it is not working.
My video stream:
Mat *depthImage = new Mat(480, 640, CV_8UC1, Scalar::all(0));
Then i try to do the adaptive thresholding, (also doesn't work with regular thresholding)
for(;;){
if( wrapper->update()){
wrapper->getDisplayDepth(depthImage);
cvAdaptiveThreshold(depthImage, depthImage,255,CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY,75,10);
imshow("Depth", *depthImage);
}
int k = waitKey(25);
if(k == 27 ) exit(0);
}
I get this error :
OpenCV Error: Bad argument (Unknown array type) in cvarrToMat, file /Users/olivierjanssens/source/OpenCV-2.3.1/modules/core/src/matrix.cpp, line 646
terminate called throwing an exception
What am i doing wrong, i can get display and see the stream perfectly.But when i add this thresholding i get the error previously mentioned. (i'm rather new to opencv btw).
Thx in advance !
Your depthImage is a pointer to a cv::Mat, which to me seems strange...
...but, if you're using the C++ syntax then you'll want to use the C++ version of adaptiveThreshold, which deals with cv::Mat, with the following definition:
void adaptiveThreshold(InputArray src, OutputArray dst, double maxValue,
int adaptiveMethod, int thresholdType, int blockSize, double C);
which will need prefixed by cv:: if you're not using that namespace already.
For example:
Mat *depthImage; // Obtain this using your method
Mat image = *depthImage; // Obtain a regular Mat to use (doesn't copy data, just headers)
adaptiveThreshold(image, image,255,CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY,75,10);
imshow("Depth Image", *depthImage);
// OR
imshow("Depth Image", image);