{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":127283,"databundleVersionId":15634477,"sourceType":"competition"}],"dockerImageVersionId":31259,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"id":"c7f7e6ae58969a3","cell_type":"markdown","source":"# 🚗 Synthetic Traffic Collision Dataset: Starter Notebook\n\n## Introduction\n\nThe ACCIDENT Synthetic Traffic Collision Dataset is a CARLA-based synthetic dataset designed for traffic incident detection and analysis. It mimics fixed-camera (CCTV) viewpoints, providing a \"sandbox\" to train and validate computer vision pipelines before moving to real-world footage.\n\n> **Why use synthetic data?** Real-world accident footage is rare, often low-resolution, and lacks precise 3D ground truth. This dataset bridges that gap with full annotations.\n\nIn this notebook, we will explore the dataset structure, parse the complex JSON annotations, and visualize the ground truth data by overlaying bounding boxes, tracking lines, and collision data directly onto the video sequences.\n\n### Dataset details\nThe dataset contains **2,211 videos**, simulated over **6 different maps**, using **14 different scenarios** in total (scenario stands for unique map location + accident type).\nEach scenario is simulated with multiple camera positions (up to ~50) and **5 distinct weather settings** (```rain```, ```clear```, ```sunset```, ```night```, and ```wet```).\nThe simulation is dynamically generated - for instance, the actors (types of vehicles, etc.) and their spawning locations are randomized, meaning no two videos are identical.\nThe dataset is imbalanced, so the number of videos per accident type differ.\nThe videos were manually filtered to remove wrong outcomes and simulation failures. However, it is possible that some videos or annotations may contain issues.\n\n## What you learn\n\n1. **Load & Inspect**: Understand the file structure and load metadata from labels.csv.\n\n2. **Parse Annotations**: Handle GZipped JSON files to extract object detections, collision events, and sensor data. Align annotation timestamps with video frames.\n\n3. **Visualize**: Render a fully annotated video showing object tracking and collision events in real-time.","metadata":{}},{"id":"cada5e17604f88d5","cell_type":"markdown","source":"# Step 1: Environment Setup","metadata":{}},{"id":"bfb6df7cd5643ef1","cell_type":"code","source":"import os\nimport os.path as osp\nimport json\nimport gzip\nimport yaml\nimport random\nimport cv2\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom collections import defaultdict, deque\nfrom typing import Any\n\n# Setting the path to the dataset\nSIM_DATASET_PATH = \"/kaggle/input/accident/sim_dataset\"\nis_kaggle = True\n","metadata":{"ExecuteTime":{"end_time":"2026-02-11T12:52:11.973085953Z","start_time":"2026-02-11T12:52:11.964786577Z"},"trusted":true,"execution":{"iopub.status.busy":"2026-02-11T13:03:48.349084Z","iopub.execute_input":"2026-02-11T13:03:48.349422Z","iopub.status.idle":"2026-02-11T13:03:48.356075Z","shell.execute_reply.started":"2026-02-11T13:03:48.349395Z","shell.execute_reply":"2026-02-11T13:03:48.354896Z"}},"outputs":[],"execution_count":null},{"id":"4bca26987e381f0a","cell_type":"markdown","source":"### Utility Functions\n\nThe annotations are stored in compressed JSON format and YAML configuration files.","metadata":{}},{"id":"dbc43f7dd9420694","cell_type":"code","source":"def load_json(path: str, use_gzip: bool = True) -> Any:\n    \"\"\"Loads JSON/GZipped JSON annotations.\"\"\"\n    if use_gzip:\n        with gzip.open(path, 'rt', encoding=\"ascii\") as zipfile:\n            return json.load(zipfile)\n    with open(path, \"r\") as fp:\n        return json.load(fp)\n\n\ndef load_yaml(path: str) -> Any:\n    \"\"\"Loads project configuration metadata.\"\"\"\n    with open(path, \"r\") as fp:\n        return yaml.safe_load(fp)\n","metadata":{"ExecuteTime":{"end_time":"2026-02-11T12:52:12.031606570Z","start_time":"2026-02-11T12:52:11.974565988Z"},"trusted":true,"execution":{"iopub.status.busy":"2026-02-11T13:03:48.358426Z","iopub.execute_input":"2026-02-11T13:03:48.358725Z","iopub.status.idle":"2026-02-11T13:03:48.382183Z","shell.execute_reply.started":"2026-02-11T13:03:48.358699Z","shell.execute_reply":"2026-02-11T13:03:48.380787Z"}},"outputs":[],"execution_count":null},{"id":"62f5f001c2e8f817","cell_type":"markdown","source":"# Step 2: Data Inspection\nThe dataset metadata is stored in labels.csv. This file acts as the central index, mapping video files to their annotations and providing high-level summary statistics for each scenario.\n\n### DataFrame Schema\n\nThe sim_df dataframe contains the following columns:\n\n| Category        | Column                   | Description                                                                                                          |\n|-----------------|--------------------------|----------------------------------------------------------------------------------------------------------------------|\n| Files           | rgb_path                 | Relative path to the raw video file (.mp4).                                                                          |\n|                 | annotations_path         | Relative path to the compressed annotation file (.json.gz).                                                          |\n| Scenario        | type                     | The category of accident simulated (e.g., t-bone, sideswipe).                                                        |\n|                 | map                      | The CARLA town/map ID where the simulation took place.                                                               |\n|                 | weather                  | Environmental conditions: clear, rain, wet, sunset, night.                                                           |\n|                 | camera_position          | Unique identifier for the camera placement (viewpoint).                                                              |\n| Timing          | accident_frame           | The exact frame index where the collision impact occurs.                                                             |\n|                 | accident_time            | The timestamp (in seconds) of the collision.                                                                         |\n|                 | duration                 | Total duration of the video clip in seconds.                                                                         |\n|                 | no_frames                | Total number of frames in the video.                                                                                 |\n| Synchronization | annotations_start_offset | The integer difference between the simulation _tick_ and the video frame 0. Used to align JSON data with MP4 frames. |\n| Spatial         | center_x, center_y       | Normalized pixel coordinates (x, y) representing the center of the collision impact.                                  |\n|                 | x1, y1, x2, y2           | Normalized 2D bounding box coordinates encompassing the collision event.                                             |\n| Video           | height, width            | Resolution of the video file (pixel dimensions).                                                                     |\n","metadata":{}},{"id":"5a1a62a84856ff98","cell_type":"code","source":"sim_df = pd.read_csv(osp.join(SIM_DATASET_PATH, \"labels.csv\"))\nprint(f\"Total Videos: {len(sim_df)}\")\nsim_df.head()","metadata":{"ExecuteTime":{"end_time":"2026-02-11T12:52:12.120766779Z","start_time":"2026-02-11T12:52:12.054961214Z"},"trusted":true,"execution":{"iopub.status.busy":"2026-02-11T13:03:48.383274Z","iopub.execute_input":"2026-02-11T13:03:48.383608Z","iopub.status.idle":"2026-02-11T13:03:48.442468Z","shell.execute_reply.started":"2026-02-11T13:03:48.383550Z","shell.execute_reply":"2026-02-11T13:03:48.441320Z"}},"outputs":[],"execution_count":null},{"id":"cb25ecac5c9fdaf5","cell_type":"markdown","source":"### Dataset statistics","metadata":{}},{"id":"d856a95195a6fb20","cell_type":"code","source":"sns.set_style(\"whitegrid\")\nfig, axes = plt.subplots(1, 3, figsize=(20, 5))\n\nsns.countplot(y=\"type\", hue=\"type\", data=sim_df, ax=axes[0], order=sim_df['type'].value_counts().index, palette=\"viridis\", legend=False)\naxes[0].set_title(\"Distribution of Accident Types\")\naxes[0].set_xlabel(\"Video Count\")\naxes[0].set_ylabel(\"Accident Type\")\n\n\nsns.countplot(x=\"weather\", hue=\"weather\", data=sim_df, ax=axes[1], palette=\"magma\", legend=False)\naxes[1].set_title(\"Distribution of Weather Conditions\")\naxes[1].set_xlabel(\"Weather Type\")\naxes[1].set_ylabel(\"Video Count\")\n\nsns.countplot(x=\"map\", hue=\"map\", data=sim_df, ax=axes[2], palette=\"cubehelix\", legend=False)\naxes[2].set_title(\"Distribution of Simulation Maps\")\naxes[2].set_xlabel(\"Map Name\")\naxes[2].set_ylabel(\"Video Count\")\n\nplt.tight_layout()\nplt.show()\n","metadata":{"ExecuteTime":{"end_time":"2026-02-11T12:52:12.381824259Z","start_time":"2026-02-11T12:52:12.180268347Z"},"trusted":true,"execution":{"iopub.status.busy":"2026-02-11T13:03:48.443738Z","iopub.execute_input":"2026-02-11T13:03:48.444023Z","iopub.status.idle":"2026-02-11T13:03:49.033083Z","shell.execute_reply.started":"2026-02-11T13:03:48.443996Z","shell.execute_reply":"2026-02-11T13:03:49.031786Z"}},"outputs":[],"execution_count":null},{"id":"d5e28d93d63ff481","cell_type":"code","source":"fig, ax = plt.subplots(1, 1, figsize=(20, 5))\n\nsns.histplot(\n    data=sim_df,\n    x=\"accident_time\",\n    kde=True,\n    color=\"teal\",\n    bins=50\n)\n\nax.set_title(\"Distribution of Accident Timing (Seconds into Video)\", fontsize=14, pad=15)\nax.set_xlabel(\"Time of Accident (Seconds)\", fontsize=12)\nax.set_ylabel(\"Number of Videos\", fontsize=12)\n\nmean_time = sim_df[\"accident_time\"].mean()\nax.axvline(mean_time, color='red', linestyle='--', label=f'Mean: {mean_time:.2f}s')\n\nmedian_time = sim_df[\"accident_time\"].median()\nax.axvline(median_time, color='orange', linestyle='--', label=f'Median: {median_time:.2f}s')\nax.legend()\n\nplt.tight_layout()\nplt.show()\n","metadata":{"ExecuteTime":{"end_time":"2026-02-11T12:52:12.662738418Z","start_time":"2026-02-11T12:52:12.504198331Z"},"trusted":true,"execution":{"iopub.status.busy":"2026-02-11T13:03:49.036005Z","iopub.execute_input":"2026-02-11T13:03:49.036343Z","iopub.status.idle":"2026-02-11T13:03:49.438001Z","shell.execute_reply.started":"2026-02-11T13:03:49.036313Z","shell.execute_reply":"2026-02-11T13:03:49.437026Z"}},"outputs":[],"execution_count":null},{"id":"9b10a96785baa24b","cell_type":"markdown","source":"# Step 3: Annotations Parsing\n\nThe dataset provides three distinct layers of data within each JSON:\n\n1. **Base** (```base```): Frame-by-frame 2D/3D bounding boxes and vehicle IDs.\n\n2. **Collision** (```collision```): Specific frames identifying the accident.\n\n3. **Sensor** (```sensor```): Static camera extrinsic data (Rotation/Location).","metadata":{}},{"id":"14ff36793652f05a","cell_type":"code","source":"# Select a random sample for visualization\nsample_index = random.randint(0, len(sim_df) - 1)\nsample = sim_df.iloc[sample_index]\n\nvideo_path = osp.join(SIM_DATASET_PATH, sample[\"rgb_path\"])\n\nif is_kaggle:  # Kaggle unzips the .gz files implicitly\n    annotations_path = osp.join(SIM_DATASET_PATH, sample[\"annotations_path\"])\n    annotations_path = annotations_path.removesuffix(\".gz\")\n    annotations_path = osp.join(annotations_path, osp.basename(annotations_path))\nelse:\n    annotations_path = osp.join(SIM_DATASET_PATH, sample[\"annotations_path\"])\n\nprint(f\"Annotation file path: {annotations_path}\")\n\n# Parse the annotation components\nannotations = load_json(annotations_path, use_gzip=not is_kaggle)\nbase = annotations[\"base\"]           # Frame object detections\ncollision = annotations[\"collision\"] # Collision event\nsensor = annotations[\"sensor\"]       # Camera sensor placement\n\nannotations_offset = sample[\"annotations_start_offset\"]\n","metadata":{"ExecuteTime":{"end_time":"2026-02-11T12:52:12.832497380Z","start_time":"2026-02-11T12:52:12.729617181Z"},"trusted":true,"execution":{"iopub.status.busy":"2026-02-11T13:03:49.439248Z","iopub.execute_input":"2026-02-11T13:03:49.439743Z","iopub.status.idle":"2026-02-11T13:03:49.693886Z","shell.execute_reply.started":"2026-02-11T13:03:49.439708Z","shell.execute_reply":"2026-02-11T13:03:49.692818Z"}},"outputs":[],"execution_count":null},{"id":"47d4eebe045997c5","cell_type":"markdown","source":"We must subtract the ```annotations_start_offset``` from the simulation ```iteration``` to align data with video frame ```0```.","metadata":{}},{"id":"a0bd809982ec398e","cell_type":"code","source":"# Map object detections to specific frames\nframe_detections = {\n    frame_annotations[\"iteration\"] - annotations_offset: frame_annotations[\"objects\"]\n    for frame_annotations in base\n}\n\n# Map collision event to specific frames\ncollision_data = {}\nfor frame_collisions in collision:\n    frame_index = frame_collisions[\"iteration\"] - annotations_offset\n    collision_data[frame_index] = {\n        \"collision_bbox\": frame_collisions[\"collision_bbox\"],\n        \"ids\": frame_collisions[\"ids\"],\n    }\n","metadata":{"ExecuteTime":{"end_time":"2026-02-11T12:52:12.925265972Z","start_time":"2026-02-11T12:52:12.862433507Z"},"trusted":true,"execution":{"iopub.status.busy":"2026-02-11T13:03:49.695406Z","iopub.execute_input":"2026-02-11T13:03:49.696140Z","iopub.status.idle":"2026-02-11T13:03:49.710102Z","shell.execute_reply.started":"2026-02-11T13:03:49.696106Z","shell.execute_reply":"2026-02-11T13:03:49.708845Z"}},"outputs":[],"execution_count":null},{"id":"d555c13863055262","cell_type":"markdown","source":"## Detection data\n\nDetection data for a single frame consists of a list of detected objects. Each object represents one actor in the simulation that is visible from the camera.\n\nEach detection contains the following fields:\n- **id**:  Unique identifier of the actor in the simulation environment.\n- **tag**:  Numeric class label of the actor.\n- **location**: 3D coordinates (x, y, and z) of the center of the actor in the simulation world coordinate system.\n- **extent**:  3D vector (x, y, and z)defining half the size of the actor's bounding box, measured from the actor's center to one of its vertices.\n- **rotation**:  Orientation (pith, yaw, and roll angles) of the actor's 3D bounding box.\n- **2d_bbox**: Pixel-space bounding box [[x1, y1], [x2, y2]] obtained by projecting the 3D bounding box to the 2D camera view plane.\n\nThe location, extent, and rotation fully describe the actor's position the 3D simulation environment.\n","metadata":{}},{"id":"976ee31f91caf750","cell_type":"code","source":"frame_detections[0]","metadata":{"ExecuteTime":{"end_time":"2026-02-11T12:52:13.056557514Z","start_time":"2026-02-11T12:52:13.002600250Z"},"trusted":true,"execution":{"iopub.status.busy":"2026-02-11T13:03:49.711241Z","iopub.execute_input":"2026-02-11T13:03:49.712234Z","iopub.status.idle":"2026-02-11T13:03:49.735198Z","shell.execute_reply.started":"2026-02-11T13:03:49.712202Z","shell.execute_reply":"2026-02-11T13:03:49.734250Z"}},"outputs":[],"execution_count":null},{"id":"d355b2a9cea8a08d","cell_type":"markdown","source":"## Collision data\n\nCollision data describes frames in which a collision occurs, along with subsequent frames capturing the aftermath of the incident.\n\nEach collision frame contains the following fields:\n- **collision_bbox**:  Pixel-space circumferential bounding box [[x1, y1], [x2, y2]] with the actors involved in the incident.\n- **ids**: List of unique identifiers of actors involved in the accident.\n\nThe collision_bbox may change over time as the involved actors move or separate following the impact.","metadata":{}},{"id":"5f490d5081efb148","cell_type":"code","source":"for accident_frame, accident_data in collision_data.items():\n    print(f\"Frame index\", accident_frame)\n    print(accident_data)\n    break","metadata":{"ExecuteTime":{"end_time":"2026-02-11T12:52:13.120016802Z","start_time":"2026-02-11T12:52:13.057064539Z"},"trusted":true,"execution":{"iopub.status.busy":"2026-02-11T13:03:49.736773Z","iopub.execute_input":"2026-02-11T13:03:49.737479Z","iopub.status.idle":"2026-02-11T13:03:49.755506Z","shell.execute_reply.started":"2026-02-11T13:03:49.737449Z","shell.execute_reply":"2026-02-11T13:03:49.754496Z"}},"outputs":[],"execution_count":null},{"id":"b54d33942f841990","cell_type":"markdown","source":"## Sensor data\n\nSensor data provide information about the camera sensor position in the simulation world coordinate system.\nThe sensor object contains the following fields:\n- **location**: 3D coordinates (x, y, and z) of the camera.\n- **rotation**:  Orientation (pith, yaw, and roll angles) of the camera.\n","metadata":{}},{"id":"8b7d88038ad221ea","cell_type":"code","source":"sensor","metadata":{"ExecuteTime":{"end_time":"2026-02-11T12:52:13.184068305Z","start_time":"2026-02-11T12:52:13.127905503Z"},"trusted":true,"execution":{"iopub.status.busy":"2026-02-11T13:03:49.756528Z","iopub.execute_input":"2026-02-11T13:03:49.756904Z","iopub.status.idle":"2026-02-11T13:03:49.777867Z","shell.execute_reply.started":"2026-02-11T13:03:49.756874Z","shell.execute_reply":"2026-02-11T13:03:49.776304Z"}},"outputs":[],"execution_count":null},{"id":"f6b210fff5f66d7c","cell_type":"markdown","source":"## Tag-Class mapping\n\nLoad the file with tag to class mapping.","metadata":{}},{"id":"2442357ebf73d44f","cell_type":"code","source":"cls_mapping = load_yaml(path=osp.join(SIM_DATASET_PATH, \"annotation_classes.yaml\"))\ntag_to_cls_mapping = cls_mapping[\"names\"]","metadata":{"ExecuteTime":{"end_time":"2026-02-11T12:52:13.233949641Z","start_time":"2026-02-11T12:52:13.184656369Z"},"trusted":true,"execution":{"iopub.status.busy":"2026-02-11T13:03:49.779439Z","iopub.execute_input":"2026-02-11T13:03:49.779778Z","iopub.status.idle":"2026-02-11T13:03:49.801988Z","shell.execute_reply.started":"2026-02-11T13:03:49.779746Z","shell.execute_reply":"2026-02-11T13:03:49.800806Z"}},"outputs":[],"execution_count":null},{"id":"aeb301102ceba061","cell_type":"markdown","source":"# Step 4: Visualization: Rendering Annotations\n\nThe following function overlays three layers of information onto the video:\n\n1. **Blue Boxes**: Standard object detections with class labels and IDs.\n2. **RED Lines**: Unique object tracklets.\n3. **Magenta Boxes**: Detected collision.","metadata":{}},{"id":"304dbce6a5d960a4","cell_type":"code","source":"def draw_tracks_on_video(\n    video_path: str,\n    frame_detections: list[dict[int, dict]],\n    collision_data: list[dict[int, dict]],\n    output_path: str,\n    tag_to_cls_mapping: dict[int, str],\n    thickness: int = 2,\n    tracklet_length: int = 10000\n) -> None:\n    \"\"\"\n        Renders object detection bounding boxes, class labels, motion trajectories,\n        and collision events onto a video file.\n\n        Args:\n            video_path: Path to the source MP4/RGB video file.\n            frame_detections: Dictionary mapping frame indices to a list of object\n                detections, where each detection contains '2d_bbox', 'id', and 'tag'.\n            collision_data: Dictionary mapping frame indices to collision metadata,\n                specifically 'collision_bbox' and involved actor 'ids'.\n            output_path: Destination path for the annotated video file.\n            tag_to_cls_mapping: Dictionary mapping integer class tags to\n                human-readable string labels (e.g., {0: \"Car\", 1: \"Pedestrian\"}).\n            thickness: Line thickness for bounding boxes and trajectory lines.\n            tracklet_length: Maximum number of previous center-points to keep in\n                memory for drawing motion tracklets.\n\n        Returns:\n            None. The result is written directly to the file specified in output_path.\n        \"\"\"\n    cap = cv2.VideoCapture(video_path)\n    if not cap.isOpened():\n        raise RuntimeError(f\"Failed to open video: {video_path}\")\n\n    fps = cap.get(cv2.CAP_PROP_FPS)\n    width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))\n    height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))\n\n    fourcc = cv2.VideoWriter_fourcc(*\"mp4v\")\n    writer = cv2.VideoWriter(output_path, fourcc, fps, (width, height))\n\n    track_history = defaultdict(lambda: deque(maxlen=tracklet_length))\n\n    frame_idx = 0\n\n    while True:\n        ret, frame = cap.read()\n        if not ret:\n            break\n\n\n        if 0 <= frame_idx < len(frame_detections):\n            detections = frame_detections[frame_idx]\n\n            for detection in detections:\n                bbox = detection[\"2d_bbox\"]\n                track_id = detection[\"id\"]\n                tag = detection[\"tag\"]\n\n                x1, y1, x2, y2 = bbox[0][0], bbox[0][1], bbox[1][0], bbox[1][1]\n                cx = int((x1 + x2) / 2)\n                cy = int((y1 + (y2 - y1) * 0.8))\n                track_history[track_id].append((cx, cy))\n\n                # --- draw detection bbox (blue) ---\n                cv2.rectangle(\n                    frame,\n                    (x1, y1),\n                    (x2, y2),\n                    color=(255, 0, 0), # BGR\n                    thickness=thickness,\n                )\n                # --- draw tag label ---\n                label = f\"{tag_to_cls_mapping[tag]}: {track_id}\"\n                font = cv2.FONT_HERSHEY_SIMPLEX\n                font_scale = 0.5\n                font_thickness = 1\n\n\n                (tw, th), baseline = cv2.getTextSize(\n                    label, font, font_scale, font_thickness\n                )\n                # top-left of label background\n                lx1 = x1\n                ly1 = max(y1 - th - baseline - 4, 0)\n                lx2 = x1 + tw + 4\n                ly2 = ly1 + th + baseline + 4\n\n                # label background\n                cv2.rectangle(\n                    frame,\n                    (lx1, ly1),\n                    (lx2, ly2),\n                    color=(255, 0, 0),\n                    thickness=-1,\n                )\n\n                # label text\n                cv2.putText(\n                    frame,\n                    label,\n                    (lx1 + 2, ly2 - baseline - 2),\n                    font,\n                    font_scale,\n                    color=(255, 255, 255),\n                    thickness=font_thickness,\n                    lineType=cv2.LINE_AA,\n                )\n\n            if frame_idx in collision_data.keys():\n                bbox = collision_data[frame_idx][\"collision_bbox\"]\n                x1, y1, x2, y2 = bbox[0][0], bbox[0][1], bbox[1][0], bbox[1][1]\n\n                cv2.rectangle(\n                    frame,\n                    (x1, y1),\n                    (x2, y2),\n                    color=(255, 0, 255),\n                    thickness=thickness,\n                )\n\n        for track_id, points in track_history.items():\n            if len(points) < 2:\n                continue\n\n            for i in range(1, len(points)):\n                cv2.line(\n                    frame,\n                    points[i - 1],\n                    points[i],\n                    color=(0, 0, 255),\n                    thickness=thickness,\n                )\n\n        writer.write(frame)\n        frame_idx += 1\n\n    cap.release()\n    writer.release()","metadata":{"ExecuteTime":{"end_time":"2026-02-11T12:52:13.297417959Z","start_time":"2026-02-11T12:52:13.240552614Z"},"trusted":true,"execution":{"iopub.status.busy":"2026-02-11T13:03:49.803354Z","iopub.execute_input":"2026-02-11T13:03:49.803741Z","iopub.status.idle":"2026-02-11T13:03:49.829885Z","shell.execute_reply.started":"2026-02-11T13:03:49.803697Z","shell.execute_reply":"2026-02-11T13:03:49.828237Z"}},"outputs":[],"execution_count":null},{"id":"79b5be84e39b1983","cell_type":"code","source":"annotated_video_output_path = osp.join(\".\", \"annotated.mp4\")\ndraw_tracks_on_video(\n    video_path=video_path,\n    frame_detections=frame_detections,\n    collision_data=collision_data,\n    output_path=annotated_video_output_path,\n    tag_to_cls_mapping=tag_to_cls_mapping,\n)","metadata":{"ExecuteTime":{"end_time":"2026-02-11T12:52:18.888593241Z","start_time":"2026-02-11T12:52:13.297939394Z"},"trusted":true,"execution":{"iopub.status.busy":"2026-02-11T13:04:23.831072Z","iopub.execute_input":"2026-02-11T13:04:23.831448Z","iopub.status.idle":"2026-02-11T13:04:35.550937Z","shell.execute_reply.started":"2026-02-11T13:04:23.831416Z","shell.execute_reply":"2026-02-11T13:04:35.549250Z"}},"outputs":[],"execution_count":null},{"id":"0a82eb91-bc9c-441d-9925-566219b5936c","cell_type":"code","source":"# Re-encode to H.264 using FFmpeg\nannotated_video_recoded = osp.join(\".\", \"final_annotated.mp4\")\nos.system(f\"ffmpeg -i {annotated_video_output_path} -vcodec libx264 -f mp4 {annotated_video_recoded} -y\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-11T13:04:35.553214Z","iopub.execute_input":"2026-02-11T13:04:35.553919Z","iopub.status.idle":"2026-02-11T13:04:57.895333Z","shell.execute_reply.started":"2026-02-11T13:04:35.553875Z","shell.execute_reply":"2026-02-11T13:04:57.894081Z"}},"outputs":[],"execution_count":null},{"id":"517bb230cdadb520","cell_type":"code","source":"from IPython.display import Video, display\n\n\nif osp.exists(annotated_video_recoded):\n    display(Video(\n        annotated_video_recoded,\n        width=800,\n        embed=True,\n    ))\nelse:\n    print(\"Video file not found. Check the output path.\")","metadata":{"ExecuteTime":{"end_time":"2026-02-11T12:52:19.336884084Z","start_time":"2026-02-11T12:52:18.940259909Z"},"trusted":true,"execution":{"iopub.status.busy":"2026-02-11T13:04:57.896501Z","iopub.execute_input":"2026-02-11T13:04:57.896779Z","iopub.status.idle":"2026-02-11T13:04:58.085022Z","shell.execute_reply.started":"2026-02-11T13:04:57.896755Z","shell.execute_reply":"2026-02-11T13:04:58.084065Z"}},"outputs":[],"execution_count":null}]}