VideoCapture 帧图像损坏:在随机帧上移动通道之一

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

相机工作正常,当我使用软件验证相机时,我没有看到损坏的帧,所以我认为这是来自 OpenCV 的问题。

我注意到随机帧(10-20 帧中的一帧)已损坏,并且其中一个通道发生了移位。下面的例子。

我将相机代码作为在后台运行的服务运行,以便任何其他应用程序都可以获取最新的帧并使用它,而无需运行读取帧循环并使用异步代码。

import threading
import time
import cv2 as cv
import numpy as np

class CameraCU81():
    def __init__(self, W=1920, H=1080, hz=30):
        self.cap = cv.VideoCapture(0)
        self.last_frame = None
        # if recording mjgp the frames hangs...
        #self.cap.set(cv.CAP_PROP_FOURCC, cv.VideoWriter_fourcc('M', 'J', 'P', 'G'))
        print(str(cv.VideoWriter_fourcc('M', 'J', 'P', 'G')))
        self.cap.set(cv.CAP_PROP_FRAME_WIDTH, W)
        self.cap.set(cv.CAP_PROP_FRAME_HEIGHT, H)
        self.cap.set(cv.CAP_PROP_FPS, hz)
        print('Starting camera 81 fps at: ' +  str(self.cap.get(cv.CAP_PROP_FPS)))
        w = str(self.cap.get(cv.CAP_PROP_FRAME_WIDTH))
        h = str(self.cap.get(cv.CAP_PROP_FRAME_HEIGHT))
        print('Starting camera 81 resolution at: ' + w + ' x ' + h)
        format = str(self.cap.get(cv.CAP_PROP_FOURCC))
        print('Starting camera 81 format: ' + format)

def __capture_frames(self):
    error_f = False
    while True:
        start_time = time.time()
        ret, frame = self.cap.read()
        if not ret:
            timeout_time = (time.time() - start_time)
            print('Frame could not be read ... is camera connected?')
            print(timeout_time)
            error_f = True
        else:
            self.last_frame = frame
            if error_f:
                timeout_time = (time.time() - start_time)
                print(timeout_time)

def get_data(self):
    return self.last_frame

def destroy(self):
    self.cap.release()

def run(self):
    t1 = threading.Thread(target=self.__capture_frames)
    t1.daemon = True
    t1.start()
python opencv video-streaming video-capture
1个回答
0
投票

正如我在评论中提到的,我非常确信这是竞争条件的情况,尽管我无法复制该问题。

问题是,当您尝试绘制图像时,您可能会传递对

self.last_frame
的引用,同时绘制到一半时 self.last_frame 图像将会发生变化,因为收到了新图像。

您必须注意到,阅读

self.last_frame
正在进入所谓的关键区域,您应该使用
Mutex
或类似的方法来保护它。

一个不相关的注释是,

VideoCapture.read()
是一个相当昂贵的调用方法,如果你不确定你正在阅读的
frame
是否会被使用,你最好使用
VideoCapture.grab

我碰巧实现了这样的代码,但它使用了

QThread
和信号。可能会有帮助。

class AsyncVideoCapture(QThread):
    finished = pyqtSignal()
    new_data = pyqtSignal([np.ndarray])

    def __init__(self, id: str):
        super().__init__()
        self.data_requested = False
        self.running = False
        self.camera = cv.VideoCapture(int(id) if id.isdigit() else id)

    def run(self):
        self.running = True
        while self.running:
            if self.data_requested:
                ret_val, frame = self.camera.read()
                if not ret_val:
                    break
                self.new_data.emit(frame)
            else:
                ret_val = self.camera.grab()
                if not ret_val:
                    break
        self.finished.emit()
        self.camera.release()

    def request_data(self):
        self.data_requested = True

    def stop(self):
        self.running = False
© www.soinside.com 2019 - 2024. All rights reserved.