Clipping Pipeline
This page documents how to use scripts/clipping/clipping.py to reproduce
short annotated clips from long-form source videos using JSON event metadata
produced by the detection pipeline.
Summary
The clipping pipeline reads JSON event metadata produced by any stage of the
detection pipeline (baseline, fine-tuned YOLO, or Seq-NMS) and reproduces
the corresponding video segments as standalone annotated clips with per-frame
bounding box overlays. All clips are written to results/result_clips/,
preserving the input directory structure relative to the metadata/ folder.
Environment Setup
Before running the clipping script, ensure your local workspace satisfies the following:
.envis populated withROOT_DIRandLOCAL_DIR(used byconfig.py).- Source videos exist under
ROOT_DIR/raw_cross_sucking_datalog/. - JSON metadata files exist under
LOCAL_DIR/results/metadata/produced by the detection pipeline.
Output Structure
results/result_clips/
├── pipeline_demo/
│ ├── yolo/
│ │ └── ch02_20250913094601/
│ │ ├── ch02_20250913094601_event001_12.3-16.8_boxed.mp4
│ │ └── ch02_20250913094601_event002_22.1-25.4_boxed.mp4
│ └── baseline/
│ └── ch02_20250913094601/
│ └── ch02_20250913094601_event001_12.3-16.8_boxed.mp4
Usage
Clip from a single JSON file
uv run scripts/clipping/clipping.py \
--input results/metadata/pipeline_demo/yolo/ch02_20250913094601_results.json
Clip from a directory of JSON files
uv run scripts/clipping/clipping.py \
--input results/metadata/pipeline_demo/yolo/
Clip to a custom output directory
uv run scripts/clipping/clipping.py \
--input results/metadata/pipeline_demo/yolo/ \
--output /tmp/clips/
Specifying a different model output
The output path mirrors the input path relative to metadata/. To clip
results from a different model, pass the corresponding metadata directory:
uv run scripts/clipping/clipping.py \
--input results/metadata/pipeline_demo/seq-nms/
Function Reference
scripts.clipping.clipping
Reproduce short annotated video clips from longer source videos.
reproduce_clip(raw_video_path, start_sec, end_sec, output_path)
Reproduce a clip from a source video between two timestamps.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
raw_video_path
|
Path
|
Path to the source |
required |
start_sec
|
float
|
Start time in seconds in the source video. |
required |
end_sec
|
float
|
End time in seconds in the source video. |
required |
output_path
|
Path
|
Destination path for the reproduced clip. |
required |
Returns:
| Type | Description |
|---|---|
bool
|
|
Notes
- Uses codec
mp4vvia OpenCV. - Output frame size and FPS are taken from the source video.
- This function does not create
output_path.parent; callers should ensure the directory exists before calling.
Examples:
.. code-block:: python
from pathlib import Path
from scripts.clipping.clipping import reproduce_clip
ok = reproduce_clip(Path("source.mp4"), 10.0, 12.5, Path("clip.mp4"))
print(ok) # True
split_by_json_events(json_path, output_dir)
Reproduce annotated clips for all events defined in JSON metadata files.
Recursively searches json_path for *.json files produced by the
detection pipeline. For each event in each JSON, reproduces a clip from
the source video and writes an annotated *_boxed.mp4 with bounding
boxes overlaid. The output directory structure mirrors the input path
relative to the metadata/ folder.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
json_path
|
Path
|
A single JSON file, or a root directory to search recursively for
|
required |
output_dir
|
Path
|
Output root directory (e.g. |
required |
Returns:
| Type | Description |
|---|---|
int
|
Total number of successfully reproduced clips across all JSON files. |
Raises:
| Type | Description |
|---|---|
FileNotFoundError
|
If a JSON references a |
Notes
Expected JSON schema (minimum):
video_path: strevents: list of dict with keysstart_sec,end_sec
Optional keys used if present:
identifier: str — used as the per-video output folder namefps: float — used for annotation frame alignmentevents[*].intersection_box: list of dict with keysframe,x1,y1,x2,y2in source-video frame coordinates
Examples:
.. code-block:: python
from pathlib import Path
from scripts.clipping.clipping import split_by_json_events
from config import RESULT_CLIPS_DIR
n = split_by_json_events(
Path("results/metadata/pipeline_demo/yolo/"),
RESULT_CLIPS_DIR,
)
print(f"{n} clips written")
annotate_clip_with_boxes(input_clip, output_clip, boxes, color=(0, 255, 0), thickness=2)
Annotate a clip with per-frame bounding boxes and write a new video.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
input_clip
|
Path
|
Path to the input clip ( |
required |
output_clip
|
Path
|
Path where the annotated clip will be written. |
required |
boxes
|
list of dict
|
Bounding boxes in clip-relative frame coordinates. Each dict must
include: |
required |
color
|
tuple of int
|
Rectangle colour in BGR. |
(0, 255, 0)
|
thickness
|
int
|
Rectangle line thickness in pixels. |
2
|
Returns:
| Type | Description |
|---|---|
bool
|
|
Notes
- Creates
output_clip.parentif it does not exist. - Supports multiple boxes per frame; boxes are grouped by frame index before rendering.
Examples:
.. code-block:: python
from pathlib import Path
from scripts.clipping.clipping import annotate_clip_with_boxes
boxes = [{"frame": 0, "x1": 100, "y1": 50, "x2": 200, "y2": 150}]
ok = annotate_clip_with_boxes(
Path("clip.mp4"), Path("clip_boxed.mp4"), boxes
)
print(ok) # True