(原+转)Eclipse中Android调用OpenCv
大部分都是参考下面的网址,如果感觉看起来不舒服,可以直接查看原网址。最后遇到了一点问题:
Description Resource Path Location Type
E:/~\code\Eclipse\opencvV4sdk\native\jni\/../libs/armeabi-v7a/libopencv_core.a(persistence.cpp.o): in function cvOpenFileStorage:persistence.cpp(.text.cvOpenFileStorage+0x1ac): error: undefined reference to 'gzrewind' ~ C/C++ Problem
可以直接拖到最后查看。
参考文章: http://www.cnblogs.com/adong7639/p/3925347.html(WINDOWS系统Eclipse+NDK+Android + OpenCv)
使用的ADT:
使用的NDK:android-ndk-r10c
使用的opencv:OpenCV-2.4.9-android-sdk
具体的配置就不说了,由于自己是NDK中直接调用opencv的函数,因而直接说明此步骤。
1. 将OpenCV-2.4.9-android-sdk 中的sdk文件夹放到Eclipse工程中,为了方便查看,可以改名成opencvV4sdk。
2. 安装OpenCV_Manager,没有测试如果不安装这个会怎么样(卸载后继续运行程序,可以正常运行。因而不确定是否一定需要这步)。
3. 利用JNI接口通过NDK平台调用OpenCV API函数
- 新建一个Android工程 NDK_OPENCV(后面将会看到这种命名方式不是很好)
默认使用MainActivitiy,包名com.example.ndk_opencv
- 构建Android的Java层代码
(1)布局文件:main.xml
<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"
tools:context="${packageName}.${activityClass}" >
<Button
android:id="@+id/imagegray"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="图像灰度化" /> <ImageView
android:id="@+id/imageview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@+id/imagegray"
android:layout_centerHorizontal="true"
android:layout_marginTop="86dp" />
</RelativeLayout>
(2) 在AndroidManifest.xml文件中加入
<!-- 在SDCard中创建与删除文件权限 -->
<uses-permission
android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- 往SDCard写入数据权限 -->
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
(3) MainActivity.java
package com.example.ndk_opencv; import android.annotation.SuppressLint;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView; @SuppressLint("SdCardPath")
public class MainActivity extends Activity {
private Button btngray;
private ImageView imageview;
private Bitmap bmp; @SuppressLint("SdCardPath")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.setTitle("Android NDK OpenCV");
btngray = (Button)findViewById(R.id.imagegray);
//btnProc.setOnClickListener(this); imageview = (ImageView)this.findViewById(R.id.imageview); bmp=BitmapFactory.decodeFile("/sdcard/andimg/img1.jpg"); imageview.setImageBitmap(bmp); //点击按钮,调用Opencv接口实现SD卡中的图片灰度化 btngray.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
bmp=BitmapFactory.decodeFile(stringNDKOPENCV());
imageview.setImageBitmap(bmp);
}
});
} //通过jni接口实现的本地函数 public native String stringNDKOPENCV(); static {
System.loadLibrary("NDK_OPENCV");
}
}
3.2 配置工程的NDK编译环境
3.2.1在工程上右键点击Android Tools->Add Native Support...,然后给我们的.so文件取个名字,例如: NDK_OPENCV(默认为工程名字)
这时候工程就会多一个jni的文件夹,jni下有Android.mk和NDK_OPENCV.cpp文件。
3.2.2工程右键,点Properties->C/C++ Build的Building Settings中去掉Use default build command,然后输入${NDKROOT}/ndk-build.cmd
3.2.3在C/C++ Build中点击Environment,点Add...添加环境变量NDKROOT,值为NDK的根目录E:\project\Android\adt-bundle-windows-x86-20140321\android-ndk-r10
3.3 编写NDK_OPENCV.cpp文件
3.3.1生成.h文件
(其实此步骤可以不管,即便不生成.h文件,也可以正常使用.so文件)
在编写NDK_OPENCV.cpp文件前,需要利用javah这个工具生成相应的.h文件,然后根据这个.h文件编写相应的C/C++代码。用eclipse编译该工程,生成相应的.class文件,这步必须在下一步之前完成,因为生成.h文件需要用到相应的.class文件。暂时不考虑报错信息。
进入到刚才建立的NDK_OPENCV工程目录中,在工程目录下执行:
Javah -classpath bin\classes -d jni com.example.ndk_opencv.MainActivity
这里-classpath表示类的路径;-d jni表示生成的.h文件存放的目录com.example.ndk_opencv.MainActivity则是完整的类名。现在可以在jni目录下看到多了一个.h文件:com_example_ndk_opencv_MainActivity.h;
打开后,可以看到.h的内容:
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_example_ndk_opencv_MainActivity */ #ifndef _Included_com_example_ndk_opencv_MainActivity
#define _Included_com_example_ndk_opencv_MainActivity
#ifdef __cplusplus
extern "C" {
#endif /* * Class: com_example_ndk_opencv_MainActivity * Method: stringNDKOPENCV * Signature: ()Ljava/lang/String; */ JNIEXPORT jstring JNICALL Java_com_example_ndk_1opencv_MainActivity_stringNDKOPENCV
(JNIEnv *, jobject); #ifdef __cplusplus }
#endif
#endif
代码解释:
- JNI接口的命名规范是:Java_ + 调用该方法的包名(包名的点用_代替) + _ + 调用该接口的类名 + _ + 方法名。函数名比较长但是完全按照:java_pacakege_class_mathod 形式来命名。也就是说:MainActivity.java中stringNDKOPENCV () 方法对应于 C/C++中的 Java_com_example_ndk_1opencv_MainActivity_stringNDKOPENCV () 方法。
- 对于实例方法, JNIEXPORT 和 JNICALL 是jni的宏,在android的jni中不需要,当然写上去也不会有错。注意下其中的注释:Signature: ()Ljava/lang/String表示函数的参数为空,这里为空是指除了JNIEnv *, jobject 这两个参数之外没有其他参数,JNIEnv*, jobject是所有jni函数必有的两个参数,分别表示jni环境和对应的java类(或对象)本身,Ljava/lang/String表示函数的返回值是java的String对象。
- ndk_1opencv 代码中的红色标记处多了个1,这个1应该表示ndk_opencv为一个整体而非继承结构,因此不建议包名出现空格,以免出错。
3.3.2 编写NDK_OPENCV.cpp
#include <jni.h>
#include <string.h>
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/imgproc/imgproc_c.h> extern "C" jstring Java_com_example_ndk_1opencv_MainActivity_stringNDKOPENCV( JNIEnv* env,
jobject thiz )
{
//return env->NewStringUTF("/sdcard/andimg/img2.jpg");
const char* file="/sdcard/andimg/img1.jpg";
IplImage* object = cvLoadImage(file,CV_LOAD_IMAGE_GRAYSCALE);
std::string filePath="/sdcard/andimg/img1_result.jpg";
jstring filePath1=env->NewStringUTF(filePath.c_str());
const char * resultpath=env->GetStringUTFChars(filePath1, );
cvSaveImage(resultpath,object);
//env->ReleaseStringUTFChars(path, file);
env->ReleaseStringUTFChars(filePath1, resultpath);
return filePath1;
}
代码解释:这段代码首先读取了SD卡中的一张图像,接着调用env->GetStringUTFChars,以灰度形式读取图像并保存在SD卡中,最后返回灰度图像的路径。
3.4利用NDK平台编译C++语言函数成.so文件
3.4.1首先需要编写Android.mk文件
LOCAL_PATH := $(call my-dir)
include$(CLEAR_VARS)
# OpenCV
OPENCV_CAMERA_MODULES:=on
OPENCV_INSTALL_MODULES:=on
OPENCV_LIB_TYPE:=STATIC
include E:\project\JavaWork\JavaExistWork\sdk\native\jni\OpenCV.mk
LOCAL_MODULE := NDK_OPENCV
LOCAL_SRC_FILES := NDK_OPENCV.cpp
include$(BUILD_SHARED_LIBRARY)
3.4.2同时建立Application.mk文件
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := armeabi-v7a
APP_PLATFORM := android-9
4测试运行
如果在Eclipse下面打开NDK_OPEC.cpp文件会出现很多错误,需要将错误删除掉,否则无法编译。
"Eclipse可能报一堆的错误提示 由于eclipse的语法检查,当你打开一个源码,尤其是引入外面开发完成的项目,因为源码不是在工程中管理的,大部分情况会报一堆的错误提示,而你是明 确这些问题实际上是不存在的,那么就可以这样子做了,设置项目属性,把eclipse多管的这些闲事给免了它的职,如下图,保存后,你会发现你的 problems窗口下非常清爽了:"
解决方法之一:需要将错误删除掉,否则无法编译。
解决方法之二:打开工程属性,选择C/C++ General 中的Code Analysis ,接着选择Useproject setting 去掉Syntax and Semantic……,这是Eclipse在检测一些不符合java中的符号报错,其实代码没有错的。
运行结果
问题:按照示例编译代码没问题,但是自己的代码调用opencv则出现如下错误:
之后,参考:
http://stackoverflow.com/questions/10858055/opencv2-4-with-android-native-activity
在Android.mk中加上了
LOCAL_LDLIBS += -lz # Compression library
之后,错误消失。
(原+转)Eclipse中Android调用OpenCv的更多相关文章
- Eclipse中Android公共库的正确建立及调用方法
Eclipse中Android公共库的正确建立及调用方法 引言 之前一直头痛于没有办法在多个程序中共享资源,用作公共类库的方法也是使用的导出jar再导入的办法,现在终于初步搞明白了,可算解脱了~,分享 ...
- 【转】Eclipse中一键调用javah生成jni的头文件
这里定义了一个本地方法jni_test,该方法返回一个String.其中System.loadLibrary是用来加载本地库的(dll或者so). 有了这个类以后,就可以调用javac命令编译,得到E ...
- java 在centos6.5+eclipse环境下调用opencv实现sift算法
java 在centos6.5+eclipse环境下调用opencv实现sift算法,代码如下: import org.opencv.core.Core; import org.opencv.core ...
- 解决eclipse中android添加重载函数时参数为arg0,arg1的问题
遇到同样的问题,发现有人已经解决了,大体意思就是为android sdk 添加 src,以下是文章链接 http://blog.csdn.net/u014084081/article/details/ ...
- 解决ubuntu eclipse中 Android SDK Manager 图标不见的方法
在eclipse中选择的步骤如下: Window ---> Custom Perspective --> command Group Availability ----> an ...
- 解决Eclipse中Android SDK Manager图标不见了的问题
在Eclipse中安装完ADT后,发现 Android SDK Manager图标不见了,Android Virtual Device Manager图标也不见了. 解决这个问题,可用如下方法: 打开 ...
- phonegap 开发指南系列(3) ----在Eclipse中Android开发环境搭建
前提条件:已在Eclipse中安装好Android SDK 和 ADT. 1.下载PhoneGap,解压. 2.用Eclipse新建一个安卓项目. 3.将phoneGap解压包里的Android文 ...
- Eclipse中android工程C++文件中出现的莫名其妙的错误
大多数是std库相关的问题,例如 vector<int> v; v.push_back(23);//这句语法是没有错误的,但是每次执行Run As的时候就会报错 尝试1:在工程名右键-Cl ...
- Eclipse中Android公共库的正确建立及调用方法(转)
转自http://www.cnblogs.com/SkyD/archive/2011/09/01/2161502.html 引言 之前一直头痛于没有办法在多个程序中共享资源,用作公共类库的方法也是使用 ...
随机推荐
- UINavigationController 导航控制器
一.导航视图控制器 1.管理视图控制器 2.控制视图控制器之间的跳转 3.是以压栈和出栈的形式来管理视图控制器 4.导航视图控制器必须要设置根视图控制器 5.导航是视图控制器包含UINavigatio ...
- Webform用户控件
用户控件一 用户控件二
- TCP粘包/拆包问题的解决
TCP粘包拆包问题 一个完整的包可能被TCP拆分成多个包,或多个小包封装成一个大的数据包发送. 解决策略 消息定长,如果不够,空位补空格 在包尾增加回车换行符进行分割,例如FTP协议 将消息分为消息头 ...
- (转) Dynamic memory
In the programs seen in previous chapters, all memory needs were determined before program executi ...
- POI操作Excel常用方法总结
转载自:http://blog.csdn.net/xjun15/article/details/5805429 一. POI简介 Apache POI是Apache软件基金会的开放源码函式库,POI提 ...
- TeXLive安装过程
Linux系统下TeXLive2016安装教程:http://www.linuxidc.com/Linux/2016-08/133913.htm 安装完成后,在当前用户的 ~/.bashrc 中加入如 ...
- EF 请求数据是缓存 求大神解释
// //AliexpressEntities MyaliexpressEntities 为了事物一致性 在别的方法里面传过来的 实质还是 ( AliexpressEntities aliexpre ...
- Qt 自定义事件详细实例(继承QEvent,然后QCoreApplication::postEvent()、sendEvent())
创建用户事件 创建一个自定义类型的事件,首先需要有一个事件号,其值通常大于QEvent::User.为了传递事件信息,因此必须编写自定义的事件类,该事件类从QEvent继承. 编写用户事件:编写用户事 ...
- SQL Server 2008空间数据应用系列七:基于Bing Maps(Silverlight) 的空间数据展现
原文:SQL Server 2008空间数据应用系列七:基于Bing Maps(Silverlight) 的空间数据展现 友情提示,您阅读本篇博文的先决条件如下: 1.本文示例基于Microsoft ...
- 安装 Kali Linux 后需要做的 20 件事
安装 Kali Linux 后需要做的 20 件事 本文含有我觉得有用的每一件事情.本文分为三大部分: 专门针对Kali用户 Kali Linux是来自Debian的一个特殊版本,Kali Linux ...