Android Studio 3.4 配置opencv JNI 实现图片相似度对比(直方图)

想做一个图片相似度比较的程序,网上也找了好多资料,基本都是哈希算法,或者就是opencv直方图比较(灰度图),准确度不高,在opencv官网有看到一个直方图比较图片相似度的,但是是C++写的,本来想用java直接模仿它的来写,可是有些函数没有。所以我就像使用JNI,让android程序直接调用C++。

网上也找了很多关于android studio 配置opencv JNI的,都是老版本的。

下面是我找资料和摸索出来的方法。适用android studio3.4,低版本就不知道了。

 

准备:

下载opencv sdk  https://opencv.org/releases/ 我下载的是3.4.5

android studio下载相关sdk tool:LLDB(我也不确定是不是一定要) NDK CMake

 

1.新建包含C++支持的项目

和老的android studio版本不一样,这里开始就直接选择 Native C++

输入项目名,下一步

选择C++11

创建完成,结构如图

现在项目已经可以运行了,android studio已经帮你把JNI都配置好了。只能用C++标准库。下面在看怎么配置opencv

2.拷贝opencv所需要的库和头文件

把opencv sdk下的OpenCV-android-sdk/sdk/native/jni/include文件夹拷贝到你的项目中src/main/cpp下面。

把opencv sdk下的OpenCV-android-sdk/sdk/native/libs/arm64-v8a文件夹拷贝到你的项目中src/main/jniLibs下面。

jniLibs文件夹要自己新建,根据不同平台拷贝相应的libs文件,也可以全部拷。

 

3.配置CMake文件

include_directories(${CMAKE_SOURCE_DIR}/include) 把你拷贝的opencv头文件include进来。

add_library(libopencv_java3 SHARED IMPORTED ) 

add_library 函数设置库名和类型,其中libopencv_java3 是用户自定义的变量名,前后保持一致即可,SHARE 表示引入的库是动态链接库 

set_target_properties 设置了OpenCV的动态链接库的路径,就是你拷贝到项目中jniLibs的路径。

target_link_libraries中再添加我们的opencv库定义的libopencv_java3

# For more information about using CMake with Android Studio, read the
# documentation: https://d.android.com/studio/projects/add-native-code.html

# Sets the minimum version of CMake required to build the native library.

cmake_minimum_required(VERSION 3.4.1)

# 设置include文件夹的地址
include_directories(${CMAKE_SOURCE_DIR}/include)
# 设置opencv的动态库
add_library(libopencv_java3 SHARED IMPORTED )
set_target_properties(libopencv_java3 PROPERTIES IMPORTED_LOCATION
        "/home/aaron/AndroidStudioProjects/OpencvDemoJNI/app/src/main/jniLibs/${ANDROID_ABI}/libopencv_java3.so")


#省略系统代码。。。。


target_link_libraries( # Specifies the target library.
        native-lib

        libopencv_java3

        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

4. 编写C++代码 --------native-lib.cpp

Java_com_example_opencvdemojni_MainActivity_stringFromJNI 系统自己生成的

jstring2str这个方法是把jstring转成string。

Java_com_example_opencvdemojni_MainActivity_compareHist 输入2个图片的路径,然后比较相似度,第三个参数是表示用哪种算法计算。

模仿官网的方法https://docs.opencv.org/2.4/doc/tutorials/imgproc/histograms/histogram_comparison/histogram_comparison.html?highlight=comparehist

 

#include <jni.h>
#include <string>
#include<opencv2/opencv.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

using namespace cv;

extern "C" JNIEXPORT jstring JNICALL
Java_com_example_opencvdemojni_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}

std::string jstring2str(JNIEnv *env, jstring jstr) {
    char *rtn = NULL;
    jclass clsstring = env->FindClass("java/lang/String");
    jstring strencode = env->NewStringUTF("GB2312");
    jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B");
    jbyteArray barr = (jbyteArray) env->CallObjectMethod(jstr, mid, strencode);
    jsize alen = env->GetArrayLength(barr);
    jbyte *ba = env->GetByteArrayElements(barr, JNI_FALSE);
    if (alen > 0) {
        rtn = (char *) malloc(alen + 1);
        memcpy(rtn, ba, alen);
        rtn[alen] = 0;
    }
    env->ReleaseByteArrayElements(barr, ba, 0);
    std::string stemp(rtn);
    free(rtn);
    return stemp;
}

extern "C" JNIEXPORT jfloat JNICALL
Java_com_example_opencvdemojni_MainActivity_compareHist(
        JNIEnv *env,
        jobject /* this */, jstring src, jstring test, jint compare_method) {
    Mat src_base, hsv_base;
    Mat src_test, hsv_test;

    src_base = imread(jstring2str(env, src), 1);
    src_test = imread(jstring2str(env, test), 1);

    cvtColor(src_base, hsv_base, COLOR_BGR2HSV, 0);
    cvtColor(src_test, hsv_test, COLOR_BGR2HSV, 0);

    /// Using 50 bins for hue and 60 for saturation
    int h_bins = 50;
    int s_bins = 60;
    int histSize[] = {h_bins, s_bins};

    // hue varies from 0 to 179, saturation from 0 to 255
    float h_ranges[] = {0, 180};
    float s_ranges[] = {0, 256};

    const float *ranges[] = {h_ranges, s_ranges};

    // Use the o-th and 1-st channels
    int channels[] = {0, 1};

    MatND hist_base;
    MatND hist_test;

    /// Calculate the histograms for the HSV images
    calcHist(&hsv_base, 1, channels, Mat(), hist_base, 2, histSize, ranges, true, false);
    normalize(hist_base, hist_base, 0, 1, NORM_MINMAX, -1, Mat());

    calcHist(&hsv_test, 1, channels, Mat(), hist_test, 2, histSize, ranges, true, false);
    normalize(hist_test, hist_test, 0, 1, NORM_MINMAX, -1, Mat());
    switch (compare_method) {
        case 0:
            //Correlation
            compare_method = CV_COMP_CORREL;
            break;
        case 1:
            //Chi-Square
            compare_method = CV_COMP_CHISQR;
            break;
        case 2:
            //Intersection
            compare_method = CV_COMP_INTERSECT;
            break;
        case 3:
            //Bhattacharyya distance
            compare_method = CV_COMP_BHATTACHARYYA;
            break;
        default:
            compare_method = CV_COMP_CHISQR;
    }

    double result = compareHist(hist_base, hist_test, compare_method);

    return result;
}

5.声明接口和使用

在MainActivity中声明你的方法

compareHist

然后就可以使用了。参数要传图片路径。

package com.example.opencvdemojni;

import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("native-lib");
    }

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

        // Example of a call to a native method
        TextView tv = findViewById(R.id.sample_text);
        tv.setText(stringFromJNI());
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
    private native float compareHist(String src,String test,int method);
}

记得要加权限,

WRITE_EXTERNAL_STORAGE

 

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

Demo地址:

https://download.csdn.net/download/aaron121314/11244589

截图

       

 

 

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值