求助:OV5640摄像头在Python+OpenCV下出现竖条像素拉伸问题
我之前在NanoPi系列板子上碰到过几乎一模一样的问题,核心原因基本都是OpenCV默认的摄像头捕获参数和OV5640的实际输出格式不兼容——毕竟mjpg-streamer是厂商适配好的演示程序,已经预设了正确的格式和分辨率,而OpenCV会用通用参数去捕获,就容易出问题。下面是我亲测有效的解决步骤:
1. 强制指定MJPG格式和匹配的分辨率
OV5640摄像头对MJPG格式的支持最好,而OpenCV默认可能会用YUYV格式捕获,这会导致图像解码时出现拉伸变形。你可以在代码里手动设置格式和分辨率:
import cv2 # 打开摄像头设备(通常是/dev/video0,不确定的话可以用v4l2工具确认) cap = cv2.VideoCapture(0) # 设置摄像头输出分辨率(要选摄像头支持的,比如640x480或1280x720) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) # 强制设置捕获格式为MJPG cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*'MJPG')) # 检查参数是否设置成功 width = cap.get(cv2.CAP_PROP_FRAME_WIDTH) height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT) print(f"当前捕获分辨率: {width}x{height}") # 捕获并保存图片 ret, frame = cap.read() if ret: cv2.imwrite("test.jpg", frame) else: print("捕获帧失败") # 释放资源 cap.release()
2. 确认摄像头的正确设备节点
有时候系统会把摄像头识别为/dev/video1而不是video0,你可以用以下命令列出所有视频设备:
v4l2-ctl --list-devices
找到CAM500B对应的设备节点,比如/dev/video1,然后把代码里的cv2.VideoCapture(0)改成cv2.VideoCapture(1)。
3. 用v4l2工具确认摄像头支持的参数
运行以下命令查看摄像头支持的所有格式和分辨率:
v4l2-ctl --device=/dev/video0 --list-formats-ext
输出里会列出所有兼容的格式(比如MJPG)和对应的分辨率,确保你在OpenCV里设置的参数和其中某一项完全匹配,不要用摄像头不支持的分辨率,否则也会导致图像变形。
4. 调整OpenCV的缓冲区参数
如果还是有问题,可以尝试减少捕获缓冲区的大小,避免旧帧数据干扰:
cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
或者先捕获原始格式再手动转换为RGB:
cap.set(cv2.CAP_PROP_CONVERT_RGB, False) ret, frame = cap.read() if ret: # 转换MJPG原始数据为RGB frame = cv2.imdecode(frame, cv2.IMREAD_COLOR) cv2.imwrite("test.jpg", frame)
5. 尝试用pyv4l2直接调用V4L2接口
如果OpenCV的问题始终无法解决,可以试试用pyv4l2库直接操作V4L2接口,绕开OpenCV的默认捕获逻辑:
from pyv4l2.frame import Frame from pyv4l2.control import Control import cv2 import numpy as np # 打开摄像头 cap = Frame('/dev/video0', format='MJPG', width=640, height=480) # 读取帧数据 frame_data = cap.get_frame() # 转换为numpy数组并解码 frame = cv2.imdecode(np.frombuffer(frame_data, dtype=np.uint8), cv2.IMREAD_COLOR) # 保存图片 cv2.imwrite("test.jpg", frame) # 释放资源 cap.close()
需要先安装pyv4l2:
pip install pyv4l2
最优先尝试的是第一步和第三步,这两个步骤解决了我当时遇到的问题。如果还是不行,大概率是系统层面的摄像头驱动参数需要调整,但这种情况比较少见。
内容的提问来源于stack exchange,提问作者Nobody Special

