🎬 Python Video Analysis Cheat Sheet

🎬 Python Video Analysis Cheat Sheet #

This document covers essential techniques for video analysis in Python, primarily using the OpenCV library. It serves as a practical guide for reading, processing, and analyzing video files to extract meaningful features.


🎞️ 1. Shot Change Detection #

Shot change detection is the process of identifying the boundaries between shots in a video. This is the first step in understanding a video’s narrative structure.

Concept: The simplest way to detect a hard cut is to measure the difference between consecutive frames. A large, sudden difference indicates a scene change.

Practical Implementation with OpenCV #

This script reads a video file and prints the frame numbers where it detects a shot change.

import cv2
import numpy as np

def detect_shot_changes(video_path, threshold=1000000):
    """
    Detects shot changes in a video based on frame-to-frame differences.

    Args:
        video_path (str): Path to the video file.
        threshold (float): The threshold for difference to be considered a shot change.
                           This value may need tuning based on the video's content.

    Returns:
        list: A list of frame numbers where shot changes were detected.
    """
    # Open the video file
    cap = cv2.VideoCapture(video_path)
    if not cap.isOpened():
        print(f"Error: Could not open video file {video_path}")
        return []

    shot_changes = []
    prev_frame = None
    frame_number = 0

    while True:
        ret, frame = cap.read()
        if not ret:
            break

        # Convert frame to grayscale for simpler difference calculation
        gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

        if prev_frame is not None:
            # Calculate the absolute difference between the current and previous frame
            diff = cv2.absdiff(gray_frame, prev_frame)
            diff_sum = np.sum(diff)

            if diff_sum > threshold:
                print(f"Shot change detected at frame: {frame_number}, Difference: {diff_sum}")
                shot_changes.append(frame_number)

        prev_frame = gray_frame
        frame_number += 1

    cap.release()
    return shot_changes

if __name__ == '__main__':
    import sys

    if len(sys.argv) != 2:
        print("Usage: python analyze_video.py <path_to_video_file>")
        sys.exit(1)

    video_file = sys.argv[1]
    changes = detect_shot_changes(video_file)
    print(f"\nFinished. Found {len(changes)} shot changes at frames: {changes}")

How to Run It #


πŸƒ 2. Motion Analysis with Optical Flow #

Optical flow estimates the motion of objects between consecutive frames. By calculating the average magnitude of motion across the entire frame, we can get a single value representing the scene’s overall “energy” or “action.”

Concept: We use the Farneback algorithm, a dense optical flow method, to compute a flow vector for every pixel. We then calculate the magnitude (length) of these vectors and average them to get a single motion score for the frame.

Practical Implementation with OpenCV #

This function calculates the average motion for each frame in a video.

import cv2
import numpy as np

def analyze_motion(video_path):
    """
    Analyzes the average motion in a video using dense optical flow.

    Args:
        video_path (str): Path to the video file.

    Returns:
        list: A list of average motion magnitudes for each frame.
    """
    cap = cv2.VideoCapture(video_path)
    if not cap.isOpened():
        print(f"Error: Could not open video file {video_path}")
        return []

    motion_magnitudes = []
    ret, prev_frame = cap.read()
    if not ret:
        return []

    prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)

    while True:
        ret, frame = cap.read()
        if not ret:
            break

        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

        # Calculate dense optical flow using Farneback method
        flow = cv2.calcOpticalFlowFarneback(prev_gray, gray, None, 0.5, 3, 15, 3, 5, 1.2, 0)

        # Calculate the magnitude of the flow vectors
        magnitude, _ = cv2.cartToPolar(flow[..., 0], flow[..., 1])

        # Store the average magnitude for the frame
        avg_magnitude = np.mean(magnitude)
        motion_magnitudes.append(avg_magnitude)

        # Move to the next frame
        prev_gray = gray

    cap.release()
    return motion_magnitudes

# You can add this to the `if __name__ == '__main__':` block
# to run it alongside shot detection.
# motion_data = analyze_motion(video_file)
# print(f"\nAnalyzed motion for {len(motion_data)} frames.")

How to Run It #

  1. Save the code as analyze_video.py.

  2. Run from your terminal:

    # You'll need opencv-python
    pip install opencv-python
    
    # Run the analysis
    python analyze_video.py /path/to/your/video.mp4