Ask Your Question

Revision history [back]

Cannot detect a simple rectangle

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));
        }
    }
}