You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Raspberry Pi 5+Arducam场景下Picamera2显示及AF异常问题咨询

问题描述

我购置了Arducam Eagle Eye 64Mpx相机,连接到运行Bookworm系统的Raspberry Pi 5上,已安装所需驱动,libcamera-still命令行工具可正常工作。需要将相机预览画面转换为CV2图像以加载到应用纹理,同时添加拍摄按钮。

问题1:预览正常但自动对焦(AF)未触发

以下代码可正常显示预览,但AF功能无响应:

import cv2
from picamera2 import Picamera2, Preview

picam2 = Picamera2(verbose_console=0)
picam2.configure(picam2.create_preview_configuration(main={'format': 'RGB888', 'size': (640, 480)}))
picam2.start_preview(Preview.NULL)
picam2.start()
picam2.set_controls({'AfMode': 1, 'AfTrigger': 1}) # Continuous autofocus

cv2.startWindowThread()
cv2.namedWindow('Camera', flags=cv2.WINDOW_GUI_NORMAL) # Mandatory to hide CV2 toolbar
while True:
    im = picam2.capture_array()
    cv2.imshow("Camera", im)
    cv2.waitKey(1)

cv2.destroyAllWindows()

问题2:流式读取显示小黑图

尝试模拟流式事件读取图像,im.shape输出为(480, 640, 3),尺寸正常,但cv2.imshow仅显示小黑图:

import io
import cv2
import time
import numpy as np
from threading import Condition
from picamera2 import Picamera2, Preview
from picamera2.encoders import MJPEGEncoder
from picamera2.outputs import FileOutput

class StreamingOutput(io.BufferedIOBase):
    def __init__(self):
        self.frame = None
        self.condition = Condition()

    def write(self, buf):
        with self.condition:
            nparr = np.frombuffer(buf, np.uint8)
            self.frame = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
            self.condition.notify_all()

picam2 = Picamera2(verbose_console=0)
picam2.configure(picam2.create_video_configuration(main={'format': 'RGB888', 'size': (640, 480)}))
output = StreamingOutput()
picam2.start_recording(MJPEGEncoder(), FileOutput(output))
picam2.streaming_output = output

cv2.startWindowThread()
cv2.namedWindow("Camera", cv2.WINDOW_NORMAL)
while True:
    with picam2.streaming_output.condition:
        picam2.streaming_output.condition.wait()
        im = picam2.streaming_output.frame
    print(im.shape)
    cv2.imshow("Camera", im)

问题分析与解决

关于自动对焦未触发的误区

  1. AfMode参数值错误:Picamera2中连续自动对焦的AfMode枚举值不是1,正确的连续AF模式对应AfModeEnum.Continuous(或数值2,建议用枚举类避免硬编码)。
  2. AfTrigger误用:连续AF模式下不需要触发AfTrigger,这个参数仅用于单次对焦模式(如Auto或Manual)。连续AF启动后会自动持续对焦,无需额外触发。
  3. 设置时机问题:建议在picam2.start()前配置AF参数,确保参数生效。可通过print(picam2.capture_metadata()['AfMode'])查询当前AF模式,验证设置是否成功。

修正后的AF设置代码:

import cv2
from picamera2 import Picamera2, Preview
from picamera2.controls import AfModeEnum

picam2 = Picamera2(verbose_console=0)
picam2.configure(picam2.create_preview_configuration(main={'format': 'RGB888', 'size': (640, 480)}))
# 先设置连续AF模式,再启动相机
picam2.set_controls({"AfMode": AfModeEnum.Continuous})
picam2.start_preview(Preview.NULL)
picam2.start()

cv2.startWindowThread()
cv2.namedWindow('Camera', flags=cv2.WINDOW_GUI_NORMAL)
while True:
    im = picam2.capture_array()
    cv2.imshow("Camera", im)
    # 按q退出,按s拍照
    key = cv2.waitKey(1)
    if key == ord('s'):
        cv2.imwrite("captured.jpg", im)
    elif key == ord('q'):
        break

cv2.destroyAllWindows()

关于流式读取显示小黑图的误区

  1. MJPEG数据流解码错误:write方法接收到的是分块的MJPEG数据,不是完整帧。直接解码分块数据会导致图像损坏,需要缓存数据直到拼接出完整的JPEG帧(以0xffd8开头、0xffd9结尾)。
  2. 缺少窗口刷新:循环中未调用cv2.waitKey(1),OpenCV窗口无法刷新,导致显示异常。
  3. 格式不匹配:MJPEG编码器需要对应格式的视频配置,应将main={'format': 'RGB888'}改为'MJPEG',避免编码兼容问题。

修正后的流式读取代码:

import io
import cv2
import numpy as np
from threading import Condition
from picamera2 import Picamera2
from picamera2.encoders import MJPEGEncoder
from picamera2.outputs import FileOutput

class StreamingOutput(io.BufferedIOBase):
    def __init__(self):
        self.frame = None
        self.condition = Condition()
        self.buffer = b''  # 缓存MJPEG分块数据,拼接完整帧

    def write(self, buf):
        with self.condition:
            self.buffer += buf
            # 定位完整JPEG帧的起止位置
            start_idx = self.buffer.find(b'\xff\xd8')
            end_idx = self.buffer.find(b'\xff\xd9')
            if start_idx != -1 and end_idx != -1:
                full_jpg = self.buffer[start_idx:end_idx+2]
                self.buffer = self.buffer[end_idx+2:]  # 清空已处理的缓存
                self.frame = cv2.imdecode(np.frombuffer(full_jpg, np.uint8), cv2.IMREAD_COLOR)
                self.condition.notify_all()

picam2 = Picamera2(verbose_console=0)
# 配置为MJPEG格式的视频流
picam2.configure(picam2.create_video_configuration(main={'format': 'MJPEG', 'size': (640, 480)}))
output = StreamingOutput()
picam2.start_recording(MJPEGEncoder(), FileOutput(output))

cv2.startWindowThread()
cv2.namedWindow("Camera", cv2.WINDOW_NORMAL)
while True:
    with output.condition:
        output.condition.wait()
        im = output.frame
    if im is not None:
        cv2.imshow("Camera", im)
    # 按q退出,按s拍照
    key = cv2.waitKey(1)
    if key == ord('s') and im is not None:
        cv2.imwrite("stream_captured.jpg", im)
    elif key == ord('q'):
        break

picam2.stop_recording()
cv2.destroyAllWindows()

内容的提问来源于stack exchange,提问作者Manitoba

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 18:05:58