如何在高通RB5开发板上用HAL3/Camera2+OpenCV获取双MIPI摄像头视频?
问题描述
使用高通RB5开发套件搭配两颗OV9282 MIPI摄像头,尝试通过Gstreamer结合OpenCV访问双目摄像头时遇到以下问题:
- 仅能显示单个摄像头画面
- Gstreamer视频流无法传入
cv2.VideoCapture供后续处理
现寻求通过HAL3/Camera2 API结合OpenCV访问双目摄像头的可行方案,以下是尝试的Gstreamer代码:
import cv2 from threading import Thread from time import sleep import gi gi.require_version("Gst", "1.0") from gi.repository import Gst, GLib Gst.init(None) main_loop = GLib.MainLoop() thread = Thread(target=main_loop.run) thread.start() pipeline_str = """ qtiqmmfsrc camera=1 ! video/x-raw, format=NV12, width=1280, height=720, framerate=15/1 ! videoconvert ! waylandsink """ pipeline = Gst.parse_launch(pipeline_str) pipeline.set_state(Gst.State.PLAYING) pipeline_str2 = """ qtiqmmfsrc camera=3 ! video/x-raw, format=NV12, width=1280, height=720, framerate=15/1 ! videoconvert ! waylandsink """ pipeline2 = Gst.parse_launch(pipeline_str2) pipeline2.set_state(Gst.State.PLAYING) cap = cv2.VideoCapture(pipeline_str, cv2.CAP_GSTREAMER) cap2 = cv2.VideoCapture(pipeline_str2, cv2.CAP_GSTREAMER) num = 0 while True: succes1, img = cap.read() succes2, img2 = cap2.read() if not succes1 or not succes2: break cv2.imshow('Img 1', img) cv2.imshow('Img 2', img2) k = cv2.waitKey(5) if k == 27: break elif k == ord('s'): cv2.imwrite('images/stereoLeft/imageL{}.png'.format(num), img) cv2.imwrite('images/stereoRight/imageR{}.png'.format(num), img2) print('images saved!') num += 1 cap.release() cap2.release() cv2.destroyAllWindows() pipeline.set_state(Gst.State.NULL) pipeline2.set_state(Gst.State.NULL) main_loop.quit()
原Gstreamer代码问题分析
- 资源冲突:同时通过
Gst.parse_launch启动Pipeline,又用cv2.VideoCapture加载同一段Pipeline字符串,导致同一摄像头被两个进程抢占,无法正常工作。 - Sink组件错误:
waylandsink是直接输出画面的显示组件,无法将视频流传递给OpenCV的VideoCapture,需替换为appsink作为OpenCV的输入源。
HAL3/Camera2 API + OpenCV 双目访问方案
高通RB5原生支持Camera2 API(基于HAL3),以下是Python环境下的实现方案:
1. 环境准备
- 安装依赖:
pip install opencv-python pycam2 - 权限配置:Linux环境下将当前用户加入
video组;Android环境下授予摄像头权限:adb shell pm grant com.your.package android.permission.CAMERA - 确认摄像头ID:通过
pycam2的CameraManager.list_cameras()查看两颗OV9282的设备ID
2. 代码实现
import cv2 import numpy as np from pycam2.camera2 import CameraManager, CameraDevice # 初始化摄像头管理器 cam_manager = CameraManager() # 查看可用摄像头(执行一次确认ID后可注释) # print(cam_manager.list_cameras()) # 绑定双目摄像头(替换为实际ID) cam_left = CameraDevice(cam_manager, camera_id=0) cam_right = CameraDevice(cam_manager, camera_id=1) # 配置摄像头参数 def configure_camera(cam): config = cam.create_default_configuration() config.set_preview_size((1280, 720)) config.set_image_format("YUV_420_888") config.set_framerate(15) return config config_left = configure_camera(cam_left) config_right = configure_camera(cam_right) # 启动摄像头 cam_left.start(config_left) cam_right.start(config_right) num = 0 while True: # 获取帧数据 frame_left = cam_left.get_frame() frame_right = cam_right.get_frame() if frame_left is None or frame_right is None: break # YUV转BGR格式(适配OV9282输出) img_left = cv2.cvtColor(np.array(frame_left.to_yuv()), cv2.COLOR_YUV2BGR_NV12) img_right = cv2.cvtColor(np.array(frame_right.to_yuv()), cv2.COLOR_YUV2BGR_NV12) # 显示与保存 cv2.imshow('Left Camera', img_left) cv2.imshow('Right Camera', img_right) k = cv2.waitKey(5) if k == 27: break elif k == ord('s'): cv2.imwrite(f'images/stereoLeft/imageL{num}.png', img_left) cv2.imwrite(f'images/stereoRight/imageR{num}.png', img_right) print('images saved!') num += 1 # 释放资源 cam_left.stop() cam_right.stop() cv2.destroyAllWindows()
3. 关键说明
- 帧同步:如需严格双目帧同步,可通过Camera2的
CaptureRequest配置同步捕获规则,确保左右帧同时采集 - 格式适配:OV9282默认输出NV12格式,需对应使用
COLOR_YUV2BGR_NV12转换参数
补充:修复原Gstreamer+OpenCV方案
若仍倾向使用Gstreamer,可修改Pipeline使用appsink替代waylandsink,并避免重复创建Pipeline:
import cv2 # 双目摄像头Gstreamer Pipeline(输出为OpenCV兼容的BGR格式) pipeline_left = "qtiqmmfsrc camera=1 ! video/x-raw, format=NV12, width=1280, height=720, framerate=15/1 ! videoconvert ! video/x-raw, format=BGR ! appsink" pipeline_right = "qtiqmmfsrc camera=3 ! video/x-raw, format=NV12, width=1280, height=720, framerate=15/1 ! videoconvert ! video/x-raw, format=BGR ! appsink" cap_left = cv2.VideoCapture(pipeline_left, cv2.CAP_GSTREAMER) cap_right = cv2.VideoCapture(pipeline_right, cv2.CAP_GSTREAMER) if not cap_left.isOpened() or not cap_right.isOpened(): print("无法打开摄像头") exit() num = 0 while True: ret_left, img_left = cap_left.read() ret_right, img_right = cap_right.read() if not ret_left or not ret_right: break cv2.imshow('Left', img_left) cv2.imshow('Right', img_right) k = cv2.waitKey(5) if k == 27: break elif k == ord('s'): cv2.imwrite(f'images/stereoLeft/imageL{num}.png', img_left) cv2.imwrite(f'images/stereoRight/imageR{num}.png', img_right) print('images saved!') num += 1 cap_left.release() cap_right.release() cv2.destroyAllWindows()
内容的提问来源于stack exchange,提问作者Fourier
相关产品推荐
相关产品推荐

