基于CLIP的关键帧选择策略:原理
这种方法将整个视频划分为多个片段(clips),并从每个片段中提取能够代表该片段的关键帧。具体过程如下:
-
使用CLIP提取特征: 第一步是使用CLIP模型对视频的第一帧进行编码,生成特征向量
,该向量包含了该帧的高级语义信息。CLIP能够将图像的视觉内容压缩为具有语义意义的特征向量。
-
计算余弦相似度: 为了确定帧与前一帧之间的变化程度,我们计算帧的特征向量之间的余弦相似度。余弦相似度通过比较向量之间的角度差异来测量它们的相似度,值越小表示帧之间的差异越大。因此,若新帧与前一帧的相似度较低,则认为该帧发生了较大变化,有可能成为关键帧。
两帧之间的余弦相似度计算公式如下:
其中:
和
是当前帧和后续帧的特征向量。
是向量的分量数。
算法通过挑选与上一个关键帧相似度最小的帧,来作为新的关键帧。
-
动态选择: 视频的第一帧总是被选为关键帧,然后对每一帧与前一关键帧的相似度进行计算。相似度较小的帧将被选为新的关键帧。这个动态的过程会循环进行,直到处理完整个视频。
基于CLIP的关键帧选择策略:代码
安装必要的库:
$ pip install ftfy regex tqdm
$ pip install git+https://github.com/openai/CLIP.git
处理整个视频,提取每一帧的特征,并基于余弦相似度选择关键帧:
import torch
import clip
from torchvision import transforms
from tqdm import tqdm
# 加载CLIP模型
device = "cuda" if torch.cuda.is_available() else "cpu"
model, preprocess = clip.load("ViT-B/32", device=device)
# 计算余弦相似度的函数
def cosine_similarity(a, b):
return torch.nn.functional.cosine_similarity(a, b)
# 关键帧选择策略
def select_keyframes(video_dataset, model, device):
keyframes = [] # 存储关键帧索引
video_features = [] # 存储帧的特征向量
with torch.no_grad():
# 提取第一帧的特征并将其设为第一个关键帧
first_frame_data = video_dataset[0]
first_frame = first_frame_data['img'].unsqueeze(0).to(device)
# 检查图像是否为RGB三通道格式
if first_frame.shape[1] == 1: # 如果是单通道,扩展为三通道
first_frame = first_frame.repeat(1, 3, 1, 1)
# 对帧进行预处理并提取特征
first_frame_preprocessed = preprocess(transforms.ToPILImage()(first_frame.squeeze(0).cpu())).unsqueeze(0).to(device)
first_frame_features = model.encode_image(first_frame_preprocessed)
# 将第一帧设为关键帧
keyframes.append(0)
video_features.append(first_frame_features)
# 遍历剩下的帧
for idx in tqdm(range(1, len(video_dataset))):
current_frame_data = video_dataset[idx]
current_frame = current_frame_data['img'].unsqueeze(0).to(device)
# 检查图像格式是否为RGB三通道
if current_frame.shape[1] == 1:
current_frame = current_frame.repeat(1, 3, 1, 1)
# 预处理当前帧并提取特征
current_frame_preprocessed = preprocess(transforms.ToPILImage()(current_frame.squeeze(0).cpu())).unsqueeze(0).to(device)
current_frame_features = model.encode_image(current_frame_preprocessed)
# 计算当前帧与上一关键帧的相似度
similarity = cosine_similarity(current_frame_features, video_features[-1])
# 如果相似度低于设定的阈值,则将当前帧设为新的关键帧
if similarity.item() < 0.96: # 可以调整阈值
keyframes.append(idx)
video_features.append(current_frame_features)
return keyframes
参考文章:《When Video Coding Meets Multimodal Large Language Models: A Unified Paradigm for Video Coding》