数据集处理
最近在做的实验需要将视频分类数据集抽帧变成图片分类的数据集,然后放入已有模型进行训练和评估。
该篇参考博文详细介绍了搭建视频分类模型的过程,但主要以处理数据集为主。所以我的实验借鉴了这篇博文对数据集处理的方法,但对个别内容有修改,并补充了一些理解。
便于处理,只取了UCF101的前10个类别,主要为了测试视频抽帧处理成图片分类数据集的效果,暂不考虑其他因素。
要点一:给每一个视频加标签
大佬博客是按照视频类名划分出标签的,但实际也可以按照视频后面给出的数字划分,这样,后面就不用单独将文字标签转为数字标签了。
大佬划分:
# 为训练视频创建标签 train_video_tag = []#标签列表 for i in range(train.shape[0]):#shape[0],遍历每条视频名(从后往前) train_video_tag.append(train['video_name'][i].split('/')[0])#按照数据帧第['video_name']列每一行的“/”划分取第0维并加入标签列表 train['tag'] = train_video_tag#给数据帧增加一列并起名类别,把标签列表赋值给这列 train.head()#显示前5行
效果:
按数字划分:
# 为训练视频创建标签 train_video_tag = []#标签列表 for i in range(train.shape[0]): train_video_tag.append(train['video_name'][i].split('avi')[1]) train['tag'] = train_video_tag train.head()
效果:
我觉得这里就是看自己需要选择,而我绕了一圈用了大佬的方法。
要点二:从训练组视频里提取帧
这块是核心代码,但是博主代码的缩进问题还是什么原因一直出不来结果。于是我整个换掉了,非常成功。参考
# 保存从训练视频中提取的帧 for i in tqdm(range(train.shape[0])):#tqmd进度条提取过程 count = 0 videoFile = train['trainvideo_name'][i]#数据帧里视频名 # 全局变量 VIDEO_PATH = 'Desktop/UCF10/videos_10/'+videoFile.split(' ')[0]# 视频地址,用空格划分出了视频名 EXTRACT_FOLDER = 'Desktop/UCF10/train_1/' # 存放帧图片的位置 EXTRACT_FREQUENCY = 50 # 帧提取频率(每秒划过多少帧,一个视频是25帧/s,故抽到的帧数少) def extract_frames(video_path, dst_folder, index): # 主操作 import cv2 video = cv2.VideoCapture()#打开视频或摄像头等 if not video.open(video_path): print("can not open the video") exit(1) count = 1 while True: _, frame = video.read()#按帧读取视频 #视频读完退出 if frame is None: break #每过50帧抽取一张 if count % EXTRACT_FREQUENCY == 0: #帧的存储格式,根据需要改,最好和视频名保持一致 save_path ='Desktop/UCF10/train_1/'+videoFile.split('/')[1].split(' ')[0] +"_frame%d.jpg" % count cv2.imwrite(save_path, frame)#存帧 count += 1 video.release() # 打印出所提取帧的总数 print("Totally save {:d} pics".format(index-1)) def main(): ''' 批量生成图片,可以不要这块代码 ''' # # 递归删除之前存放帧图片的文件夹,并新建一个 # import shutil # try: # shutil.rmtree(EXTRACT_FOLDER) # except OSError: # pass # import os # os.mkdir(EXTRACT_FOLDER) # 抽取帧图片,并保存到指定路径 extract_frames(VIDEO_PATH, EXTRACT_FOLDER, 1) if __name__ == '__main__': main()
效果:
要点三:把帧的名称和相对应的标签保存在.csv文件里。创建这个文件可以帮助我们读取在下一阶段要用到的帧
from tqdm import tqdm from glob import glob import pandas as pd # 获得所有图像的名称 images = glob("Desktop/UCF10/train_1_50/*.jpg") train_image = [] train_class = [] for i in tqdm(range(len(images))): # 创建图像的名称 train_image.append(images[i].split('50\\')[1]) # 创建图像的标签 train_class.append(images[i].split('v_')[1].split('_')[0]) # 将图像和它们的标签保存到数据帧里 train_data = pd.DataFrame() train_data['image'] = train_image train_data['class'] = train_class # 将数据帧转为csv.文件 train_data.to_csv('Desktop/UCF10/train_new.csv',header=True, index=False)
这步在创建图像和标签名称那里的字符串划分可以适当修改,我用大佬的划分不出来。。。
读取该csv文件:
import pandas as pd train = pd.read_csv('Desktop/UCF10/train_new.csv') train.head()
效果:
要点四:利用这个.csv文件,提取出帧储存为一个Numpy 数组。这里做了改进多张图片转成一个.npy文件存储
要点五:划分训练集验证集及相应标签
import pandas as pd from sklearn.model_selection import train_test_split #读取存有图片名和对应类别名的.csv文件 train = pd.read_csv('train_new.csv') # 区分目标 y = train['class'] # 创建训练集和验证集 X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42, test_size=0.2, stratify = y)
之后大佬的文章是搭建vgg16的分类模型,并给训练集和验证集创建了目标变量的数据列。但我只需要数据集,所以把上面的结果保存即可。
保存训练集和验证集
import numpy as np np.save("Desktop/UCF10/train1/Xtr01", X_train) np.save("Desktop/UCF10/train1/Ytr01", y_train) np.save("Desktop/UCF10/test1/Xte01", X_test) np.save("Desktop/UCF10/test1/Yte01", y_test)
最后,将文字标签转换成数字标签,如果划分标签的时候按照数字划分,就不用这一步。
数据集放入模型测试
已有vgg16模型的超参设置是用来跑cifar_10的,learning_rate = 0.02,batch_size = 100,epoch = 1,momentuma = 0.5
但输入这个处理过的数据集,结果,损失是nan,迭代一次精度只有11%左右,而且每次测试精度都一模一样。
于是调整超参数:learning_rate = 0.002,batch_size = 20,epoch = 1,momentuma = 0.5
得到测试的损失和精度分别为:
然后可以查看下真实标签和预测标签的结果
查看实际上没什么意义,老师说看标签对不对,其实看测试精度就可以了。