本文主要是介绍Window系统Eclipse+NDK+Android+OpenCv开发教程,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1.Android NDK环境搭建
1.3 配置OpenCv
下载 OpenCV-2.4.4-android-sdk解压出来,可以看到文件下有apk文件,doc文档,sample例子程序,以及OpenCV4Android-sdk。
其 中,OpenCV4Android-sdk目录即是我们开发opencv所需要的类库;samples目录中存放着若干opencv应用示例(包括人脸检测等),可为我们进行 android下的opencv开发提供参考;doc目录为opencv类库的使用说明及api文档等;而apk目录则存放着对应于各内核版本的。
1.3.1 安装OpenCV_Manager
OpenCV_2.4.3.2_Manager_2.4应用安装包。此应用用来管理手机设备中的opencv类库,在运行opencv应用之前,必须确保手机中已经安装了OpenCV_2.4.4.4_Manager_2.6_*.apk,否则opencv应用将会因为无法加载opencv类库而无法运行。
可以根据自己的手机类型来安装OpenCV_2.4.4.4_Manager.apk.
通过查询自己的手机CPU信息
adb shell
cat /proc/cpuinfo
我的手机是arm v7 –neon 架构的,Android版本为4.4.4选择第3个,第四个是适用于低版本Android系统的手机。
安装完毕后,可以测试OpenCV_2.4.4.4_Manager.apk.是否正确。
在samples文件架中找个例子安装包,如example-15-puzzle.apk,安装到手机测试这个拼图游戏是否正常运行。
1.3.2 OpenCV4Android-sdk引入工作空间
(1) 将OpenCV4Android-sdk目录copy至后面的Android工程的工作空间;
(2)打开eclipse,将OpenCV-SDK引入到工作空间中,如下图所示:
第二部分 开始实战---使用封装的OpenCV API开发android(不通过jni接口)
2.1 创建工程
(1) 打开 eclipse ,创建 android 应用工程 API_OPENCV ;
(2) 在手机的的SD卡根目录/sdcard上新建一个目录andimg ,放入图像img1.jpg
(3) 在 Package Explorer 中选择项目 API_OPENCV ,单击右键在弹出菜单中选择Properties ,然后在弹出的 Properties 窗口中左侧选择 Android ,然后点击右下方的Add 按钮,选择 OpenCV Library 2.4.4 并点击 OK ,操作完成后,会将 OpenCV 类库添加到 API_OPENCV 的 Android Dependencies 中,如下图所示:
2.2 工程代码:
(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.xm l 文件中加入
<!-- 在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.api_opencv;
import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.Utils;
import org.opencv.core.Mat;
import org.opencv.imgproc.Imgproc;
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.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class MainActivity extends Activity {
private Button btngray;
private ImageView imageview;
private Bitmap bmp;
//OpenCV类库加载并初始化成功后的回调函数,在此我们不进行任何操作
private BaseLoaderCallback mOpenCVCallBack = new BaseLoaderCallback(this) {
@Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
} break;
default:
{
super.onManagerConnected(status);
} break;
}
}
};
@SuppressLint("SdCardPath")
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
this.setTitle("Android API OpenCV");
btngray = (Button)findViewById(R.id.imagegray);
imageview = (ImageView)this.findViewById(R.id.imageview);
bmp=BitmapFactory.decodeFile("/sdcard/andimg/img1.jpg");
imageview.setImageBitmap(bmp);
btngray.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
Mat rgbMat = new Mat();
Mat grayMat = new Mat();
//获取lena彩色图像所对应的像素数据
Utils.bitmapToMat(bmp, rgbMat);
//将彩色图像数据转换为灰度图像数据并存储到grayMat中
Imgproc.cvtColor(rgbMat, grayMat, Imgproc.COLOR_RGB2GRAY);
//创建一个灰度图像
Bitmap grayBmp = Bitmap.createBitmap(bmp.getWidth(), bmp.getHeight(), Config.RGB_565);
//将矩阵grayMat转换为灰度图像
Utils.matToBitmap(grayMat, grayBmp);
imageview.setImageBitmap(grayBmp);
}
});
}
@Override
public void onResume()
{
//通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是
//OpenCV_2.4.4_Manager_2.4_*.apk程序包,存在于OpenCV安装包的apk目录中
super.onResume();
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_4, this, mOpenCVCallBack);
}
}
2.3 运行结果
第三部分 开始实战--- 利用JNI接口通过NDK平台调用OpenCV API函数
3.1新建一个Android工程 NDK_OPENCV(后面将会看到这种命名方式不是很好)
默认使用MainActivitiy,包名com.example.ndk_opencv
3.2构建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编译环境
在工程上右键点击Android Tools->Add Native Support...,然后给我们的.so文件取个名字,例如: NDK_OPENCV(默认为工程名字)
这时候工程就会多一个jni的文件夹,jni下有Android.mk和 NDK_OPENCV .cpp文件。
工程右键,点Properties->C/C++ Build的Building Settings中去掉Use default build command,然后输入${NDKROOT}/ndk-build.cmd
在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文件
在编写 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, 0);
cvSaveImage(resultpath,object);
//env->ReleaseStringUTFChars(path, file);
env->ReleaseStringUTFChars(filePath1, resultpath);
return filePath1;
}
代码解释:
- 这段代码首先读取了SD卡中的一张图像,接着调用env->GetStringUTFChars,以灰度形式读取图像并保存在SD卡中,最后返回灰度图像的路径。
- Java_com_example_ ndk_1opencv _MainActivity_stringNDKOPENCV( JNIEnv* env,jobject thiz )是根据.h文件给出的
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 : = NDKCPP
LOCAL_SRC_FILES : = NDKCPP.cpp
include $(BUILD_SHARED_LIBRARY)
其中 include E:/project/JavaWork/JavaExistWork/sdk/native/jni/OpenCV.mk 为OpenCV SDK的路径MK文件路径,引入Opencv库
3.4.2同时建立Application.mk文件
APP_STL : = gnustl_static
APP_CPPFLAGS : = -frtti -fexceptions
APP_ABI : = armeabi-v7a
APP_PLATFORM : = android-9
4测试运行
如果在Eclipse下面打开NDK_OPECV文件会出现很多错误,需要将错误删除掉,否则无法编译。
运行结果
原文地址:http://www.th7.cn/Program/Android/201408/265565.shtml
这篇关于Window系统Eclipse+NDK+Android+OpenCv开发教程的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!