余烬

 

openCV逐帧读取与跳转到指定帧的帧计数对应时间不同:MP4

使用python的openCV库操作视频时发现一些时间对不上的问题。

想要写一个脚本,利用python识别视频中无意义的黑屏帧,然后利用ffmpeg减掉,但是程序给出的黑屏帧索引总是不对,仔细检查后发现总是比黑屏的地方晚一点。

手动跳转到黒帧300帧之后检查发现程序判断为黒帧,但是逐帧读取认为305(程序偷懒了,每5帧判断一次)才是黒帧。
于是在脚本中添加了一小段代码检查一些逐帧grab和set跳转之间的差别。

运行结果表明二者在帧索引为300时,读到的帧的内容并不相同,导致结果判断也不一致。

可能的原因是视频帧率存在波动,set函数假设视频帧率固定然后跳转,而逐帧读取受到帧率波动影响。

视频的参数如下,MP4,.h264,30.05fps(帧率有点奇怪)

贴出全部代码如下:

import traceback
import cv2
import numpy as np
import sys

def is_black_frame_gpu(frame, threshold=5):
    # 将帧转换为GPU上的Mat对象
    gpu_frame = cv2.cuda_GpuMat()
    gpu_frame.upload(frame)
    # 将帧转换为灰度图
    gray_gpu = cv2.cuda.cvtColor(gpu_frame, cv2.COLOR_BGR2GRAY)
    # 计算帧的平均亮度
    avg_brightness_gpu = cv2.cuda.mean(gray_gpu)
    avg_brightness = avg_brightness_gpu[0]  # 提取平均值
    return avg_brightness < threshold

def is_black_frame(frame, threshold=5):
    # 将帧转换为灰度图
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    # 计算帧的平均亮度
    avg_brightness = np.mean(gray)
    return avg_brightness < threshold

def find_black_transition(video_path):
    cap = cv2.VideoCapture(video_path)
    black_frame_indices = []
    black_count = 0
    frame_index = 0
    isBlack = False
    lastIsBlack = False
    ret = True
    frame = False

    while True:
        if frame_index:
            ret = cap.grab()
        if not ret:
            break
        if frame_index % 5 == 0:
            ret,frame = cap.retrieve()
            if frame is not None:
                lastIsBlack = isBlack
                try:
                    isBlack = is_black_frame(frame)
                    if (frame_index == 300):
                        print(cap.get(cv2.CAP_PROP_POS_FRAMES))
                        ret,frame = cap.retrieve()
                        test0 = is_black_frame(frame)
                        cap.set(cv2.CAP_PROP_POS_FRAMES, 300)
                        ret,frame = cap.retrieve()
                        test1 = is_black_frame(frame)
                        print(test0,test1)
                        exit()
                except cv2.error:
                    print("frame is None:",frame is None)
                    print(frame)
                    traceback.print_exc()
                    exit()
                if not lastIsBlack and isBlack:
                    black_frame_indices.append(frame_index)
        frame_index += 1
    cap.release()
    return black_frame_indices

if __name__ == "__main__":
    video_path = ''
    if len(sys.argv) > 1:
        video_path = sys.argv[1]
    if len(video_path) <= 0:
        exit()
    black_transitions = find_black_transition(video_path)
    print("done")
    print(black_transitions)

posted on   _余烬  阅读(4)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 上周热点回顾(3.3-3.9)
· AI 智能体引爆开源社区「GitHub 热点速览」

导航

统计

点击右上角即可分享
微信分享提示