python利用ffmpeg和opencv检测视频是否有黑场

 小白交流,大咖绕行!主要代码源于网络,个人添加了一些(画蛇添足)的东西。

需要解决的问题:

1、检测一个视频是否含有黑场(黑帧);

2、检测黑场的参数要根据要求,可以调整;

3、在追求的准确度的同时,能耗时越少越好;

解决方案:

通过搜索,基本得到两种方案(代码见后面):

1、python + opencv  (只需要安装以及配置python,以及opencv库)

import time

def frames_to_timecode(framerate, frames):
    """
    视频 通过视频帧转换成时间
    :param framerate: 视频帧率
    :param frames: 当前视频帧数
    :return:时间(00:00:01:01)
    """
    return '{0:02d}:{1:02d}:{2:02d}:{3:02d}'.format(int(frames / (3600 * framerate)),
                                                    int(frames / (60 * framerate) % 60),
                                                    int(frames / framerate % 60),
                                                    int(frames % framerate))

def video_black_test(videodir):
    import cv2
    # 把图片转换为单通道的灰度图
    video_for_test = cv2.VideoCapture(videodir)
    fps = 0
    blackfps = 0
    while (video_for_test.isOpened()):
        retval, image = video_for_test.read()
        if retval == True:
            gray_img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
            # 获取灰度图矩阵的行数和列数
            r, c = gray_img.shape[:2]
            piexs_sum = r * c  # 整个灰度图的像素个数为r*c
            # 获取偏暗的像素(表示0~19的灰度值为暗) 此处阈值可以修改
            dark_points = (gray_img < 20)
            target_array = gray_img[dark_points]
            dark_sum = target_array.size
            # 判断灰度值为暗的百分比
            dark_prop = dark_sum / (piexs_sum)
            if dark_prop >= 0.85:
                print("有黑场,在:", frames_to_timecode(25, fps))
                blackfps = blackfps + 1
        else:
            video_for_test.release()
            cv2.destroyAllWindows()
            break

startt = time.time()   # --计算程序运行时间-开始
videodir = r"I:\Desktop\C00591.mp4"    
video_black_test(videodir)
end = time.time()      # --计算程序运行时间-结束
runt = end - startt
print(runt, '秒')      # --打印程序运行耗时

2、python + ffmpeg (需要安装配置python 和 ffmpeg)

import os
import subprocess
import time
import datetime

def black_detect(video):
    dt = datetime.datetime.now()
    logname = str(dt)[:4] + str(dt)[5:7] + str(dt)[8:10] + str(dt)[11:13] + str(dt)[14:16] + str(dt)[17:19]
    report_file_path = "I\:\\blackvideo-{}.log".format(logname)
    report_file_path_convert = report_file_path[0] + report_file_path[2:]             # ------------路径转换
    report_file_name = {"FFREPORT": "file={}:level=32".format(report_file_path)}      # ------------环境变量设置

    cmd = r'ffmpeg  -report -v quiet -i {} -vf blackdetect=d=0.04:pix_th=0.05:pic_th=0.80  -f null - '.format(video)
    print(cmd)
    try:
        popen = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, shell=False, env=report_file_name)
        popen.wait()
        # stdout, stderr = popen.stderr
        time.sleep(0.5)
    except Exception as e:
        print(e)
    if os.path.exists(report_file_path_convert):  # --判断是否生成日志文件
        with open(report_file_path_convert, 'r') as rf:
            content = rf.readlines()
        black_duration = {}
        part = 1
        for con in content:  # --循环查找并记录日志内的黑场内容
            if 'black_start' in con:
                print(con)
                black_info = con.split(' ')[-1:-4:-1]
                part_black_info = dict(map(lambda x: x.replace('n', '').split(':'), black_info))
                black_duration[part] = part_black_info
                part += 1
                print(black_duration)
    else:
        print('未检测到黑场...')


startt = time.time()
videodir = "I:\Desktop\C00591.mp4"
black_detect(videodir)
end = time.time()
runt = end - startt
print(runt, '秒')      # --打印程序运行耗时

方案分析:

1、两种方案都能实现需求中的(1)和(2)

2、对同一个视频(视频:长度11分20秒,1080P,25FPS)进行检测,方案(opencv)大约耗时81秒方案(ffmpeg)大约耗时13秒。差距有点大,不知道是不是代码本身的问题,有知道的大神可以指点一下,谢谢!

3、opencv 主要是检测每一帧的灰度图, ffmpeg则是内部滤镜blackdetect实现

4、两个比较需要注意的地方:

        (1)opencv的代码比较简单易懂,略过。ffmpeg的则略微麻烦,在网络查询到的代码,均是FFREPORT=file=report_name.log:level=32 ffmpeg -report -v quiet -i video.mp4 -vf blackdetect=d=0.5:pix_th=0.40:pic_th=0.85 -f null -

但我在pthon运行时没有任何反应,在CMD中运行,提示FFREPORT不是有效的命令。可能是我的ffmpeg的环境变量设置补恰当所致。庆幸的是Popen提供环境变量env的设置,解决了FFREPORT的问题。

        (2)在设置FFREPORT时,我需要将日志文件转移到一个绝对地址上去(个人习惯),但是以下两种格式都无法正常执行:

r"I:\blackvideo-{}.log".format(logname)
"I:\\blackvideo-{}.log".format(logname)

在外网看见有人写成下面的样式,而只有这种格式,才能正常生成日志(有知道的大神,能不能科普一下为什么吗,谢谢谢谢!): 

"I\:\\blackvideo-{}.log".format(logname)

参考:

FFMPEG 中的黑场检测_blackframe_普通网友的博客-CSDN博客

python图像质量检测(一):黑屏检测_.DDDD的博客-CSDN博客

视频黑场检测

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值