Spaces:
Sleeping
Sleeping
| import cv2 | |
| import torch | |
| import numpy as np | |
| def extract_video_features(video_path, model, processor, device): | |
| """提取视频关键帧特征 | |
| Args: | |
| video_path: 视频文件路径 | |
| model: CLIP模型 | |
| processor: CLIP处理器 | |
| device: 计算设备 | |
| Returns: | |
| features: 形状为 (n_frames, feature_dim) 的特征数组 | |
| timestamps: 对应帧的时间戳(秒) | |
| """ | |
| # 打开视频文件 | |
| cap = cv2.VideoCapture(video_path) | |
| if not cap.isOpened(): | |
| raise ValueError(f"无法打开视频文件: {video_path}") | |
| # 获取视频属性 | |
| fps = cap.get(cv2.CAP_PROP_FPS) | |
| total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) | |
| # 处理无效帧率 | |
| if fps <= 0: | |
| fps = 30 # 默认帧率 | |
| print(f"警告: 视频帧率无效,使用默认值 {fps}") | |
| # 每3秒提取一帧 | |
| frame_interval = max(1, int(fps * 2)) # 确保至少为1 | |
| features = [] | |
| timestamps = [] | |
| for i in range(0, total_frames, frame_interval): | |
| start_frame = i | |
| cap.set(cv2.CAP_PROP_POS_FRAMES, start_frame) | |
| ret, frame = cap.read() # 读取该位置的帧(图片) | |
| if not ret: | |
| break | |
| try: | |
| # 预处理帧 | |
| frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) | |
| # 提取特征 | |
| inputs = processor(images=frame_rgb, return_tensors="pt").to(device) | |
| with torch.no_grad(): | |
| frame_features = model.get_image_features(**inputs) | |
| # 保存结果 | |
| features.append(frame_features.cpu().numpy().squeeze()) # 去除batch维度,二维变一维(v_row维) array([ 9.67003047e-01, 7.20102668e-01, -6.19670749e-03, -1.22871208e+00, ...] | |
| timestamps.append(start_frame / fps) | |
| except Exception as e: | |
| print(f"处理帧 {i} 时出错: {str(e)}") | |
| continue | |
| cap.release() | |
| # 转换为numpy数组 | |
| if len(features) > 0: | |
| features = np.vstack(features) # 形状: (n_frames, feature_dim) | |
| timestamps = np.array(timestamps) | |
| else: | |
| features = np.empty((0, 512)) # 空数组 | |
| timestamps = np.array([]) | |
| return features, timestamps, total_frames, fps |