Android基于CMake進(jìn)行OpenCV開發(fā)配置

一、創(chuàng)建支持C++的android基礎(chǔ)模版項(xiàng)目

新建項(xiàng)目佑女,勾選【Include C++ support】烟馅,后續(xù)一直按【next】按鈕取默認(rèn)設(shè)置即可。

image.png

最終生成的目錄結(jié)構(gòu)如下圖:


image.png

此時(shí)直接build并運(yùn)行能正確看到效果玖像。

打開MainActivity,可以看到生成的示例代碼:

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 = (TextView) 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();
}

再打開 native-lib.cpp 文件齐饮,也可以看到自動生成的JNI風(fēng)格代碼:

#include <jni.h>
#include <string>

extern "C" JNIEXPORT jstring

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

其中Java_com_woodstream_opencvdemo_MainActivity_stringFromJNI就包含了java對應(yīng)方法的不少信息捐寥。

為了看看IDE是怎么操作的笤昨,回到MainActivity,寫入一個新的方法:

public native int[] gray(int[] buf, int w, int h);
image.png

此時(shí)方法名會標(biāo)紅握恳,在IDE的智能提示下選擇Create function xxx瞒窒,會自動跳轉(zhuǎn)到native-lib.cpp文件,并且自動添加了代碼:

extern "C"
JNIEXPORT jintArray JNICALL
Java_com_woodstream_opencvdemo_MainActivity_gray(JNIEnv *env, jobject instance, jintArray buf_,
                                                 jint w, jint h) {
    jint *buf = env->GetIntArrayElements(buf_, NULL);

    // TODO

    env->ReleaseIntArrayElements(buf_, buf, 0);
}

就這么簡單的步驟就可以進(jìn)行JNI的開發(fā)乡洼,可見Android Studio(下稱AS)大為減少我們編寫JNI的工作量崇裁,而它又是怎么工作的?常規(guī)的makefile什么的不用了束昵?

二拔稳、默認(rèn)CMake的構(gòu)建方式

  • 可以看到目錄有一個CMakeLists.txt文件。
  • 打開build.gradle锹雏,看到有外部native編譯的配置:


    image.png
  • 打開app/build/intermediates/cmake目錄壳炎,看到其子目錄下生成了so文件:


    image.png

    從這幾個信息可以知道AS默認(rèn)是通過CMake來完成上述操作的,當(dāng)然也支持android.mk的方式逼侦,但比后者要方便不少。

三腰耙、用CMake的方式集成OpenCV

首先榛丢,可以先看下此文:Android 接入 OpenCV庫的三種方式
除非你是用java寫圖像處理算法,不然不建議用第一種方式挺庞,因?yàn)閳D像識別實(shí)現(xiàn)考慮由C++來完成晰赞,所以選用第二種方式,此時(shí)如下步驟搭建OpenCV的環(huán)境:

  1. https://opencv.org/releases.html下載源碼包并解壓选侨。
  2. 新建jniLibs文件夾掖鱼,把OpenCV中sdk/native/libs內(nèi)容復(fù)制到其下:


    image.png
  3. 修改CMakeLists.txt文件:
# 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.
set(pathToOpenCv /Users/woodstream/Documents/dev/projects/android/OpenCV-android-sdk)#設(shè)置OpenCv的路徑變量
cmake_minimum_required(VERSION 3.4.1)
#支持-std=gnu++11
set(CMAKE_VERBOSE_MAKEFILE on)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11")
#配置加載native依賴
include_directories(${pathToOpenCv}/sdk/native/jni/include)
#動態(tài)方式加載
add_library(lib_opencv STATIC IMPORTED ) #表示創(chuàng)建一個導(dǎo)入庫,靜態(tài)方式
#引入libopencv_java3.so文件
set_target_properties(lib_opencv
                       PROPERTIES
                       IMPORTED_LOCATION ${PROJECT_SOURCE_DIR}/src/main/jniLibs/${}/libopencv_java3.so
                       )

# Creates and names a library, sets it as either STATIC
# or SHARED, and provides the relative paths to its source code.
# You can define multiple libraries, and CMake builds them for you.
# Gradle automatically packages shared libraries with your APK.
#自己的源文件
add_library( # Sets the name of the library.
             native-lib

             # Sets the library as a shared library.
             SHARED

             # Provides a relative path to your source file(s).
             src/main/cpp/native-lib.cpp )

# Searches for a specified prebuilt library and stores the path as a
# variable. Because CMake includes system libraries in the search path by
# default, you only need to specify the name of the public NDK library
# you want to add. CMake verifies that the library exists before
# completing its build.

find_library( # Sets the name of the path variable.
              log-lib

              # Specifies the name of the NDK library that
              # you want CMake to locate.
              log )

# Specifies libraries CMake should link to your target library. You
# can link multiple libraries, such as libraries you define in this
# build script, prebuilt third-party libraries, or system libraries.

target_link_libraries( # Specifies the target library.
                       native-lib

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

至此環(huán)境已經(jīng)搭好了(主要修改pathToOpenCv援制、set_target_properties的IMPORTED_LOCATION戏挡、add_library的source file)。

四晨仑、編寫代碼測試效果

完善C++文件native-lib.app先前生成的gray方法:

#include <jni.h>
#include <string>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;

extern "C"
JNIEXPORT jintArray JNICALL
Java_com_eastcom_cpptest_MainActivity_gray(JNIEnv *env, jobject instance, jintArray buf, jint w,
                                           jint h) {
    jint *cbuf = env->GetIntArrayElements(buf, JNI_FALSE );
    if (cbuf == NULL) {
        return 0;
    }

    Mat imgData(h, w, CV_8UC4, (unsigned char *) cbuf);

    uchar* ptr = imgData.ptr(0);
    for(int i = 0; i < w*h; i ++){
        //計(jì)算公式:Y(亮度) = 0.299*R + 0.587*G + 0.114*B
        //對于一個int四字節(jié)褐墅,其彩色值存儲方式為: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;
    }

    int size = w * h;
    jintArray result = env->NewIntArray(size);
    env->SetIntArrayRegion(result, 0, size, cbuf);
    env->ReleaseIntArrayElements(buf, cbuf, 0);
    return result;
}

MainActivity改成:

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);
        
        Bitmap bitmap = ((BitmapDrawable) getResources().getDrawable(
                R.mipmap.pic_test)).getBitmap();
        int w = bitmap.getWidth(), h = bitmap.getHeight();
        int[] pix = new int[w * h];
        bitmap.getPixels(pix, 0, w, 0, 0, w, h);
        // 調(diào)用JNI實(shí)現(xiàn)的gray方法
        int [] resultPixes = gray(pix,w,h);
        Bitmap result = Bitmap.createBitmap(w,h, Bitmap.Config.RGB_565);
        result.setPixels(resultPixes, 0, w, 0, 0,w, h);

        ImageView img = (ImageView)findViewById(R.id.img2);
        img.setImageBitmap(result);
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    public native int[] gray(int[] buf, int w, int h);

    public native String stringFromJNI();
}

activity_main.xml布局文件改成:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="16dp"
    android:paddingLeft="16dp"
    android:paddingRight="16dp"
    android:paddingTop="16dp"
    android:orientation="vertical"
    tools:context="com.eastcom.cpptest.MainActivity">

    <TextView
        android:id="@+id/txt"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="原圖:" />

    <ImageView
        android:id="@+id/img"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@mipmap/pic_test"/>


    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:text="處理后的圖:" />

    <ImageView
        android:id="@+id/img2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</LinearLayout>

此時(shí)編譯運(yùn)行可以看到效果如圖:

運(yùn)行圖
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市洪己,隨后出現(xiàn)的幾起案子妥凳,更是在濱河造成了極大的恐慌,老刑警劉巖答捕,帶你破解...
    沈念sama閱讀 221,548評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件逝钥,死亡現(xiàn)場離奇詭異,居然都是意外死亡拱镐,警方通過查閱死者的電腦和手機(jī)艘款,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評論 3 399
  • 文/潘曉璐 我一進(jìn)店門持际,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人磷箕,你說我怎么就攤上這事选酗。” “怎么了岳枷?”我有些...
    開封第一講書人閱讀 167,990評論 0 360
  • 文/不壞的土叔 我叫張陵芒填,是天一觀的道長。 經(jīng)常有香客問我空繁,道長殿衰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,618評論 1 296
  • 正文 為了忘掉前任盛泡,我火速辦了婚禮闷祥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘傲诵。我一直安慰自己凯砍,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評論 6 397
  • 文/花漫 我一把揭開白布拴竹。 她就那樣靜靜地躺著悟衩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪栓拜。 梳的紋絲不亂的頭發(fā)上座泳,一...
    開封第一講書人閱讀 52,246評論 1 308
  • 那天,我揣著相機(jī)與錄音幕与,去河邊找鬼挑势。 笑死,一個胖子當(dāng)著我的面吹牛啦鸣,可吹牛的內(nèi)容都是我干的潮饱。 我是一名探鬼主播,決...
    沈念sama閱讀 40,819評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼诫给,長吁一口氣:“原來是場噩夢啊……” “哼饼齿!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起蝙搔,我...
    開封第一講書人閱讀 39,725評論 0 276
  • 序言:老撾萬榮一對情侶失蹤缕溉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后吃型,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體证鸥,經(jīng)...
    沈念sama閱讀 46,268評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了枉层。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泉褐。...
    茶點(diǎn)故事閱讀 40,488評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖鸟蜡,靈堂內(nèi)的尸體忽然破棺而出膜赃,到底是詐尸還是另有隱情,我是刑警寧澤揉忘,帶...
    沈念sama閱讀 36,181評論 5 350
  • 正文 年R本政府宣布跳座,位于F島的核電站,受9級特大地震影響泣矛,放射性物質(zhì)發(fā)生泄漏疲眷。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評論 3 333
  • 文/蒙蒙 一您朽、第九天 我趴在偏房一處隱蔽的房頂上張望狂丝。 院中可真熱鬧,春花似錦哗总、人聲如沸几颜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽菠剩。三九已至,卻和暖如春耻煤,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背准颓。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評論 1 272
  • 我被黑心中介騙來泰國打工哈蝇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人攘已。 一個月前我還...
    沈念sama閱讀 48,897評論 3 376
  • 正文 我出身青樓炮赦,卻偏偏與公主長得像,于是被迫代替她去往敵國和親样勃。 傳聞我的和親對象是個殘疾皇子吠勘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評論 2 359

推薦閱讀更多精彩內(nèi)容