0

I am trying to implement an SVM with OpenCV that classifies images of sedans and SUVs. I have heavily referenced this post: using OpenCV and SVM with images

I have 29 training images of sedans and SUVs, and I stretch each image out to be 1 really long row, thus making my training Mat a size of 29ximage_area. The picture below shows that the training_mat comes out all in white, which I'm not sure is correct and it may be affecting my result.

This may be due to the training_mat being a float type. If the training_mat is changed to be CV_8UC1 for example, I can see clearly that each image is unfurled in the training_mat but the svm->train function does not accept the training_mat.

I use the labels_mat as the supervised version of the implementation. A 1 means an SUV, and a -1 means a sedan. In the picture below, when I attempt to use the SVM model to predict an SUV, I get a value of like -800000000000. No matter what I do (change parameters, use an all white test image, all black test image, change labels to only be 1 or -1) I always get that same -80000000000 value. Now any negative result may just mean -1 (sedan) but I cant be sure because it never changes. If anyone has insight on this that would be appreciated

Here is my code, result, and all white training_mat. Result Image

int num_train_images = 29;      //29 images will be used to train the SVM
int image_area = 150 * 200;     
Mat training_mat(num_train_images, image_area, CV_32FC1);   // Creates a 29 rows by 30000 columns... 29 150x200 images will be put into 1 row per image

                                                            //Converts 29 2D images into a really long row per image
for (int file_count = 1; file_count < (num_train_images + 1); file_count++) 
{
    ss << name << file_count << type;       //'Vehicle_1.jpg' ... 'Vehicle_2.jpg' ... etc ...
    string filename = ss.str();
    ss.str("");

    Mat training_img = imread(filename, 0);     //Reads the training images from the folder

    int ii = 0;                                 //Scans each column
    for (int i = 0; i < training_img.rows; i++) 
    {
        for (int j = 0; j < training_img.cols; j++)
        {
            training_mat.at<float>(file_count - 1, ii) = training_img.at<uchar>(i, j);  //Fills the training_mat with the read image
            ii++; 
        }
    }
}

imshow("Training Mat", training_mat);
waitKey(0);

//Labels are used as the supervised learning portion of the SVM. If it is a 1, its an SUV test image. -1 means a sedan. 
int labels[29] = { 1, 1, -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, 1, 1, 1, -1, -1, -1, -1, 1, 1, 1, -1, 1 };

//Place the labels into into a 29 row by 1 column matrix. 
Mat labels_mat(num_train_images, 1, CV_32S);

cout << "Beginning Training..." << endl;

//Set SVM Parameters (not sure about these values)
Ptr<SVM> svm = SVM::create();
svm->setType(SVM::C_SVC);
svm->setKernel(SVM::RBF);
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));
svm->setGamma(1);
svm->setDegree(3);

cout << "Parameters Set..." << endl;

svm->train(training_mat, ROW_SAMPLE, labels_mat);

cout << "End Training" << endl;

waitKey(0);

Mat test_image(1, image_area, CV_32FC1);        //Creates a 1 x 1200 matrix to house the test image. 

Mat SUV_image = imread("SUV_1.jpg", 0);         //Read the file folder

int jj = 0;
for (int i = 0; i < SUV_image.rows; i++)
{
    for (int j = 0; j < SUV_image.cols; j++)
    {
        test_image.at<float>(0, jj) = SUV_image.at<uchar>(i, j);    //Fills the training_mat
        jj++;
    }
}

//Should return a 1 if its an SUV, or a -1 if its a sedan
float result = svm->predict(test_image);

if (result < 0)
    cout << "Sedan" << endl;
else
    cout << "SUV" << endl;

cout << "Result: " << result << endl;

namedWindow("Test Image", CV_WINDOW_NORMAL);
imshow("Test Image", SUV_image);
waitKey(0);
David Rose
  • 53
  • 1
  • 5
  • I think your labes have to be in float and not in int.. it is not explained, but all the examples I have seen does that. At least is easy to try. Also, in OpenCV the cv::Mat in floats are suppose to be between 0-1 for displaying purposes. This means that if it is bigger than 1.0 it will be white... so it could be normal if the values can be bigger than 1.0. to visualize it you can do cv::normalize(floatMat, anotherMat, 0,255,cv::NORM_MINMAX, CV_8U); (i may have the order of the last 2 parameters wrong, since I wrote it by memory) – api55 Dec 21 '17 at 08:17

1 Answers1

0

Refer to this post for a solution to this problem I was having. Using SVM with HOG Features to Classify Vehicles

In this, I use HOG features instead of just plain pixel values of the images. The training_mat is no longer white, and the classifier works well. Additionally, the output result is a 1 or -1.

David Rose
  • 53
  • 1
  • 5