|
import cv2
|
|
import numpy as np
|
|
import random
|
|
|
|
def extract_video_frames(video_path, n_frames=30, frame_size=(96, 96)):
|
|
"""
|
|
Simplified robust frame extractor for short videos (2-10 sec)
|
|
- Automatically handles varying video lengths
|
|
- Ensures consistent output shape
|
|
- Optimized for MP4/MPEG
|
|
"""
|
|
|
|
cap = cv2.VideoCapture(video_path)
|
|
if not cap.isOpened():
|
|
print(f"Error: Could not open video {video_path}")
|
|
return None
|
|
|
|
total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
|
|
fps = cap.get(cv2.CAP_PROP_FPS)
|
|
|
|
|
|
if total_frames < 1 or fps < 1:
|
|
print(f"Error: Invalid video (frames:{total_frames}, fps:{fps})")
|
|
cap.release()
|
|
return None
|
|
|
|
|
|
video_length = total_frames / fps
|
|
frame_step = max(1, int(total_frames / n_frames))
|
|
|
|
frames = []
|
|
last_good_frame = None
|
|
|
|
for i in range(n_frames):
|
|
|
|
pos = min(int(i * (total_frames / n_frames)), total_frames - 1)
|
|
cap.set(cv2.CAP_PROP_POS_FRAMES, pos)
|
|
|
|
ret, frame = cap.read()
|
|
|
|
|
|
if not ret or frame is None:
|
|
if last_good_frame is not None:
|
|
frame = last_good_frame.copy()
|
|
else:
|
|
|
|
frame = np.full((*frame_size[::-1], 3), 0.8, dtype=np.float32)
|
|
else:
|
|
|
|
frame = cv2.resize(frame, frame_size)
|
|
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
|
frame = frame.astype(np.float32) / 255.0
|
|
last_good_frame = frame
|
|
|
|
frames.append(frame)
|
|
|
|
cap.release()
|
|
return np.array(frames) |