Metadata-Version: 2.4
Name: pixpick
Version: 0.2.5
Summary: Draw on the frame. Get the coordinates back in Python.
Author-email: K-saif <khansf466@gmail.com>
Maintainer-email: K-saif <khansf466@gmail.com>
License: MIT
Project-URL: Homepage, https://github.com/K-saif/pixpick
Project-URL: Documentation, https://k-saif.github.io/pixpick/
Project-URL: Bug Tracker, https://github.com/K-saif/pixpick/issues
Keywords: computer-vision,yolo,sam2,sam3,supervision,roi,coordinate-picker,coordinates,visual-prompt
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Scientific/Engineering :: Image Recognition
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: opencv-python>=4.5
Requires-Dist: numpy>=1.21
Dynamic: license-file

<div align="center">

# PixPick

**Draw on the frame. Get the coordinates back in Python.**

Boxes, polygons, lines and points — picked interactively, returned as objects that drop straight into YOLO, SAM and Supervision.

[![PyPI version](https://badge.fury.io/py/pixpick.svg)](https://badge.fury.io/py/pixpick)
[![Downloads](https://static.pepy.tech/badge/pixpick/month)](https://pepy.tech/projects/pixpick)
[![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
[![Documentation](https://img.shields.io/badge/docs-online-blue)](https://k-saif.github.io/pixpick/)

</div>

<img src="https://raw.githubusercontent.com/K-saif/pixpick/main/docs/pixpick_main.png" alt="Project Overview" width="100%">

---
## The problem

Every CV pipeline starts with coordinates you don't have yet.

```python
# YOLO
counter = RegionCounter(region=[(120, 80), (640, 80), (640, 480), (120, 480)])   # where do these come from?

# SAM2 / SAM3
masks = predictor.predict(box=np.array([120, 80, 640, 480]))                     # same question
```

So you do one of three things:

- **Guess and rerun.** Type some numbers, run, squint at the output, nudge, run again.
- **Write the throwaway script.** `cv2.setMouseCallback`, `print(x, y)`, copy from the terminal, paste into the real code, delete the script. Next project — write it again.
- **Open an annotation tool** just to read pixel values off the cursor.

None of that is the work. It's the step everyone hates and nobody automated.

## The fix

```python
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_prompts=dict(bboxes=region.yolo_prompt, cls=classes))

# SAM/SAM2/SAM3:
predictor.predict(box=region.sam)
```

A window opens on your image or video frame. You draw. The coordinates come back as Python objects, already in the shape each framework wants. No terminal copy-paste, no throwaway scripts.

All selectors accept a `frame=` argument when the source is a video file.

---

## Install

```bash
pip install pixpick
```

---

## Selectors

| Selector | How to use | Returns |
|---|---|---|
| `pixpick.box()` | Left-click + drag | `Box` |
| `pixpick.polygon()` | Click vertices | `Polygon` |
| `pixpick.line()` | Click start → click end | `Line` |
| `pixpick.point()` | Click points (fg / bg) | `Point` / `MultiPoint` |

Make several selections in one pass and you get the matching wrapper — `Multibox`, `MultiPolygon`, `MultiLine` or `MultiPoint` — each holding a list of the singular objects.

For more information on controls, see [Getting Started](docs/getting-started.md).

---

## Output formats

Every selection object carries all the formats you'll ever need.

```python
# ── Box ──────────────────────────────────────────────────────
region = pixpick.box("frame.jpg")

region.xyxy              # [x1, y1, x2, y2]            absolute pixels
region.xywh              # [x, y, w, h]                absolute pixels
region.cxcywh            # [cx, cy, w, h]              absolute pixels (YOLO 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                # [x1, y1, x2, y2]  tight bounds around the polygon
zone.npoints             # int


## ── Line ─────────────────────────────────────────────────────
line = pixpick.line("frame.jpg")

line.points              # [(x0,y0), (x1,y1)]           absolute pixels
line.as_numpy            # np.array shape (2, 2)
line.norm                # [(x0n,y0n), (x1n,y1n)]       0.0 – 1.0
line.center              # (cx, cy)
line.length              # pixels
line.vertical            # [(x,y), (x,y)]  same line re-drawn vertically


## ── Point ────────────────────────────────────────────────────
pick = pixpick.point("frame.jpg")        # one click → Point

pick.xy                  # (x, y)                       absolute pixels
pick.label               # 1 = foreground, 0 = background
pick.norm                # (xn, yn)                     0.0 – 1.0
pick.is_foreground       # bool
pick.rescale(640, 640)   # → Point remapped to another resolution
```
For more details, see [Selectors](docs/selectors.md).

---

## Framework integration

| Framework | Selector | Properties |
|---|---|---|
| Ultralytics YOLOE — visual prompt | `Box` | `region.yolo_prompt` |
| Ultralytics YOLO — region | `Box`/`Polygon` | `region.yolo_region` |
| SAM / SAM2 / SAM3 — box prompt | `Box` | `region.sam` |
| SAM / SAM2 / SAM3 — point prompt | `Point` / `MultiPoint` | `picks.sam` |
| Supervision PolygonZone — polygon | `Polygon` | `zone.supervision` |
| Supervision KeyPoints — points | `Point` / `MultiPoint` | `picks.supervision` |
| Any other format | all selectors | `region.raw` |

---

## Persistence

Pick once, reuse forever.

```python
region.save("zone.json")
region = pixpick.load("zone.json")   # Box and Polygon both work
```

Production pattern — pick interactively the first time, load on every subsequent run:

```python
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)
```

---

## Docs

| | |
|---|---|
| 🚀 [Getting Started](https://github.com/K-saif/pixpick/blob/main/docs/getting-started.md) | Installation, first selection, controls |
| 🎯 [Selectors](https://github.com/K-saif/pixpick/blob/main/docs/selectors.md) | All properties and methods for Box and Polygon |
| 🔌 [Framework Integration](https://github.com/K-saif/pixpick/blob/main/docs/frameworks.md) | YOLO, SAM2/SAM3 and more |
| 💾 [Persistence](https://github.com/K-saif/pixpick/blob/main/docs/persistence.md) | Save, load, JSON schema |
| 🏗️ [Architecture](https://github.com/K-saif/pixpick/blob/main/docs/architecture.md) | How it's built and how to extend it |
| 🗺️ [Roadmap](https://github.com/K-saif/pixpick/blob/main/docs/roadmap.md) | What's coming next |


---

## Contributing

We welcome contributions! Please open a GitHub issue or submit a pull request. For more information, see [Contribution Guidelines](https://github.com/K-saif/pixpick/blob/main/docs/CONTRIBUTING.md).

<a href="https://github.com/k-saif/pixpick/graphs/contributors">
  <img src="https://contrib.rocks/image?repo=k-saif/pixpick" />
</a>
