Object identification#

Upload a video with the objects a computer vision model found in each frame, such as counts and confidence scores. In a run, the detections chart in sync with the video, and checklists can flag frames that need review.

The examples also need pip install polars huggingface_hub.

Connect the client#

This guide assumes you have installed the client and setup your API keys.

from nominal.core import NominalClient

client = NominalClient.from_profile("default")

Download the sample#

The sample is drone footage annotated by the RT-DETR model, and a CSV with one row per detected object. The video is 225 MB.

import polars as pl
from huggingface_hub import hf_hub_download

repo = {"repo_id": "nominal-io/drone-flight-object-identification", "repo_type": "dataset"}
video_path = hf_hub_download(filename="all_scores_bounding_box_output.mov", **repo)
detections = pl.read_csv(hf_hub_download(filename="object_detection_metadata.csv", **repo))

Each row has the frame number, timestamp, object label, confidence score, bounding box, and per-frame counts such as car_count and total_object_count. The first frame is at 2011-11-11T11:11:11 UTC.

Upload the detections and the video#

Put both in one dataset so they share timestamps. Convert the video first, as in Video ingest:

from datetime import datetime, timezone

from nominal.experimental.video_processing import normalize_video
from nominal.thirdparty.pandas import upload_dataframe

dataset = upload_dataframe(
    client,
    detections.to_pandas(),
    "Drone flight detections",
    "timestamps",
    timestamp_type="iso_8601",
)

normalize_video(video_path, "drone.mp4")
start = datetime(2011, 11, 11, 11, 11, 11, tzinfo=timezone.utc)
dataset.add_video("drone.mp4", channel="rt_detr_video", start=start).poll_until_ingestion_completed()

The video’s start must match the detections’ first timestamp, or the two won’t line up.

Review the detections#

Create a run over the detections’ time range:

end = datetime.fromisoformat(str(detections["timestamps"].max())).replace(tzinfo=timezone.utc)
run = client.create_run("RT-DETR drone analysis", start=start, end=end)
run.add_dataset("rt_detr", dataset)
print(run.nominal_url)

In a workbook on the run, add a video panel for rt_detr_video and charts of the counts and scores.

Detect objects in your own video#

To make a detections table from your own video, read its frames with OpenCV and run a model on each. This example uses RT-DETR from transformers, and needs pip install opencv-python torch transformers pillow. Long videos can take hours.

from datetime import timedelta

import cv2
import torch
from PIL import Image
from transformers import RTDetrForObjectDetection, RTDetrImageProcessor

processor = RTDetrImageProcessor.from_pretrained("PekingU/rtdetr_r50vd")
model = RTDetrForObjectDetection.from_pretrained("PekingU/rtdetr_r50vd")

rows = []
cap = cv2.VideoCapture("my_video.mp4")
while True:
    ok, frame = cap.read()
    if not ok:
        break
    timestamp = start + timedelta(milliseconds=cap.get(cv2.CAP_PROP_POS_MSEC))
    image = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
    with torch.no_grad():
        outputs = model(**processor(images=image, return_tensors="pt"))
    result = processor.post_process_object_detection(
        outputs, target_sizes=torch.tensor([image.size[::-1]]), threshold=0.3
    )[0]
    for score, label in zip(result["scores"], result["labels"]):
        rows.append({"timestamp": timestamp, "object": model.config.id2label[label.item()], "score": score.item()})
cap.release()

detections = pl.DataFrame(rows)

Count objects per frame with Polars, such as detections.group_by("timestamp", "object").len(), and upload the result as above.