从两个视频源读取帧不同步 |开放式CV

Posted

技术标签:

【中文标题】从两个视频源读取帧不同步 |开放式CV【英文标题】:Reading frames from two video sources is not in sync | OpenCV 【发布时间】:2022-01-23 01:45:44 【问题描述】:

我正在编写一个 python OpenCV 脚本,该脚本将从两个视频流中读取并将一个放在另一个上(画中画),并且两者都应该在最终视频上保持同步。我的目标是将一个视频放在另一个视频的左下角。它有点工作,但问题是,即使我同时初始化了两个视频源并从中读取帧,当我显示处理后的帧时,视频并不同步。我创建了一个专用线程,它同时从两个视频中读取帧,并将两者(作为元组)附加到帧对列表(缓冲区)中。然后主线程从缓冲区中获取帧对,处理最后一帧,并使用imshow 显示它。但是一个视频比另一个视频早了几秒钟。我尝试在主线程中读取帧,但同样的问题。 该程序还从字幕文件中读取一些信息并将文本添加到最后一帧。但这工作正常。所以只需忽略getTelemetry() 函数。 我真的很感激一些帮助。谢谢

import cv2
import time
import _thread

telemetry = []
tel = []


def getTelemetry():
    global telemetry, tel
    file = open("subs.srt", "r")
    lines = file.readlines()
    chars = '-.0123456789'
    distance, altitude, horizontal_speed, vertical_speed = None, None, None, None
    for line in lines:
        if line.startswith("F"):
            # print(line.strip('\n'))
            distance = line[line.index('D ')+2:line.index(', H') - 1]
            altitude = line[line.index('H ')+2:line.index(', H.S') - 1]
            horizontal_speed = line[line.index(
                'H.S ')+4:line.index(', V.S') - 3]
            vertical_speed = line[line.index('V.S ')+4:-5]
            for char in distance:
                if char not in chars:
                    distance = '0'
            for char in altitude:
                if char not in chars:
                    altitude = '0'
            for char in horizontal_speed:
                if char not in chars:
                    horizontal_speed = '0'
            for char in vertical_speed:
                if char not in chars:
                    vertical_speed = '0'

            distance_float = float(distance)
            altitude_float = float(altitude)
            horizontal_speed_float = float(horizontal_speed)
            vertical_speed_float = float(vertical_speed)
            telemetry.append([distance_float, altitude_float,
                              horizontal_speed_float, vertical_speed_float])
            # print(distance_float, altitude_float, horizontal_speed_float,
            #      vertical_speed_float)

    # Put each element of telemetry 60 times in tel
    for i in range(0, len(telemetry)):
        for j in range(0, 60):
            tel.append(telemetry[i])
    # print(len(tel))


frame_buffer = []


def fil_buffer():
    global frame_buffer
    video = cv2.VideoCapture("Input_File.avi")
    video2 = cv2.VideoCapture("Screenrecorder-2021-12-07-16-15-26-217.mp4")
    # For each frame in the video
    while(video.isOpened() and video2.isOpened()):
        ret, frame = video.read()
        ret2, frame2 = video2.read()
        if ret == True and ret2 == True:
            frame_buffer.append((frame, frame2))

    video.release()
    video2.release()


if __name__ == '__main__':
    getTelemetry()
    _thread.start_new_thread(fil_buffer, ())
    time.sleep(5)
    print(len(frame_buffer))
    j = 0
    while len(frame_buffer) != 0:
        x = frame_buffer.pop(0)
        frame1 = x[0]
        frame2 = x[1]
        # print(tel[j][0])
        cv2.putText(frame1, "Distance: " + str(tel[j][0]), (10, 30),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
        cv2.putText(frame1, "Altitude: " + str(tel[j][1]), (10, 60),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
        cv2.putText(frame1, "Horizontal Speed: " + str(tel[j][2]), (10, 90),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
        cv2.putText(frame1, "Vertical Speed: " + str(tel[j][3]), (10, 120),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2)
        # Resize frame2 to 25%
        frame2 = cv2.resize(frame2, (0, 0), fx=0.25, fy=0.25)
        # Put frame2 over frame1
        frame1[500:frame2.shape[0]+500, 0:frame2.shape[1]] = frame2
        cv2.imshow('frame', frame1)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

【问题讨论】:

这两个视频最初是同步的,然后它们就分开了,还是从一开始就不同步?您是否尝试过在两者上运行ffprobe 来检查它们的帧速率等?您是否尝试过仅使用 ffmpeg 从两者中提取第 1 帧和第 300 帧并检查它们是否以这种方式同步? 我刚刚意识到两个视频的帧速率不同。这绝对是问题所在。一个视频是 60 fps,另一个是 30 fps。为了解决这个问题,我应该从第一个视频中读取两帧,从第二个视频中读取一帧。那能解决问题吗?或者我可以在不改变播放速度的情况下使用 ffmpeg 将 30 fps 提高到 60 fps?这会将每个帧复制到下一个插槽,从而使帧速率加倍。你怎么看? 这取决于您是否真的需要更高的帧速率。如果这样做,请使用 30fps(较慢速率)帧两次,连续 60fps 帧。如果没有,请从 60fps 视频中删除备用帧。 【参考方案1】:

正如 Mark 在 cmets 中所提到的,相机不需要同步,首先。即使具有相同的硬件,它们也可以具有不同的 FPS。此外,在您的 fil_buffer() 函数中,从两个摄像头读取帧是顺序的,即您先读取摄像头 A,然后读取摄像头 B。这肯定会增加摄像头 A 的一定程度的延迟。我想解决这个问题方式。

    在各自的单独线程中为每个摄像头运行帧读取任务。 在同一个线程中,您可以将读取的相机帧推送到自己的堆栈中(不是队列/列表)。 在您的主函数中,您应该读取该堆栈,并立即清除它。这可确保您始终读取堆栈中最新的可用帧。

我假设您的 main 函数中的处理时间将大于读取帧所花费的时间。这应该适用于您的应用程序。

(几个月前,我写了this article 写了关于通过摄像头获得更高的 FPS。它的实现是用 C++ 编写的,但它有一个结构可以在各自的单独线程中运行多个摄像头。我一直在使用相同的结构读取多个 FLIR 相机,以 50-55 的 FPS 读取它们并相互同步。)

【讨论】:

以上是关于从两个视频源读取帧不同步 |开放式CV的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV 遇到 cv::FAST 问题

在开放 CV 中使用单应性从同一场景的相同相机拍摄的两个图像之间的视图映射,除了相机位置不平行

开放CV 4 |没有模块名称 cv2.cv2 |

有没有办法使用 cv2.approxPolyDP 来近似开放曲线?

图像未在开放cv写入功能中保存

使用开放CV和python提取或获取图像中几个点的平均RGB颜色