android studio使用jni調用opencv庫實現圖片轉換【詳細實例】(二)

代碼過程實現

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;

好了到這裏已經全部完成了。下面來看看效果:

如果還有問題的話可以參考我的代碼:點我下載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章