视频质量评价SimpleVQA
一、研究意义
例子
二、介绍
三、文章解读
3.1 论文动机
3.2论文思路
3.3方法
3.3.1网络框架
3.3.2公式解读
3.3.3核心创新
3.3.4理解
!!!作者对模型的改进
本人算法框体
3.3.5实验细节:
四、代码复现
4.1代码文件简介
4.2数据集下载
4.3环境
4.4测试训练
4.4.1复现结果
五、后话
本文所涉及所有资源均在 传知代码平台可获取。
一、研究意义
用户生成内容(UGC)视频的质量评估对于确保终端用户的观看体验具有重要作用。典型的UGC视频如抖音视频、游戏视频等等。人们在观看这些视频的时候都希望有一个清晰的、稳定的视频带来更好的用户体验。
例子
如下图,模糊的视频让人没有观看欲望,但是这个草原的视频会吸引人们的注意甚至想去身临其境。所以,视频质量评价算法模型的意义在于筛选出高质量的视频供人们观看,并且为下游的视频去模糊、视频画质提升任务做上游工作。
二、介绍
A Deep Learning based No-reference Quality Assessment Model for UGC Videos是一篇CCF A类会议ACM MM2023年上发表的文章。
- 源码中给出了LSVQ数据集上的训练的模型,本文补充KoNViD、youtube_ugc数据集上的训练模型
- 源码中REDME文件中只给出了如何运行代码,本文对代码进行详细解读,解释每一块的作用
- 本文提供多个数据集的下载连接,方便读者快速下载使用
三、文章解读
3.1 论文动机
对于视频质量评价而言,视频的质量主要取决于视频的内容、视频的稳定性、视频有无失真。所以基于上述内容,本文从空间-时间进行建模以对视频的质量进行整体评价。
3.2论文思路
提出一个时空模型对视频的图像和时间信息进行处理,最终得到视频预测的质量分数。
- 视频抽帧处理:将视频每一秒抽取一帧关键帧
- 空间信息处理:使用ImageNet上预训练的ResNet提取视频的空间信息
- 时间信息处理:使用冻结参数的slowfast网络提取时间信息
- 时空信息融合:使用concatenate连接时空特征
- 质量分数回归:使用多层感知机MLP进行质量回归
3.3方法
3.3.1网络框架
- Input video即是数据集中训练数据,将输入视频进行Frame extraction,代码中是每一秒抽取第一帧作为视频的关键帧,并且只使用8秒,不足8秒的视频复制前面的帧。所以,最终一个视频得到的帧数为8
- Chunks即代表一个视频的所有帧,2D frames代表抽出来的帧。将Chunks馈送到Motion feature extraction模块,将2D frames馈送到Spatial feature extraction模块,分别进行特征提取
- Motion feature extraction模块是参数冻结的,可以直接使用训练好的参数进行特征提取,这个模块其内涵是使用3D CNN,Spatial feature extraction模块是可训练的,这个模块其内涵是预训练的ResNet,预训练的ResNet可以帮助模型提取充分的语义信息,并且将4个stage的特征图进行全局平均值和标准差池化,以满足多尺度视频
- 使用cat操作进行特征融合,就是很简单的在通道维度进行特征拼接。再到MLP进行质量回归,MLP也是需要训练的
3.3.2公式解读
- 抽取关键帧:将视频每一秒提取关键帧,对于N秒视频就抽取N帧,得到帧集合。代码中每一个视频都归一化抽取8帧。
import numpy as np
import os
import pandas as pd
import cv2# / home/dataset/LSVQLSVQ video_name LSVQ_image
def extract_frame(videos_dir, video_name, save_folder):
filename = os.path.join(videos_dir, video_name + '.mp4')
video_capture = cv2.VideoCapture()
video_capture.open(filename)
cap = cv2.VideoCapture(filename) video_length = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
video_frame_rate = int(round(cap.get(cv2.CAP_PROP_FPS))) video_height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) # the heigh of frames
video_width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) # the width of frames # 按短边进行等比例缩放
if video_height > video_width:
video_width_resize = 520
video_height_resize = int(video_width_resize / video_width * video_height)
else:
video_height_resize = 520
video_width_resize = int(video_height_resize / video_height * video_width) dim = (video_width_resize, video_height_resize) video_read_index = 0 frame_idx = 0 video_length_min = 8 for i in range(video_length):
has_frames, frame = video_capture.read()
if has_frames:
# key frame
if (video_read_index < video_length) and (frame_idx % video_frame_rate == 0): # 保存 帧数/帧率个帧,每次保存第一帧
read_frame = cv2.resize(frame, dim)
exit_folder(os.path.join(save_folder, video_name))
cv2.imwrite(os.path.join(save_folder, video_name,
'{:03d}'.format(video_read_index) + '.png'), read_frame)
video_read_index += 1
frame_idx += 1 if video_read_index < video_length_min: # 不足video_length_min个帧,直接复制前面的一帧
for i in range(video_read_index, video_length_min):
cv2.imwrite(os.path.join(save_folder, video_name,
'{:03d}'.format(i) + '.png'), read_frame) returndef exit_folder(folder_name):
if not os.path.exists(folder_name):
os.makedirs(folder_name) returnif __name__ == "__main__":
# train subset
filename_path = '/data/user/gbb/SimpleVQA-main/data/LSVQ_whole_train.csv'
column_names = ['name', 'p1', 'p2', 'p3',
'height', 'width', 'mos_p1',
'mos_p2', 'mos_p3', 'mos',
'frame_number', 'fn_last_frame', 'left_p1',
'right_p1', 'top_p1', 'bottom_p1',
'start_p1', 'end_p1', 'left_p2',
'right_p2', 'top_p2', 'bottom_p2',
'start_p2', 'end_p2', 'left_p3',
'right_p3', 'top_p3', 'bottom_p3',
'start_p3', 'end_p3', 'top_vid',
'left_vid', 'bottom_vid', 'right_vid',
'start_vid', 'end_vid', 'is_test', 'is_valid'] dataInfo = pd.read_csv(filename_path, header=0, sep=',', names=column_names, index_col=False, encoding="utf-8-sig") video_names = dataInfo['name']
n_video = len(video_names)
videos_dir = '/data/dataset/LSVQ' save_folder = 'LSVQ_image'
for i in range(n_video):
video_name = video_names.iloc[i]
print('start extract {}th video: {}'.format(i, video_name))
extract_frame(videos_dir, video_name, save_folder)
- 提取时空特征:空间特征提取就是对每一张的图像进行特征提取,时间特征提取就是对整个视频进行处理,提取视频的时间信息。空间特征提取器公式中使用fw.空间特征提取器是在Imgenet上预训练的Resnet50,fwk是提取出的特征图。
时间特征提取器是预训练的Slowfast网络,时间特征提取器论文中公式使用MOTION表示.
- 特征融合与质量回归:使用最简单的concatnate也可以有很好的效果
使用多层感知机MLP进行质量回归
3.3.3核心创新
- 提出了一种有效、高效的基于深度学习的UGC VQA模型,该模型包括特征提取模块、质量回归模块和质量池模块。该模型不仅在五个流行的UGC VQA数据库上取得了显著的性能,而且具有较低的计算复杂度,非常适合实际应用。
- 特征提取模块提取两种质量感知特征:空间失真的空间特征和运动失真的时空特征,其中空间特征通过端到端的方式从视频帧的原始像素中学习,时空特征通过预训练的动作识别网络来提取。
- 提出了一种多尺度质量融合策略来解决不同分辨率的质量评价问题,其中多尺度权重是通过考虑观看环境信息从人类视觉系统的对比度敏感度函数中获得的。
3.3.4理解
以下是我自己对这个模型的理解解释图,对输入维度做了一定解释。时间特征流由于多了时间信息会比空间特征流多一个维度特征。所有在进行cat操作的时候需要降维。降维处理:先进行全局平均池化再将帧数维度和通道维度融合成一个维度。
!!!作者对模型的改进
举个例子:同样的设备,同一个摄影师,同一个模特,拍照姿势也一样,只有背景不同,保持单一变量的条件下。站在垃圾堆前面拍摄的视频和站在来福士前面拍摄的视频,人们在进行主观评价做数据标注时,肯定会觉得在来福士前面拍摄的更好看。因为背景的美学已经开始影响视频的质量分数了。所以,本人从这个方面对论文模型进行改进。
本人算法框体
- 视频抽帧
- 空间信息提取分为两个分支:第一、美学特征提取网络;第二、技术特征提取网络
- 时间信息提取
- 特征融合与质量回归
由于本人改进主要针对图像美学分支,从而在这里重点概述。
美学特征提取网络:
特征提取网络使用Resnet50框架,使用现在图像美学质量评价领域最大的数据集AVA数据集进行预训练。然后加载预训练权重。再使用图像美学数据集AADB进行美学属性回归,从而使网络具有图像美学特征提取能力。保存训练最好的权重。1、2、3、4、5、6个特征分别使AADB数据集中的6种美学客观属性。得到美学特征提取网络后,将视频关键帧馈送到美学特征提取网络中提取美学特征。
注:附件中有美学分支详细代码
3.3.5实验细节:
- 损失函数:L1RankLoss
- 优化器:Adam
- 超参数设置如下:
parser = argparse.ArgumentParser()
# input parameters
parser.add_argument('--database', type=str, default='LSVQ') # LSVQ
parser.add_argument('--model_name', type=str, default='UGC_BVQA_model') # UGC_BVQA_model
# training parameters
parser.add_argument('--conv_base_lr', type=float, default=1e-5)
parser.add_argument('--decay_ratio', type=float, default=0.9) # 0.9
parser.add_argument('--decay_interval', type=int, default=2) #多少步长来控制权重衰减
parser.add_argument('--n_trial', type=int, default=0)
parser.add_argument('--results_path', type=str)
parser.add_argument('--exp_version', type=int, default=0) # 0
parser.add_argument('--print_samples', type=int, default=1000)
parser.add_argument('--train_batch_size', type=int, default=8) #16
parser.add_argument('--num_workers', type=int, default=6) # 6
parser.add_argument('--resize', type=int, default=520)
parser.add_argument('--crop_size', type=int, default=448)
parser.add_argument('--epochs', type=int, default=20)
# misc
parser.add_argument('--ckpt_path', type=str, default='ckpts') #用于存储最好的效果
parser.add_argument('--multi_gpu', action='store_true') # 当命令行中触发multi_gpu参数时,返回为True,没有触发的时候返回False
parser.add_argument('--gpu_ids', type=list, default=None)
parser.add_argument('--loss_type', type=str, default='L1RankLoss') config = parser.parse_args()
四、代码复现
在附件中下载代码文件,先看到对应的代码文件结构,以下是代码文件简介。
4.1代码文件简介
- 文件夹Aes存放图像美学代码
- 文件夹ckpts存放权重
- 文件夹data存放数据集的csv文件
- datasettimages_originalsize存放的图像美学数据集AADB
- 文件夹model存放模型
- data_loader.py数据集加载处理代码
- extract_frame_***.py抽取各个数据集的帧代码
- extract_slowfast_feature_***.py抽取各个数据集的时间特征代码
- test_on_pretrained_model.py和test_demo.py分别是美学和视频的测试代码
- 其他文件都是包文件或者本人该模型的测试代码
4.2数据集下载
数据集文件数据较大,自行下载
视频质量评价目前最大的数据集:LSVQ、Konvid1k
图像美学数据集:AVA、AADB注:数据集下载链接放在附件README中!
4.3环境
- python=3.8.8
- torch=1.10.2
- torchvision=0.11.3
- scipy
4.4测试训练
以抽帧模块为演示。
- 安装相应的包代码中import部分,可以在终端使用pip install安装(简单方便)
- 数据集路径修改,其他代码类似操作,将路径修改到自己对应文件
- 运行,右键run或者终端输入python extract_frame_LSVQ.py命令
4.4.1复现结果
本人挂在后台运行。实验结果如下
五、后话
附件
- 有源码中没有的新的模型
- 有源码没有的模块详细注释
- 有源码没有的模型权重
原文:A Deep Learning based No-reference Quality Assessment Modelfor UGC Videos、 github代码
感觉不错,点击我,立即使用