点击蓝字?关注【测试先锋】,不再迷路!一起成为互联网测试精英,前瞻测试技术~导语全参考清晰度测算的时候,输入两个视频帧序列,但是视频帧序列没有对齐,怎么知道丢了哪帧?又怎么知道补回哪一帧?今天介绍一种直播视频帧的对齐方案,如果您有更好的方法,欢迎在公众号下方留言联系作者探讨交流(文章留言近期开放),再次感谢您的关注和阅读。1/  问题背景全参考测算视频质量,广泛存在在视频业务场景。开始算法计算时,是需要仔细的对齐这一系列的帧再能做计算的,因为全参考的计算原理是根据两张相同场景的图片数据,做比较测算。仔细想想:“帧对齐”其实这是一个挺麻烦的事儿,为什么这么说?因为:第一、帧非常多(手机端直播业务一般在 18-25fps,pc 直播业务一般 60fps),想让人工挑出到底哪帧丢了,这是非常不现实的。第二、由于人眼的一个重要特性——视觉惰性,表现在人眼会存在一个视觉暂留,肉眼基本看不出来连续两帧的区别。人眼可以保留 0.1-0.4秒的影像。所以每一个视频都是一个非常快的“走马灯”,人们是很难通过图像特征来区别每一帧。

所以,“帧对齐”这个问题,拆解为两个问题:如何识别每一个帧+找到未对齐的帧 这两个问题。根据上述分析,我们可以拿到具体的折损测试方案:

输入源为两个视频,分别是“原视频”和“待比较视频”(折损视频),首先将两个视频进行拆帧处理;将视频处理为一系列的图片帧文件,然后进行帧对齐处理(将帧的分辨率处理成一致的分辨率,将丢帧补齐,将卡帧删掉并记录帧号),输出两列对齐后的视频帧序列,再合成对齐帧后的视频序列,再进行VMAF,PSNR等全参考得分的分数计算。

了解了上述的测试方案,我们来看下每一个部分都是怎么解决的。

2/ 如何识别每一帧 识别帧的两个思路:物理识别与代码识别。物理识别是指,放大每一帧之间的区别,或者专门打上帧的标签来识别不同的图片。代码识别目前笔者没有找到比较有效的方法来区别两帧,因为在截取为 jpg 时这个信息已经丢失了。所以这里还是倾向于“物理识别”方案。这里根据两位测试前辈(在这特别感谢 eriel,austin)曾经尝试过的经验,有两种方法:方法一:给每一帧标记物理序号至某一个固定位置

方法二:给每一帧上方标记一个黑白条形码至某一个固定位置,再来读黑白条形码

然后,再通过代码/工具识别这个更容易识别的物理特征。总之,上述两种方法都是为了放大帧和帧之间的区别。因为篇幅关系,现在我介绍一下方法一的方案具体怎么做,也给出一些代码/命令,感兴趣的小伙伴可以动手试一试:方案 1:先画后切-  step1:使用ffmpeg - drawtext 命令给整个视频画帧号

ffmpeg -i input.mp4 -vf drawtext=fontcolor=black:box=1:boxcolor=white:fontsize=40:fontfile=msyh.ttf:line_spacing=7:text=%{n}:x=0:y=0 -vframes 600  -y -qscale 0  out.mp4

这样,你就得到了一个画好了帧号的视频:

然后再执行切帧操作,这里关键参数是

text={n}

这个写法是表示标注的是帧号。更多写法可以参考 ffmpeg 说明书。    -  step 2:切帧命令 ffmpeg image2  或 opencv 切帧ffmpeg image2 命令:

ffmpeg -i out-1.flv -r 1 -q:v -f image2 ./result/image-%3d.jpeg

不知道为什么使用 ffmpeg 我总觉得切出来的损耗很高(可能是使用的无损参数有点问题),所以我用 opencv 实现了一把,这种方案看起来损耗至少看起来没那么大(opencv实现代码如下):

def cutFrame(srcFilePath,dstFolderPath):    srcFileName = srcFilePath.split('/')[-1].split('.')[0]    print(srcFileName)    dstFolderPath = dstFolderPath + srcFileName + '/'    times=0    #提取视频的频率,每1帧提取一个    frameFrequency=1    if not os.path.exists(dstFolderPath):        #如果文件目录不存在则创建目录        os.makedirs(dstFolderPath)    camera = cv2.VideoCapture(srcFilePath)    count = 0    while True:        times+=1        res, image = camera.read()        if not res:            print('error ! not res , not image')            break        countMax = 400        if times%frameFrequency==0 and count < countMax:            count+=1            print(count)            cv2.imwrite(dstFolderPath + srcFileName + '-'+ str(times-1)+'.jpg', image)            print(dstFolderPath + srcFileName +'-'+ str(times)+'.jpg')    print('图片提取结束')    camera.release()

经过上面两步,你将得到:
             - 一个标记了帧号的视频文件- 每一帧都有帧号的图片文件集但在后面的识别图片帧号会遇到一个新的坑:你不知道需要具体需要预测的图片的坐标是多少(因为你在输入预测图片时,需要知道图片的具体 x,y,而不是整张图片输入),也就是说 个位数帧,和十位数帧,和百位数帧,具体的 x,y 都是不一样的,分别是(14,22);(28,22);(42,22) :

因为你在预测的时候,不知道具体帧号,所以这个预测位置你不好判断是多长。如果你一刀切使用最长的(42,22),个位数帧的空余位置,因为你的模型/ocr 工具 没有学习过,所以会预测出奇怪的字符串。为了解决这个裁切数字准确的问题,我们有了第二个方案:更好的方案 2先切后画-  step 1:切帧命令 ffmpeg image2  或 opencv 切帧同上文方案 1-  step 2:切好的帧画上帧号,具体命令和方案 1 不一样(text 参数)

ffmpeg -i test.jpg -vf drawtext=fontcolor=black:box=1:boxcolor=white:fontsize=40:fontfile=msyh.ttf:line_spacing=7:text='00001':x=0:y=0 -vframes 600  -y -qscale 0  output.jpg

这里的 text 参数

 text = '00001'

,可以通过读step1 的名字拿到(切视频的时候的视频帧是命名是可以控制的,比如 frame-01.jpg,你可以拿到'01',然后再通过格式化%03d 的方式,对齐帧号为“00001”,再填到命令中去,这样所有的帧号就都是 4 位数甚至更多,从而做到了对齐。)经过上面两步,你将得到:- 一个标注了帧号的且对齐了位数的图片集

看到这样的图片标注集合,别提多舒服了~可是,下一个问题来了,如果使用方案 2,那“带标记的视频源”如何拿到呢?这是折损的初始输入部分。这个问题简单,你可以通过 opencv 来合成无声视频片段,这个也是几乎视觉无损的:

def frameToAvi(srcFolderPath,dstFolderPath):        for root, dir, files in os.walk(srcFolderPath):            count = 0            for f in files:                #print(f)                if not f.endwith('jpg'):                    continue                else:                    count += 1            fourcc = cv2.VideoWriter_fourcc(*'XVID')            videoWriter = cv2.VideoWriter(dstFolderPath+'/'+srcFolderPath.split('/')[-1]+'.avi', fourcc, 18, (1088,1920)) ## 一定要对上  宽高,不然写不进去   3506463247-106.avi            for i in range(0,count):                img12 = cv2.imread(root + '/' + '1-' + str(i) + '.jpg')                print(root + '/' + '1-' + str(i) + '.jpg is reading')                cv2.imshow('img',img12)                cv2.waitKey(1)                videoWriter.write(img12)                print(root + '/' + '1-' + str(i) + '.jpg is succeed')            videoWriter.release()            print('over')

上面的代码拼图片链接,使用 os.path.join() 会更好,另外值得一提的是:

videoWriter = cv2.VideoWriter(dstFolderPath+'/'+srcFolderPath.split('/')[-1]+'.avi', fourcc, 18, (1088,1920)) ## 一定要对上 fps 宽高,不然写不进去   3506463247-106.avi

cv2.videoWriter 方法,要写生成视频的宽高,这里的宽高数据要从你切的图里面获得(opencv可以得到,你也可以打开右键图片简介读取),批量视频就写死,各种不同的视频就读一张图。fps 根据你的需求来调整,一切参数尽量模拟原未标号的视频。到这里,方案 2 就全部结束了。3/使用 OCR 识别模型/调用 OCR 工具,识别帧号未对齐的帧 经过part2 的一系列骚操作,你下一步需要做的就是使用 ocr 工具来识别帧号,工具如何制作和使用已经在我的前期公众号推送中说明了:《“自己动手,丰衣足食”——训练一个属于自己的OCR文字识别库(mac环境)》,我把我遇到的坑和解决方案都记录下来了;当然如果你嫌麻烦,你也可以使用在线的ocr 转换服务。4/ 丢帧的 2 种处理方法测试过程中发现不同流的丢帧处理方法不太一样,一共有 2 种类型,一种是传输过程中直接丢弃,另一种是延续上一帧,也就是说: - 传输过程中直接丢弃的方案,收集到的帧号是: 0,1,2,3,5 ... 丢了第 4 帧。- 传输过程中延续上一帧的方案,收集到的帧号是:0,1,2,3,3,5... 丢掉的第 4 帧用上一帧来弥补。值得一提的是,丢帧率和网络情况也是强相关的,如果对丢帧率的专项测试,需要将自己的网络情况仔细整理并划分类别(或者专业的网络损失实验室)来做这项专项测试。对帧率等指标感兴趣的朋友,可以参考我的这篇往期文章:《码率、分辨率、帧率那点事儿》对于全参考系算法的一些坑,我们下篇再讲,2020 年十一双节欢庆,预祝各位读者朋友节日快乐,月圆人团圆~!?

注:以上图片部分来自互联网,如有侵权请后台联系公众号,会第一时间删除,谢谢!

ffmpeg如何在结尾添加帧_一种“视频帧对齐”的测试方案实践相关推荐

  1. python 视频抽帧_一种用于超高帧频图像流到标准模拟视频流转换的抽帧方法与流程...

    本发明属于图像处理技术领域,涉及一种用于超高帧频图像流到标准模拟视频流转换的抽帧方法. 背景技术: 在红外成像制导系统中,随着导弹与目标的距离接近,目标逐渐增大形成不稳定的斑状,最后以很快的速度充满整 ...

  2. kotlin调用类中的方法_一种轻松的方法来测试Kotlin中令人沮丧的静态方法调用

    kotlin调用类中的方法 by Oleksii Fedorov 通过Oleksii Fedorov 一种轻松的方法来测试Kotlin中令人沮丧的静态方法调用 (A stress-free way t ...

  3. dbscan聚类算法_一种视频人群流的轨迹聚类方法

    tags: KLT光流法,K-means聚类算法,DBSCAN聚类算法 方法简介 运动轨迹是一种在视频场景中捕捉复杂时间动态的有效方法.因此,我们将人流分割问题转化为一个轨迹提取和聚类任务.该方法分为 ...

  4. python视频提取关键帧_一种视频关键帧提取算法的制作方法

    本发明属于信息安全技术领域,涉及视频内容信息的提取,具体来说,是一种视频关键帧提取算法. 背景技术: 随着Internet的应用和普及,多媒体信息检索系统对社会各领域产生越来越大的影响.传统的信息检索 ...

  5. ios屏幕录制60帧_探索iOS屏幕帧缓冲区–内核反转实验

    ios屏幕录制60帧 It's been over two years since I last published a blog, so I thought I'd give this anothe ...

  6. jq 给按钮添加方法_手机进行视频编辑的方法,原来如此简单,免费、高效、省心...

    相信大家都知道,我们的手机有很多强大的功能,但是视频编辑功能,你会用吗? 一.手机编辑 1.功能介绍 相信大家平时都会用到很多视频编辑的方法,但是下面这些,你知道吗,主要有滤镜.裁剪的功能哦! 2.具 ...

  7. java 处理视频帧_如何将视频处理成每帧的图片?.最好是java实现..

    兼容性不咋地.预览就算了. Your browser does not support HTML5 video tag. Please download FireFox 3.5 or higher. ...

  8. 游戏本自动掉帧_玩游戏掉帧怎么办?

    电脑玩游戏卡怎么办?在玩游戏时电脑卡真的是会气死人的,特别是在打团的时候卡了,想砸电脑有木有?那么电脑玩游戏卡怎么办呢?给大家介绍几个方法,可以尝试改善卡顿. 软件方面: 1. 开启电源性能模式 打开 ...

  9. rxtx串口事件不触发_一种串口高效收发思路及方案

    摘要:本文在探讨传统数据收发不足之后,介绍如何使用带FIFO的串口来减少接收中断次数,通过一种自定义通讯协议格式,给出帧打包方法:之后介绍一种特殊的串口数据发送方法,可在避免使用串口发送中断的情况下, ...

最新文章

  1. 【Clion+Pycharm 网络编程】C++实现服务端,Python实现客户端
  2. CentOS 6.5 安装与配置LAMP
  3. 3DSlicer3:模块管理(一)颜色、DCM、数据、模型、注释
  4. hdu5442(2015长春网络赛F题)
  5. DCMTK:测试CT像框FG类
  6. JUC队列-ConcurrentLinkedQueue(四)
  7. 128位计算机 ps2,64位就是最强电脑?难道就没有128位的电脑吗
  8. Bear in the Field(CF-385E)
  9. 浙江师范大学c语言函数实验答案,浙江师范大学2012年秋C语言考试卷与答案
  10. 11静态static
  11. C# 数据类型转换
  12. rfid 标签内存_RFID有源与无源的区别与联系
  13. 前台 时不时报 could not proxy request_长春中考成绩不理想可以报的高中
  14. 计算机10大经典算法
  15. MATLAB-高斯滤波的实现
  16. HTML,CSS 样式模板大全
  17. java矩形面积_Java编程求矩形的面积
  18. Python实战题 · 计算圆面积
  19. python从srt文件中只提取歌词
  20. hive drop表恢复手册

热门文章

  1. linux里ip地址正常但远程连接不上,linux系统上解决postgres远程连接不上的问题
  2. 请领导审阅并提意见应怎么说_职场中,领导不喜欢你,暗中排挤你,怎么办?老员工给你支5招!...
  3. 最长上升子序列三种模板(n^2模板,二分模板,树状数组模板)
  4. php获取随机图片,PHP 随机显示某张图片
  5. 【sklearrn学习】朴素贝叶斯
  6. 【算法竞赛学习】二手车交易价格预测-Task5模型融合
  7. Spring MVC 基于注解的class文件打成jar包后注入失败
  8. Windows驱动开发VXD/WDM/WDF/DDK/WDK的联系和区别
  9. 阿里资深技术专家:如何快速成长为技术大牛?
  10. Mac平台上的几款串口工具