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

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

博主QQ:1356438802

QQ群:473383394——UVC&OpenCV47


引言

前面几篇文章我已经在Windows / Ubuntu / Android 三个平台成功安装了opencv的使用/编程环境,但是我需要在android平台使用usb video  camera(即UVC)。当然在Ubuntu上,默认编译出来的opencv库本身就支持V4L2(UVC的操作API函数集),而Windows是将UVC纳入了DirectShow框架,默认也是支持的;唯独对于Android平台,有且仅有对Android Native Camera的支持,即通常说的前摄像头、后摄像头。所以我接下来的工作就是将V4L2加入Opencv4Andorid!

PS1: 前面那篇ubuntu安装opencv的文章,是在Ubuntu虚拟机里面做的。这篇文章是在Ubuntu物理机上做的,所以工具和环境我又装了一遍。

PS2: 参考文章《OpenCV4Android编译http://blog.sina.com.cn/s/blog_602f87700102vdnw.html》《透析Android以JNI调OpenCV的三种方式(让OpenCVManager永不困扰)http://blog.csdn.net/yanzi1225627/article/details/27863615

PS3: 本文章的最后编译的opencv4android sdk和几个例程app——http://download.csdn.net/detail/luoyouren/9566690

一、工具和环境变量安装

1. sudo apt-get install cmake




2. sudo apt-get install ant



1.8版本可能会出错!
再到http://ant.apache.org官网下载1.9.7版本安装到/opt目录,
修改/usr/bin/ant的软链接,指向/opt/apache-ant-1.9.7/bin/ant


3. 环境变量:sudo vim /etc/profile


source /etc/profile

二、直接编译

1. sh scripts/cmake_android_arm.sh
   
   
#!/bin/sh
cd `dirname $0`/..
 
mkdir -p build_android_arm
cd build_android_arm
 
cmake -DCMAKE_BUILD_WITH_INSTALL_RPATH=ON -DCMAKE_TOOLCHAIN_FILE=../android/android.toolchain.cmake $@ ../..
log_build_for_android_1.txt,和log_build_for_ubuntu.txt对比




可以看出对于opencv for android,只提供AndroidNativeCamera的Video I/O,OpenCV modules多了androidcamera / java。

2. 编译
   
   
cd build_android_arm
make
make install


编译完成




生成最终文件


(注意我每修改编译一次都会将build_android_arm文件夹复制保存一份,以备之后要使用)SDK: build_android_arm_1

三、修改后编译

1. -DBUILD_EXAMPLES=1
    
    
-- Tests and samples:
-- Tests: YES
-- Performance tests: YES
-- C/C++ Examples: NO

把所有Example都编译出来


2. 打开对V4L2的支持
a. 查看CMakeLists.txt文件908行处


   
   
if(DEFINED WITH_V4L)
if(HAVE_CAMV4L)
set(HAVE_CAMV4L_STR "YES")
else()
set(HAVE_CAMV4L_STR "NO")
endif()
if(HAVE_CAMV4L2)
set(HAVE_CAMV4L2_STR "YES")
elseif(HAVE_VIDEOIO)
set(HAVE_CAMV4L2_STR "YES(videoio)")
else()
set(HAVE_CAMV4L2_STR "NO")
endif()
status(" V4L/V4L2:" HAVE_LIBV4L
THEN "Using libv4l1 (ver ${ALIASOF_libv4l1_VERSION}) / libv4l2 (ver ${ALIASOF_libv4l2_VERSION})"
ELSE "${HAVE_CAMV4L_STR}/${HAVE_CAMV4L2_STR}")
endif(DEFINED WITH_V4L)
如果要支持V4L2,必须有WITH_V4L和HAVE_CAMV4L2

b. 但是在CMakeLists.txt文件159行处


   
   
OCV_OPTION(WITH_V4L "Include Video 4 Linux support" ON IF (UNIX AND NOT ANDROID) )
OCV_OPTION(WITH_LIBV4L "Use libv4l for Video 4 Linux support" ON IF (UNIX AND NOT ANDROID) )
UNIX AND NOT ANDROID,意思是,非Android的unix平台才设置为ON

c. 在CMakeLists.txt文件473行处


cmake/OpenCVFindLibsVideo.cmake


在这里,已经把HAVE_LIBV4L / HAVE_CAMV4L / HAVE_CAMV4L2 / HAVE_VIDEOIO的设置全部clear

d. 注意必须写在同一行!
WITH_LIBV4L这个已经没有用了,不再设置它。



e. sh scripts/cmake_android_arm.sh  > log_build_for_android_2.txt
发现没什么变化



f. 继续修改
   
   
OCV_OPTION(WITH_V4L "Include Video 4 Linux support" ON IF (UNIX AND NOT ANDROID) )
CMakeList.txt改成
   
   
OCV_OPTION(WITH_V4L "Include Video 4 Linux support" ON IF (UNIX))

并且在cmake/OpenCVFindLibsVideo.cmake中增加打印信息
   
   
# --- V4L ---
#luoyouren-20160629
status(" before seting ...")
status(" WITH_V4L:" ${WITH_V4L})
status(" HAVE_LIBV4L:" ${HAVE_LIBV4L})
status(" HAVE_CAMV4L:" ${HAVE_CAMV4L})
status(" HAVE_CAMV4L2:" ${HAVE_CAMV4L2})
status(" HAVE_VIDEOIO:" ${HAVE_VIDEOIO})
ocv_clear_vars(HAVE_LIBV4L HAVE_CAMV4L HAVE_CAMV4L2 HAVE_VIDEOIO)
if(WITH_V4L)
if(WITH_LIBV4L)
CHECK_MODULE(libv4l1 HAVE_LIBV4L1)
CHECK_MODULE(libv4l2 HAVE_LIBV4L2)
if(HAVE_LIBV4L1 AND HAVE_LIBV4L2)
set(HAVE_LIBV4L YES)
else()
set(HAVE_LIBV4L NO)
endif()
endif()
CHECK_INCLUDE_FILE(linux/videodev.h HAVE_CAMV4L)
CHECK_INCLUDE_FILE(linux/videodev2.h HAVE_CAMV4L2)
CHECK_INCLUDE_FILE(sys/videoio.h HAVE_VIDEOIO)
status(" seting ...")
status(" WITH_V4L:" ${WITH_V4L})
status(" HAVE_LIBV4L:" ${HAVE_LIBV4L})
status(" HAVE_CAMV4L:" ${HAVE_CAMV4L})
status(" HAVE_CAMV4L2:" ${HAVE_CAMV4L2})
status(" HAVE_VIDEOIO:" ${HAVE_VIDEOIO})
endif(WITH_V4L)
#luoyouren-20160629
#set(WITH_V4L ON)
#set(HAVE_CAMV4L2 ON)
status(" after seting ...")
status(" WITH_V4L:" ${WITH_V4L})
status(" HAVE_LIBV4L:" ${HAVE_LIBV4L})
status(" HAVE_CAMV4L:" ${HAVE_CAMV4L})
status(" HAVE_CAMV4L2:" ${HAVE_CAMV4L2})
status(" HAVE_VIDEOIO:" ${HAVE_VIDEOIO})

结果显示
V4L/V4L2都没有打开




before setting时HAVE_CAMV4L2=ON,但是setting后HAVE_CAMV4L2= 
下面三条语句,头文件存在与否决定了HAVE_CAMV4L、HAVE_CAMV4L2、HAVE_VIDEOIO的值
   
   
  CHECK_INCLUDE_FILE(linux/videodev.h HAVE_CAMV4L)
CHECK_INCLUDE_FILE(linux/videodev2.h HAVE_CAMV4L2)
CHECK_INCLUDE_FILE(sys/videoio.h HAVE_VIDEOIO)
linux/videodev2.h不存在
这个文件在NDK目录下
   
   
/opt/ndk/android-ndk-r9/platforms/android-8/arch-arm/usr/include/linux/videodev2.h

先不管这个问题,直接强制设置:
   
   
# --- V4L ---
#luoyouren-20160629
status(" before seting ...")
status(" WITH_V4L:" ${WITH_V4L})
status(" HAVE_LIBV4L:" ${HAVE_LIBV4L})
status(" HAVE_CAMV4L:" ${HAVE_CAMV4L})
status(" HAVE_CAMV4L2:" ${HAVE_CAMV4L2})
status(" HAVE_VIDEOIO:" ${HAVE_VIDEOIO})
ocv_clear_vars(HAVE_LIBV4L HAVE_CAMV4L HAVE_CAMV4L2 HAVE_VIDEOIO)
if(WITH_V4L)
if(WITH_LIBV4L)
CHECK_MODULE(libv4l1 HAVE_LIBV4L1)
CHECK_MODULE(libv4l2 HAVE_LIBV4L2)
if(HAVE_LIBV4L1 AND HAVE_LIBV4L2)
set(HAVE_LIBV4L YES)
else()
set(HAVE_LIBV4L NO)
endif()
endif()
CHECK_INCLUDE_FILE(linux/videodev.h HAVE_CAMV4L)
CHECK_INCLUDE_FILE(linux/videodev2.h HAVE_CAMV4L2)
CHECK_INCLUDE_FILE(sys/videoio.h HAVE_VIDEOIO)
status(" seting ...")
status(" WITH_V4L:" ${WITH_V4L})
status(" HAVE_LIBV4L:" ${HAVE_LIBV4L})
status(" HAVE_CAMV4L:" ${HAVE_CAMV4L})
status(" HAVE_CAMV4L2:" ${HAVE_CAMV4L2})
status(" HAVE_VIDEOIO:" ${HAVE_VIDEOIO})
endif(WITH_V4L)
#luoyouren-20160629
set(HAVE_CAMV4L2 ON)
status(" after seting ...")
status(" WITH_V4L:" ${WITH_V4L})
status(" HAVE_LIBV4L:" ${HAVE_LIBV4L})
status(" HAVE_CAMV4L:" ${HAVE_CAMV4L})
status(" HAVE_CAMV4L2:" ${HAVE_CAMV4L2})
status(" HAVE_VIDEOIO:" ${HAVE_VIDEOIO})
结果





g. 再编译
   
   
cd build_android_arm
make
make install
SDK: build_android_arm_2

四、对V4L2部分代码添加android_log

1. cap_v4l.cpp增加android_log
   
   
#include <android/log.h>
#undef LOG_TAG
#undef LOGD
#undef LOGE
#undef LOGI
#define LOG_TAG "OpenCV::android_v4l2"
#define LOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__))
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__))
然后在关键的一些函数增加log打印信息
重新编译,结果SDK: build_android_arm_3

2. 导入app测试新编译的opencv lib是否可用
a. 首先要去除APP对openCV Manager的依赖
详见《yanzi_OpenCV4Android_3》
另外注意lib库的编译方式
   
   
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
 
#博客案例:OpenCV4Android释疑:,透析Android以JNI调OpenCV的三种方式(让OpenCVManager永不困扰)
LIB_TYPE = STATIC
ifeq ($(LIB_TYPE), STATIC)
#STATIC链接时,可以不额外携带其依赖库
#当JNI里面调用了cvCaptureFromCAM去打开AndroidNativeCamera,就需要OPENCV_CAMERA_MODULES:=on
#来增加libnative_camera_r4.4.0.so
OPENCV_LIB_TYPE:=STATIC
OPENCV_INSTALL_MODULES:=on
OPENCV_CAMERA_MODULES:=on
else
#SHARED链接时,必须携带其依赖库,否则运行报错
OPENCV_LIB_TYPE:=SHARED
OPENCV_INSTALL_MODULES:=on
OPENCV_CAMERA_MODULES:=on
endif
 
 
#原始openCV4Android SDK
#include ../../openCV_2410_sdk/native/jni/OpenCV.mk
 
#添加V4L2,重新编译后的openCV4Android SDK
include ../../openCV_2410_sdk_v4l2/native/jni/OpenCV.mk
 
$(warning "****************************************")
$(warning $(LOCAL_C_INCLUDES))
 
LOCAL_LDLIBS += -llog
LOCAL_SHARED_LIBRARIES += \
libandroid_runtime\
liblog \
libcutils \
libnativehelper \
libcore/include
 
LOCAL_C_INCLUDES += $(LOCAL_PATH)
LOCAL_SRC_FILES := ImageProc.cpp
LOCAL_MODULE := image_proc
include $(BUILD_SHARED_LIBRARY)

b. 同时在系统上删除opencv manager相关
Firmware: 706K_uvc_V003_[eng]_A706K-emmc_800X480_20160630_103200_[0630_1045]

c. 安装运行
yanzi_OpenCV4Android_3.apk
   
   
01-01 02:15:19.843: I/luo.uvc.jni(6649): open uvc3 ......
01-01 02:15:19.844: I/OPENCV_LUO(6649): usb camera Java_luo_uvc_jni_ImageProc_connectCamera start ....
01-01 02:15:19.844: I/OPENCV_LUO(6649): usb camera (-1) Java_luo_uvc_jni_ImageProc_connectCamera
01-01 02:15:19.844: I/OpenCV::android_v4l2(6649): CvCaptureCAM_V4L_CPP::CvCaptureCAM_V4L_CPP(-1)
01-01 02:15:19.844: I/OpenCV::android_v4l2(6649): icvCaptureFromCAM_V4L::use /dev/video0
01-01 02:15:19.844: E/OPENCV_LUO(6649): usb camera 0 open success!
01-01 02:15:19.844: I/luo.uvc.jni(6649): open uvc success!!!
从log信息可以看出,JNI已经成功打开了/dev/video0设备
而且实验得知index = -1 或者0,都会打开/dev/video0设备

3. 测试客户的CameraTouch.apk
a. 直接运行奔溃

   
   
02:20:51.968: D/dalvikvm(6834): Trying to load lib /data/app-lib/CameraTouch/libNDKBase.so 0x41ce1eb0
01-01 02:20:51.986: E/ION_DEBUG(6834): [add_system_map_entry]so libNDKBase.so address 0x612b7000 size 3563520 has been load into memory ion_debug_lock 0x404ad01c
01-01 02:20:52.033: D/dalvikvm(6834): Added shared lib /data/app-lib/CameraTouch/libNDKBase.so 0x41ce1eb0
01-01 02:20:52.034: D/dalvikvm(6834): No JNI_OnLoad found in /data/app-lib/CameraTouch/libNDKBase.so 0x41ce1eb0, skipping init
01-01 02:20:52.035: D/NDKBASE(6834): CMPBase::CMPBase()
01-01 02:20:52.036: D/NDKBASE(6834): CHelper::Open END
01-01 02:20:52.036: D/NDKBASE(6834): Java_com_indesign_cameratouch_NDKBase_OpenTouchNDK
01-01 02:20:52.037: D/NDKBASE(6834): CImageBase::captureThread start
01-01 02:20:52.037: D/NDKBASE(6834): CImageBase::captureThread start111
01-01 02:20:52.038: D/NDKBASE(6834): CImageBase::captureThread start00
01-01 02:20:52.038: D/NDKBASE(6834): CImageBase::captureThread start11
01-01 02:20:52.040: D/NDKBASE(6834): CCamInfo::checkDevice start
01-01 02:20:52.040: D/NDKBASE(6834): CCamInfo::checkDevice 1111
01-01 02:20:52.041: D/NDKBASE(6834): usb_device_added, Name: /dev/bus/usb/001/004
01-01 02:20:52.042: D/NDKBASE(6834): usb_device_added, Name: /dev/bus/usb/001/001
01-01 02:20:52.042: D/NDKBASE(6834): CCamInfo::checkDevice END0
01-01 02:20:52.042: D/NDKBASE(6834): CImageBase::captureThread start22

b. 把新编译出来的opencv4android lib库预置入系统再运行
Firmware: 706K_uvc_V003_[eng]_A706K-emmc_800X480_20160630_103200_[0630_1711]

c. 增加cvCreateCameraCapture()中的log再编译lib再植入系统
SDK: build_android_arm_4
Firmware: 706K_uvc_V003_[eng]_A706K-emmc_800X480_20160630_103200_[0630_1905]

   
   
07-01 02:41:07.644: D/NDKBASE(6805): CMPBase::CMPBase()
07-01 02:41:07.645: D/NDKBASE(6805): CHelper::Open END
07-01 02:41:07.645: D/NDKBASE(6805): Java_com_indesign_cameratouch_NDKBase_OpenTouchNDK
07-01 02:41:07.645: D/NDKBASE(6805): CImageBase::captureThread start
07-01 02:41:07.645: D/NDKBASE(6805): CImageBase::captureThread start111
07-01 02:41:07.645: D/NDKBASE(6805): CImageBase::captureThread start00
07-01 02:41:07.645: D/NDKBASE(6805): CImageBase::captureThread start11
07-01 02:41:07.645: D/NDKBASE(6805): CCamInfo::checkDevice start
07-01 02:41:07.645: D/NDKBASE(6805): CCamInfo::checkDevice 1111
07-01 02:41:07.646: D/NDKBASE(6805): usb_device_added, Name: /dev/bus/usb/001/002
07-01 02:41:07.646: D/NDKBASE(6805): usb_device_added, Name: /dev/bus/usb/001/001
07-01 02:41:07.646: D/NDKBASE(6805): CCamInfo::checkDevice END1
07-01 02:41:07.646: D/NDKBASE(6805): CImageBase::captureThread start333
07-01 02:41:07.646: D/NDKBASE(6805): CameraId: 0, checking.
07-01 02:41:07.646: D/NDKBASE(6805): CameraId:cvCaptureFromCAM star
07-01 02:41:07.647: D/OpenCV::camera(6805): CvCapture_Android::CvCapture_Android(0)
07-01 02:41:07.647: D/OpenCV::camera(6805): Library name: libNDKBase.so
07-01 02:41:07.647: D/OpenCV::camera(6805): Library base address: 0x61191000
07-01 02:41:07.691: D/OpenCV::camera(6805): Libraries folder found: /data/app-lib/CameraTouch/
07-01 02:41:07.691: D/OpenCV::camera(6805): CameraWrapperConnector::connectToLib: folderPath=/data/app-lib/CameraTouch/
07-01 02:41:07.706: V/ActivityManager(684): Broadcast: Intent { act=android.intent.action.DROPBOX_ENTRY_ADDED flg=0x10 (has extras) } ordered=false userid=0 callerApp=ProcessRecord{41d6b1a0 684:system/1000}
07-01 02:41:07.706: D/dalvikvm(684): threadid=83: exiting
07-01 02:41:07.714: D/dalvikvm(684): threadid=83: bye!
07-01 02:41:07.841: E/OpenCV::camera(6805): ||libnative_camera_r4.1.1.so
07-01 02:41:07.841: E/OpenCV::camera(6805): ||libnative_camera_r4.0.3.so
07-01 02:41:07.841: E/OpenCV::camera(6805): ||libnative_camera_r2.3.3.so
07-01 02:41:07.841: E/OpenCV::camera(6805): ||libnative_camera_r4.2.0.so
07-01 02:41:07.841: E/OpenCV::camera(6805): ||libnative_camera_r2.2.0.so
07-01 02:41:07.841: E/OpenCV::camera(6805): ||libnative_camera_r3.0.1.so
07-01 02:41:07.841: E/OpenCV::camera(6805): ||libnative_camera_r4.3.0.so
07-01 02:41:07.841: E/OpenCV::camera(6805): ||libnative_camera_r4.0.0.so
07-01 02:41:07.841: E/OpenCV::camera(6805): ||libnative_camera_r4.4.0.so
07-01 02:41:07.841: D/OpenCV::camera(6805): try to load library 'libnative_camera_r4.4.0.so'
07-01 02:41:07.852: E/ION_DEBUG(6805): [add_system_map_entry]so libnative_camera_r4.4.0.so address 0x614f9000 size 282624 has been load into memory ion_debug_lock 0x4048601c
07-01 02:41:07.853: D/OpenCV::camera(6805): Loaded library '/data/app-lib/CameraTouch/libnative_camera_r4.4.0.so'
07-01 02:41:07.854: D/OpenCV_NativeCamera(6805): CameraHandler::initCameraConnect(0x6122beed, 0, 0x6055fde8, 0x0)
07-01 02:41:07.855: D/OpenCV_NativeCamera(6805): Current process name for camera init: com.indesign.cameratouch
07-01 02:41:08.036: D/CameraService(132): CameraService::connect E (pid 6805 "com.indesign.cameratouch", id 0)
07-01 02:41:08.036: E/CameraService(132): CameraService::connect X (pid 6805) rejected (invalid cameraId 0).
07-01 02:41:08.037: W/CameraBase(6805): An error occurred while connecting to camera: 0
07-01 02:41:08.038: E/OpenCV_NativeCamera(6805): initCameraConnect: Unable to connect to CameraService
07-01 02:41:08.038: E/OpenCV::camera(6805): CameraWrapperConnector::connectWrapper ERROR: the initializing function returned false
07-01 02:41:08.038: E/OpenCV::camera(6805): Native_camera returned opening error: 6
07-01 02:41:08.038: D/NDKBASE(6805): CameraId: 0, fail.
07-01 02:41:08.038: D/NDKBASE(6805): CImageBase::captureThread start333
07-01 02:41:08.038: D/NDKBASE(6805): CameraId: 1, checking.
07-01 02:41:08.038: D/NDKBASE(6805): CameraId:cvCaptureFromCAM star
07-01 02:41:08.038: D/OpenCV::camera(6805): CvCapture_Android::CvCapture_Android(1)
07-01 02:41:08.038: D/OpenCV_NativeCamera(6805): CameraHandler::initCameraConnect(0x6122beed, 1, 0x6055fde8, 0x0)
07-01 02:41:08.038: D/OpenCV_NativeCamera(6805): Current process name for camera init: com.indesign.cameratouch
07-01 02:41:08.040: D/CameraService(132): CameraService::connect E (pid 6805 "com.indesign.cameratouch", id 1)
07-01 02:41:08.040: E/CameraService(132): CameraService::connect X (pid 6805) rejected (invalid cameraId 1).
07-01 02:41:08.041: W/CameraBase(6805): An error occurred while connecting to camera: 1
07-01 02:41:08.041: E/OpenCV_NativeCamera(6805): initCameraConnect: Unable to connect to CameraService
07-01 02:41:08.041: E/OpenCV::camera(6805): CameraWrapperConnector::connectWrapper ERROR: the initializing function returned false
07-01 02:41:08.041: E/OpenCV::camera(6805): Native_camera returned opening error: 6
07-01 02:41:08.041: D/NDKBASE(6805): CameraId: 1, fail.

经验证CameraTouch.apk始终调用的是CvCapture_Android去打开Native Camera,并没有去调用CvCaptureCAM_V4L_CPP去打开video0设备,猜测CameraTouch.apk的opencv依赖库没有加入V4L2.

4. 更改yanzi_OpenCV4Android.apk实现获取video0的图像
a. 去除Android系统所有opencv相关文件
OpenCV_2.4.10_Manager_2.19_armv7a-neon.apk
Opencv for android lib.so 
CameraTouch.apk

Firmware: 706K_uvc_V004_[eng]_A706K-emmc_800X480_20160701_185957_[0702_0906]

b. 获取video0的图像

   
   
frame = cvQueryFrame(capture); //取图片帧
cvQueryFrame调用出问题,继续修改opencv源码增加log
SDK: build_android_arm_5

yanzi_OpenCV4Android_4.apk测试结果:崩溃


分析:select timeout说明没有获取到frame,但是icvRetrieveFrameCAM_V4L函数进行了frame.imageData拷贝工作,估计操作了空指针,于是报SIGSEGV段错误

c. 修改bug

   
   
case PALETTE_YUYV:
LOGI("icvRetrieveFrameCAM_V4L: capture->palette = PALETTE_YUYV");
yuyv_to_rgb24(capture->form.fmt.pix.width,
capture->form.fmt.pix.height,
(unsigned char*)(capture->buffers[capture->bufferIndex].start),
(unsigned char*)capture->frame.imageData);
break;
其中的源数据地址(unsigned char*)(capture->buffers[capture->bufferIndex].start可能是无效的,
所以预先设置一个默认值, 使得源数据地址是有效地址,防止段错误:
capture->bufferIndex = MAX_V4L_BUFFERS;

SDK: build_android_arm_6

d. yanzi_OpenCV4Android_4.apk运行正常
#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 0 Java_luo_uvc_jni_ImageProc_releaseCamera start ....\n");

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

	LOGI("usb camera 0 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 */


可以获取的图像帧数据,前面的bug实际上是,初始化摄像头时,set format 为YUYV格式而且return success,但是我的MTK Android平台不支持YUYV格式,只支持MJPEG格式,所以出现select timeout,然后就出现段错误。


至此,opencv4android sdk对于V4L2的支持,已经添加完成,已经可以正常获取图像。接下来需要测试其稳定性,另外新的sdk对于Android Native Camera的支持理论上来说,没有被破坏,具体需要实验验证!









评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值