Android下OpenCV的環境搭建

目錄(?)[-] html

  1. 前言
  2. 系統環境
  3. 相關工具
  4. Android ADT環境搭建
    1. Android SDK環境變量的配置
    2. Android NDK的安裝與配置
  5. OpenCV for Android 環境搭建
  6. 基於SDK的OpenCV開發
  7. 基於NDK的OpenCV開發
    1. Android上層程序的編寫
      1. 來自CODE的代碼片 activity_mainxml
      2. 來自CODE的代碼片 MainActivityjava
      3. 來自CODE的代碼片 ImageProcjava
    2. 生成C頭文件
    3. 底層C程序的編寫
      1. 來自CODE的代碼片 Androidmk
      2. 來自CODE的代碼片 Applicationmk
      3. 來自CODE的代碼片 ImageProccpp
    4. 編譯和運行程序
  8. 總結

    前言

        最近須要在Android移動設備上進行OpenCV開發,搭建環境是第一步,我在網上看了n個相關的中文和英文的教程,終於成功搭建環境,如今跟你們分享一下成果,但願爲你們減小沒必要要的困惑和麻煩。 java

    系統環境

        win7/win8(注:個人系統是win8專業版) android

    相關工具

    1.Android ADT Bundle for Windows(注: 我下的是adt-bundle-windows-x86_64-20131030)
    下載地址:https://developer.android.com/sdk/index.html?hl=sk
    2.Android NDK(注:我下的是android-ndk-r8e-windows-x86_64)
    下載地址:https://developer.android.com/tools/sdk/ndk/index.html
    3.OpenCV for Android(注:我下的是OpenCV-2.4.8-android-sdk)
    下載地址:http://sourceforge.net/projects/opencvlibrary/files/opencv-android/ windows

    Android ADT環境搭建

        在下面的操做前,保證你的PC機上已經安裝了JDK,關於JDK的安裝及其環境變量的配置,在此再也不介紹,網上資料不少。 app

    解壓下載的Android ADT Bundle for Windows到某一目錄下,我解壓在D:\MySoftware目錄下。 eclipse

    Android SDK環境變量的配置

            打開 計算機->屬性->高級系統設置->高級->環境變量,在系統變量欄目下新建「ANDROID_SDK_HOME」變量,變量值爲adt-bundle-windows目錄下sdk目錄的路徑,個人是"D:\MySoftware\adt-bundle-windows-x86_64-20131030\sdk",如圖: ide

        在Path變量值中添加"%ANDROID_SDK_HOME%\tools;%ANDROID_SDK_HOME%\platform-tools" 函數

    進入cmd命令窗口,檢查SDK是否安裝成功。
    運行 android –h 若是有下面的輸出,代表安裝成功: 工具

          打開%ANDROID_SDK_HOME%\eclipse下的eclipse.exe,如今進行本身的安卓開發之旅了。 測試

    Android NDK的安裝與配置

       將下載下來的Android NDK解壓到某一目錄,這裏我解壓到的目錄是「D:\MySoftware」。

    打開%ANDROID_SDK_HOME%\eclipse下的eclipse.exe,在eclipse中,選擇windows->Preference->Android->NDK,而後添加剛纔解壓的NDK目錄的路徑,如圖:

    點擊"ok"按鈕,至此NDK環境搭建完成。

    OpenCV for Android 環境搭建

        解壓下載的OpenCV for Android到某一目錄下。我解壓到的目錄是「D:\MySoftware」。將解壓後的目錄下的sdk(個人是:D:\MySoftware\OpenCV-2.4.8-android-sdk\sdk)目錄拷貝到你的android的workspace目錄下,更名爲:OpenCV-SDK(也能夠改爲其它名)。

        在eclipse中,選擇File->import,選擇Existing project into Workspace:

        選擇「next」,而後以下圖,選擇OpenCV-SDK目錄的路徑:

    點擊「Finish」完成。

    基於SDK的OpenCV開發

        這種情形下,咱們能夠直接調用android爲咱們封裝好的openCV接口進行開發,咱們只須要上面的OpenCV for Android環境就能夠進行開發。

        在eclipse中,選擇File->import,選擇Existing project into Workspace,選擇...\OpenCV-***-android-sdk\sample(個人是D:\MySoftware\OpenCV-2.4.8-android-sdk\samples)目錄下的「OpenCV Tutorial 1 - Camera Preview」:

        點擊「Finish」完成。此時工程會報錯,需進行以下操做:

        選中工程,右擊選擇Properties,而後在左邊選擇Android,在Project build target欄中選擇一個:

        在Library欄目中選擇"add",增長OpenCV類庫:

        選中OpenCV Library,點擊OK

        點擊ok完成操做,此時你會發現項目再也不報錯。

        若是此時依然出現錯誤,多是項目太舊,與新的target不太兼容的緣故,此時按如下操做應該能解決問題:

        選中項目,右鍵選擇build path->configure build path...

        選中Android Dependencies和 Android Private Libraries,點擊「Remove」進行刪除。點擊「OK」完成。

        此時選中工程,右鍵選擇 Android tools->fix project properties。錯誤消失。

    你可使用真機或模擬器運行運行該程序,這是個基於openCV的攝像頭調用程序。須要注意的是,在運行前你須要安裝OpenCV_***_Manager_**_*.apk,不然opencv應用將會由於沒法加載opencv類庫而沒法運行。OpenCV_***_Manager_**_*.apk存在於...\OpenCV-***-android-sdk\apk(個人是D:\MySoftware\OpenCV-2.4.8-android-sdk\apk)目錄下。我安裝的是「OpenCV_2.4.8_Manager_2.16_armeabi.apk」。

        固然,你也能夠本身新建android工程,而後按上述方法進行openCV庫的引用,而後調用相關接口,進行本身的項目開發。

        然而android只是對openCV的部分進行了封裝,有許多openCV的功能並無被封裝,因此要實現不少複雜的功能還必須用C/C++進行實現,這就是咱們下面要介紹的方式。

    基於NDK的OpenCV開發

    下面我將以一個實例向你們展現基於NDK的OpenCV開發。

        新建android工程NdkOpenCV,將一張圖片添加到資源文件,並命名爲"test.jpg",按上面所示將OpenCV Library添加到工程中。

    Android上層程序的編寫

    1. activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
    
    <Button 
        android:id="@+id/btn"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/app_name"/>
    
    <ImageView
        android:id="@+id/image_view"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:contentDescription="@string/app_name"/>


</LinearLayout>

 

2. MainActivity.java

package my.example.ndkopencv;


import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import android.os.Bundle;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap.Config;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;


public class MainActivity extends Activity implements OnClickListener{


    private Button btnProc;
    private ImageView imageView;
    private Bitmap bmp;
    
    //OpenCV類庫加載並初始化成功後的回調函數,在此咱們不進行任何操做
     private BaseLoaderCallback  mLoaderCallback = new BaseLoaderCallback(this) {
        @Override
        public void onManagerConnected(int status) {
            switch (status) {
                case LoaderCallbackInterface.SUCCESS:{
                    System.loadLibrary("image_proc");
                } break;
                default:{
                    super.onManagerConnected(status);
                } break;
            }
        }
    };
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnProc = (Button) findViewById(R.id.btn);
        imageView = (ImageView) findViewById(R.id.image_view);
        //將測試圖片加載程序中並進行顯示
         bmp = BitmapFactory.decodeResource(getResources(), R.drawable.test);
        imageView.setImageBitmap(bmp);
        btnProc.setOnClickListener(this);
    }


    @Override
    public void onClick(View v) {
         
        int w = bmp.getWidth();
        int h = bmp.getHeight();
        int[] pixels = new int[w*h];     
        bmp.getPixels(pixels, 0, w, 0, 0, w, h);
        int[] resultInt = ImageProc.grayProc(pixels, w, h);
        Bitmap resultImg = Bitmap.createBitmap(w, h, Config.ARGB_8888);
        resultImg.setPixels(resultInt, 0, w, 0, 0, w, h);
        imageView.setImageBitmap(resultImg);    
    }
    
    @Override
    public void onResume(){
        super.onResume();
        //經過OpenCV引擎服務加載並初始化OpenCV類庫
        OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback);
    }
}
3. ImageProc.java
package my.example.ndkopencv;


public class ImageProc {
    public static native int[] grayProc(int[] pixels, int w, int h);
}
生成C++頭文件

    打開cmd,進入android工程所在的目錄下的bin/classes目錄下,執行javah ****.ImageProc命令:

         在F:\MyCode\android\NdkOpenCV\bin\classes目錄下多了個my_example_ndkopencv_ImageProc.h文件,將該文件重命名爲ImageProc.h。

    底層C++程序的編寫

    在項目中創建jni文件夾,將上面生成的ImageProc.h文件移動到jni文件夾下。而後分別新建Android.mk,Application.mk,ImageProc.cpp文件,這三個文件內容以下:

    1.Android.mk

    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    include ../OpenCV-SDK/native/jni/OpenCV.mk
    LOCAL_SRC_FILES  := ImageProc.cpp
    LOCAL_MODULE     := image_proc
    include $(BUILD_SHARED_LIBRARY)

    代碼說明:

    第一行:指明當前編譯路徑;

    第二行:清空變量;

    第三行:將OpenCV類庫中的編譯文件包含進來,如此一來在咱們的工程中便可使用OpenCV類庫;

    第四行:指定須要編譯的C++源文件;

    第五行:指定編譯生成的類庫名稱;

    第六行:調用命令將源文件編譯爲靜態庫。

    2.Application.mk

    APP_STL := gnustl_static
    APP_CPPFLAGS := -frtti -fexceptions
    APP_ABI := armeabi-v7a
    APP_PLATFORM := android-8

    3.ImageProc.cpp

     
    #include <ImageProc.h>
    #include <opencv2/core/core.hpp>
    #include <string>
    #include <vector>
    
    
    using namespace cv;
    using namespace std;
    
    
    JNIEXPORT jintArray JNICALL Java_my_example_ndkopencv_ImageProc_grayProc(JNIEnv* env, jclass obj, jintArray buf, jint w, jint h){
        jint *cbuf;
        cbuf = env->GetIntArrayElements(buf, 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 ++){
            //計算公式: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;
        }
    
    
        int size=w * h;
        jintArray result = env->NewIntArray(size);
        env->SetIntArrayRegion(result, 0, size, cbuf);
        env->ReleaseIntArrayElements(buf, cbuf, 0);
        return result;
    }

     

    上面操做完成後,選中工程,右鍵選擇Android tools->add native support...

    點擊「Finish」完成。

    而後選中工程,右鍵選擇properties,在左側選擇C/C++ General->Paths and Symbols.

    在右側選擇"Add",而後選擇File System,選擇OpenCV-SDK所在目錄下的「native\jni\include」路徑,並選擇「ok」:

    點擊「ok」,完成。

    編譯和運行程序

    如今運行程序,eclipse會先調用ndk-build對C++程序進行編譯,若是你使用的是NDK8以上的版本,當前可能會出現以下信息:

    Android NDK: WARNING:jni/Android.mk:detection_based_tracker: non-system libraries in linker flags: -lopencv_java
    Android NDK:     This is likely to result in incorrect builds. Try using LOCAL_S

    這是NDK9目前的問題(當前最新版本是android-ndk-r9d-windows-x86_64),但願在從此可以改進,這也正是我爲何要用NDK8的緣由。

    點擊「NdkOpenCV」按鈕,對比兩張圖:

    至此,Android下OpenCV的環境搭建已經完成。

    總結

         在此須要說明一下,傳統的編譯底層C++方法是經過在Cygwin中進行的,因爲新版ADT和NDK給咱們帶來的便捷,咱們能夠不安裝Cygwin進行android下的openCV開發。若是你想了解Cygwin下編譯上述程序的方法,我會在從此的博客中爲你們介紹。

相關文章
相關標籤/搜索