我的Opencv4Android添加V4L2支持的移植记录(4)

32 篇文章 2 订阅
14 篇文章 0 订阅

博主QQ:1356438802

QQ群:473383394——UVC&OpenCV47



这次我们来对《我的Opencv4Android添加V4L2支持的移植记录(2)》的实时预览进行一些优化。


先来看那篇文章中源码的ImageProc.cpp文件

#include "ImageProc.h"


#include "cv.h"
#include "highgui.h"

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"

#include <string>
#include <vector>

using namespace cv;
using namespace std;

#ifdef __cplusplus
extern "C" {
#pragma message("------------------------ ImageProc.cpp")
#endif

CvCapture *pCapture = NULL;
IplImage *frame = NULL;
int id;

JNIEXPORT jintArray JNICALL Java_luo_uvc_jni_ImageProc_grayProc(JNIEnv* env,
		jclass obj, jintArray buf, jint w, jint h)
{
	jint *cbuf;
	cbuf = env->GetIntArrayElements(buf, false);
	if (cbuf == NULL)
	{
		return 0;
	}

	Mat imgData(h, w, CV_8UC4, (unsigned char*) cbuf);

	uchar* ptr = imgData.ptr(0);
	for (int i = 0; i < w * h; i++)
	{
		//计算公式:Y(亮度) = 0.299*R + 0.587*G + 0.114*B
		//对于一个int四字节,其彩色值存储方式为:BGRA
		int grayScale = (int) (ptr[4 * i + 2] * 0.299 + ptr[4 * i + 1] * 0.587
				+ ptr[4 * i + 0] * 0.114);
		ptr[4 * i + 1] = grayScale;
		ptr[4 * i + 2] = grayScale;
		ptr[4 * i + 0] = grayScale;
	}

	int size = w * h;
	jintArray result = env->NewIntArray(size);
	env->SetIntArrayRegion(result, 0, size, cbuf);

	env->ReleaseIntArrayElements(buf, cbuf, 0);

	return result;
}

JNIEXPORT jint JNICALL Java_luo_uvc_jni_ImageProc_connectCamera(JNIEnv* env,
		jclass obj, jint device)
{

	id = device;
	pCapture = NULL;

	LOGI("usb camera id=%d Java_luo_uvc_jni_ImageProc_connectCamera start ....\n", id);

	//查找UVC设备
	pCapture = cvCaptureFromCAM(id);
	if (NULL != pCapture)
	{
		LOGE("usb camera open success!\n");
		return 0;
	}

	LOGI("usb camera Java_luo_uvc_jni_ImageProc_connectCamera end ....\n");

	return -1;
}

JNIEXPORT jint JNICALL Java_luo_uvc_jni_ImageProc_releaseCamera(JNIEnv* env,
		jclass obj)
{
	LOGI("usb camera Java_luo_uvc_jni_ImageProc_releaseCamera start ....\n");

	if (NULL != pCapture)
	{
		cvReleaseCapture(&pCapture);
		pCapture = NULL;
	}

	LOGI("usb camera Java_luo_uvc_jni_ImageProc_releaseCamera end ....\n");

	return 0;
}

struct FrameInfoClass
{
    jfieldID width;
    jfieldID heigth;
    jfieldID imageSize;
    jfieldID pixels;
};

JNIEXPORT jobject JNICALL Java_luo_uvc_jni_ImageProc_getFrame(JNIEnv* _env,
		jclass obj)
{
	LOGI("------------Java_luo_uvc_jni_ImageProc_getFrame\n");
	if(NULL != pCapture)
	{
		LOGI("------------start cvQueryFrame\n");
		frame = NULL;
		frame = cvQueryFrame(pCapture); //取图片帧
		if(NULL == frame)
		{
			LOGE("cvQueryFrame(capture) failed!!!!!!!!!!!!!!!!!!!!!!!");
			return NULL;
		}

		struct FrameInfoClass frameInfoClass;

		//内部类用$
		//luo/uvc/jni/ImageProc$FrameInfo
		jclass class2 = _env->FindClass("luo/uvc/jni/ImageProc$FrameInfo");
		LOGI("1=GetFieldID\n");

		frameInfoClass.width = _env->GetFieldID(class2, "mWidth", "I");
		LOGI("2=GetFieldID\n");

		frameInfoClass.heigth = _env->GetFieldID(class2, "mHeight", "I");
		LOGI("3=GetFieldID\n");

		frameInfoClass.imageSize = _env->GetFieldID(class2, "mImageSize", "I");
		LOGI("4=GetFieldID\n");

		frameInfoClass.pixels = _env->GetFieldID(class2, "mPixels", "[I");
		LOGI("5=GetFieldID\n");

		//
		jobject joFrame = _env->AllocObject(class2);

		LOGI("6=GetFieldID\n");
		LOGI("frame->width = %d\n", frame->width);
		LOGI("frame->height = %d\n", frame->height);
		LOGI("frame->imageSize = %d\n", frame->imageSize);

		_env->SetIntField(joFrame, frameInfoClass.width, frame->width);
		_env->SetIntField(joFrame, frameInfoClass.heigth, frame->height);
		_env->SetIntField(joFrame, frameInfoClass.imageSize, frame->imageSize);

		int size = frame->width * frame->height;
		//创建一个新的java数组(jarray),但是jarray不是C数组类型,不能直接访问jarray
		jintArray jiArr = _env->NewIntArray(size);
		jint *ji;

		#if 1   //可用
		LOGI("7=GetFieldID\n");

		//RGB --> ARGB8888
		Mat frameRGB(frame->height, frame->width, CV_8UC3, frame->imageData), frameARGB;
		cvtColor(frameRGB, frameARGB, CV_RGB2RGBA);

		//JNI支持一系列的Get/Release<Type>ArrayElement 函数,允许本地代码获取一个指向基本C类型数组的元素的指针。
		ji = _env->GetIntArrayElements(jiArr, 0);

		memcpy((jbyte *)ji, frameARGB.data, 4 * size);

		_env->ReleaseIntArrayElements(jiArr, ji, 0); //可加,可不加

		_env->SetObjectField(joFrame, frameInfoClass.pixels, jiArr);

		LOGI("8=GetFieldID\n");

		#else   //可用
		//可以使用GetIntArrayRegion函数来把一个 int数组中的所有元素复制到一个C缓冲区中
		//SetIntArrayRegion则是逆过程
		LOGI("13=GetFieldID\n");
		_env->SetIntArrayRegion(jiArr, 0, 2, abc);
		_env->SetObjectField(joFrame, company_class.money, jiArr);

		#endif

		LOGI("Java_luo_uvc_jni_ImageProc_getFrame end\n");

		return joFrame;

	}

	LOGI("=================Java_luo_uvc_jni_ImageProc_getFrame failed\n");

	return 0;
}


JNIEXPORT jint JNICALL Java_luo_uvc_jni_ImageProc_getWidth(JNIEnv* env,
		jclass obj)
{
	return 0;
}

JNIEXPORT jint JNICALL Java_luo_uvc_jni_ImageProc_getHeight(JNIEnv* env,
		jclass obj)
{
	return 0;
}

#ifdef __cplusplus
}
#endif
/* end of extern */

其中Java_luo_uvc_jni_ImageProc_getFrame这个函数是提取图像,给SurfaceView刷新显示的,由于它整个流程操作数据块比较多,而且在JNI层构造了一个FrameInfo对象,效率很低。我们对其进行改造。

void Java_luo_uvc_jni_ImageProc_getFrame(JNIEnv* env, jobject thiz,
		jobject bitmap)
{
	AndroidBitmapInfo info;
	void *pixels;
	char *pixel;
	int ret;

	int width = 0;
	int height = 0;
	int ImageSize = 0;

	if (NULL != pCapture)
	{
		//1. get frame
		LOGI("------------start cvQueryFrame\n");
		frame = NULL;
		frame = cvQueryFrame(pCapture);
		if (NULL == frame)
		{
			LOGE("cvQueryFrame(capture) failed!!!!!!!!!!!!!!!!!!!!!!!");
			return;
		}

		if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0)
		{
			LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret);
			return;
		}

		width = info.width;
		height = info.height;
		ImageSize = width * height;
		LOGI("------------info.width=%d, info.height=%d\n", info.width,
				info.height);

		if (info.format != ANDROID_BITMAP_FORMAT_RGBA_8888)
		{
			LOGE("Bitmap format is not RGBA_8888 !");
			return;
		}

		if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0)
		{
			LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret);
			return;
		}

		pixel = (char *)pixels;
		for (int i = 0; i < ImageSize; i++)
		{
			//需要注意的是对于ARGB_8888类型的图像而言,其每一个像素值在int型数据中的存储序列为BGRA。
			*(pixel + 4 * i + 0) = *(frame->imageData + 3 * i + 2);
			*(pixel + 4 * i + 1) = *(frame->imageData + 3 * i + 1);
			*(pixel + 4 * i + 2) = *(frame->imageData + 3 * i + 0);
			*(pixel + 4 * i + 3) = 0xFF;

		}

		AndroidBitmap_unlockPixels(env, bitmap);

	}
}

其实就是取java层的Bitmap对象的data空间,直接把frame-->imageData拷贝过去。特别注意这里的RGB-->ARGB_8888格式转换方式,上面是用MAT矩阵转换,而我这里采取直接复制的方式,本质是一样的。 对于ARGB_8888类型的图像而言,其每一个像素值在int型数据中的存储序列为BGRA。


经过这样的修改后,预览的实时性有很大的提高!


示例下载:http://download.csdn.net/detail/luoyouren/9594703













  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值