簡體   English   中英

"如何提高 OpenCV cv2.VideoCapture(0).read() 的性能"

[英]How to increase performance of OpenCV cv2.VideoCapture(0).read()

我正在使用英特爾核心 i7-4510u 在 Kali linux 上運行此腳本:

import cv2
from datetime import datetime
vid_cam = cv2.VideoCapture(0)
vid_cam.set(cv2.CAP_PROP_FPS, 25)
vid_cam.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
vid_cam.set(cv2.CAP_PROP_FRAME_HEIGHT, 360)

lastDate = datetime.now().second
fcount = 0
while(vid_cam.isOpened()):
    if(datetime.now().second>lastDate):
        lastDate = datetime.now().second
        print("Fps: " + str(fcount))
        fcount = 0
    else:
        fcount += 1
    ret, image_frame = vid_cam.read()
    cv2.imshow('frame', image_frame)
    if cv2.waitKey(100) & 0xFF == ord('q'):
        break
vid_cam.release()
cv2.destroyAllWindows()

如果我運行它,它會打印Fps: 4
如果我檢查任務管理器,我的 cpu 大約是 2%
問題可能出在哪里?

一個潛在的原因可能是讀取幀時的 I/O 延遲。 由於cv2.VideoCapture().read()是一個阻塞操作,所以主程序會停止,直到從相機設備讀取幀並返回。 提高性能的一種方法是生成另一個線程來並行處理抓取幀,而不是依賴單個線程順序抓取幀。 我們可以通過創建一個新線程來提高性能,該線程只輪詢新幀,而主線程處理當前幀。 這是多線程框架的片段。

from threading import Thread
import cv2, time

class VideoStreamWidget(object):
    def __init__(self, src=0):
        self.capture = cv2.VideoCapture(src)
        # Start the thread to read frames from the video stream
        self.thread = Thread(target=self.update, args=())
        self.thread.daemon = True
        self.thread.start()

    def update(self):
        # Read the next frame from the stream in a different thread
        while True:
            if self.capture.isOpened():
                (self.status, self.frame) = self.capture.read()
            time.sleep(.01)

    def show_frame(self):
        # Display frames in main program
        cv2.imshow('frame', self.frame)
        key = cv2.waitKey(1)
        if key == ord('q'):
            self.capture.release()
            cv2.destroyAllWindows()
            exit(1)

if __name__ == '__main__':
    video_stream_widget = VideoStreamWidget()
    while True:
        try:
            video_stream_widget.show_frame()
        except AttributeError:
            pass

大多數情況下,人們不會考慮通過網絡獲取數據所需的數據速率(帶寬)

1920 x 1080 像素,30 FPS,每像素 24 位需要 1.5 Gbit/s。 這不適合通過 USB 2。

這就是為什么許多網絡攝像頭實施壓縮的原因。 一種常見的壓縮方式是 MJPEG,即 JPEG 作為視頻。

您可以告訴 OpenCV 告訴媒體 API(V4L、dshow、MSMF、AVFoundation...)從相機請求。 它不會靠自己,我已經學會了。

# cap = cv.VideoCapture(...)
cap.set(cv.CAP_PROP_FOURCC, cv.VideoWriter_fourcc(*"MJPG"))

每幀更少的數據意味着傳輸速度更快,每次允許更多的幀。

將其與其他屬性(FRAME_WIDTH 等)混合時,順序很重要。 我認為 FOURCC 設置需要放在首位,但如果這沒有幫助,請嘗試其他命令。

當網絡攝像頭注意到 USB 控制器上沒有足夠的可用數據速率時,它可能會決定減小幀大小或幀速率,或者應用更強的壓縮(更差的圖片)。 當您將多個相機連接到同一個 USB 集線器時,就會發生這種情況。 這種協商可能會導致打開需要幾秒鍾,甚至一分鍾。 如果打開相機很慢,可能是 USB 控制器已經為其他設備預留了一些帶寬。


影響幀速率的是,當您在該循環的其他代碼只需要大量時間時! 無法解決這個問題,除非讓那部分代碼更快。

通常不重要的是將閱讀轉移到自己的線程中。 在 OpenCV 情況下(使用imshow ),線程根本沒有意義。 除了處理下一幀(例如,GUI 循環)之外,線程只有在通常用於等待的時間還有其他事情要做時才有意義。 與消費者的溝通需要適當。 繁忙的循環不是解決方案。

在實際的 GUI(不是OpenCV 的imshow )的情況下,正確的做法線程,但它需要在幀進入時更新小部件。不能有任何重復讀取變量並分配小部件的旋轉循環圖像或任何東西。

相機將按照自己的節奏(無論您做什么)生成幀,並將它們放入隊列中。 閱讀框架的成本相當低(但並非沒有)。

您必須從相機讀取,否則幀會排隊。 如果您的閱讀速度低於相機的幀速率,您會看到延遲增加,即在相機前面的移動需要幾秒鍾才能顯示在屏幕上。

如果您嘗試更快地閱讀,read() 調用將阻塞,直到有可用的幀。 然后你會在那個電話中“浪費”時間。 那段時間你會做什么? 您還沒有新數據,因此在該幀到達之前無需計算任何內容。 不如等等吧?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM