vagheshpatel's picture
Sync scene-change-detection from metro-analytics-catalog
d6ea02e verified
|
Raw
History Blame Contribute Delete
6.28 kB
---
license: mit
license_link: LICENSE
library_name: opencv
tags:
- opencv
- intel
- scene-change-detection
- histogram
- edge-ai
- metro
language:
- en
---
# 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](../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](https://docs.openvino.ai/2026/get-started/install-openvino.html) (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:
```bash
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:
```bash
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`.
```python
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:
```python
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:
```text
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](expected_output_openvino.gif)
---
## License
Licensed under the MIT License. See [LICENSE](LICENSE) for details.
## References
- [OpenCV Histogram Comparison](https://docs.opencv.org/4.x/d8/dc8/tutorial_histogram_comparison.html)
- [OpenCV calcHist Reference](https://docs.opencv.org/4.x/d6/dc7/group__imgproc__hist.html)
- [OpenVINO Documentation](https://docs.openvino.ai/)