Joaquín L. Robles
Joaquín L. Robles

Reputation: 6494

How to train an SVM with opencv based on a set of images?

I have a folder of positives and another of negatives images in JPG format, and I want to train an SVM based on that images, I've done the following but I receive an error:

Mat classes = new Mat();
Mat trainingData = new Mat();

Mat trainingImages = new Mat();
Mat trainingLabels = new Mat();

CvSVM clasificador;

for (File file : new File(path + "positives/").listFiles()) {
        Mat img = Highgui.imread(file.getAbsolutePath());
        img.reshape(1, 1);

        trainingImages.push_back(img);
        trainingLabels.push_back(Mat.ones(new Size(1, 1), CvType.CV_32FC1));
    }

    for (File file : new File(path + "negatives/").listFiles()) {
        Mat img = Highgui.imread(file.getAbsolutePath());
        img.reshape(1, 1);

        trainingImages.push_back(img);
        trainingLabels.push_back(Mat.zeros(new Size(1, 1), CvType.CV_32FC1));
    }

    trainingImages.copyTo(trainingData);
    trainingData.convertTo(trainingData, CvType.CV_32FC1);
    trainingLabels.copyTo(classes);

    CvSVMParams params = new CvSVMParams();
    params.set_kernel_type(CvSVM.LINEAR);

    clasificador = new CvSVM(trainingData, classes, new Mat(), new Mat(), params);

When I try to run that I obtain:

OpenCV Error: Bad argument (train data must be floating-point matrix) in cvCheckTrainData, file ..\..\..\src\opencv\modules\ml\src\inner_functions.cpp, line 857
Exception in thread "main" CvException [org.opencv.core.CvException: ..\..\..\src\opencv\modules\ml\src\inner_functions.cpp:857: error: (-5) train data must be floating-point matrix in function cvCheckTrainData
]
    at org.opencv.ml.CvSVM.CvSVM_1(Native Method)
    at org.opencv.ml.CvSVM.<init>(CvSVM.java:80)

I can't manage to train the SVM, any idea? Thanks

Upvotes: 6

Views: 14033

Answers (2)

Bee
Bee

Reputation: 2502

Assuming that you know what you are doing by reshaping an image and using it to train SVM, the most probable cause of this is that your

Mat img = Highgui.imread(file.getAbsolutePath());

fails to actually read an image, generating a matrix img with null data property, which will eventually trigger the following in the OpenCV code:

// check parameter types and sizes
if( !CV_IS_MAT(train_data) || CV_MAT_TYPE(train_data->type) != CV_32FC1 )
    CV_ERROR( CV_StsBadArg, "train data must be floating-point matrix" );

Basically train_data fails the first condition (being a valid matrix) rather than failing the second condition (being of type CV_32FC1).

In addition, even though reshape works on the *this object, it acts like a filter and its effect is not permanent. If it's used in a single statement without immediately being used or assigned to another variable it will be useless. Change the following lines in your code:

img.reshape(1, 1);
trainingImages.push_back(img);

to:

trainingImages.push_back(img.reshape(1, 1));

Upvotes: 11

morynicz
morynicz

Reputation: 2332

Just as the error says, You need to change type of Your matrix, from integer type, probably CV_8U, to floating point one, CV_32F or CV_64F. To do it You can use cv::Mat::convertTo(). Here is a bit about depths and types of matrices.

Upvotes: 0

Related Questions