使用较高分辨率时 OpenCV 捕获速度非常慢

问题描述 投票:0回答:2

我从网络摄像头读取图像并在其中找到一些运动数据。 我写了一个小类,它测量从读取图像、检测运动等所有步骤,然后打印它。

现在,当我在没有特定分辨率的情况下初始化网络摄像头时,拍摄的帧的大小为 640x480。现在我想提高分辨率,所以我将其设置为1920x1080:

WEBCAM_RAW_RES = (640, 480)
FRAMERATE = 20
vid = cv2.VideoCapture(0)
vid.set(cv2.CAP_PROP_FPS, FRAMERATE)
vid.set(cv2.CAP_PROP_FRAME_WIDTH, WEBCAM_RAW_RES[0])
vid.set(cv2.CAP_PROP_FRAME_HEIGHT, WEBCAM_RAW_RES[1])

它可以工作,但是 vid.read() 语句的平均时间从 ~10ms 增加到 >200ms。所以我将其更改为 1280x800,vid.read() 语句下降到 ~80ms。

顺便说一句,这是支持的网络摄像头分辨率:

pi@rpi:~/ $ v4l2-ctl -d /dev/video0 --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
        Type: Video Capture

        [0]: 'MJPG' (Motion-JPEG, compressed)
                Size: Discrete 1920x1080
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1280x800
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1280x720
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 640x400
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 320x240
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 640x480
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
        [1]: 'YUYV' (YUYV 4:2:2)
                Size: Discrete 1920x1080
                        Interval: Discrete 0.200s (5.000 fps)
                        Interval: Discrete 0.333s (3.000 fps)
                Size: Discrete 1280x800
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 1280x720
                        Interval: Discrete 0.100s (10.000 fps)
                        Interval: Discrete 0.200s (5.000 fps)
                Size: Discrete 640x400
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                Size: Discrete 320x240
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                Size: Discrete 640x480
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.040s (25.000 fps)
                        Interval: Discrete 0.050s (20.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)

如何在不延迟 200 毫秒的情况下获得更高的分辨率?我必须切换到 MJPEG 流格式吗?我在网上找不到任何相关信息...


这是我的整个代码:

import os
import cv2
from MotionDetectorBlob import MotionDetectorBlob
from utils import CalcTimer, resize_and_crop
from config import *

WEBCAM_RAW_RES = (640, 480)
FRAMERATE = 20

def start_webcam():
    print("Setting up webcam and finding the correct brightness.")
    vid = cv2.VideoCapture(0)
    vid.set(cv2.CAP_PROP_FPS, FRAMERATE)
    vid.set(cv2.CAP_PROP_FRAME_WIDTH, WEBCAM_RAW_RES[0])
    vid.set(cv2.CAP_PROP_FRAME_HEIGHT, WEBCAM_RAW_RES[1])
    vid.set(cv2.CAP_PROP_AUTO_EXPOSURE, 3)  # auto mode
    time.sleep(5)  # find brightness
    #vid.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1)  # manual exposure mode
    vid.set(cv2.CAP_PROP_AUTO_WB, 0)  # manual awb
    vid.set(cv2.CAP_PROP_WB_TEMPERATURE, 4000)  # manual awb
    print("Webcam setup done.")

    detector = MotionDetectorBlob()

    firstrun = True

    timer = CalcTimer()
    while True:

        # Capture the video frame
        # by frame
        try:
            timer.start()
            ret, frame = vid.read()
            print(f"original webcam res: {frame.shape}")
            timer.measure("read")

            frame = cv2.rotate(frame, cv2.ROTATE_90_CLOCKWISE)
            timer.measure("rotate")

            # as we skip analyser, directly write the frames
            data = detector.detect(frame)

            print(timer.results())
        except KeyboardInterrupt:
            break

    # After the loop release the cap object
    vid.release()

start_webcam()
python opencv stream webcam
2个回答
3
投票

vid.read() 性能缓慢的主要原因是您使用的是 YUYV 格式,该格式未压缩,比 MJPG 格式需要更多的带宽和处理能力,MJPG 格式经过压缩,可以更快地处理更高分辨率。

要切换到 MJPG 格式,您需要在初始化 vid 对象后在代码中再添加一行:

vid = cv2.VideoCapture(0)
vid.set(cv2.CAP_PROP_FPS, FRAMERATE)
vid.set(cv2.CAP_PROP_FRAME_WIDTH, WEBCAM_RAW_RES[0])
vid.set(cv2.CAP_PROP_FRAME_HEIGHT, WEBCAM_RAW_RES[1])
vid.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*"MJPG")) # add this line

这将告诉 OpenCV 使用 MJPG 编解码器来捕获视频流。您还可以使用 vid.get() 方法和适当的属性代码(例如 cv2.CAP_PROP_FOURCC 和 cv2.CAP_PROP_FORMAT)来检查网络摄像头支持的格式和编解码器。

说明:YUYV 格式是一种原始格式,它用两个字节对每个像素进行编码,一个用于亮度 (Y),一个用于色度 (UV)。这意味着对于 1920x1080 分辨率,每帧将有 1920x1080x2 = 4147200 字节,或大约 4 MB。要以 20 FPS 传输如此大量的数据,您需要 4x20 = 80 MB/s 的带宽,这对于 USB 网络摄像头来说相当高。

MJPG格式是一种压缩格式,使用JPEG算法将每一帧编码为图像。这会显着减小每帧的大小,具体取决于图像的质量和复杂性。例如,分辨率为 1920x1080 的典型 JPEG 图像的大小约为 200 KB 或 0.2 MB。要以 20 FPS 传输如此大量的数据,需要 0.2x20 = 4 MB/s 的带宽,这比 YUYV 格式要低得多。 因此,通过使用 MJPG 格式,您可以减少延迟并提高 vid.read() 的速度,并节省一些用于处理帧的 CPU 周期。


0
投票

就我而言,如果每次更改分辨率时也更改 fourcc,效果会很好。内部更改分辨率时,除非单独指定视频格式,否则似乎会设置为默认格式。

© www.soinside.com 2019 - 2024. All rights reserved.