angel208
angel208

Reputation: 281

Training an SVM using hu moments

im learning about SVM, so im making a sample program that trains an SVM to detect if a symbol is in an image or if its not. All the images are black and white (the symbols would be black and the background white). I have 12 training images, 6 positives (with the symbol) and 6 negatives (without it). Im using hu moments to get the descriptors of every image and then i construct the training matrix with those descriptors. also i have a Labels matrix, which contains a label for each image: 1 if its positive and 0 if its negative. but im getting an error (something like a segmentation fault) at the line where i train the SVM. here is my code:

using namespace cv;
using namespace std;

int main(int argc, char* argv[])
{
    //arrays where the labels and the features will be stored
    float labels[12] ;
    float trainingData[12][7] ;

    Moments moment;
    double hu[7];

  //===============extracting the descriptos for each positive image=========
    for ( int i = 0; i <= 5; i++){

        //the images are called t0.png ... t5.png and are in the folder train
        std::string path("train/t");
        path += std::to_string(i);
        path += ".png";

        Mat input = imread(path, 0); //read the images
        bitwise_not(input, input); //invert black and white
        Mat BinaryInput;
        threshold(input, BinaryInput, 100, 255, cv::THRESH_BINARY); //apply theshold

        moment = moments(BinaryInput, true); //calculate the moments of the current image
        HuMoments(moment, hu); //calculate the hu moments (this will be our descriptor)

        //setting the row i of the training data as the hu moments
        for (int j = 0; j <= 6; j++){
            trainingData[i][j] = (float)hu[j];
        }

        labels[i] = 1; //label=1 because is a positive image
    }

  //===============extracting the descriptos for each negative image=========
    for (int i = 0; i <= 5; i++){

        //the images are called tn0.png ... tn5.png and are in the folder train
        std::string path("train/tn");
        path += std::to_string(i);
        path += ".png";

        Mat input = imread(path, 0); //read the images
        bitwise_not(input, input); //invert black and white
        Mat BinaryInput;
        threshold(input, BinaryInput, 100, 255, cv::THRESH_BINARY); //apply theshold

        moment = moments(BinaryInput, true); //calculate the moments of the current image
        HuMoments(moment, hu); //calculate the hu moments (this will be our descriptor)

        for (int j = 0; j <= 6; j++){
            trainingData[i + 6][j] = (float)hu[j];
        }

         labels[i + 6] = 0;  //label=0 because is a negative image

    }
    
//===========================training the SVM================
    //we convert the labels and trainingData matrixes to Mat objects
    Mat labelsMat(12, 1, CV_32FC1, labels);
    Mat trainingDataMat(12, 7, CV_32FC1, trainingData);

    //create the SVM
    Ptr<ml::SVM> svm = ml::SVM::create();
    
    //set the parameters of the SVM
    svm->setType(ml::SVM::C_SVC);
    svm->setKernel(ml::SVM::LINEAR);
    CvTermCriteria criteria = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);
    svm->setTermCriteria(criteria);

     //Train the SVM !!!!!HERE OCCURS THE ERROR!!!!!!
     svm->train(trainingDataMat, ml::ROW_SAMPLE, labelsMat);


    //Testing the SVM...
    Mat test = imread("train/t1.png", 0); //this should be a positive test
    bitwise_not(test, test);
    Mat testBin;
    threshold(test, testBin, 100, 255, cv::THRESH_BINARY);

    Moments momentP = moments(testBin, true); //calculate the moments of the test image

    double huP[7];
    HuMoments(momentP, huP);

    Mat testMat(1, 7, CV_32FC1, huP); //setting the hu moments to the test matrix

    double resp = svm->predict(testMat); //pretiction of the SVM
    printf("%f", resp); //Response

    getchar();

}

i know that the program is running fine until that line because i printed labelsMat and trainingDataMat and the values inside them are ok. Even in the console i can see that the program is running fine until that exact line executes. the console then shows this message:

OpenCV error: Bad argument (in the case of classification problem the responses must be categorical;  either specify varType when creating TrainDatam or pass integer responses)

i dont really know what this means. any idea of what could be causing the problem? if you need any other details please tell me.

EDIT

for future readers:

the problem was in the way i defined the labels array as an array of float and the LabelsMat as a Mat of CV_32FC1. the array that contains the labels needs to have integers inside, so i changed:

float labels[12];

to

int labels[12];

and also changed

Mat labelsMat(12, 1, CV_32FC1, labels);

to

Mat labelsMat(12, 1, CV_32SC1, labels);

and that solved the error. Thank you

Upvotes: 1

Views: 880

Answers (1)

mattyb
mattyb

Reputation: 1161

Trying changing:

Mat labelsMat(12, 1, CV_32FC1, labels);

to

Mat labelsMat(12, 1, CV_32SC1, labels);

From: http://answers.opencv.org/question/63715/svm-java-opencv-3/

If that doesn't work, hopefully one of these posts will help you:

Opencv 3.0 SVM train classification issues

OpenCV SVM Training Data

Upvotes: 2

Related Questions