Android JUnit test with OpenCV

This article shows how to do image matching in android JUnit test.

The following shows the method to search for a second image in a first image and return a simularity percentage.
  1. Import OpenCV to android
  2. Code to do the comparing
  3. Improve code
    Thanks to all of them, saved my time.

1.1 Download the latest OpenCV sdk from OpenCV.org, choose "Android pack", decompress the zip file to local.
1.2 Import the OpenCV to Android Studio, in the project, from "File -> New -> Import Module", choose "sdk/java" folder in OpenCV android sdk folder.
1.3 Update "build.gradle" under the "imported module" to update the 4 fields to match the "app/build.gradle"
a. compileSdkVersion
b. buildToolsVersion
c. minSdkVersion
d. targetSdkVersion
1.4 Add module dependency by "File -> Project Structure", and in "app" select the "Dependencies", click "+" on the top right corner, choose "Module Dependency" and select the imported OpenCV module.
1.5 Copy libs folder under "sdk/native" to android studio under "app/src/main".
1.6 Under "app/src/main/libs", remove the unnecessary folders according to your platform. In this case, I removed all folders except for "armeabi" and "armeabi-v7a".
Then remove the unnecessary files from the remaining folders under "app/src/main/libs/", in my case, I removed all files except for the one "libopencv_java3.so" in the two remaining folders.
1.7 In android studio, rename the copied libs directory to 'jniLibs'.
This step is very important, since Android Studio expects native libs in app/src/main/jniLibs instead of libs folder. And the new folder name MUST exactly be jniLibs.
(OR create a jni folder in the first place:

  • Locate Project
  • Locate app
  • Right click - New - Folder - JNI Folder)
    1.8 In the test class, add the following code, and we can get the result from the log:
    private static String TAG = "Test";

    static {
        System.loadLibrary("opencv_java3");
    }

    static {
        if (!OpenCVLoader.initDebug()){
            Log.w(TAG, "static initializer: Fail to load opencv libs !");
            Log.w(TAG, "static initializer: Thus fail the case.");
            fail();
        } else {
            Log.i(TAG, "static initializer: Succeed to load opencv libs !");
        }
    }

If we get the log "static initializer: Succeed to load opencv libs !", then the whole importing thing is done!

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

The first stage is done.

The second and the third stages are shown below :
private static final double THRESHOLD = 0.95;
private static String TAG = "Test";

Boolean matchImages(Mat img, Mat template, String outFile, String suffix) throws IOException {
        Log.i(TAG, "matchImages: Run image match method complex version.");
        outFile += suffix;
        if (new File(outFile).exists()){
            Boolean flag = new File(outFile).delete();
            Log.i(TAG, "matchImages: The result file already exists , delete it now : " + flag);
        }

        //Mat img = Utils.loadResource(mContext, inFileID, Imgcodecs.CV_LOAD_IMAGE_COLOR);
        if (!img.empty()){
            Log.i(TAG, "matchImages: Load source image succeed !");
        } else {
            Log.w(TAG, "matchImages: Fail to load source image !!!");
        }

        //Mat template = Utils.loadResource(mContext, templateFileID, Imgcodecs.CV_LOAD_IMAGE_COLOR);

        if (!template.empty()) {
            Log.i(TAG, "matchImages: Load template image succeed !");
        } else {
            Log.w(TAG, "matchImages: Fail to load template image !!!");
        }

        int result_cols = img.cols() - template.cols() + 1;
        int result_rows = img.rows() - template.rows() + 1;
        Mat result = new Mat(result_rows, result_cols, CvType.CV_32FC1);

        //NEVER do the matching and NOT normalize
        Imgproc.matchTemplate(img, template, result, Imgproc.TM_CCOEFF_NORMED);

        //Localize the best match with minMaxLoc
        Core.MinMaxLocResult mmr = Core.minMaxLoc(result);

        Point matchLoc;

        matchLoc = mmr.maxLoc;

        Log.i(TAG, "Match percentage : " + mmr.maxVal);

        //Draw the rectangle.
        Imgproc.rectangle(img, matchLoc, new Point(matchLoc.x + template.cols(), matchLoc.y + template.rows()),
                new Scalar(0, 255, 0), 8);

        //Save the visualized detection
        Log.i(TAG, "matchImages: Write to " + outFile);
        Imgcodecs.imwrite(outFile, img);
        if (mmr.maxVal >= THRESHOLD) {
            Log.i(TAG, "matchImages: Match percentage is above the THRESHOLD.");
            Log.i(TAG, "matchImages: ###### Found match . ######");
            return true;
        } else {
            Log.w(TAG, "matchImages: Match percentage is below the THRESHOLD!!!");
            Log.w(TAG, "matchImages: ****** None match . ******");
            return false;
        }
    }

As suggested, certain points MUST be noticed:

a. The matching method should better be "Imgproc.TM_CCOEFF_NORMED".
b. With this matching method, "mmr.maxVal" returns the highest simularity percentage of the images.
c. The following code should NOT be applied if we'd like to get a proper percentage:

Core.normalize(result, result, 0, 1, Core.NORM_MINMAX, -1, new Mat());

d. The format of the two Mat images MUST be exactly the same. That is :

Mat.channels()
Mat.type()

If not, android studio is likely to throw an error.
Transfer one to match the other before do image matching.
Refer to:

And that's all.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Correctness AdapterViewChildren Summary: AdapterViews can...
    MarcusMa阅读 12,871评论 0 6
  • afinalAfinal是一个android的ioc,orm框架 https://github.com/yangf...
    passiontim阅读 15,721评论 2 45
  • 若是想着遥远的远方 就会有遍地的荒凉 还有那光脚的悲伤 所以我们抓住了太阳 双脚滚烫 遗忘了远方的荒凉 远方那个地...
    _三公子_阅读 1,417评论 0 0
  • 湘西的年是最有味道的,浓浓的年味从冬月就开始了:打粑粑,推豆腐,过赶年,洗年脚,当然还有百狮会,调年盘歌……热热闹...
    财神出位阅读 3,980评论 1 4
  • 相信所有的经历都是渡缘的船 相信有爱的心会遇见美好 相信偌大的地球空间里 没有早一步亦没有晚一步的遇见 让过去过去...
    舍得_之间阅读 1,677评论 7 5