在android中,通过JNI读取Bitmap文件并调用opencv进行处理,分为四步:1,activity中创建Bitmap对象;2,通过JNI定义native方法并传递Bitmap对象进去;,3,解析Bitmap对象;4,利用解析数据生成opencv的Mat对象,并进行相关处理。
1,activity中创建Bitmap对象
android支持几种Bitmap格式,RGBA_8888,RGB_565,RGBA_4444,A_8等等,格式不同存储方式就不同,在后面解析时的处理方法也自然不同。在activity中读入图像文件并创建Bitmap对象时,可以指定Bitmap的格式。为了后面更易于转换成Mat,我设定的格式是RGBA_8888。方法如下:
//指定图像的路径,这里是在sd卡中
String src_path = Environment.getExternalStorageDirectory().getPath()+"/up.jpg";
String body_path = Environment.getExternalStorageDirectory().getPath()+"/down.jpg";
//读取sd卡中的图像,变为bitmap对象
File file1 = new File(src_path);
File file2 = new File(body_path);
//若该文件存在
if (file1.exists() && file2.exists()) {
//指定Bitmap的格式
Options opt = new Options();
opt.inPreferredConfig = Bitmap.Config.ARGB_8888;
//读取文件并创建Bitmap对象
Bitmap bmp1 = BitmapFactory.decodeFile(src_path,opt);
Bitmap bmp2 = BitmapFactory.decodeFile(body_path,opt);
}
2,通过JNI定义native方法并传递Bitmap对象进去
要把Bitmap作为native方法的参数传递进去,只要将其定义为Object类型即可,例如:
public native int bodyDetect(Object bmp1,Object bmp2,double meanRatio,int[] target_rect);
前两个参数都是Bitmap对象,利用javah生成的头文件如下:
JNIEXPORT jint JNICALL Java_com_example_helloworld_BodyDetect_bodyDetect (JNIEnv *, jobject, jobject, jobject, jdouble, jintArray);
3,解析Bitmap对象
在jni的cpp文件中将传进来的Bitmap对象的内容解析出来,主要利用了android的两个函数:AndroidBitmap_getInfo(...),AndroidBitmap_lockPixels(..),AndroidBitmap_unlockPixels(...)。流程如下:
#ifndef LOGE
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,"@",__VA_ARGS__)
#endif
JNIEXPORT jint JNICALL Java_com_example_helloworld_BodyDetect_bodyDetect
(JNIEnv * env, jobject obj, jobject jbmp1, jobject jbmp2, jdouble jmeanRatio,jintArray jtarget_rect)
{
AndroidBitmapInfo bmp1info;
void* bmp1pixels;
AndroidBitmapInfo bmp2info;
void* bmp2pixels;
int height,width,ret,y,x;
//解析bitmap
if ((ret = AndroidBitmap_getInfo(env, jbmp1, &bmp1info)) < 0) {
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
return -1;
}
if ((ret = AndroidBitmap_getInfo(env, jbmp2, &bmp2info)) < 0) {
LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
return -1;
}
if (bmp1info.format != ANDROID_BITMAP_FORMAT_RGBA_8888 || bmp1info.format != ANDROID_BITMAP_FORMAT_RGBA_8888) {
LOGE("Bitmap format is not RGBA_8888!");
return -1;
}
if ((ret = AndroidBitmap_lockPixels(env, jbmp1, &bmp1pixels)) < 0) {
LOGE("First Bitmap LockPixels Failed return=%d!", ret);
return -1;
}
if ((ret = AndroidBitmap_lockPixels(env, jbmp2, &bmp2pixels)) < 0) {
LOGE("Second Bitmap LockPixels Failed return=%d!", ret);
return -1;
}
。。。
AndroidBitmap_unlockPixels(env, jbmp1);
AndroidBitmap_unlockPixels(env, jbmp2);
}
4,利用解析数据生成opencv的Mat对象,并进行相关处理。
RGBA_8888格式的Bitmap,一个像素占32位,分别是A:8bit,R:8bit;G:8bit;B:8bit。对应到opencv的Mat对象,有个一个Mat的构造函数,结果接受外部数据数组并生Mat对象,这将大大方便转换过程,不用逐像素的操作了。如下:
。。。
//将bitmap转成灰度图像
height = bmp1info.height;
width = bmp1info.width;
Mat src(height,width,CV_8UC4,bmp1pixels);
Mat body(height,width,CV_8UC4,bmp2pixels);
if(!(src.data &&body.data)){
LOGE("bitmap failed convert to Mat return=%d!", ret);
return -1;
}
//转换为灰度图像
cvtColor(src,src,CV_RGBA2GRAY);
cvtColor(body,body,CV_RGBA2GRAY);
。。。
这里由Bitmap对象转换成Mat这么容易,是因为RGBA_8888格式的存储方式正好与Mat的CV_8UC4对应。如果是其他格式的Bitmap转成Mat,则要麻烦多了。可以参考几个帖子:
http://blog.csdn.net/youngc527/article/details/25424729
http://bbs.csdn.net/topics/390773967
http://blog.csdn.net/wwj_748/article/details/8206299
待调好了这种方式,再作补充。

本文介绍如何在Android应用中通过JNI调用OpenCV处理Bitmap图像,包括创建Bitmap对象、定义JNI方法传递Bitmap、解析Bitmap内容及转换为OpenCV Mat对象等步骤。

5892

被折叠的 条评论
为什么被折叠?



