Ask Your Question
0

BagOfWords works in C#, but not in C++

asked 2018-10-01 13:08:30 -0600

caiocanalli gravatar image

updated 2018-10-01 13:08:45 -0600

Hello guys,

As suggested in this post, I implemented in C++, the same method I used to train my SVM in C #. Initially, I load the vocabulary generated by the program in C# through a JNI call in C++, because the FileStorage class is not available in OpenCV4Android:

JNIEXPORT
void JNICALL Java_test_vision_MainActivity_loadVocabulary(
        JNIEnv* env,
        jobject,
        jstring vocabularyPath,
        jlong addrVocabulary)
{
    const char *str = env->GetStringUTFChars(vocabularyPath, 0);

    Mat& vocabulary = *(Mat*)addrVocabulary;

    cv::FileStorage opencv_file(str, cv::FileStorage::READ);
    opencv_file["vocabulary"] >> vocabulary;
    opencv_file.release();
}

After that, I load an image through Java, and pass the Mat object to a second C++ method, which has all the implementation of BagOfWords and SVM Predict.

Java:

Mat image = Utils.loadResource(MainActivity.this, R.raw.image, Imgcodecs.CV_LOAD_IMAGE_GRAYSCALE);

predict(trainedData,
            vocabularyMat.getNativeObjAddr(),
            image.getNativeObjAddr(),
            bowDescriptor.getNativeObjAddr());

C++

JNIEXPORT
void JNICALL Java_test_vision_MainActivity_predict(
        JNIEnv* env,
        jobject,
        jstring trainedData,
        jlong addrVocabulary,
        jlong addrRgba,
        jlong addrBowDescriptor) {

    const char *str = env->GetStringUTFChars(trainedData, 0);

    Mat& vocabulary = *(Mat*)addrVocabulary;
    Mat& bowDescriptor = *(Mat*)addrBowDescriptor;

    int dictionarySize = 32;

    Ptr<DescriptorExtractor> extractor = KAZE::create();

    Ptr<BFMatcher> bFMatcher = new BFMatcher(cv::NORM_L2);

    Ptr<BOWKMeansTrainer> bOWKMeansTrainer
            = new BOWKMeansTrainer(
                    dictionarySize,
                    TermCriteria(
                            TermCriteria::MAX_ITER +
                            TermCriteria::EPS,
                            10,
                            0.0001),
                    1, KMEANS_PP_CENTERS);

    Ptr<BOWImgDescriptorExtractor> bOWImgDescriptorExtractor =
            new BOWImgDescriptorExtractor(extractor, bFMatcher);

    Ptr<ml::SVM> svm = ml::SVM::create();
    svm->setType(ml::SVM::C_SVC);
    svm->load(str);

    bOWImgDescriptorExtractor->setVocabulary(vocabulary);

    std::vector<KeyPoint> keyPoints;

    Mat& src = *(Mat*)addrRgba;

    try {
        extractor->detect(src, keyPoints);
        bOWImgDescriptorExtractor->compute(src, keyPoints, bowDescriptor);
    } catch(exception& e) {
        const char *teste = e.what();
        cout << teste;
    }

    float response = svm->predict(bowDescriptor);

    cout << response;
}

However, I have received this error when calling bOWImgDescriptorExtractor.compute:

"OpenCV(3.4.3) /build/3_4_pack-android/opencv/modules/core/src/batch_distance.cpp:238: error: (-215:Assertion failed) type == src2.type() && src1.cols == src2.cols && (type == CV_32F || type == CV_8U) in function 'void cv::batchDistance(cv::InputArray, cv::InputArray, cv::OutputArray, int, cv::OutputArray, int, int, cv::InputArray, int, bool)'\n"

Sorry for the size of the question, but I tried to put as much information as possible.

Thank you.

edit retag flag offensive close merge delete

Comments

also: svm->load(str); -- common pitfall. it's a static method returning a new object ! try:

svm = SVM::load(str);

`

berak gravatar imageberak ( 2018-10-01 21:09:17 -0600 )edit

Hi @berek!

I discovered this a bit after answering the question. Actually, this is the correct way to load the SVM.

Ptr<SVM> svm = SVM::create();
svm = Algorithm::load<SVM>(path);

Finally I was able to call predict and correctly sort some images Yeaaaah!

Thanks for your help, it was essential!

caiocanalli gravatar imagecaiocanalli ( 2018-10-01 21:47:06 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
0

answered 2018-10-01 21:04:56 -0600

caiocanalli gravatar image

I found the problem. The issue was that I was creating an instance of KAZE detector, without setting extended and upright.

By constituting this line, I can extract the descriptors correctly.

Ptr<DescriptorExtractor> extractor = KAZE::create(true, true);

Sucess!

edit flag offensive delete link more

Question Tools

1 follower

Stats

Asked: 2018-10-01 13:08:30 -0600

Seen: 241 times

Last updated: Oct 01 '18