android调用opencv的方法有三种,利于OPENCVSDK manager调用,这种方法最简单,不过需要安装客户端,相对来说,很多适合都是不适用的。一种是使用OPENCV提供的JAVA库加SO库调用,这种方法相当来说,省掉了多安装一个APP的负责,更有利于软件推广。最后一种是利于JNI调用OPENV的C/C+语言库完成相关功能模块开发,并给JAVA层提供相应的调用接口,这种方式个人感觉效率最高。
使用OPENCV开发相机,一般是借且三种方式,一种是camera的previcewcallback接口提供的预览回调,一种是使用camera2的 ImageReader接口,还有一种使用OPENGL的shader开发相应接口,一旦加了特殊处理,都会产生丢帧。
从相机获取的数据都是YUV格式的BYTE数组,在opencv中先把其转为RGB数组,再对其做畸变,美颜,人脸查找,应用分割或者其他滤镜等技术。
先创建JAVA调用,这里写两个函数,一个YUV转为灰度,一个YUV转为RGBA,文件名字ImageProc,包名myopencv
package myopencv; public class ImageProc { static { System.loadLibrary("ImageProc"); } public static native boolean convertGray(int width, int height, byte[] NV21FrameData, int[] pixels); public static native boolean convertRGBA(int width, int height, byte[] yuv, int[] pixels); }
调用JAVAH生成头文件,头文件不是必需的,如果熟了,可以直接CPP文件
javah -classpath F:\luna5\mycam\bin\classes\ -jni myopencv.ImageProc
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class myopencv_ImageProc */
#ifndef _Included_myopencv_ImageProc
#define _Included_myopencv_ImageProc
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: myopencv_ImageProc
* Method: convertGray
* Signature: (II[B[I)Z
*/
JNIEXPORT jboolean JNICALL Java_myopencv_ImageProc_convertGray
(JNIEnv *, jclass, jint, jint, jbyteArray, jintArray);
/*
* Class: myopencv_ImageProc
* Method: convertRGBA
* Signature: (II[B[I)Z
*/
JNIEXPORT jboolean JNICALL Java_myopencv_ImageProc_convertRGBA
(JNIEnv *, jclass, jint, jint, jbyteArray, jintArray);
#ifdef __cplusplus
}
#endif
#endif
使用opencv编写相应的功能代码
编写MK文件,Application.mk,为了兼容性,参数使用 ALL,生成所有支持的CPU的库#include <stdio.h> #include <jni.h> #include<Android/log.h> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> using namespace std; using namespace cv; #define TAG "Camera XXXXX" // 这个是自定义的LOG的标识 #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,TAG,__VA_ARGS__) // 定义LOGD类型 extern "C" { jboolean Java_myopencv_ImageProc_convertGray( JNIEnv* env, jobject thiz, jint width, jint height, jbyteArray NV21FrameData, jintArray outPixels) { jbyte * pNV21FrameData = env->GetByteArrayElements(NV21FrameData, 0); jint * poutPixels = env->GetIntArrayElements(outPixels, 0); Mat mNV(height, width, CV_8UC1, (unsigned char*)pNV21FrameData); Mat mBgra(height, width, CV_8UC4, (unsigned char*) poutPixels); cvtColor(mNV, mBgra, CV_GRAY2RGBA); env->ReleaseByteArrayElements(NV21FrameData, pNV21FrameData, 0); env->ReleaseIntArrayElements(outPixels, poutPixels, 0); return true; } jboolean Java_myopencv_ImageProc_convertRGBA( JNIEnv *env, jobject thiz, jint width, jint height, jbyteArray yuv, jintArray outPixels) { jbyte * pBuf = (jbyte*)env->GetByteArrayElements(yuv, 0); jint * poutPixels = env->GetIntArrayElements(outPixels, 0); Mat image(height + height/2, width, CV_8UC1, (unsigned char *)pBuf); Mat mBgra(height, width, CV_8UC4, (unsigned char*) poutPixels); cvtColor(image, mBgra, CV_YUV420sp2RGBA); LOGD("jiaXXX %X", poutPixels[0]); env->ReleaseByteArrayElements(yuv, pBuf, 0); env->ReleaseIntArrayElements(outPixels, poutPixels, 0); return true; } jboolean Java_myopencv_ImageProc_convertBeauty( JNIEnv *env, jobject thiz, jint width, jint height, jbyteArray yuv, jintArray outPixels) { return true; } jboolean Java_myopencv_ImageProc_convertBackBlur( JNIEnv *env, jobject thiz, jint width, jint height, jbyteArray yuv, jintArray outPixels) { return true; } }
APP_STL := gnustl_static
APP_CPPFLAGS := -frtti -fexceptions
APP_ABI := all
APP_PLATFORM := android-8
编写Android.mk文件
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
OPENCV_LIB_TYPE:=STATIC
OPENCV_INSTALL_MODULES:=on
include C:/Users/jiazhiguo/Downloads/opencv/sources/samples/android/sdk/native/jni/OpenCV.mk
LOCAL_MODULE := ImageProc
LOCAL_SRC_FILES := ImageProc.cpp
LOCAL_LDLIBS += -llog -ldl
include $(BUILD_SHARED_LIBRARY)
注意路径,由于是使用OPENCV开发,对OPENCV有依赖,编译时需要OPENCV路径,我的OPENCV的SDK路径在C盘,需要改成自己的
ndk-build生成相应libImageProc.so库在项目中使用.
ImageProc.convertRGBA(previewSizeWidth, previewSizeHeight, mData, pixels);