基于OpenCV与Python的动作识别:等帧数视频帧提取方案咨询
Hey there! I’ve worked on similar action recognition pipelines before, so I can share a practical, straightforward approach to extract an equal number of frames from videos of varying lengths using OpenCV and Python.
The key is to sample frames uniformly across the entire duration of the video. For longer videos, we calculate a skip interval so that we pick frames spread evenly from start to finish. For shorter videos that have fewer frames than your target n, we can either take all available frames and repeat the last few to hit n, or adjust based on your project needs.
1. Get Video Metadata
First, we need to fetch the total number of frames in the video using OpenCV’s VideoCapture class. This helps us calculate how often we should skip frames.
2. Calculate Sampling Interval
If the total frames are greater than or equal to your target n, compute the interval as total_frames // n. If there are fewer frames than n, we’ll take every frame and pad with duplicates if needed.
3. Extract and Save Frames
Loop through the video, saving frames at the calculated intervals.
Here’s a basic working code example:
import cv2 import os def extract_equal_frames(video_path, output_dir, num_frames=10): # Create output directory if it doesn't exist os.makedirs(output_dir, exist_ok=True) # Initialize video capture cap = cv2.VideoCapture(video_path) if not cap.isOpened(): print(f"Error: Failed to open video file {video_path}") return # Get total number of frames in the video total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # Calculate frame skip interval (ensure we don't skip 0 frames) skip_interval = max(total_frames // num_frames, 1) frame_idx = 0 saved_frames = 0 last_saved_frame = None while saved_frames < num_frames: ret, frame = cap.read() if not ret: # If video ends before we collect n frames, repeat the last saved frame if last_saved_frame is not None: frame = last_saved_frame else: print(f"Error: No frames could be read from {video_path}") break # Save frame if it's at the skip interval, or if we're short on frames if frame_idx % skip_interval == 0 or saved_frames >= total_frames: output_path = os.path.join(output_dir, f"frame_{saved_frames:04d}.jpg") cv2.imwrite(output_path, frame) last_saved_frame = frame saved_frames += 1 frame_idx += 1 cap.release() print(f"Successfully extracted {saved_frames} frames to {output_dir}") # Example usage extract_equal_frames("your_video.mp4", "extracted_frames", num_frames=15)
For very long videos, iterating through every frame can be slow. Instead, we can generate a list of evenly spaced frame indices and jump directly to those frames using cap.set():
import cv2 import os import numpy as np def extract_equal_frames_optimized(video_path, output_dir, num_frames=10): os.makedirs(output_dir, exist_ok=True) cap = cv2.VideoCapture(video_path) if not cap.isOpened(): print(f"Error: Failed to open video file {video_path}") return total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # Generate evenly spaced indices across the entire video frame_indices = np.linspace(0, total_frames - 1, num_frames, dtype=int) saved_frames = 0 for idx in frame_indices: # Jump directly to the target frame cap.set(cv2.CAP_PROP_POS_FRAMES, idx) ret, frame = cap.read() if ret: output_path = os.path.join(output_dir, f"frame_{saved_frames:04d}.jpg") cv2.imwrite(output_path, frame) saved_frames += 1 else: print(f"Warning: Could not read frame {idx} from {video_path}") cap.release() print(f"Successfully extracted {saved_frames} frames to {output_dir}")
This method is much faster because it avoids processing every single frame in long videos.
- Handle Video Encoding Quirks: Some videos might report an incorrect total frame count due to encoding issues. Adding checks for
ret(frame read success) ensures your code doesn’t crash unexpectedly. - Frame Quality: Use
.pnginstead of.jpgif you want lossless frame storage (trades off for larger file sizes). - Edge Cases: For videos with fewer frames than
num_frames, you can choose to repeat frames, stop at the available frames, or interpolate between frames—adjust the code based on your action recognition model’s requirements.
内容的提问来源于stack exchange,提问作者abhay gurrala

