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