You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python从视频提取大量帧内存占用过高,求高效优化方案

Fixing High Memory Usage When Extracting OpenCV Video Frames

Hey there! Let's sort out that memory overload you're hitting while pulling frames from your videos. The root cause here is super clear: your current code loads every frame into a single list in memory all at once. Even 3000 frames can add up quickly—each frame is a multi-channel array (like 3 channels for RGB), and storing all of them together eats up RAM fast.

Here are a few efficient fixes to get this under control:

1. Process Frames On-the-Fly (Don't Store All in Memory)

Instead of hoarding all frames in a list, process or save each frame immediately as you read it. This keeps your memory footprint tiny because you only hold one frame in RAM at a time.

Example: Save Frames as Image Files

This is great if you want to work with individual image files later:

import cv2
import os

video_name1 = "videosDataset/AMAZExNHORMS2019_Lo-res.mp4"
video_name2 = "videosDataset/CAMILLATHULINS2019_Lo-res.mp4"

def extract_and_save_frames(video_path, output_dir, start_ratio=0.5, end_ratio=2/3):
    # Create output folder if it doesn't exist
    os.makedirs(output_dir, exist_ok=True)
    
    cap = cv2.VideoCapture(video_path)
    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    start_frame = int(total_frames * start_ratio)
    end_frame = int(total_frames * end_ratio)
    
    print(f"Total video frames: {total_frames}")
    print(f"Extracting frames {start_frame} to {end_frame}")
    
    current_frame = 0
    saved_count = 0
    
    while cap.isOpened():
        ret, frame = cap.read()
        if not ret:
            break
        
        # Skip frames before our target range
        if current_frame < start_frame:
            current_frame += 1
            continue
        
        # Stop once we pass the end of our range
        if current_frame > end_frame:
            break
        
        # Save frame as JPG (adjust format/quality as needed)
        frame_filename = os.path.join(output_dir, f"frame_{saved_count:04d}.jpg")
        # Optional: Compress JPG to save space (quality 0-100)
        cv2.imwrite(frame_filename, frame, [cv2.IMWRITE_JPEG_QUALITY, 85])
        
        saved_count += 1
        current_frame += 1
        
        # Print progress every 100 frames to avoid clutter
        if saved_count % 100 == 0:
            progress = (saved_count / (end_frame - start_frame)) * 100
            print(f"Progress: {round(progress, 2)}%")
    
    cap.release()
    print(f"Done! Extracted {saved_count} frames to {output_dir}")

# Extract frames from both videos
extract_and_save_frames(video_name1, "extracted_frames/video1")
extract_and_save_frames(video_name2, "extracted_frames/video2")

Example: Append Frames to Pickle (Without Loading All)

If you still want to use pickle for your dataset, append each frame to the pickle file incrementally instead of storing all in a list first:

import cv2
import pickle

video_name1 = "videosDataset/AMAZExNHORMS2019_Lo-res.mp4"

def save_frames_to_pickle(video_path, pickle_path, start_ratio=0.5, end_ratio=2/3):
    cap = cv2.VideoCapture(video_path)
    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
    start_frame = int(total_frames * start_ratio)
    end_frame = int(total_frames * end_ratio)
    
    current_frame = 0
    
    # Open pickle file in append mode to add frames one by one
    with open(pickle_path, 'ab') as pickle_file:
        while cap.isOpened():
            ret, frame = cap.read()
            if not ret:
                break
            
            if current_frame < start_frame:
                current_frame += 1
                continue
            
            if current_frame > end_frame:
                break
            
            # Dump single frame to pickle
            pickle.dump(frame, pickle_file)
            current_frame += 1
            
            progress = (current_frame - start_frame) / (end_frame - start_frame) * 100
            print(f"Progress: {round(progress, 2)}%")
    
    cap.release()
    print(f"Frames saved to {pickle_path}")

# Usage
save_frames_to_pickle(video_name1, "frames1.pkl")

2. Stop Using cap.set() Repeatedly

Your original code uses cap.set(1, i) to jump to each frame, which is surprisingly inefficient. OpenCV has to seek through the video for every frame, which slows things down and can cause unexpected behavior. The examples above read frames sequentially instead—just skip the ones you don't need, which is way faster and more reliable.

Extra Optimization Tips

  • Resize frames: If your computer vision task doesn't need full-resolution frames, shrink them before saving with frame = cv2.resize(frame, (640, 480)) (adjust dimensions to your needs). This cuts down memory and storage drastically.
  • Use efficient formats: JPG is lighter than PNG for most cases. If you need lossless storage, consider TIFF or adjust PNG compression.
  • Batch processing (if needed): If you must process multiple frames at once, use small batches instead of loading everything—this balances memory usage and processing speed.

内容的提问来源于stack exchange,提问作者Otor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 08:48:08