I am using code inspired by https://github.com/opencv/opencv/blob/master/samples/cpp/train_HOG.cpp. My code is barely any different, and yet cannot detect ANYTHING. Any help would be appreciated. When running the program, it says (as I have instructed it to if this happens) that the list of detections is empty...
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include "opencv2/imgcodecs.hpp"
#include <opencv2/highgui.hpp>
#include <opencv2/ml.hpp>
#include <opencv2/objdetect.hpp>
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include <time.h>
using namespace cv;
using namespace cv::ml;
using namespace std;
void getSvmDetector(Ptr<SVM> & svm, vector < float > & detector);
void draw_locations(Mat & img, const vector < Rect > & locations, const Scalar & color);
void load_images(string dir, vector< Mat > & images, int numFiles);
void compute_hog(vector < Mat > & mats, vector < Mat > & gradient, Size & s);
void train_svm(const vector < Mat > & gradient_list, const vector < int > & labels);
void convert_to_ml(const vector< Mat > & train_samples, Mat & trainData);
int main(int, char**)
{
int numPos = 6;
int numNeg = 20;
vector< Mat > pos_lst;
vector< Mat > neg_lst;
vector< Mat > gradient_list;
vector < int > labels;
string posDir = "C:/Users/danekstein/Desktop/rectangle/";
string negDir = "C:/Users/danekstein/Desktop/nr/";
// load and label positive images
cout << "positive images loading..." << endl;
load_images(posDir, pos_lst, numPos);
labels.assign(pos_lst.size(), +1);
// size with only positives
const unsigned int old = (unsigned)labels.size();
// load and label positive images
cout << "negative images loading..." << endl;
load_images(negDir, neg_lst, numNeg);
labels.insert(labels.end(), neg_lst.size(), -1);
// check the labels were successfully added
CV_Assert(old < labels.size());
cout << "computing hog for positives" << endl;
compute_hog(pos_lst, gradient_list, Size(256, 128));
cout << "computing hog for negatives" << endl;
compute_hog(neg_lst, gradient_list, Size(256, 128));
train_svm(gradient_list, labels);
Scalar border_color(0, 255, 0);
Mat img, draw;
Ptr<SVM> svm;
HOGDescriptor hog = HOGDescriptor::HOGDescriptor();
hog.winSize = Size(256, 128);
// locations where a plane is detected
vector< Rect > locations;
// loading the trained svm
svm = StatModel::load<SVM>("C:/Users/danekstein/Desktop/r.yml");
// set the trained svm to the hog
vector< float > hog_detector;
getSvmDetector(svm, hog_detector);
// set the detector
hog.setSVMDetector(hog_detector);
Mat image = imread("C:/Users/danekstein/Desktop/rectangle/1.jpg");
locations.clear();
cout << "detecting features from sample" << endl;
hog.detectMultiScale(image,locations);
draw = image.clone();
draw_locations(draw, locations, border_color);
imshow("Image", draw);
waitKey(0);
destroyAllWindows();
}
void load_images(string dir, vector< Mat > & images, int numImages) {
for (int i = 0; i < numImages; i++) {
Mat im = imread(dir + to_string(i) + ".jpg");
if (im.empty()) cout << "not good";
#ifdef _DEBUG
#endif
images.push_back(im.clone());
}
}
void compute_hog(vector < Mat > & mats, vector < Mat > & gradients, Size & size) {
HOGDescriptor hog;
hog.winSize = size;
Mat gray;
vector< Point > location;
vector< float > descriptors;
vector< Mat >::const_iterator img = mats.begin();
vector< Mat >::const_iterator end = mats.end();
for (; img != end; ++img) {
cvtColor(*img, gray, COLOR_BGR2GRAY);
hog.compute(gray, descriptors, Size(1,1), Size(0, 0), location);
gradients.push_back(Mat(descriptors).clone());
}
}
void getSvmDetector(Ptr<SVM> & svm, vector< float> & detector) {
// grab the support vectors... yay!
Mat sv = svm->getSupportVectors();
const int sv_total = sv.rows;
// get the decision function
Mat alpha, svidx;
double rho = svm->getDecisionFunction(0, alpha, svidx);
CV_Assert(alpha.total() == 1 && svidx.total() == 1 && sv_total == 1);
CV_Assert((alpha.type() == CV_64F && alpha.at<double>(0) == 1.) ||
(alpha.type() == CV_32F && alpha.at<float>(0) == 1.f));
CV_Assert(sv.type() == CV_32F);
detector.clear();
detector.resize(sv.cols + 1);
memcpy(&detector[0], sv.ptr(), sv.cols * sizeof(detector[0]));
detector[sv.cols] = (float)-rho;
}
void draw_locations(Mat & img, const vector < Rect > & locations, const Scalar & color) {
if (!locations.empty()) {
vector< Rect >::const_iterator loc = locations.begin();
vector< Rect >::const_iterator end = locations.end();
for (; loc != end; ++loc) {
rectangle(img, *loc, color, 2);
}
}
else { cout << "locations are empty" << endl; }
}
void train_svm(const vector < Mat > & gradient_list, const vector < int > & labels) {
Mat train_data;
convert_to_ml(gradient_list, train_data);
clog << "training..." << endl;
Ptr<SVM> svm = SVM::create();
svm->setCoef0(0.0);
svm->setDegree(3);
svm->setTermCriteria(TermCriteria(CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 1000, 1e-3));
svm->setGamma(0);
svm->setKernel(SVM::LINEAR);
svm->setNu(0.5);
svm->setP(0.1); // for EPSILON_SVR, epsilon in loss function?
svm->setC(0.01); // From paper, soft classifier
svm->setType(SVM::EPS_SVR); // C_SVC; // EPSILON_SVR; // may be also NU_SVR; // do regression task
svm->train(train_data, ROW_SAMPLE, Mat(labels));
clog << "finished training" << endl;
svm->save("C:/Users/danekstein/Desktop/r.yml");
}
void convert_to_ml(const vector< Mat > & train_samples, Mat& trainData)
{
//--Convert data
const int rows = (int)train_samples.size();
const int cols = (int)std::max(train_samples[0].cols, train_samples[0].rows);
cv::Mat tmp(1, cols, CV_32FC1); //< used for transposition if needed
trainData = cv::Mat(rows, cols, CV_32FC1);
vector< Mat >::const_iterator itr = train_samples.begin();
vector< Mat >::const_iterator end = train_samples.end();
for (int i = 0; itr != end; ++itr, ++i)
{
CV_Assert(itr->cols == 1 ||
itr->rows == 1);
if (itr->cols == 1)
{
transpose(*(itr), tmp);
tmp.copyTo(trainData.row(i));
}
else if (itr->rows == 1)
{
itr->copyTo(trainData.row(i));
}
}
}