Android引入OpenCV

簡(jiǎn)介

在移動(dòng)開發(fā)中闺鲸,如果我們要實(shí)現(xiàn)一些圖像處理相關(guān)的功能,難免要用到OpenCV赛糟。而OpenCV是用c++開發(fā)的派任。我們?cè)贏ndroid中,需要使用jni的方法去使用它璧南。

引入配置

我們引入jni開發(fā)的基本配置方法掌逛,已經(jīng)在另一篇博客中介紹過了,不再贅述司倚。這一次我們無非是要引入第三方的c++庫豆混。

首先,我們找到或新建jniLibs文件夾动知,然后將依賴的動(dòng)態(tài)庫和靜態(tài)庫(路徑為OpenCV-android-sdk\sdk\native\libs)拷貝到\src\main\jniLibs下面皿伺。

然后,找到cpp文件夾盒粮。將include文件夾(路徑OpenCV-android-sdk\sdk\native\jni\include)拷貝到cpp(路徑\app\src\main\cpp)文件夾里心傀。

接著,我們需要引入c++的相關(guān)支持拆讯。在module的build.gradle里面加入:

externalNativeBuild {
    cmake {
        //arguments  '-DANDROID_TOOLCHAIN=clang', '-DANDROID_STL=gnustl_static'
        cppFlags "-std=c++11","-frtti", "-fexceptions"
    }
}
ndk{
    abiFilters 'armeabi-v7a'
}

最后脂男,我們需要在CMakeLists.txt中,加入opencv相關(guān)的聲明种呐。由于配置比較復(fù)雜宰翅,在此直接將demo的CMakeLists.txt的內(nèi)容貼到這里。

# 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)

# 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.

set(CMAKE_VERBOSE_MAKEFILE on)
set(libs "${CMAKE_SOURCE_DIR}/src/main/jniLibs")
include_directories(${CMAKE_SOURCE_DIR}/src/main/cpp/include)

add_library(libopencv_java3 SHARED IMPORTED )
set_target_properties(libopencv_java3 PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_java3.so")

add_library(libopencv_calib3d STATIC IMPORTED )
set_target_properties(libopencv_calib3d PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_calib3d.a")

add_library(libopencv_core STATIC IMPORTED )
set_target_properties(libopencv_core PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_core.a")

add_library(libopencv_features2d STATIC IMPORTED )
set_target_properties(libopencv_features2d PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_features2d.a")

add_library(libopencv_flann STATIC IMPORTED )
set_target_properties(libopencv_flann PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_flann.a")

add_library(libopencv_highgui STATIC IMPORTED )
set_target_properties(libopencv_highgui PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_highgui.a")

add_library(libopencv_imgcodecs STATIC IMPORTED )
set_target_properties(libopencv_imgcodecs PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_imgcodecs.a")

add_library(libopencv_imgproc STATIC IMPORTED )
set_target_properties(libopencv_imgproc PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_imgproc.a")

add_library(libopencv_ml STATIC IMPORTED )
set_target_properties(libopencv_ml PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_ml.a")

add_library(libopencv_objdetect STATIC IMPORTED )
set_target_properties(libopencv_objdetect PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_objdetect.a")

add_library(libopencv_photo STATIC IMPORTED )
set_target_properties(libopencv_photo PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_photo.a")

add_library(libopencv_shape STATIC IMPORTED )
set_target_properties(libopencv_shape PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_shape.a")

add_library(libopencv_stitching STATIC IMPORTED )
set_target_properties(libopencv_stitching PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_stitching.a")

add_library(libopencv_superres STATIC IMPORTED )
set_target_properties(libopencv_superres PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_superres.a")

add_library(libopencv_video STATIC IMPORTED )
set_target_properties(libopencv_video PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_video.a")

add_library(libopencv_videoio STATIC IMPORTED )
set_target_properties(libopencv_videoio PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_videoio.a")

add_library(libopencv_videostab STATIC IMPORTED )
set_target_properties(libopencv_videostab PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_videostab.a")

add_library(libopencv_ts STATIC IMPORTED )
set_target_properties(libopencv_ts PROPERTIES
    IMPORTED_LOCATION "${libs}/${ANDROID_ABI}/libopencv_ts.a")

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++11 -fexceptions -frtti")

#include_directories(D:/Projects/Android/CLMAndroid/OpenCV-android-sdk/sdk/native/jni/include )
#set(OpenCV_DIR D:/Projects/Android/CLMAndroid/OpenCV-android-sdk/sdk/native/jni)
#find_package(OpenCV REQUIRED)
#target_link_libraries(${OpenCV_LIBS})

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 android log
    libopencv_java3 libopencv_calib3d libopencv_core libopencv_features2d libopencv_flann libopencv_highgui libopencv_imgcodecs
    libopencv_imgproc libopencv_ml libopencv_objdetect libopencv_photo libopencv_shape libopencv_stitching libopencv_superres
    libopencv_video libopencv_videoio libopencv_videostab
                       # Links the target library to the log library
                       # included in the NDK.
                       ${log-lib} )

這樣配置之后爽室,我們就可以在cpp中汁讼,直接使用OpenCV庫了。在此貼一個(gè)簡(jiǎn)單的均值濾波:

#include <jni.h>
#include <string>
#include <opencv2/opencv.hpp>
#include <bits/stdc++.h>
#include <android/log.h>
#include<opencv2/core/core.hpp>
#include"opencv2/imgproc/imgproc.hpp"


using namespace cv;
using namespace std;

#define MAKE_ARGB(a, r, g, b) ((a&0xff)<<24) | ((r&0xff)<<16) | ((g&0xff)<<8) | (b&0xff)
#define MAKE_RGB565(r, g, b) ((((r) >> 3) << 11) | (((g) >> 2) << 5) | ((b) >> 3))

extern "C"
{

    JNIEXPORT jintArray JNICALL
    Java_com_live_longsiyang_opencvdemo_OpenCVNativeManager_getBlurImage(JNIEnv *env, jobject thiz,
                                                                         jintArray pixels_, jint w,
                                                                         jint h) {
        int colorType = CV_8UC4;
    
        jint *pixels = env->GetIntArrayElements(pixels_, NULL);
    
        Mat imgMat(h, w, colorType, pixels);
    
        Mat out(h, w, colorType);
    
        blur(imgMat, out, Size(20, 20));
    
        env->ReleaseIntArrayElements(pixels_, pixels, 0);
    
        int *outIntImage = new int[w * h];
    
        for (int i = 0; i < w * h; i++) {
            int a, r, g, b;
            for (int j = 0; j < 4; j++) {
                a = out.data[i * 4 + 3];
                r = out.data[i * 4 + 2];
                g = out.data[i * 4 + 1];
                b = out.data[i * 4 + 0];
                outIntImage[i] = (int) out.data[i * 4 + j];
            }
            outIntImage[i] = MAKE_ARGB(a,r,g,b);
    
        }
    
        jintArray result = env->NewIntArray(w * h);
    
        env->SetIntArrayRegion(result, 0, w * h, outIntImage);
        return result;
    
    }
}


這樣我們就能看到一個(gè)基本的模糊效果的demo阔墩。

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {


    static {
        System.loadLibrary("native-lib");
    }


    ImageView mIvTest;
    Button mBtnTest;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mIvTest = (ImageView) findViewById(R.id.img_test);
        mIvTest.setImageResource(R.drawable.beauty_steward_course_video_thumb_icon);
        mBtnTest = (Button) findViewById(R.id.btn_test);
        mBtnTest.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Bitmap srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.beauty_steward_course_video_thumb_icon);
                int w = srcBitmap.getWidth();
                int h = srcBitmap.getHeight();
                int[] pixels = new int[w*h];
                srcBitmap.getPixels(pixels,0,w,0,0,w,h);
                int[] outPixels = OpenCVNativeManager.getBlurImage(pixels ,w,h);
                Bitmap destBitmap = Bitmap.createBitmap(w,h, Bitmap.Config.ARGB_8888);
                destBitmap.setPixels(outPixels,0,w,0,0,w,h);
                mIvTest.setImageBitmap(destBitmap);

            }
        });
        findViewById(R.id.btn_reset).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mIvTest.setImageResource(R.drawable.beauty_steward_course_video_thumb_icon);
            }
        });
    }


}
image.png

導(dǎo)出.so

image.png

在build中找到這個(gè)so嘿架,這就是我們需要的文件。此外啸箫,由于我們使用了opencv相關(guān)的庫耸彪,我們還需要將opencv的相關(guān)文件復(fù)制出來。將其導(dǎo)入我們需要的工程忘苛。

image.png

導(dǎo)入之后蝉娜,我們只需要在module的build.gradle里面加入:

android {
    ...

    sourceSets {
        main {
            jniLibs.srcDirs = ['src/main/jniLibs']
            aidl.srcDirs = ['src/main/aidl']
        }
    }
}

之后,我們就可以直接調(diào)用

System.loadLibrary("native-lib");

值得注意的是扎唾,JNI的方法是與路徑名相關(guān)的召川,所以當(dāng)我們以這樣的方法調(diào)用native方法時(shí),我們需要路徑名匹配胸遇。

以上荧呐。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市纸镊,隨后出現(xiàn)的幾起案子倍阐,更是在濱河造成了極大的恐慌,老刑警劉巖薄腻,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件收捣,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡庵楷,警方通過查閱死者的電腦和手機(jī)罢艾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來尽纽,“玉大人咐蚯,你說我怎么就攤上這事∨撸” “怎么了春锋?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)差凹。 經(jīng)常有香客問我期奔,道長(zhǎng)侧馅,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任呐萌,我火速辦了婚禮馁痴,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘肺孤。我一直安慰自己罗晕,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布赠堵。 她就那樣靜靜地躺著小渊,像睡著了一般。 火紅的嫁衣襯著肌膚如雪茫叭。 梳的紋絲不亂的頭發(fā)上酬屉,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音杂靶,去河邊找鬼梆惯。 笑死,一個(gè)胖子當(dāng)著我的面吹牛吗垮,可吹牛的內(nèi)容都是我干的垛吗。 我是一名探鬼主播,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼烁登,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼怯屉!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起饵沧,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤锨络,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后狼牺,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體羡儿,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年是钥,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了掠归。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡悄泥,死狀恐怖虏冻,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情弹囚,我是刑警寧澤厨相,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響蛮穿,放射性物質(zhì)發(fā)生泄漏庶骄。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一践磅、第九天 我趴在偏房一處隱蔽的房頂上張望瓢姻。 院中可真熱鬧,春花似錦音诈、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至儡嘶,卻和暖如春喇聊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蹦狂。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工誓篱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人凯楔。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓窜骄,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親摆屯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子邻遏,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

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