Skip to content

Selectors

A selector opens a UI, captures user input, and returns a typed Selection object. The selection object holds all coordinate math and framework conversion methods.

Every selector accepts an image path, a video path, or a BGR numpy array, and takes frame= to choose the video frame.

Each selector returns a single object when you make one selection, and a Multi* wrapper when you make several. Every Multi* type holds a list of the singular objects and exposes the same properties, returning one entry per item.

Selector Returns (one) Returns (several)
pixpick.box() Box Multibox
pixpick.polygon() Polygon MultiPolygon
pixpick.line() Line MultiLine
pixpick.point() Point MultiPoint

Box

region = pixpick.box("video.mp4", frame=10)

Drag a rectangle. Drag again to add more — pixpick.box() returns a Box for one rectangle and a Multibox for several. Reversed drags are normalised, so x1 < x2 and y1 < y2 always hold.

Properties

Property Description
xyxy [x1, y1, x2, y2] absolute pixels
xywh [x, y, w, h] absolute pixels
cxcywh [cx, cy, w, h] absolute pixels (YOLO format)
norm [x1, y1, x2, y2] 0.0 – 1.0
norm_xywh [x, y, w, h] 0.0 – 1.0 normalised absolute pixels
center (cx, cy) absolute pixels
area int pixels²
as_numpy np.array shape (4,) int32

Framework properties

Property Description
yolo_region [(x1,y1), (x2,y1), (x2,y2), (x1,y2)] — the four corners, for YOLO region arguments
yolo_prompt np.array shape (1, 4) — YOLOE bboxes visual prompt
sam [x1, y1, x2, y2] — SAM box prompt
raw dict with all coordinate formats in one place

Visualise

canvas = region.visualize(image)                          # default green
canvas = region.visualize(image, color=(0,0,255), thickness=2)
cv2.imshow("result", canvas)
cv2.waitKey(0)

Persistence

region.save("selection.json")
region = pixpick.load("selection.json")   # or Box.load("selection.json")

Multi-box results

region = pixpick.box("image.jpg")

region.boxes        # [Box(...), Box(...), ...]   ← real Box objects
region.xyxy         # [[x1, y1, x2, y2], ...]
region.center       # [(cx, cy), ...]
region.as_numpy     # np.array shape (N, 4) int32
region.yolo_prompt  # np.array shape (N, 4)
region.nboxes       # int

region.boxes[0].area                # every Box property is available per box
region.boxes[0].visualize(image)

Build one from Box objects, not raw coordinates — raw lists raise TypeError:

Multibox(
    boxes=[Box(x1=100, y1=50, x2=400, y2=300, image_width=1920, image_height=1080)],
    image_width=1920,
    image_height=1080,
)

Polygon

zone = pixpick.polygon("video.mp4", frame=10)

Click vertices in order. Minimum 3 points before Enter confirms. Press Space to bank the current polygon and start another — several polygons return a MultiPolygon.

Properties

Property Description
points list of (x, y) tuples, absolute pixels
as_numpy np.array shape (N, 2) int32
norm list of (x, y) tuples, 0.0 – 1.0
norm_numpy np.array shape (N, 2) float32
npoints int
bbox Box — tight box around every point
image_width / image_height int — source image size

Framework properties

Property Description
yolo_region the vertex list, for YOLO region arguments
supervision {"polygon": np.array} — unpack into sv.PolygonZone(**zone.supervision)
raw dict with all coordinate formats in one place

Visualise

canvas = zone.visualize(image)                        # default green, 15% fill
canvas = zone.visualize(image, color=(0,0,255), fill_alpha=0.3)

Persistence

zone.save("zone.json")
zone = pixpick.load("zone.json")   # or Polygon.load("zone.json")

Multi-polygon results

zones = pixpick.polygon("frame.jpg")

zones.polygons      # [Polygon(...), Polygon(...), ...]  ← real Polygon objects
zones.as_numpy      # [np.array (N,2), np.array (N,2), ...]  one array per polygon
zones.norm          # [[(x0n,y0n), ...], ...]
zones.npoints       # [int, int, ...]
zones.box           # [[x1,y1,x2,y2], ...]   bounds of each polygon
zones.supervision   # [{"polygon": np.array}, ...]

zones.polygons[0].npoints           # every Polygon property is available per polygon

Line

line = pixpick.line("image.jpg")

Click the start point, then the end point — that is one line. Keep clicking pairs to add more; several lines return a MultiLine.

Properties

Property Description
points [(x1, y1), (x2, y2)] absolute pixels
start (x1, y1) absolute pixels
end (x2, y2) absolute pixels
center (cx, cy) absolute pixels
length float pixels
vector (dx, dy) from start to end
as_numpy np.array shape (2, 2) int32
norm [(x1n, y1n), (x2n, y2n)] 0.0 – 1.0
norm_numpy np.array shape (2, 2) float32
horizontal [(x, y), (x, y)] — the same line re-drawn horizontally through its centre
vertical [(x, y), (x, y)] — the same line re-drawn vertically through its centre
raw dict with all formats in one place

Note: horizontal and vertical return coordinates, not booleans. They give you a line of the same length, re-aligned through the original's centre — handy for snapping a hand-drawn counting line to an axis.

Visualise

canvas = line.visualize(image)                        # default green
canvas = line.visualize(image, color=(0,0,255), thickness=2)

Persistence

line.save("line.json")
line = pixpick.load("line.json")   # or Line.load("line.json")

Multi-line results

lines = pixpick.line("frame.jpg")

lines.lines          # [Line(...), Line(...), ...]   ← real Line objects
lines.points         # [[(x1,y1), (x2,y2)], ...]
lines.start          # [(x1,y1), ...]
lines.end            # [(x2,y2), ...]
lines.length         # [length1, length2, ...]
lines.center         # [(cx, cy), ...]
lines.as_numpy       # np.array shape (N, 2, 2) int32
lines.nlines         # int

lines.lines[0].center       # every Line property is available per line

MultiLine saves as "type": "multiline" and reloads through pixpick.load().


Point

pick  = pixpick.point("image.jpg")     # one click  → Point
picks = pixpick.point("image.jpg")     # several    → MultiPoint

Left-click marks a foreground point, Shift+left-click marks a background point — the labels SAM uses to include or exclude a region.

Point properties

Property Description
xy (x, y) absolute pixels
label 1 foreground, 0 background
is_foreground / is_background bool
norm (xn, yn) 0.0 – 1.0
as_numpy np.array shape (2,) int32
norm_numpy np.array shape (2,) float32
raw dict with all formats in one place

MultiPoint properties

Property Description
points [Point(...), ...] — real Point objects
xy [(x0, y0), (x1, y1), ...] absolute pixels
labels [1, 0, ...] one per point
foreground / background [Point(...), ...] filtered by label
n_foreground / n_background int
npoints int
centroid (cx, cy) mean of all points
bbox Box — tight box around every point
as_polygon Polygon — the points as a shape (needs 3+)
as_numpy np.array shape (N, 2) int32
norm / norm_numpy normalised, 0.0 – 1.0
raw dict with all formats in one place

Framework properties

Both types expose the same adapters, so code written against one works with the other.

Property Description
sam {"point_coords": (N,2) float32, "point_labels": (N,) int32} — unpack with **
sam_coords the coordinate array on its own
sam_labels the label array on its own
supervision {"xy": (1, N, 2) float32} — unpack into sv.KeyPoints()

Rescale

Pick on a full-resolution frame, run inference on a resized one:

picks_640 = picks.rescale(640, 640)

Visualise

canvas = picks.visualize(image)   # green foreground, red background
canvas = picks.visualize(image, foreground_color=(255,0,0), radius=8)

Persistence

picks.save("picks.json")
picks = pixpick.load("picks.json")   # Point → "point", MultiPoint → "multipoint"

Coming in future releases

Selector Interaction Returns Release
pixpick.perspective() 4-corner click Perspective v0.3.0