如何在Android中使用OpenCV

 我来答
金牛座gxy
2015-08-18 · TA获得超过1291个赞
知道小有建树答主
回答量:223
采纳率:50%
帮助的人:75.3万
展开全部

如何在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="http://schemas.android.com/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进行处理,得到下面的结果:

huanglenzhi
2014-12-12 · 知道合伙人数码行家
huanglenzhi
知道合伙人数码行家
采纳数:117538 获赞数:517176
长期从事计算机组装,维护,网络组建及管理。对计算机硬件、操作系统安装、典型网络设备具有详细认知。

向TA提问 私信TA
展开全部
  我们都知道要学opencv必须会C或者C++语言,但是opencv为了照顾我们这些java程序员,整出来了个java-opencv预编译包。说白了,包里面就是一个个用java写的opencv代码,这样我们就可以通过类和对象的方式去调用这个opencv包里面的方法了。
  这个包和我们普通的java工程一样。

  我们只要把这个工程导入到和我们项目工程的同一个目录下,然后做以下操作就可以调用opencv库函数了。对你的工程点击右键选择Properties。

  然后点击Add按钮,将OpenCV-2.3.1这个工程添加到Is Library里面就ok了。记住:OpenCV-2.3.1这个工程必须和你的工程在同一个工作空间。这样你就可以在java中使用openCV做图像处理啦。
本回答被提问者和网友采纳
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
百度网友49680e6
2014-12-12 · TA获得超过125个赞
知道小有建树答主
回答量:59
采纳率:0%
帮助的人:90.6万
展开全部
OpenCV已经提供了OpenCV For Android版本的,可以参考官方说明:http://opencv.willowgarage.com/wiki/Android以及这个链接
http://blog.csdn.net/sjz_iron/article/details/8569687
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
百度网友88e669a48
2014-12-12
知道答主
回答量:21
采纳率:0%
帮助的人:17.8万
展开全部
opencv是C++库,所以一般都要使用NDK,JNI。
详细的教程:
官方(需要梯子):http://opencv.willowgarage.com/wiki/Android
http://jingyan.baidu.com/article/d8072ac45aa46fec95cefdc3.html
http://www.xuebuyuan.com/541923.html
http://underthehood.blog.51cto.com/2531780/670169/
网上的教程一般不是最新的。如果需要最新的Opencv库的话,最好翻 墙到官方网站,照着教程设置就可以了
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
zzzzzzzzzzzlzk
2014-12-12 · TA获得超过502个赞
知道答主
回答量:239
采纳率:0%
帮助的人:64.1万
展开全部
Be
Xx.
Xx
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
收起 更多回答(3)
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式