Object Detection using SVM

asked 2015-12-14 05:01:56 -0600

kaushikmit gravatar image

updated 2015-12-15 10:47:17 -0600

I was following this answer, which explains step by step the coding for svm. But I am having a runtime error in the predict function, here is the code I came up with

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include<opencv2/ml.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace cv;
using namespace cv::ml;

int main ( int argc, char** argv )
{
    cout << "Manas\n";
    char* filename;
    Mat input_image;
    VideoCapture capture(0);
    FileStorage fs;
    fs.open("SVM.xml", FileStorage::READ);
    Mat SVM_TrainingData;
    Mat SVM_Classes;
    fs["TrainingData"] >> SVM_TrainingData;
    fs["classes"] >> SVM_Classes;
    Ptr<SVM> SVM_params = SVM::create();
    SVM_params->setType(SVM::C_SVC);
    SVM_params->setKernel(SVM::LINEAR);
    SVM_params->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 0.01));
    Ptr<TrainData> td = TrainData::create(SVM_TrainingData, ROW_SAMPLE, SVM_Classes);
    SVM_params->train(td);
    while (true)
    {
        capture.read(input_image);
        resize(input_image, input_image, Size(200, 200));

        Mat img_gray;
        cvtColor(input_image, img_gray, CV_BGR2GRAY);
        blur(img_gray, img_gray, Size(5,5));
        Mat p= img_gray.reshape(1, img_gray.channels()*img_gray.size().area());
        p.convertTo(p, CV_32F);

        int response = (int)SVM_params->predict( p );
        if(response==1) cout<<"Detected";
        imshow("Plate Detected", input_image);

        int c = waitKey(10);
        if (c == 27)
            break;
    }
    return 0;
}

I am sure I am missing something, but i can't figure out what.Please suggest what else shall i include.

Update

Here is the code that I am using for training my images

#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <cv.h>
#include <highgui.h>
#include <cvaux.h>
#include <iostream>
#include <vector>
#include<string.h>
using namespace std;
using namespace cv;

int main ( int argc, char** argv )
{
    cout << "OpenCV Training SVM Automatic Number Plate Recognition\n";
    cout << "\n";

    char* path_Plates;
    char* path_NoPlates;
    int numPlates;
    int numNoPlates;
    int imageWidth=150;
    int imageHeight=150;

    //Check if user specify image to process
    if(1)
    {
        numPlates= 12;
        numNoPlates= 90 ;
        path_Plates= "/home/kaushik/opencv_work/Manas6/Pics/Positive_Images/";
        path_NoPlates= "/home/kaushik/opencv_work/Manas6/Pics/Negative_Images/i";

    }else{
        cout << "Usage:\n" << argv[0] << " <num Plate Files> <num Non Plate Files> <path to plate folder files> <path to non plate files> \n";
        return 0;
    }

    Mat classes;//(numPlates+numNoPlates, 1, CV_32FC1);
    Mat trainingData;//(numPlates+numNoPlates, imageWidth*imageHeight, CV_32FC1 );

    Mat trainingImages;
    vector<int> trainingLabels;

    for(int i=1; i<= numPlates; i++)
    {

        stringstream ss(stringstream::in | stringstream::out);
        ss<<path_Plates<<i<<".jpg";
        try{

            const char* a = ss.str().c_str();
            printf("\n%s\n",a);
            Mat img = imread(ss.str(), CV_LOAD_IMAGE_UNCHANGED);
            img= img.clone().reshape(1, 1);
            //imshow("Window",img);
            //cout<<ss.str();
            trainingImages.push_back(img);
            trainingLabels.push_back(1);
        }
        catch(Exception e){;}
    }

    for(int i=0; i< numNoPlates; i++)
    {
        stringstream ss(stringstream::in | stringstream::out);
        ss << path_NoPlates<<i << ".jpg";
        try
        {
            const char* a = ss.str().c_str();
            printf("\n%s\n",a);
            Mat img=imread(ss.str(),CV_LOAD_IMAGE_UNCHANGED);
            //imshow("Win",img);
            img= img.clone().reshape(1, 1);
            trainingImages.push_back(img);
            trainingLabels.push_back(0);
            //cout<<ss.str();
        }
        catch(Exception e){;}
    }

    Mat(trainingImages).copyTo(trainingData);
    //trainingData = trainingData.reshape(1,trainingData.rows);
    trainingData.convertTo(trainingData, CV_32FC1);
    Mat(trainingLabels).copyTo(classes);

    FileStorage fs ...
(more)
edit retag flag offensive close merge delete

Comments

And what is the error? And by the way, are you re-training the SVM in each loop iteration? That's a clear waste of time

LorenaGdL gravatar imageLorenaGdL ( 2015-12-14 05:16:37 -0600 )edit

Thanx for the suggestion. I removed the train() function outside the loop. The error is samples.cols == var_count. in predict fnction

kaushikmit gravatar imagekaushikmit ( 2015-12-14 05:59:20 -0600 )edit
1

That means that the sample vectors used for training do not have the same length as the vector provided to the predict function. Make sure you're doing the same operations/resizing in both parts

LorenaGdL gravatar imageLorenaGdL ( 2015-12-14 06:24:28 -0600 )edit

Thanx @LorenaGdL, but how do I do it ? Shall I upload my train function which saves the xml file?

kaushikmit gravatar imagekaushikmit ( 2015-12-14 07:15:42 -0600 )edit
1

Let's write-down the proper workflow, because I feel you're not sure about what you're expected to do:

  1. Preparing training samples (offline process, done 1 time): for each image, use some descriptor to extract features. The simplest features are raw pixel values (though using them won't get you anywhere). At the end, each image has gone through process X, and is described a 1D-vector of length L
  2. SVM training (offline process, done 1 time): using your database samples, train your SVM. Train it independently, and save the trained model to a .xml file
  3. Detection: before entering the per-frame loop, load your previously trained SVM from the saved .xml file. Inside the loop, apply for each frame process X, to obtain vector of length L. Use such vector in predict function
LorenaGdL gravatar imageLorenaGdL ( 2015-12-15 07:46:13 -0600 )edit

@LorenaGdL thanx for the steps. Seems as if I already have covered the second and third points. But I don't have any clue about the first step. Can you please help me with it. I was using this for converting to 1d array Mat p= img_gray.reshape(1, img_gray.channels()*img_gray.size().area());.

kaushikmit gravatar imagekaushikmit ( 2015-12-15 08:24:12 -0600 )edit

As I said, you need to use the same function as the one used during the preparation of samples. That for the program to work. To make it work properly (i.e. correctly detecting objects) you will need to use other features rather than pixel values. The topic is extensive, Google will help better there

LorenaGdL gravatar imageLorenaGdL ( 2015-12-15 08:34:21 -0600 )edit