Ask Your Question
0

Problem when training SVM with ORB descriptors (Android)

asked 2018-09-23 16:19:21 -0600

caiocanalli gravatar image

Hello guys!

I have a folder with 20 positive and 10 negative images and I'm trying to train an SVM through the image descriptors using ORB. I'm getting the following error when calling svm.TrainAuto:

E/cv::error(): OpenCV(3.4.1) Error: Assertion failed (samples.type() == 5 || samples.type() == 4) in void cv::ml::TrainDataImpl::setData(cv::InputArray, int, cv::InputArray, cv::InputArray, cv::InputArray, cv::InputArray, cv::InputArray, cv::InputArray), file /build/master_pack-android/opencv/modules/ml/src/data.cpp, line 259

E/org.opencv.ml: ml::trainAuto_11() caught cv::Exception: OpenCV(3.4.1) /build/master_pack-android/opencv/modules/ml/src/data.cpp:259: error: (-215) samples.type() == 5 || samples.type() == 4 in function void cv::ml::TrainDataImpl::setData(cv::InputArray, int, cv::InputArray, cv::InputArray, cv::InputArray, cv::InputArray, cv::InputArray, cv::InputArray)

The code I'm using is below:

public class TrainingActivity extends Activity {

private final String TAG = "OpenCV";

private Button mTrainingButton;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_training);

    mTrainingButton = findViewById(R.id.trainingButton);
}

@Override
protected void onResume() {
    super.onResume();
    initOpenCV();
}

public void onTrainingButtonClick(View view) {
    train();
}

private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback() {
    @Override
    public void onManagerConnected(int status) {
        switch (status) {
            case LoaderCallbackInterface.SUCCESS:
                onLoaderCallbackSuccess();
                break;
            default:
                super.onManagerConnected(status);
        }
    }
};

private void initOpenCV() {
    if (OpenCVLoader.initDebug())
        mLoaderCallback.onManagerConnected(LoaderCallbackInterface.SUCCESS);
    else
        OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_3_4_0, this, mLoaderCallback);
}

private void onLoaderCallbackSuccess() {
    mTrainingButton.setVisibility(View.VISIBLE);
}

private void train() {

    final ORB orb = ORB.create();

    Mat extractorTrainingData = new Mat();
    Mat extractorTrainingLabel = new Mat();

    String path = "/OpenCV/training/open/positives";

    File[] files = FileHelper.getFiles(path);

    // Positives

    for (File file : files) {

        try {
            Mat image = Imgcodecs.imread(file.getAbsolutePath());

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

            Log.d(TAG, grayImage.dump());

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

            Log.d(TAG, keyPoints.dump());

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

            Log.d(TAG, descriptors.dump());

            extractorTrainingData.push_back(descriptors);
            extractorTrainingLabel.push_back(Mat.ones(new Size(1, 1), CvType.CV_32S));

        } catch (Exception e) {
            Log.d(TAG, e.getMessage());
        }
    }

    path = "/OpenCV/training/open/negatives";

    files = FileHelper.getFiles(path);

    // Negatives

    for (File file : files) {

        try {
            Mat image = Imgcodecs.imread(file.getAbsolutePath());

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

            Log.d(TAG, grayImage.dump());

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

            Log.d(TAG, keyPoints.dump());

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

            Log.d(TAG, descriptors.dump());

            extractorTrainingData.push_back(descriptors);
            extractorTrainingLabel.push_back(Mat.zeros(new Size(1, 1), CvType.CV_32S));

        } catch (Exception e) {
            Log.d(TAG, e.getMessage());
        }
    }

    try {

        SVM svm = SVM.create();
        svm.setKernel(SVM.RBF);
        svm.setType(SVM.C_SVC);

        //Mat mat = extractorTrainingData.reshape(1, 1);

        //Boolean result = svm.trainAuto(
        //        mat, Ml.ROW_SAMPLE, extractorTrainingLabel);

        Boolean result = svm.trainAuto(
                extractorTrainingData, Ml.ROW_SAMPLE, extractorTrainingLabel);

        String xml = Environment
                .getExternalStorageDirectory() + "/images/svm.xml";

        if (result)
            svm.save(xml);

    } catch (Exception e) {
        Log.d(TAG, e.getMessage());
    }
}

}

I've tried using the reshape function in these settings:

Mat mat = extractorTrainingData.reshape(1, 1);
Boolean result = svm.trainAuto(mat, Ml.ROW_SAMPLE, extractorTrainingLabel);

Mat ...
(more)
edit retag flag offensive close merge delete

1 answer

Sort by » oldest newest most voted
0

answered 2018-09-24 05:11:28 -0600

berak gravatar image

updated 2018-09-24 08:05:28 -0600

I'm trying to train an SVM through the image descriptors using ORB

that won't work. you have to reconsider your approach.

ORB (or any binary) descriptors are useless here, those are uchar, bitstrings, not numbers at all, and the SVM needs float data, and operate a dot product on it.

also, different images will retrieve diffeent numbers of keypoints/descriptors, while you need fixed sized features for machine learning of any kind. (1 label and 1 train sample(row) per image)

MatOfFloat descriptors = new MatOfFloat();

that's wrong, as long as you're using binary descriptors.

I'm using Android 7.1.1, OpenCV 3.4.1, Android Studio 3.0.2

irrelevant. the problem is the wrong idea.


usually, float features, like SIFT / SURF / AKAZE(UPRIGHT) are used here, and the problem with the varying featuresize and choosing the best features from your measurement can be overtaken by BagOfWords, VLAD or similar embeddings. look it up.

edit flag offensive delete link more

Comments

Hi @berak, thanks for the reply.

ORB (or any binary) descriptors are useless...

In case, I chose to use ORB because it seems that SIFT and SURF are not available in OpenCV for Android 3.x, because they are patented and have been moved for opencv_contrib.

In this case, you have some suggestion of which descriptor I can use to work with SVM?

I tried BagOfWords, however, I had a problem with the BOWImgDescriptorExtractor class. It does not have a public builder and so I ended up leaving that approach aside.

It seems like there is an OpenCV4Android problem, but not for C ++ and Python. Unfortunately, my knowledge in these two languages and very weak.

Any suggestions on how to get around this problem?   Thank you!

caiocanalli gravatar imagecaiocanalli ( 2018-09-24 19:04:53 -0600 )edit

I tried BagOfWords,

opencv's java wrappers for this are still broken here, you have to come up with your own clustering.

SIFT and SURF are not available in OpenCV for Android

they are, once you build the SDK from src with the opencv_contrib modules.

and you can still use AKAZE(UPRIGHT)

berak gravatar imageberak ( 2018-09-24 20:21:54 -0600 )edit

Ok, thank you!

caiocanalli gravatar imagecaiocanalli ( 2018-09-24 20:25:52 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2018-09-23 16:19:05 -0600

Seen: 844 times

Last updated: Sep 24 '18