Metadata-Version: 2.4
Name: drawbox-cv
Version: 0.1.1
Summary: A modular, interactive bounding box frame labeler with zoom and pan support.
License: MIT
License-File: LICENSE
Requires-Python: >=3.8
Requires-Dist: numpy>=1.20.0
Requires-Dist: opencv-python>=4.8.0.0
Requires-Dist: pillow>=10.0.0
Description-Content-Type: text/markdown

# DrawBox-CV

A modular, cross-platform, Tkinter-based interactive frame annotator for computer vision datasets. 

DrawBox-CV provides a desktop-based, lightweight interactive labeling GUI (similar to a local Roboflow editor), enabling real-time frame-by-frame labeling with mouse zoom and pan, dynamic color mapping, unlimited custom classes, and multi-format labels export.

---

## Key Features

*   **Pristine Tkinter GUI Engine**: A clean, cross-platform desktop interface that natively supports resizing to fit any monitor resolution.
*   **Interactive Zoom & Pan**:
    *   **Zoom**: Scroll mouse wheel (zoom is centered directly around your mouse cursor).
    *   **Pan**: Drag with **Right-click** to pan and move the canvas.
*   **Bounding Box Editing**:
    *   **Draw**: Click and drag with **Left-click** on an empty area.
    *   **Move**: Drag inside an existing box with **Left-click**.
    *   **Resize**: Drag the white corner handles with **Left-click**.
    *   **Select**: Click a box with **Ctrl + Left-click** to select it and activate its label class.
*   **Visual Selection Indicators**:
    *   Currently selected boxes are drawn with a **Red** outline.
    *   Hovering over any box highlights it in **Gold**.
    *   Automatically assigns unique HSV colors to your classes, strictly avoiding colors close to Red or Gold to prevent confusion.
*   **Instruction Collapsing**: Click the **`▼ Instructions`** or **`▼ Classes`** headers on the sidebars to hide/reveal panels instantly.

---

## Installation

Ensure you have Python 3.8 or newer installed on your system.

### 1. Install System Prerequisites (Linux Only)
On Linux systems (e.g., Ubuntu/Debian), Tkinter requires system-level libraries. Install them via your package manager:
```bash
sudo apt update
sudo apt install python3-tk
```
*(Windows and macOS include Tkinter by default during Python installation).*

### 2. Install Package
You can install `drawbox-cv` using `pip` or `uv`:

#### Using pip:
```bash
pip install drawbox-cv
```

#### Using uv:
```bash
uv add drawbox-cv
```

---

## How to Run

DrawBox-CV can be launched either via Python code or directly from your terminal.

### 1. Running via Python Code (API)

```python
from drawbox import AnnotatorApp, AnnotatorConfig

# 1. Create a configuration for your labeling session
config = AnnotatorConfig(
    frames_dir="path/to/your/images",      # Required: Path to the folder containing your source images (.jpg, .png, etc.)
    output_labels_dir="output",            # Optional: Base directory where all label folders, classes.txt, and crops will be saved. Default is "output".
    start_frame=0,                         # Optional: Frame index to start labeling from. Default is 0.
    initial_label_file="",                 # Optional: Path to a file containing initial labels to load on startup. Default is "".
    initial_label_format="tf",             # Optional: Format of the initial labels file ("tf", "yolo", "coco", "voc"). Default is "tf".
    formats=["yolo"],                      # Optional: List of formats to save simultaneously ("tf", "yolo", "coco", "voc"). Default is ["yolo"].
    save_crops=False,                      # Optional: Crop the annotated bounding boxes and save them into separate subfolders. Default is False.
    crops_out_dir=None,                    # Optional: Custom folder to save crop images. Defaults to output_labels_dir/crops.
    carry_over_labels=False                # Optional: Copy edited labels from the previous frame to the next frame automatically. Default is False.
)

# 2. Initialize the main Tkinter application with the configuration
app = AnnotatorApp(config)

# 3. Launch the graphical interface and start labeling!
app.mainloop()
```

### 2. Running via Terminal (CLI)

Once installed, you can launch the interactive CLI runner from any folder in your terminal simply by typing:
```bash
drawbox
```
Or, if running directly from the source directory:
```bash
python -m drawbox
```
The CLI will walk you through prompts to specify the input frames folder, output formats, and other options.

---

## Configuration Parameter Options

Below are the details of all configuration parameters accepted by `AnnotatorConfig`:

| Parameter | Type | Default | Description | Options / Example |
| --- | --- | --- | --- | --- |
| **`frames_dir`** | `str` | *Required* | Path to the directory containing images to label. | `"data/frames"` |
| **`output_labels_dir`** | `str` | `"output"` | Path to the base directory where labels are exported. | `"labels_output"` |
| **`start_frame`** | `int` | `0` | Starting frame index inside the directory. | `15` |
| **`initial_label_file`** | `str` | `""` | Optional initial file with annotations to pre-populate labels. | `"prelabels.json"` |
| **`initial_label_format`** | `str` | `"tf"` | Format of the initial labels file. | `"tf"`, `"yolo"`, `"coco"`, `"voc"` |
| **`formats`** | `list[str]` | `["yolo"]` | List of output formats to write concurrently upon saving. | `["yolo", "coco", "voc", "tf"]` |
| **`save_crops`** | `bool` | `False` | Whether to crop and save the bounding boxes as PNG crops. | `True`, `False` |
| **`crops_out_dir`** | `str` | `None` | Custom output folder for crops (defaults to `output_labels_dir/crops`). | `"my_crops"` |
| **`carry_over_labels`** | `bool` | `False` | Automatically carry over bounding boxes to subsequent frames. | `True`, `False` |

---

## Output Directory Layout

Annotations are exported into organized subfolders matching each format inside the base `output_labels_dir` directory:
```
output_labels_dir/
├── classes.txt                       # Unique class ID mapped to class names (e.g. "0: car")
├── yolo/                             # Normalized yolo coordinates: [class_id, x_center, y_center, width, height]
│   ├── frame_001.txt
│   └── frame_002.txt
├── voc/                              # XML format files matching Pascal VOC standards
│   ├── frame_001.xml
│   └── frame_002.xml
├── tf/                               # Normalized coordinate text files: [class_id, xmin, ymin, xmax, ymax]
│   ├── frame_001.txt
│   └── frame_002.txt
└── crops/                            # categorised PNG crops for each class (if save_crops is Enabled)
    └── 0_car/
        ├── 0.png
        └── 1.png
```

---

## Keyboard Shortcuts Map

| Key | Description |
| --- | --- |
| **`s` / `S`** / **`Enter`** | Save labels and move to **Next** frame |
| **`k` / `K`** / **`Right Arrow`** / **`Down Arrow`** | Skip current frame without saving, and move to **Next** frame |
| **`a` / `A`** / **`Left Arrow`** / **`Up Arrow`** | Move back to **Previous** frame |
| **`f` / `F`** | Center and fit the image to the window size |
| **`Ctrl + Z`** | Undo the last change |
| **`Ctrl + Shift + Z`** | Redo the last change |
| **`r` / `R`** | Copy previous frame's labels to current frame |
| **`Ctrl + Left Click`** | Select bounding box and its class label (allows drawing nested boxes) |
| **`Delete` / `Backspace`** | Delete the currently selected bounding box |
| **`0` – `9`** | Quick-select corresponding class IDs |
| **`q` / `Esc`** | Close window and exit app |
