android studio使用jni调用opencv库实现图片转换【详细实例】(二)

16 篇文章 0 订阅
14 篇文章 0 订阅

代码过程实现

AndroidStudio平台JNI对Opencv环境搭建请参考文章 https://blog.csdn.net/u014159143/article/details/88975487

平台开发环境

  • Android Studio 3.2
  • opencv-3.4.3-android-sdk

配置文件修改

1、将opencv和app的build.gradle中配置改成一致:

compileSdkVersion 28
minSdkVersion 17
targetSdkVersion 28

2、修改openCVLibrary343\src\main\AndroidManifest.xml文件中的配置(根据你的需要修改)

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="org.opencv"
      android:versionCode="3430"
      android:versionName="3.4.3">
    <!--uses-sdk android:minSdkVersion="17" android:targetSdkVersion="28" /-->
</manifest>

3、在app的build.gradle文件中指定jnilib目录

android {
    compileSdkVersion 28
    defaultConfig {
        ... ...
        externalNativeBuild {
            cmake {
                cppFlags "-std=c++11 -frtti -fexceptions"
            }
        }
    }
    ... ...
    externalNativeBuild {
        cmake {
            path "CMakeLists.txt"
        }
    }
    sourceSets{
        main{
            jniLibs.srcDirs = ['libs']
        }
    }
}

4、在CMakeLists.txt文件中添加opencv的库配置

cmake_minimum_required(VERSION 3.4.1)
# 添加opencv的头文件目录
include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include)
# 导入opencv的so
add_library(opencv_java3 SHARED IMPORTED)
set_target_properties(opencv_java3 PROPERTIES IMPORTED_LOCATION
        ${CMAKE_SOURCE_DIR}/libs/${ANDROID_ABI}/libopencv_java3.so)
... ...
target_link_libraries( # Specifies the target library.
        native-lib opencv_java3
        # Links the target library to the log library
        # included in the NDK.
        ${log-lib})

千万注意:以上代码中的三个库名称可以写成opencv_java3、libopencv_java3、mylib等等,这里我先前纠结了很久,主要是发现网上有写成opencv_java3的也有写成libopencv_java3的,后来我查了下cmake的原理才明白, 它的原理就是将你调用的库重新编译成一个文件,当然编译成的名字还是libopencv_java3.so(你可以对比下apk中的so库和libs下的已经不一样了),叫啥名字无所谓,只是方便jni编译和调用而已,但是一定要一致,否则将报错。

好了如果AS没有报错误,恭喜你,你的平台环境已经搭建完成,现在只需要修改代码就可实现你想要的功能了,这里我们还是用网上比较多的图片二值化效果:

编写功能代码

1、编写布局文件layout.xml

首先将你要用的图片拖进来:

编写你的布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <ImageView
        android:id="@+id/ivOld"
        android:layout_width="wrap_content"
        android:layout_height="200dp"
        android:layout_gravity="center_horizontal"
        android:src="@mipmap/luffy"/>
    <Button
        android:id="@+id/btChange"
        android:layout_gravity="center_horizontal"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="点我没用,好看而已,哈哈!"/>
    <ImageView
        android:id="@+id/ivNew"
        android:layout_width="wrap_content"
        android:layout_height="200dp"
        android:layout_gravity="center_horizontal" />
</LinearLayout>

2、编写MainActivity.java代码

package com.hello;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
import android.widget.TextView;
import org.opencv.core.Mat;
public class MainActivity extends AppCompatActivity {
    // Used to load the 'native-lib' library on application startup.
    static {
        System.loadLibrary("opencv_java3");
        System.loadLibrary("native-lib");
    }
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ImageView ivOld = (ImageView)findViewById(R.id.ivOld);
        ImageView ivNew = (ImageView)findViewById(R.id.ivNew);
		
        Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.luffy);
        int width = bitmap.getWidth();
        int height = bitmap.getHeight();
        int[] pixArr = new int[width*height];
        bitmap.getPixels(pixArr,0,width,0,0,width,height);
        gray(pixArr,width,height);
        Bitmap newBitmap = Bitmap.createBitmap(width,height,Bitmap.Config.RGB_565);
        newBitmap.setPixels(pixArr,0,width,0,0,width,height);
        ivNew.setImageBitmap(newBitmap);
    }
    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI();
    public native int[] gray(int [] pix,int w,int h);
}

说明一下,这里的gray函数是我想添加的native函数,教大家一个快速生成jni接口的方法:将光标放在gray上,按住Alt+Enter,选择Create fuction将自动生成Jni接口函数,怎么样帅不帅,还傻傻的自己写或者javac编译么,哈哈,智能改变工作。

还有一点需要说明的是System.loadlibrary(opencv_java3),在高版本android设备上是不需要的,但是如果低版本就必须写上,而且是在调用opencv_java3的jni库前面写,具体原因不知道,这是我在调试android4.2版本的时候遇到的,都是血与泪的教训啊。

3、编写native-lib.cpp

#include <jni.h>
#include <string>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <opencv2/opencv.hpp>
using namespace cv;
extern "C" JNIEXPORT jstring JNICALL
Java_com_test_MainActivity_stringFromJNI(
        JNIEnv *env,
        jobject /* this */) {
    std::string hello = "Hello from C++";
    return env->NewStringUTF(hello.c_str());
}
extern "C"
JNIEXPORT jintArray JNICALL
Java_com_test_MainActivity_gray(JNIEnv *env, jobject instance, jintArray pix_, jint w, jint h) {
    jint *pix = env->GetIntArrayElements(pix_, NULL);
    if (pix == NULL) {
        return 0;
    }
#if 1
    //将c++图片转成Opencv图片
    Mat imgData(h, w, CV_8UC4, (unsigned char *) pix);
    uchar* ptr =  imgData.ptr(0);
    for(int i = 0; i < w*h; i ++){
        //计算公式:Y(亮度) = 0.299*R + 0.587*G + 0.114*B
        //对于一个int四字节,其彩色值存储方式为:BGRA
        int grayScale = (int)(ptr[4*i+2]*0.299 + ptr[4*i+1]*0.587 + ptr[4*i+0]*0.114);
        ptr[4*i+1] = grayScale;
        ptr[4*i+2] = grayScale;
        ptr[4*i+0] = grayScale;
    }
#endif
    int size = w * h;
    jintArray result = env->NewIntArray(size);
    env->SetIntArrayRegion(result, 0, size, pix);
    env->ReleaseIntArrayElements(pix_, pix, 0);
    return result;
}

切记一定要加上opencv2/opencv.hpp和using namespace cv;

好了到这里已经全部完成了。下面来看看效果:

如果还有问题的话可以参考我的代码:点我下载

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值