Skip to main content
You detect objects in images and video frames, filter by object class, and draw the bounding boxes. What’s in this recipe:
  • Preview YOLOX detections and save them for each image
  • Query images and video frames by COCO class id
  • Draw detections and assemble annotated frames into a video

Problem

You have images or videos and need to find objects such as people and cars. You want to query which images or frames contain those objects and inspect their bounding boxes.

Solution

You use YOLOX, an anchor-free object detector, to return a box around each detected object. pixeltable.functions.yolox.yolox() runs one of yolox_nano, yolox_tiny, yolox_s, yolox_m, yolox_l, or yolox_x on an image. On a video, frame_iterator() makes one row per frame, and the same function runs on frame. The call belongs in a computed column, so an insert stores the boxes with the row. Weights come from pixeltable-yolox. This UDF runs on CPU. You use the Query-then-Commit pattern: preview detections with a query on a few rows, then save the same expression with add_computed_column() to process every row.

Setup

You need Python 3.11 or newer. You run these snippets in a notebook or Python REPL.

Load images

Each run creates a fresh catalog directory. The video example uses the same demo namespace.

Detect objects in an image table

yolox() returns three lists of equal length:
  • bboxes: [xmin, ymin, xmax, ymax] in pixels
  • scores: confidence from 0 to 1, already filtered by threshold (default 0.5)
  • labels: COCO class ids. 0 is person and 2 is car. Names are yolox.data.datasets.COCO_CLASSES.
bboxes_draw() paints those boxes onto the image. You pass the class names so the label text reads person.

Test image detection with a query

You preview detections on two images before saving a computed column.

Commit changes with a computed column

You save the same expression, then add class names and annotated images.

Query the detections

threshold drops low-confidence boxes inside yolox(). labels.contains() keeps rows that include a class id. This keeps images with a person (0):
0.8 returns fewer boxes. 0.25 returns more. Model-size tradeoffs are in Detect objects in images. Box color and fill are in Visualize object detections.

Detect objects in video frames

frame_iterator() adds frame, frame_attrs, and pos. fps=1.0 extracts one frame per second. If you set fps above the video’s own rate, the iterator returns every frame. Adding the detection column runs yolox() on each extracted frame. yolox_tiny is the smaller model. yolox_m and yolox_x are the larger ones.
You preview detections on two frames, then save the same expression for all frames.
Frames that contain a car (COCO id 2):
make_video() stitches the annotated frames back into one clip. pos is each frame’s place in the view. fps=1 plays those frames at one per second, the same spacing frame_iterator() used.
num_frames and keyframes_only are documented on Iterators and in Extract frames from videos. Comparing yolox_tiny, yolox_m, and yolox_x with mean average precision is in Object detection in videos. yolo_to_coco() converts bboxes and labels to COCO annotations: bbox as [x, y, width, height], plus category.

In an application

These snippets call pxt.create_table() and add_computed_column() so you can run them in a notebook or a REPL. An application declares the same columns on a TableModel in app.py and creates them with pxt schema update. For use from a script or across sessions, you define class_names() in an importable module and import it.

See also

Last modified on October 15, 2026