Scene Change Detection

Property Value
Category Scene Analytics (classical computer vision)
Base Model Not applicable -- uses frame histogram comparison
Source Framework OpenCV
Supported Precisions Not applicable
Inference Engine OpenCV (CPU)
Hardware CPU, GPU (OpenCV UMat optional)
Detected Class(es) Scene-change events

Overview

Scene Change Detection is a Metro Analytics use case that flags abrupt or sustained changes in what a camera is showing, such as a shot cut, a camera being repositioned, or a large change in the field of view. It compares the color-histogram signature of each frame against the previous frame using the Bhattacharyya distance and raises an event when the distance exceeds a threshold.

Histogram and similarity scoring is more robust and far cheaper than running an object detector for this signal, so this use case intentionally avoids a neural model. For semantic scene understanding (for example "platform" versus "concourse"), pair this with the object-detection use case.

Typical Metro deployments include:

  • Camera Repositioning Alerts -- detect when a PTZ camera moves to a new view.
  • Video Segmentation -- split long recordings into scenes for indexing.
  • Content Validation -- confirm a feed switched to the expected source.
  • Pre-filter for Analytics -- re-initialize trackers when the scene changes.

Prerequisites

  • Python 3.11+
  • Install OpenVINO (latest version)
  • ffmpeg (used by export_and_quantize.sh to build the sample montage)

Create and activate a Python virtual environment before running the scripts:

python3 -m venv .venv --system-site-packages
source .venv/bin/activate

Note: The --system-site-packages flag is required so the virtual environment can access the system-installed OpenVINO Python packages (which provide OpenCV).


Getting Started

Download the Sample Video

This use case does not export or quantize a model. Run the provided script to prepare the sample test video:

chmod +x export_and_quantize.sh
./export_and_quantize.sh

A single continuous shot never triggers a scene change, so the script downloads several distinct sample clips and joins them with hard cuts into test_video.mp4 (four 2-second scenes). This produces a clear scene change every two seconds for the detector to flag. The script requires ffmpeg to build the montage.

OpenCV Sample

The sample below computes a normalized HSV histogram for each frame, compares it to the previous frame with the Bhattacharyya distance, and flags a scene change when the distance exceeds CHANGE_THRESHOLD. The annotated frames are written to output_opencv.mp4.

import cv2
import numpy as np

INPUT_VIDEO = "test_video.mp4"
CHANGE_THRESHOLD = 0.45  # Bhattacharyya distance in [0, 1]; higher = more change

cap = cv2.VideoCapture(INPUT_VIDEO)
fps = cap.get(cv2.CAP_PROP_FPS) or 30.0
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
writer = cv2.VideoWriter(
    "output_opencv.mp4", cv2.VideoWriter_fourcc(*"mp4v"), fps, (width, height))


def frame_histogram(bgr):
    hsv = cv2.cvtColor(bgr, cv2.COLOR_BGR2HSV)
    hist = cv2.calcHist([hsv], [0, 1], None, [50, 60], [0, 180, 0, 256])
    cv2.normalize(hist, hist, 0, 1, cv2.NORM_MINMAX)
    return hist


prev_hist = None
frame_idx = 0
scene_changes = 0
while True:
    ok, frame = cap.read()
    if not ok:
        break
    frame_idx += 1
    hist = frame_histogram(frame)

    distance = 0.0
    changed = False
    if prev_hist is not None:
        distance = cv2.compareHist(prev_hist, hist, cv2.HISTCMP_BHATTACHARYYA)
        changed = distance >= CHANGE_THRESHOLD
    prev_hist = hist

    if changed:
        scene_changes += 1
        print(f"Frame {frame_idx}: SCENE CHANGE (distance={distance:.3f})",
              flush=True)
    color = (0, 0, 255) if changed else (0, 255, 0)
    label = f"dist={distance:.3f}" + (" CHANGE" if changed else "")
    cv2.putText(frame, label, (10, 30),
                cv2.FONT_HERSHEY_SIMPLEX, 0.8, color, 2)
    writer.write(frame)

cap.release()
writer.release()
print(f"Scene changes detected: {scene_changes}", flush=True)

Device targets:

  • "CPU" -- default for OpenCV histogram comparison.
  • "GPU" -- wrap frames in cv2.UMat to use the OpenCV transparent API on Intel GPUs.
  • "NPU" -- not applicable; histogram comparison is not a neural workload.

Scene-Change Terminal Logging

Every time the Bhattacharyya distance crosses CHANGE_THRESHOLD, the sample treats it as a new scene and prints a line to the terminal with the frame number and the distance that triggered it. A running total is printed when the video ends. This makes the terminal a lightweight event log you can pipe to a file or another process without inspecting the annotated video.

The relevant lines in the sample are:

if changed:
    scene_changes += 1
    print(f"Frame {frame_idx}: SCENE CHANGE (distance={distance:.3f})",
          flush=True)

Expected Terminal Output

Running the sample against the four-scene montage produces one log line per cut (at ~2s, ~4s, and ~6s), followed by the summary:

Frame 61: SCENE CHANGE (distance=0.949)
Frame 121: SCENE CHANGE (distance=0.988)
Frame 181: SCENE CHANGE (distance=0.854)
Scene changes detected: 3

Expected Output

The annotated video draws each frame's distance in green and turns the label red on the frame where a scene change is detected:

OpenCV expected output


License

Licensed under the MIT License. See LICENSE for details.

References

Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Collection including Intel/scene-change-detection