树莓派4B+OV9281相机:OpenCV isOpened为True但无法读取帧
树莓派Bullseye系统下OV9281单色相机无法被OpenCV读取的问题排查与修复
问题背景
使用树莓派4B(搭载最新Bullseye系统)搭配Waveshare OV9281-110全局快门单色相机时,通过libcamera-still -o test.png可正常捕获图像,但OpenCV调用VideoCapture时出现异常:isOpened()返回True,但grab()返回False,read()返回(False, None)。此前使用树莓派相机1.3时可正常读取。
用户测试代码:
import cv2 cam_port = 0 cam = cv2.VideoCapture(cam_port) print(cv2.__version__) print(cam.isOpened()) print(cam.grab()) print(cam.read()) cam.release()
输出:
4.5.5 True False (False, None)
相机设备信息(v4l2-ctl --device /dev/video0 --all):
Driver Info: Driver name : unicam Card type : unicam Bus info : platform:fe801000.csi Driver version : 5.15.56 Capabilities : 0xa5a00001 Video Capture Metadata Capture Read/Write Streaming Extended Pix Format Device Capabilities Device Caps : 0x25200001 Video Capture Read/Write Streaming Extended Pix Format Media Driver Info: Driver name : unicam Model : unicam Serial : Bus info : platform:fe801000.csi Media version : 5.15.56 Hardware revision: 0x00000000 (0) Driver version : 5.15.56 Interface Info: ID : 0x03000005 Type : V4L Video Entity Info: ID : 0x00000003 (3) Name : unicam-image Function : V4L2 I/O Flags : default Pad 0x01000004 : 0: Sink Link 0x02000007: from remote pad 0x1000002 of entity 'ov9281 10-0060': Data, Enabled, Immutable Priority: 2 Video input : 0 (unicam-image: ok) Format Video Capture: Width/Height : 640/480 Pixel Format : 'BGR3' (24-bit BGR 8-8-8) Field : None Bytes per Line : 1920 Size Image : 921600 Colorspace : sRGB Transfer Function : sRGB YCbCr/HSV Encoding: ITU-R 601 Quantization : Full Range Flags
核心原因分析
Bullseye系统默认采用libcamera相机栈替代传统v4l2直接访问,而OV9281作为单色全局快门相机,其像素格式兼容性、OpenCV对libcamera的支持程度是主要问题点。
排查与修复方案
方案1:手动指定相机像素格式
从设备信息看,当前相机输出格式为BGR3(24位彩色),但OV9281是单色相机,可尝试强制设置灰度格式或兼容的压缩格式:
修改测试代码:
import cv2 cam = cv2.VideoCapture(0) # 设置分辨率 cam.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cam.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) # 尝试设置单色灰度格式Y800 cam.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter.fourcc('Y','8','0','0')) # 如果Y800失败,尝试MJPG压缩格式 # cam.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter.fourcc('M','J','P','G')) print(cv2.__version__) print(cam.isOpened()) ret_grab = cam.grab() print(ret_grab) ret_read, frame = cam.read() print(ret_read, frame is not None) if ret_read: cv2.imwrite("test_opencv.png", frame) cam.release()
方案2:使用v4l2loopback虚拟设备中转流
通过libcamera将相机流推送到虚拟v4l2设备,让OpenCV读取该虚拟设备:
- 安装依赖工具:
sudo apt update && sudo apt install v4l2loopback-dkms v4l2loopback-utils
- 加载虚拟设备模块:
sudo modprobe v4l2loopback video_nr=1 card_label="VirtualCam"
- 启动libcamera流并推送到虚拟设备:
libcamera-vid -t 0 --width 640 --height 480 --codec yuv420 -o - | v4l2loopback-ctl set-pixelformat /dev/video1 YU12
- 修改OpenCV代码读取虚拟设备:
import cv2 # 读取虚拟设备/dev/video1 cam = cv2.VideoCapture(1) print(cv2.__version__) print(cam.isOpened()) ret, frame = cam.read() print(ret, frame is not None) if ret: cv2.imwrite("test_virtual.png", frame) cam.release()
方案3:重新编译支持libcamera的OpenCV
如果上述方案无效,需重新编译OpenCV并启用libcamera支持:
- 安装编译依赖:
sudo apt update && sudo apt install build-essential cmake git libgtk2.0-dev pkg-config libavcodec-dev libavformat-dev libswscale-dev libcamera-dev libcamera-apps-lite
- 克隆OpenCV及扩展模块:
git clone https://github.com/opencv/opencv.git git clone https://github.com/opencv/opencv_contrib.git
- 编译安装:
cd opencv && mkdir build && cd build cmake -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local -D WITH_LIBCAMERA=ON -D OPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules .. make -j4 # 树莓派4B使用4线程编译 sudo make install
- 使用libcamera后端测试:
import cv2 # 直接指定libcamera后端 cam = cv2.VideoCapture(cv2.CAP_LIBCAMERA) print(cv2.__version__) print(cam.isOpened()) ret, frame = cam.read() print(ret, frame is not None) if ret: cv2.imwrite("test_libcamera.png", frame) cam.release()
内容的提问来源于stack exchange,提问作者some1
相关产品推荐
相关产品推荐

