File size: 6,279 Bytes
d6ea02e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | ---
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:

---
## 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/)
|