Every major CV framework needs coordinates before it can run.
regioncounter = RegionCounter(region=[120, 80, 640, 480]) # YOLO — where does this region come from?
predictor.predict(box=np.array([120, 80, 640, 480])) # SAM2/SAM3 — same problemThe standard workflow: open CVAT or Roboflow → grab coordinates → paste them back into code. Every. Single. Time.
import pixpick
region = pixpick.box("video.mp4", frame=10) # drag a box on a specific video frame
zone = pixpick.polygon("image.jpg") # click polygon vertices
# coordinates are ready — unpack directly into any framework
# YOLO:
regioncounter = RegionCounter(
region=zone.yolo_region(), # pass region points
model="yolo26n.pt",
)
# same for YOLOE
model.predict("image.jpg", visual_prompt= region.yolo_prompt())
# SAM/SAM2/SAM3:
predictor.predict(box=region.sam())A window opens on your image, video, or a specific video frame. You interact. You get framework-ready coordinates back in Python. No round-trips.
pixpick.box() and pixpick.polygon() both accept a frame= argument when the source is a video file.
pip install pixpick| Selector | How to use | Returns |
|---|---|---|
pixpick.box() |
Left-click + drag | Box |
pixpick.polygon() |
Click vertices → Enter to confirm |
Polygon |
Box controls — drag to draw · R to reset · Esc to cancel
Polygon controls — LMB add point · RMB undo · Z clear · Enter confirm · Esc cancel
Every selection object carries all the formats you'll ever need.
# ── Box ──────────────────────────────────────────────────────
region = pixpick.box("frame.jpg")
region.xyxy # [x1, y1, x2, y2] absolute pixels
region.xywh # [x, y, w, h] absolute pixels
region.norm_xywh # [x, y, w, h] 0.0 – 1.0 ← YOLO label format
region.center # (cx, cy)
region.area # pixels²
# ── Polygon ───────────────────────────────────────────────────
zone = pixpick.polygon("frame.jpg")
zone.points # [(x0,y0), (x1,y1), ...] absolute pixels
zone.as_numpy # np.array shape (N, 2)
zone.norm # [(x0n,y0n), ...] 0.0 – 1.0
zone.bbox # → Box tight bbox around the polygon
zone.npoints # intFor more details, see Selectors.
| Framework | Selector | Method |
|---|---|---|
| Ultralytics YOLOE — visual prompt | Box |
region.yolo_prompt() |
| Ultralytics YOLO — region | Box/Polygon |
region.yolo_region() |
| SAM / SAM2 / SAM3 — box prompt | Box |
region.sam() |
| Any other format | Box / Polygon |
region.raw() |
Pick once, reuse forever.
region.save("zone.json")
region = pixpick.load("zone.json") # Box and Polygon both workProduction pattern — pick interactively the first time, load on every subsequent run:
from pathlib import Path
import pixpick
ZONE = "config/count_zone.json"
zone = pixpick.load(ZONE) if Path(ZONE).exists() else pixpick.polygon("frame.jpg")
zone.save(ZONE)| 🚀 Getting Started | Installation, first selection, controls |
| 🎯 Selectors | All properties and methods for Box and Polygon |
| 🔌 Framework Integration | YOLO, SAM2/SAM3 and more |
| 💾 Persistence | Save, load, JSON schema |
| 🏗️ Architecture | How it's built and how to extend it |
| 🗺️ Roadmap | What's coming next |
We welcome contributions! Please open a GitHub issue or submit a pull request. For more information, see CONTRIBUTING.md.
