Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

SVM predict error on OpenCV4Android

Hi guys,

I performed the training of an SVM based on the code below. I used C # for familiarity with the language. I tried doing with Java, directly on Android, but I had some problems as described in this question, mainly due to the absence of the class BOWImgDescriptorExtractor:

C# Trainning

public class Training
{
    KAZE extractor;
    BFMatcher bFMatcher;
    BOWKMeansTrainer bOWKMeansTrainer;
    BOWImgDescriptorExtractor bOWImgDescriptorExtractor;

    Mat descriptorsExtractor;
    Mat descriptorsBOWImgDescriptorExtractor;

    int dictionarySize = 32;

    Dictionary<int, int> images;
    List<int> imagesType = new List<int> { 0, 1 };

    public Training()
    {
        extractor = new KAZE(true, true);
        bFMatcher = new BFMatcher(DistanceType.L2);

        bOWKMeansTrainer = new BOWKMeansTrainer(
            dictionarySize, new MCvTermCriteria(10, 0.001),
            1, KMeansInitType.PPCenters);

        bOWImgDescriptorExtractor =
            new BOWImgDescriptorExtractor(extractor, bFMatcher);

        descriptorsExtractor = new Mat();
        descriptorsBOWImgDescriptorExtractor =
            new Mat(0, dictionarySize, DepthType.Cv32F, 1);

        images = new Dictionary<int, int>();
        images.Add(0, 15);
        images.Add(1, 17);
    }

    public void Train()
    {
        string path = System.Reflection.Assembly.GetExecutingAssembly().Location;
        path = Directory.GetParent(Directory.GetParent(path).ToString()).ToString();

        // Step 1

        for (var i = 0; i < imagesType.Count; i++)
        {
            var type = imagesType[i];

            for (var j = 1; j <= images[type]; j++)
            {
                var file = $@"{path}\Train\{type} ({j}).jpg";
                var image = new Image<Bgr, Byte>(file);

                MKeyPoint[] keyPoints = extractor.Detect(image);

                Mat descriptors = new Mat();
                extractor.Compute(image, new VectorOfKeyPoint(keyPoints), descriptors);

                descriptorsExtractor.PushBack(descriptors);
            }
        }

        bOWKMeansTrainer.Add(descriptorsExtractor);

        // Step 2

        int count = bOWKMeansTrainer.DescriptorCount;
        Console.WriteLine($"Clustering {count} descriptors");

        Mat dictionary = new Mat();
        bOWKMeansTrainer.Cluster(dictionary);

        bOWImgDescriptorExtractor.SetVocabulary(dictionary);

        // Step 3

        Matrix<int> labels;
        List<int> listLabels = new List<int>();

        for (var i = 0; i < imagesType.Count; i++)
        {
            var type = imagesType[i];

            for (var j = 1; j <= images[type]; j++)
            {
                var file = $@"{path}\Train\{type} ({j}).jpg";
                var image = new Image<Bgr, Byte>(file);

                MKeyPoint[] keyPoints = extractor.Detect(image);

                Mat descriptors = new Mat();
                bOWImgDescriptorExtractor.Compute(image, new VectorOfKeyPoint(keyPoints), descriptors);

                descriptorsBOWImgDescriptorExtractor.PushBack(descriptors);
                listLabels.Add(type);
            }
        }

        labels = new Matrix<int>(listLabels.ToArray());

        // Step 4

        SVM svm = new SVM();
        svm.SetKernel(SVM.SvmKernelType.Rbf);
        svm.Type = SVM.SvmType.CSvc;
        svm.Gamma = 0.50625000000000009;
        svm.C = 312.50000000000000;

        svm.TermCriteria = new MCvTermCriteria(100, 0.000001);

        bool result = svm.Train(
            descriptorsBOWImgDescriptorExtractor,
            Emgu.CV.ML.MlEnum.DataLayoutType.RowSample,
            labels);

        svm.Save("output.xml");

        /////////////////////////////////////////////

        var file1 = $@"{path}\Train\{1} ({18}).jpg";
        var img = new Image<Bgr, Byte>(file1);

        MKeyPoint[] keypoints = null;
        var bowDescriptor = new Mat();

        keypoints = extractor.Detect(img);
        bOWImgDescriptorExtractor.Compute(
            img,
            new VectorOfKeyPoint(keypoints),
            bowDescriptor);

        var response = svm.Predict(bowDescriptor);

        Console.WriteLine($"Result {response}");
    }
}

Question

http://answers.opencv.org/question/199980/problem-when-training-svm-with-orb-descriptors-android/

As suggested, I conducted the training using KAZE (UpRight) and BagOfWords. After generating the output.xml file, I loaded it on Android and tried to sort a simple image.

Output.xml

https://pastebin.com/fDm8Ynnx

This is the code I'm using to sort the image:

private void predict(Mat image) {

    Mat grayImage = new Mat();
    Imgproc.cvtColor(image, grayImage, Imgproc.COLOR_BGR2GRAY);

    KAZE kaze = KAZE.create();
    kaze.setUpright(true);
    kaze.setExtended(true);

    MatOfKeyPoint keyPoints = new MatOfKeyPoint();
    kaze.detect(grayImage, keyPoints);

    MatOfFloat descriptors = new MatOfFloat();
    kaze.compute(grayImage, keyPoints, descriptors);

    try {
        float result = svm.predict(descriptors);
    } catch(Exception e) {
        Log.d(TAG, e.getMessage());
    }
}

However, I have obtained this exception:

error: (-215:Assertion failed) samples.cols == var_count && samples.type() == CV_32F in function 'virtual float cv::ml::SVMImpl::predict(cv::InputArray, cv::OutputArray, int) const

I've tried several settings, but they all give me the same error.

descriptors.convertTo(descriptors, CvType.CV_32F);
try {
    float result = svm.predict(descriptors);
} catch(Exception e) {
    Log.d(TAG, e.getMessage());
}

Mat mat = descriptors.reshape(1, 1);
try {
    float result = svm.predict(mat);
} catch(Exception e) {
    Log.d(TAG, e.getMessage());
}

Mat mat = descriptors.reshape(descriptors.cols(), 1);
try {
    float result = svm.predict(mat);
} catch(Exception e) {
    Log.d(TAG, e.getMessage());
}

-----------------------------------------------------------------

Mat testMat = image.clone().reshape(image.cols(),1);
testMat.convertTo(testMat, CvType.CV_32F);
try {
    float result = svm.predict(testMat);
} catch(Exception e) {
    Log.d(TAG, e.getMessage());
}

In this case:

1 - Since I'm only using one image, I do not need to use BagOfWords. I can directly use the descriptors obtained by KAZE. Is this correct?

2 - In some examples that I found in other languages, people directly use the Mat object of the loaded image. Is it possible to call svm.predict using this Mat object?

Thank you!