openCV4Android环境搭建

开发环境:windows+ADT Bundle+CDT+OpenCV-2.4.4-android-sdk

一、OpenCV2.4简介

OpenCV近年来发展迅猛,随着Android智能终端的发展,越来越多的传统科研平台都转向Android移动终端。记得2010年人们还不大知道Android,当时第一次用OpenCV还是用的1.0.2版本在VC6.0上。早期的OpenCV只提供C语言接口,你要申请个矩阵还得CvMat *mat  = cvCreateMat(...)写一大串,这样做是为了保证程序的运行效率,带来的不便是要开发者手动管理内存分配,稍有不慎内存泄漏那是常有的事。在OpenCV的发展历程上,第一次飞跃是2009101日发布的2.0版本,该版本支持C++接口 了,是直接从1.2版本跳到2.0。不久又推出了2.1,自此后想要移植OpenCV至嵌入式系统,在编译时必须借助CMake工具,而以往的不用。

第二次飞跃是在20106月发布的2.32.3.1版本,除提供C++接口向下兼容C接口外,新增了Java接口,且是对准Android平台。更重要的是以前官方不支持ndk-build,这次终于一统JNI接口调用方式,方便在Android上开发使用。201242日发布了2.4版本,支持windows/LinuxMac/Android/IOS四大系统。

最新的版本是20131111日发布的2.7版本。我电脑上配置的是2.4.4版本。

2.4之后,为了和Android的系统架构保持同步,准确说是吸收Android框架层的优点,引入了OpenCV Manager的概念,其本质就是一个Service,用来管理OpenCV动态链接库。它工作在APPOpenCV的动态链接库之间。OpenCV Manager的结构就是模仿AndroidBinder机制。其架构图如下:

 

APP在运行时会首先检查OpenCV Manager存在不,如果不存在则会提示安装。如果存在,就会连接这个服务,进一步初始化加载OpenCV库。流程如下:

 

对于开发者而言,了解即可。从应用层面讲,将OpenCV-2.4.4-android-sdk解压后,会看到如下文件夹:

 

其中sdk就是开包时要用到的包,samples是自带的示例,doc是说明文档,apk则就是OpenCV Manager。手机想要运行基于OpenCVJava接口的程序,就必须先安OpenCV Manager

 

不同的手机选择不同的版本,如果是英特尔平台就选那个带x86的。比较老的手机不支持ARMv7的选第三个。根据android的版本选择前两个。我手机支持的是第一种。安装后即可。

二、Android APP通过Java接口调OpenCV

1、配置

配置其实比较简单,比之前的用JNI接口调OpenCV要简单很多,不过为了保持同步,也即以后的开发中可以随意混用Java接口和JNI接口,我们仍将压缩包解压到跟工作空间平级的目录。然后将解压后的sdk文件夹命名为OpenCV4Android-sdk,拷贝到新建的工作空间中。假设新建的工作空间名为OpenCV4Android

 

【备注:这里让它两平级是为了以后JNI调用时无需修改mk文件。注意解压后会嵌套一个目录,把它拷到最外层。sdk文件夹命名和拷贝到新的工作空间都不是必须的。】

打开Eclipse切换到这个新的工作空间,右键import---General---Existing Projects into workspaces,选择OpenCV解压后的那个sdk包。导入后看是否有错误,我的是提示找不到java.util.List这个包,原来是没有加载进来AndroidSDK。选中项目,按快捷键Alter + Enter,点Android,选中一个SDK,要求3.0以上。然后clean一下,看bin文件夹下的opencv library - 2.4.4.jar是否生成,如果它生成了就表示已经导入成功。

2、新建项目并引入上面的jar

任意新建一个Android Application Project,然后选中该项目快捷键Alter + Enter,在下面的加库区域点Add,将导入工作空间的opencv sdk选中:

 

可以看到在Android Dependencies中将刚到导包bin目录下生成的jar文件导进去了。之后就可以使用opencvAPI了。

【备注:说白了就是为了把这个jar包导进来。在生成这个jar包后可以把它拷出来,新建一个user library参见导原生cameraeclipse这篇, 之后将包加进来是一样的。这个包只有200kb,也可以将其直接拷贝到工程目录下的libs文件夹,也是ok的。但是这样做后,就看不到jar包里具体的子包了,如org.opencv.ml这些。】

3、一个完成的demo:将一个图片灰度化

项目名字为GrayProcess,下面贴源码:

布局文件:

[html] view plaincopyprint?

1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  

2.     xmlns:tools="http://schemas.android.com/tools"  

3.     android:layout_width="match_parent"  

4.     android:layout_height="match_parent"  

5.     android:paddingBottom="@dimen/activity_vertical_margin"  

6.     android:paddingLeft="@dimen/activity_horizontal_margin"  

7.     android:paddingRight="@dimen/activity_horizontal_margin"  

8.     android:paddingTop="@dimen/activity_vertical_margin"  

9.     tools:context=".MainActivity" >  

10.   

11.     <TextView  

12.         android:layout_width="wrap_content"  

13.         android:layout_height="wrap_content"  

14.         android:layout_alignParentTop="true"  

15.         android:text="@string/wellcome_words" />  

16.     <ImageView   

17.         android:id="@+id/img_huaishi"  

18.         android:layout_width="wrap_content"  

19.         android:layout_height="wrap_content"  

20.         android:background="@drawable/nanhuaijin"  

21.         android:layout_centerInParent="true"/>  

22.     <Button  

23.         android:id="@+id/btn_gray_process"  

24.         android:layout_width="wrap_content"  

25.         android:layout_height="wrap_content"  

26.         android:layout_below="@id/img_huaishi"  

27.         android:layout_centerHorizontal="true"  

28.         android:text="灰度化"/>"  

29.   

30. </RelativeLayout>  

java文件:

[java] view plaincopyprint?

1. package com.example.grayprocess;  

2.   

3. import org.opencv.android.BaseLoaderCallback;  

4. import org.opencv.android.OpenCVLoader;  

5. import org.opencv.android.Utils;  

6. import org.opencv.core.Mat;  

7. import org.opencv.imgproc.Imgproc;  

8.   

9. import android.app.Activity;  

10. import android.graphics.Bitmap;  

11. import android.graphics.Bitmap.Config;  

12. import android.graphics.BitmapFactory;  

13. import android.os.Bundle;  

14. import android.os.Handler;  

15. import android.util.Log;  

16. import android.view.Menu;  

17. import android.view.View;  

18. import android.view.View.OnClickListener;  

19. import android.widget.Button;  

20. import android.widget.ImageView;  

21.   

22. public class MainActivity extends Activity {  

23.   

24.     Button btnProcess;  

25.     Bitmap srcBitmap;  

26.     Bitmap grayBitmap;  

27.     ImageView imgHuaishi;  

28.     private static boolean flag = true;   

29.     private static boolean isFirst = true;   

30.     private static final String TAG = "MainActivity";  

31.   

32.     //OpenCV库加载并初始化成功后的回调函数  

33.     private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {  

34.   

35.         @Override  

36.         public void onManagerConnected(int status) {  

37.             // TODO Auto-generated method stub  

38.             switch (status){  

39.             case BaseLoaderCallback.SUCCESS:  

40.                 Log.i(TAG, "成功加载");  

41.                 break;  

42.             default:  

43.                 super.onManagerConnected(status);  

44.                 Log.i(TAG, "加载失败");  

45.                 break;  

46.             }  

47.               

48.         }  

49.     };  

50.     @Override  

51.     protected void onCreate(Bundle savedInstanceState) {  

52.         super.onCreate(savedInstanceState);  

53.         setContentView(R.layout.activity_main);  

54.         initUI();  

55.       

56.         btnProcess.setOnClickListener(new ProcessClickListener());  

57.     }  

58.   

59.   

60.     @Override  

61.     public boolean onCreateOptionsMenu(Menu menu) {  

62.         // Inflate the menu; this adds items to the action bar if it is present.  

63.         getMenuInflater().inflate(R.menu.main, menu);  

64.         return true;  

65.     }  

66.   

67.     public void initUI(){  

68.         btnProcess = (Button)findViewById(R.id.btn_gray_process);  

69.         imgHuaishi = (ImageView)findViewById(R.id.img_huaishi);  

70.         Log.i(TAG, "initUI sucess...");  

71.   

72.     }  

73.   

74.     public void procSrc2Gray(){  

75.         Mat rgbMat = new Mat();  

76.         Mat grayMat = new Mat();  

77.         srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.nanhuaijin);  

78.         grayBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), Config.RGB_565);  

79.         Utils.bitmapToMat(srcBitmap, rgbMat);//convert original bitmap to Mat, R G B.  

80.         Imgproc.cvtColor(rgbMat, grayMat, Imgproc.COLOR_RGB2GRAY);//rgbMat to gray grayMat  

81.         Utils.matToBitmap(grayMat, grayBitmap); //convert mat to bitmap  

82.         Log.i(TAG, "procSrc2Gray sucess...");  

83.     }  

84.   

85.     private class ProcessClickListener implements OnClickListener{  

86.           

87.         @Override  

88.         public void onClick(View v) {  

89.             // TODO Auto-generated method stub  

90.             if(isFirst)  

91.             {  

92.                 procSrc2Gray();  

93.                 isFirst = false;  

94.             }  

95.             if(flag){  

96.                 imgHuaishi.setImageBitmap(grayBitmap);  

97.                 btnProcess.setText("查看原图");  

98.                 flag = false;  

99.             }  

100.             else{  

101.                 imgHuaishi.setImageBitmap(srcBitmap);  

102.                 btnProcess.setText("灰度化");  

103.                 flag = true;  

104.             }  

105.         }  

106.   

107.     }  

108.   

109.     @Override  

110.     protected void onResume() {  

111.         // TODO Auto-generated method stub  

112.         super.onResume();  

113.         //load OpenCV engine and init OpenCV library  

114.         OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_4, getApplicationContext(), mLoaderCallback);  

115.         Log.i(TAG, "onResume sucess load OpenCV...");  

116. //      new Handler().postDelayed(new Runnable(){  

117. //  

118. //          @Override  

119. //          public void run() {  

120. //              // TODO Auto-generated method stub  

121. //              procSrc2Gray();  

122. //          }  

123. //            

124. //      }, 1000);  

125.           

126.     }  

127.       

128.       

129.       

130.   

131. }  

功能很简单,就是将一个图片灰度化,然后再次点击恢复成原来的。里面有几个需要注意的事项:

aBitmapMat互相转换:Utils.bitmapToMat  Utils.matToBitmap

b、加载一个图片到BitmapBitmapFactory.decodeResource(getResources(), R.drawable.nanhuaijin);

c、颜色转换:Imgproc.cvtColor(rgbMat, grayMat, Imgproc.COLOR_RGB2GRAY);

dgrayBitmap的格式Config.ARGB_8888Config.RGB_565都是可以的

e、最重要的一点:app在找OpenCV里的一些包时必须在onResume函数OpenCVLoader.initAsync()之后,否则会找不到库。最初我将procSrc2Gray();放在initUI()之后直接挂掉,后来放到OpenCVLoader.initAsync()依旧不行。除了上面代码里的方法外,还可以用一个延迟,默认等加载完包初始化后,再进行图像处理的操作:

[java] view plaincopyprint?

1. new Handler().postDelayed(new Runnable(){  

2.   

3.     @Override  

4.     public void run() {  

5.         // TODO Auto-generated method stub  

6.         procSrc2Gray();  

7.     }  

8.       

9. }, 1000);  

这样就ok了,在按键监听里无需在判断是否是第一次了。程序运行结果:

 

 

 

最后解释下OpenCV4Android4应该是for的意思。另外,近年来还流行个词叫JavaCV。它和OpenCV4Android完全补一个概念,但都是java接口调用OpenCv。后文会撰文介绍其搭建方式和使用。通过JNI的方式调用OpenCV参见:http://blog.csdn.net/yanzi1225627/article/details/8525720

三、OpenCV网站导航

1http://opencv.org/  这是OpenCV的官方网站

2http://wiki.opencv.org.cn/index.php/ 这是国内的官网老版

3http://www.opencv.org.cn/  国内的官网新版

     鉴于自OpenCV新增C++接口后,国内的书籍就很少,几乎没有。尤其是增加OpenCV4Android Java接口后就更少了。后续将以专栏围绕翻译OpenCV4Android Java/C++ API,及介绍如何将数字图像处理与Android APP开发融合。


示例中的代码下载:http://download.csdn.net/detail/yanzi1225627/6602691

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值