當前位置:編程學習大全網 - 源碼下載 - 如何在Android中使用OpenCV

如何在Android中使用OpenCV

如何在Android程序中使用OpenCV

有兩種方式(重點講後面壹種):

1.使用OpenCV Java API。

OpenCV安裝路徑"F:\OpenCV-2.3.1-android-bin"下有兩個文件夾,

將文件夾"OpenCV-2.3.1"拷貝到妳的Eclipse工作空間所在的目錄,也就是在妳的項目的上壹級目錄中,然後導入到工作空間中,在Package Explorer中選擇妳的項目,單機右鍵在彈出菜單中選擇Properties,然後在彈出的Properties窗口中左側選擇Android,然後點擊右下方的Add按鈕,選擇OpenCV-2.3.1並點擊OK,

此時,展開妳的項目樹,妳可以看到新加了壹個OpenCV-2.3.1_src目錄,如下圖,那麽就是正確添加了OpenCV Java API,否則就是妳放置OpenCV-2.3.1的目錄路徑不正確。

然後就可以在妳的Java源文件中導入OpenCV的API包,並且使用OpenCV API了,OpenCV API的包的形式如下:

Org.opencv.(OpenCV模塊名).(OpenCV類名)

例如:

Org.opencv.core.Mat

2.利用JNI編寫C++ OpenCV代碼,通過Android NDK創建動態庫(.so)

新建壹個工作空間,例如"TestOpenCV",在Window->Preferences中設置好Android SDK的路徑。

然後新建壹個Android項目,Build Target選擇Android2.2,命名為"HaveImgFun",活動名改為HaveImgFun,Package name中填寫com.testopencv.haveimgfun,最後點擊finish。

如同使用OpenCV Java API那樣,將OpenCV-2.3.1文件夾拷貝到與工作空間同壹級目錄中;另外,將"F:\OpenCV-2.3.1-android-bin\samples"下的includeOpenCV.mk文件拷貝到和項目HaveImgFun同壹級目錄中:

(上面這個各個文件夾和文件的放置很重要,因為OpenCV-2.3.1下的OpenCV.mk中有很多相對路徑的指定,如果不是這樣放置,在NDK生成動態庫時可能會報文件或文件夾無法找到的錯誤)

選擇Package Explorer中妳的項目,右鍵選擇new->folder,新建壹個名為jni的文件夾,用來存放妳的c/c++代碼。

然後把res->layout下的main.xml的內容改為下面所示:

1 <?xml version="1.0" encoding="utf-8"?>?

2 <LinearLayout ? xmlns:android="/apk/res/android"?

3 android:orientation="vertical"?

4 android:layout_width="fill_parent" ?

5 android:layout_height="fill_parent"?

6 >?

7 <Button android:layout_height="wrap_content" ?

8 android:layout_width="fill_parent" ?

9 android:id="@+id/btnNDK" ?

10 android:text="使用C++ OpenCV進行處理" />?

11 <Button android:layout_height="wrap_content" ?

12 android:layout_width="fill_parent" ?

13 android:id="@+id/btnRestore" ?

14 android:text="還原" /> ?

15 <ImageView android:id="@+id/ImageView01" ?

16 android:layout_width="fill_parent" ?

17 android:layout_height="fill_parent" /> ?

18 </LinearLayout>

上面的代碼就是壹個線性布局裏面包含2個按鈕加上壹個顯示圖像的ImageView

在文件夾src下的com.testopencv.haveimgfun包中新建壹個類用於包裝使用了opencv c++代碼的動態庫的導出函數,類名為LibImgFun。

Eclipse會為妳創建壹個新的文件LibImgFun.java,將裏面的內容改為:

1 package com.testopencv.haveimgfun;?

2 public class LibImgFun { ?

3 static { ?

4 System.loadLibrary("ImgFun"); ?

5 } ?

6 ? /**?

7 * @param width the current view width?

8 * @param height the current view height?

9 */?

10 public static native int[] ImgFun(int[] buf, int w, int h); ?

11 }

從上面的代碼可以得知,我們的動態庫名字應該為“libImgFun.so”,註意"public static native int[] ImgFun(int[] buf, int w, int h)"中的native關鍵字,表明這個函數來自native code。static表示這是壹個靜態函數,這樣就可以直接用類名去調用。

在jni文件夾下建立壹個"ImgFun.cpp"的文件,內容改為下面所示:

1 #include <jni.h>?

2 #include <stdio.h>?

3 #include <stdlib.h>?

4 #include <opencv2/opencv.hpp>?

5 using namespace cv;

6 ?

7 extern "C"

8 {?

9 JNIEXPORT jintArray JNICALL Java_com_testopencv_haveimgfun_LibImgFun_ImgFun(JNIEnv* env, jobject obj, jintArray buf, int w, int h);?

10 JNIEXPORT jintArray JNICALL Java_com_testopencv_haveimgfun_LibImgFun_ImgFun(JNIEnv* env, jobject obj, jintArray buf, int w, int h){?

11 ?

12 jint *cbuf;?

13 cbuf = env->GetIntArrayElements(buf, false);?

14 if(cbuf == NULL)?

15 {?

16 return 0;?

17 }?

18 ?

19 Mat myimg(h, w, CV_8UC4, (unsigned char*)cbuf); ?

20 for(int j=0;j<myimg.rows/2;j++)?

21 {?

22 myimg.row(j).setTo(Scalar(0,0,0,0));?

23 }?

24 ?

25 int size=w * h;?

26 jintArray result = env->NewIntArray(size);?

27 env->SetIntArrayRegion(result, 0, size, cbuf);?

28 env->ReleaseIntArrayElements(buf, cbuf, 0);?

29 return result;?

30 }?

31 }

上面的代碼中#include <jni.h>是必須要包含的頭文件,#include <opencv2/opencv.hpp>是opencv要包含的頭文件。

動態庫要導出的函數如下聲明:

JNIEXPORT jintArray JNICALL Java_com_testopencv_haveimgfun_LibImgFun_ImgFun(JNIEnv* env, jobject obj, jintArray buf, int w, int h);

JNIEXPORT 和JNICALL是必須要加的關鍵字

jintArray就是int[],這裏返回類型要麽為空,要麽為jni中定義的類型,事實上就是C\C++類型前面加上j,如果是數組,則在後面加上Array。

函數名的命名規則如下:

Java_(包路徑)_(類名)_(函數名) (JNIEnv *env, jobject obj, 自己定義的參數...)

包路徑中的"."用"_"(下劃線)代替,類名就是上面包裝該動態庫函數的類的名字,最後壹個才是真正的函數名;JNIEnv *env和jobject obj這兩個參數時必須的,用來調用JNI環境下的壹些函數;後面就是妳自己定義的參數。在這裏,jintArray buf代表了傳進來的圖像的數據,int w是圖像的寬,int h是圖像的高。

這個函數的功能是將傳進來的圖像的上半部分塗成黑色。

然後再在jni下新建兩個文件"Android.mk"文件和"Application.mk"文件,這兩個文件事實上就是簡單的Makefile文件。

其中將Android.mk的內容改為如下所示:

LOCAL_PATH?:=?$(call?my-dir)?

include?$(CLEAR_VARS)?

include?../includeOpenCV.mk?

ifeq?("$(wildcard?$(OPENCV_MK_PATH))","")?

#try?to?load?OpenCV.mk?from?default?install?location?

include?$(TOOLCHAIN_PREBUILT_ROOT)/user/share/OpenCV/OpenCV.mk?

else?

include?$(OPENCV_MK_PATH)?

endif?

LOCAL_MODULE:=?ImgFun?

LOCAL_SRC_FILES?:=?ImgFun.cpp?

include?$(BUILD_SHARED_LIBRARY)?

Application.mk的內容改為如下所示:

APP_STL:=gnustl_static?

APP_CPPFLAGS:=-frtti?-fexceptions?

APP_ABI:=armeabi?armeabi-v7a?

其中APP_ABI指定的是目標平臺的CPU架構。(經過很多測試,android2.2必須指定為armeabi,android2.2以上的使用armeabi-v7a,如果沒有設置對,很有可能安裝到android虛擬機失敗,當然妳同時如上面寫上也是可以的)

上面的步驟完成後,就可以使用NDK生成動態庫了,打開cygwin,cd到項目目錄下:

輸入$NDK/ndk-build命令,開始創建動態庫。

這時候刷新Eclipse的Package Explorer會出現兩個新的文件夾obj和libs。

現在,只剩最後壹步完成這個測試程序。

將壹張圖片,例如"lena.jpg"放到項目res->drawable-hdpi目錄中並刷新該目錄。

然後將HaveImgFun.java的內容改為下面所示:

1 package com.testopencv.haveimgfun;?

2 ?

3 import android.app.Activity; ?

4 import android.graphics.Bitmap; ?

5 import android.graphics.Bitmap.Config; ?

6 import android.graphics.drawable.BitmapDrawable; ?

7 import android.os.Bundle; ?

8 import android.widget.Button; ?

9 import android.view.View; ?

10 import android.widget.ImageView; ?

11 ?

12 public class HaveImgFun extends Activity{?

13 /** Called when the activity is first created. */ ?

14 ImageView imgView; ?

15 Button btnNDK, btnRestore;?

16 ?

17 @Override ?

18 public void onCreate(Bundle savedInstanceState) { ?

19 super.onCreate(savedInstanceState); ?

20 setContentView(R.layout.main); ?

21 ?

22 this.setTitle("使用NDK轉換灰度圖"); ?

23 btnRestore=(Button)this.findViewById(R.id.btnRestore); ?

24 btnRestore.setOnClickListener(new ClickEvent()); ?

25 btnNDK=(Button)this.findViewById(R.id.btnNDK); ?

26 btnNDK.setOnClickListener(new ClickEvent()); ?

27 imgView=(ImageView)this.findViewById(R.id.ImageView01); ?

28 Bitmap img=((BitmapDrawable) getResources().getDrawable(R.drawable.lena)).getBitmap(); ?

29 imgView.setImageBitmap(img); ?

30 }?

31 ?

32 class ClickEvent implements View.OnClickListener{ ?

33 public void onClick(View v){?

34 if(v == btnNDK){

35 long current=System.currentTimeMillis(); ?

36 Bitmap img1=((BitmapDrawable) getResources().getDrawable(R.drawable.lena)).getBitmap(); ?

37 int w=img1.getWidth(),h=img1.getHeight(); ?

38 int[] pix = new int[w * h]; ?

39 img1.getPixels(pix, 0, w, 0, 0, w, h); ?

40 int[] resultInt=LibImgFun.ImgFun(pix, w, h); ?

41 Bitmap resultImg=Bitmap.createBitmap(w, h, Config.RGB_565); ?

42 resultImg.setPixels(resultInt, 0, w, 0, 0,w, h); ?

43 long performance=System.currentTimeMillis()-current; ?

44 imgView.setImageBitmap(resultImg); ?

45 HaveImgFun.this.setTitle("w:"+String.valueOf(img1.getWidth())+",h:"+String.valueOf(img1.getHeight())+"NDK耗時"+String.valueOf(performance)+" 毫秒");?

46 } else if(v == btnRestore){ ?

47 Bitmap img2=((BitmapDrawable) getResources().getDrawable(R.drawable.lena)).getBitmap(); ?

48 imgView.setImageBitmap(img2); ?

49 HaveImgFun.this.setTitle("使用OpenCV進行圖像處理");

50 }?

51 ?}

52 }?

53 }

點擊全部保存,OK,現在可以選擇壹個Android虛擬機運行看壹下效果,配置好Run Configuration然後點擊Run,得到下面的結果:

點擊使用C++ OpenCV進行處理,得到下面的結果:

  • 上一篇:本科機械專業轉金融怎麽樣?
  • 下一篇:小米澎湃操作系統列表
  • copyright 2024編程學習大全網