标签:opencv android开发 手机
本文是基于网上一大牛的博客写的,大体的东西是类似的:
http://blog.csdn.net/yanzi1225627/article/details/16917961
首先是Android环境,网上很多的教程环境的配置比较的麻烦,因为多数是Android的早期版本的环境配置方法。
不知道Android在什么时候已经提供了现成的开发环境(sdk+Eclipse+ide)。现在Android的官方网站可以下载到最新的Android的开发环境,再在电脑上安装Java环境。解压Android的下载包可以就可以直接使用了。
Android开发环境下载:http://developer.android.com/sdk/index.html
jdk下载:http://www.oracle.com/technetwork/java/javasebusiness/downloads/java-archive-downloads-javase6-419409.html#jdk-6u45-oth-JPR
下载OpenCV-x.x.x-android-sdk:http://sourceforge.net/projects/opencvlibrary/files/opencv-android/2.4.9/OpenCV-2.4.9-android-sdk.zip/download
开发环境: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的发展历程上,第一次飞跃是2009年10月1日发布的2.0版本,该版本支持C++接口
了,是直接从1.2版本跳到2.0。不久又推出了2.1,自此后想要移植OpenCV至嵌入式系统,在编译时必须借助CMake工具,而以往的不用。
第二次飞跃是在2010年6月发布的2.3、2.3.1版本,除提供C++接口向下兼容C接口外,新增了Java接口,且是对准Android平台。更重要的是以前官方不支持ndk-build,这次终于一统JNI接口调用方式,方便在Android上开发使用。2012年4月2日发布了2.4版本,支持windows/Linux、Mac/Android/IOS四大系统。
最新的版本是2013年11月11日发布的2.7版本。我电脑上配置的是2.4.4版本。
从2.4之后,为了和Android的系统架构保持同步,准确说是吸收Android框架层的优点,引入了OpenCV Manager的概念,其本质就是一个Service,用来管理OpenCV动态链接库。它工作在APP和OpenCV的动态链接库之间。OpenCV Manager的结构就是模仿Android的Binder机制。其架构图如下:
APP在运行时会首先检查OpenCV Manager存在不,如果不存在则会提示安装。如果存在,就会连接这个服务,进一步初始化加载OpenCV库。流程如下:
对于开发者而言,了解即可。从应用层面讲,将OpenCV-2.4.4-android-sdk解压后,会看到如下文件夹:
其中sdk就是开包时要用到的包,samples是自带的示例,doc是说明文档,apk则就是OpenCV Manager。手机想要运行基于OpenCV的Java接口的程序,就必须先安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这个包,原来是没有加载进来Android的SDK。选中项目,按快捷键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文件导进去了。之后就可以使用opencv的API了。
【备注:说白了就是为了把这个jar包导进来。在生成这个jar包后可以把它拷出来,新建一个user library参见导原生camera到eclipse这篇,
之后将包加进来是一样的。这个包只有200多kb,也可以将其直接拷贝到工程目录下的libs文件夹,也是ok的。但是这样做后,就看不到jar包里具体的子包了,如org.opencv.ml这些。】
3、一个完成的demo:将一个图片灰度化
项目名字为GrayProcess,下面贴源码:
布局文件:
-
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
-
xmlns:tools="http://schemas.android.com/tools"
-
android:layout_width="match_parent"
-
android:layout_height="match_parent"
-
android:paddingBottom="@dimen/activity_vertical_margin"
-
android:paddingLeft="@dimen/activity_horizontal_margin"
-
android:paddingRight="@dimen/activity_horizontal_margin"
-
android:paddingTop="@dimen/activity_vertical_margin"
-
tools:context=".MainActivity" >
-
-
<TextView
-
android:layout_width="wrap_content"
-
android:layout_height="wrap_content"
-
android:layout_alignParentTop="true"
-
android:text="@string/wellcome_words" />
-
<ImageView
-
android:id="@+id/img_huaishi"
-
android:layout_width="wrap_content"
-
android:layout_height="wrap_content"
-
android:background="@drawable/nanhuaijin"
-
android:layout_centerInParent="true"/>
-
<Button
-
android:id="@+id/btn_gray_process"
-
android:layout_width="wrap_content"
-
android:layout_height="wrap_content"
-
android:layout_below="@id/img_huaishi"
-
android:layout_centerHorizontal="true"
-
android:text="灰度化"/>"
-
-
</RelativeLayout>
java文件:
-
package com.example.grayprocess;
-
-
import org.opencv.android.BaseLoaderCallback;
-
import org.opencv.android.OpenCVLoader;
-
import org.opencv.android.Utils;
-
import org.opencv.core.Mat;
-
import org.opencv.imgproc.Imgproc;
-
-
import android.app.Activity;
-
import android.graphics.Bitmap;
-
import android.graphics.Bitmap.Config;
-
import android.graphics.BitmapFactory;
-
import android.os.Bundle;
-
import android.os.Handler;
-
import android.util.Log;
-
import android.view.Menu;
-
import android.view.View;
-
import android.view.View.OnClickListener;
-
import android.widget.Button;
-
import android.widget.ImageView;
-
-
public class MainActivity extends Activity {
-
-
Button btnProcess;
-
Bitmap srcBitmap;
-
Bitmap grayBitmap;
-
ImageView imgHuaishi;
-
private static boolean flag = true;
-
private static boolean isFirst = true;
-
private static final String TAG = "MainActivity";
-
-
-
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
-
-
@Override
-
public void onManagerConnected(int status) {
-
-
switch (status){
-
case BaseLoaderCallback.SUCCESS:
-
Log.i(TAG, "成功加载");
-
break;
-
default:
-
super.onManagerConnected(status);
-
Log.i(TAG, "加载失败");
-
break;
-
}
-
-
}
-
};
-
@Override
-
protected void onCreate(Bundle savedInstanceState) {
-
super.onCreate(savedInstanceState);
-
setContentView(R.layout.activity_main);
-
initUI();
-
-
btnProcess.setOnClickListener(new ProcessClickListener());
-
}
-
-
-
@Override
-
public boolean onCreateOptionsMenu(Menu menu) {
-
-
getMenuInflater().inflate(R.menu.main, menu);
-
return true;
-
}
-
-
public void initUI(){
-
btnProcess = (Button)findViewById(R.id.btn_gray_process);
-
imgHuaishi = (ImageView)findViewById(R.id.img_huaishi);
-
Log.i(TAG, "initUI sucess...");
-
-
}
-
-
public void procSrc2Gray(){
-
Mat rgbMat = new Mat();
-
Mat grayMat = new Mat();
-
srcBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.nanhuaijin);
-
grayBitmap = Bitmap.createBitmap(srcBitmap.getWidth(), srcBitmap.getHeight(), Config.RGB_565);
-
Utils.bitmapToMat(srcBitmap, rgbMat);
-
Imgproc.cvtColor(rgbMat, grayMat, Imgproc.COLOR_RGB2GRAY);
-
Utils.matToBitmap(grayMat, grayBitmap);
-
Log.i(TAG, "procSrc2Gray sucess...");
-
}
-
-
private class ProcessClickListener implements OnClickListener{
-
-
@Override
-
public void onClick(View v) {
-
-
if(isFirst)
-
{
-
procSrc2Gray();
-
isFirst = false;
-
}
-
if(flag){
-
imgHuaishi.setImageBitmap(grayBitmap);
-
btnProcess.setText("查看原图");
-
flag = false;
-
}
-
else{
-
imgHuaishi.setImageBitmap(srcBitmap);
-
btnProcess.setText("灰度化");
-
flag = true;
-
}
-
}
-
-
}
-
-
@Override
-
protected void onResume() {
-
-
super.onResume();
-
-
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_4, getApplicationContext(), mLoaderCallback);
-
Log.i(TAG, "onResume sucess load OpenCV...");
-
-
-
-
-
-
-
-
-
-
-
}
-
-
-
-
-
}
功能很简单,就是将一个图片灰度化,然后再次点击恢复成原来的。里面有几个需要注意的事项:
a、Bitmap和Mat互相转换:Utils.bitmapToMat Utils.matToBitmap
b、加载一个图片到Bitmap:BitmapFactory.decodeResource(getResources(), R.drawable.nanhuaijin);
c、颜色转换:Imgproc.cvtColor(rgbMat, grayMat, Imgproc.COLOR_RGB2GRAY);
d、grayBitmap的格式Config.ARGB_8888和Config.RGB_565都是可以的
e、最重要的一点:app在找OpenCV里的一些包时必须在onResume函数OpenCVLoader.initAsync()之后,否则会找不到库。最初我将procSrc2Gray();放在initUI()之后直接挂掉,后来放到OpenCVLoader.initAsync()依旧不行。除了上面代码里的方法外,还可以用一个延迟,默认等加载完包初始化后,再进行图像处理的操作:
-
new Handler().postDelayed(new Runnable(){
-
-
@Override
-
public void run() {
-
-
procSrc2Gray();
-
}
-
-
}, 1000);
这样就ok了,在按键监听里无需在判断是否是第一次了。程序运行结果:
三、OpenCV网站导航
鉴于自OpenCV新增C++接口后,国内的书籍就很少,几乎没有。尤其是增加OpenCV4Android Java接口后就更少了。后续将以专栏围绕翻译OpenCV4Android Java/C++ API,及介绍如何将数字图像处理与Android APP开发融合。
Opencv4Android环境搭建及第一个例子
标签:opencv android开发 手机
原文地址:http://blog.csdn.net/yuexin2/article/details/38820601