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)
问题分析与解决
关于自动对焦未触发的误区
- AfMode参数值错误:Picamera2中连续自动对焦的
AfMode枚举值不是1,正确的连续AF模式对应AfModeEnum.Continuous(或数值2,建议用枚举类避免硬编码)。 - AfTrigger误用:连续AF模式下不需要触发
AfTrigger,这个参数仅用于单次对焦模式(如Auto或Manual)。连续AF启动后会自动持续对焦,无需额外触发。 - 设置时机问题:建议在
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()
关于流式读取显示小黑图的误区
- MJPEG数据流解码错误:
write方法接收到的是分块的MJPEG数据,不是完整帧。直接解码分块数据会导致图像损坏,需要缓存数据直到拼接出完整的JPEG帧(以0xffd8开头、0xffd9结尾)。 - 缺少窗口刷新:循环中未调用
cv2.waitKey(1),OpenCV窗口无法刷新,导致显示异常。 - 格式不匹配: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
相关产品推荐
相关产品推荐

