DEV Community

Saif Khan
Saif Khan

Posted on

Stop Copy-Pasting Coordinates Into Your CV Pipeline

Every time I needed a coordinates of box, polygon and line for tasks like YOLO RegionCounter, YOLOE visual prompt and SAM box coordinate, I had to do this:

  1. Open CVAT/Roboflow
  2. Upload an image
  3. Draw a region
  4. Copy the coordinates
  5. Go back to VS Code
  6. Paste them in

OR

Write complex opencv code.

All that just to get coordinates.

And then the camera angle shifts slightly, or I want to test a different region, and I repeat the whole thing again.

After doing this enough times I stopped accepting it as normal and started looking for a better way. There wasn't one. So I built it.


CVAT and Label Studio are great — just not for this

Let me be clear: CVAT, Label Studio, Roboflow — these are excellent tools. If you're annotating a dataset with thousands of images, use them.

But when you're iterating on a CV pipeline and you just need the coordinates of one region on one frame, spinning up a full annotation platform is massive overkill. You don't need a project, a task, an annotation job, an export step. You need coordinates and you need them in the next ten seconds.

That's the gap I was trying to fill.


What I built

pip install pixpick
Enter fullscreen mode Exit fullscreen mode
import pixpick

region = pixpick.box("frame.jpg")       # for video ("video.mp4", frame=5)
print(region.xyxy)   # [120, 80, 640, 480]
Enter fullscreen mode Exit fullscreen mode

A window opens on your image. You drag a box. The window closes. You have coordinates.

No accounts, no uploads, no annotation projects. Just Python.


YOLO RegionCounter — the use case that started this

This is the workflow that pushed me to build pixpick.

YOLO's RegionCounter needs a polygon defining the counting zone. Without pixpick:

# where did these coordinates come from? you had to get them somewhere
regioncounter = RegionCounter(region=[120, 80, 640, 480])

Enter fullscreen mode Exit fullscreen mode

With pixpick:

import pixpick

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

regioncounter = RegionCounter(
     region=zone.yolo_region(),  # pass region points
     model="yolo26n.pt",
 )
Enter fullscreen mode Exit fullscreen mode

Click the zone vertices directly on the frame. No mental arithmetic, no pixel hunting.

select region


Real-world use cases

Ultralytics YOLO RegionCounter

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",
 )
Enter fullscreen mode Exit fullscreen mode

SAM / SAM2 box prompt

import pixpick

region = pixpick.box("image.jpg")
predictor.predict(box=region.sam())
Enter fullscreen mode Exit fullscreen mode

YOLOE visual prompt

region = pixpick.box("frame.jpg")
model.predict("frame.jpg", visual_prompt=region.yolo_prompt())
Enter fullscreen mode Exit fullscreen mode

Supervision PolygonZone

import supervision as sv
import pixpick

zone   = pixpick.polygon("frame.jpg")
sv_zone = sv.PolygonZone(polygon=zone.as_numpy)
Enter fullscreen mode Exit fullscreen mode

What formats does it give you?

Every selection object carries all the coordinate formats you'd need — no manual conversion:

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]        ← normalised 0–1 (YOLO label format)
region.center      # (cx, cy)
region.area        # pixels²
region.raw()       # all formats at once as a dict
Enter fullscreen mode Exit fullscreen mode
zone = pixpick.polygon("frame.jpg")

zone.points        # [(x0,y0), (x1,y1), ...]
zone.as_numpy      # np.array shape (N, 2)
zone.norm          # normalised points
zone.bbox          # tight Box around the polygon
zone.npoints       # vertex count
Enter fullscreen mode Exit fullscreen mode

Why not just use OpenCV's selectROI()?

Good question. cv2.selectROI() does let you draw a box interactively. But it has real limitations:

cv2.selectROI() pixpick
Box selection
Polygon selection
Line selection
Normalised coordinates
YOLO format
SAM2 format
Save and reload
Works on arrays limited

selectROI gives you (x, y, w, h). That's it. You then have to convert to xyxy, normalise, reformat for SAM, reformat for Supervision — all manually, every time.


Saving selections and reloading them

This is the feature I didn't know I needed until I had it.

Production pipelines often run the same camera feed indefinitely. You don't want to pick the counting zone every time the script restarts. With pixpick:

from pathlib import Path
import pixpick

ZONE_FILE = "config/zone.json"

if Path(ZONE_FILE).exists():
    zone = pixpick.load(ZONE_FILE)
else:
    zone = pixpick.polygon("video.mp4", frame=5)
    zone.save(ZONE_FILE)

# rest of the pipeline uses zone normally
Enter fullscreen mode Exit fullscreen mode

Pick once. Reload forever. If the camera shifts, delete the JSON and pick again.


Being transparent about why I built this

I didn't build pixpick because I had a grand plan. I built it because I was in the middle of setting up a YOLO RegionCounter and other framewokrs, I got annoyed enough to stop and fix the underlying problem instead of just powering through it.

The library is not trying to replace annotation tools. It's trying to remove one specific friction point that slows down CV engineers during development and iteration.


Current selectors

Selector How Returns
pixpick.box() Left-click and drag Box
pixpick.polygon() Click vertices → Enter to confirm Polygon
pixpick.line() Click two endpoints Line

Controls

Box: drag to draw · Z to reset · Esc to cancel

Polygon: LMB add point · RMB undo last · Z clear · Enter confirm

Line: click start · click end · Z to reset · Esc to cancel


About the 30K downloads

pixpick was released a few weeks ago and has already crossed 30,000 downloads.

I'll be honest — that number surprised me. I built this for myself. But apparently the CVAT round-trip was frustrating enough people that they immediately installed a library the moment it existed.

The download count includes CI bots and mirrors, so the real number is lower. But the GitHub issues, feature requests, and questions that came in after release are real. People are using it for use cases I hadn't even considered when I built it.


Links

pip install pixpick
Enter fullscreen mode Exit fullscreen mode

Give a star If PixPick saves you time, a GitHub star ⭐ would mean a lot.


What's the most repetitive part of your computer vision workflow that you've just accepted as normal? I'd like to know — might be the next thing worth fixing.

Top comments (0)