A Roboflow-style image annotation tool for Windows built with Python and PyQt6. Supports bounding box detection, polygon and brush-based segmentation, AI-assisted labeling via SAM 2 and YOLO, and exports to all major training formats.
- Features
- Project structure
- Installation
- Quick start
- Annotation tools
- AI-assisted labeling
- Mask preview
- Export formats
- Session management
- Class presets
- Keyboard shortcuts
- License
- Smooth zoom (5% to 4000%) via scroll wheel or
+/- - Pan via middle-click drag or Space + left-click drag
- Fit-to-view with
F - Thumbnail sidebar with lazy background loading β handles thousands of images without freezing
- Keyboard image navigation with arrow keys or
A/D - Live cursor coordinates in status bar
- Zoom slider in status bar
- Bounding box β click and drag, normalized YOLO-format storage
- Polygon β click-by-click point placement, right-click or double-click to close
- Freehand β draw and release, auto-simplified with Douglas-Peucker via OpenCV
- Brush β paint filled regions, erase overflows, commit to smooth polygon on Enter
- 1px minimum brush size
- Adjustable opacity
- Eraser mode toggle
- Gaussian-smoothed contour extraction on commit
- Mask eraser β double-click any existing polygon to load it into the brush overlay and paint-erase parts of it, then commit the corrected shape
- Select and move β drag bounding boxes and polygons to reposition, coordinates written back to the annotation store on release
- Full undo/redo stack (
Ctrl+Z/Ctrl+Y) - Per-class color coding with editable class manager
- Live mask preview dock (semantic or instance, grayscale or color)
- Export to YOLO, COCO JSON, Pascal VOC, and PNG masks
- SAM 2 point mode β left-click to add a foreground point, Shift+click for background, SAM segments the object
- SAM 2 box mode β draw a box around an object, SAM segments the best match inside
- YOLO auto-detection β load any
.ptmodel, run inference on the current image, detections appear as suggestions - Suggestions shown as dashed cyan (SAM) or amber (YOLO) overlays
- Accept all suggestions with Enter or the Accept all button
- Reject all with Escape or the Reject all button
- SAM loads in a background thread with animated spinner and staged status messages
- Supports auto-download via ultralytics cache or manual
.ptfile selection - Model combo shows β cached / β¬ needs download status for each variant
- Device auto-detection: OpenVINO GPU β OpenVINO CPU β CUDA β CPU
labelapp/
βββ __init__.py
βββ annotations.py # Data models, AnnotationStore, undo commands, ToolMode
βββ canvas.py # Phase 2 β QGraphicsView image viewer, zoom, pan
βββ constants.py # Colors, sizes, defaults
βββ brush.py # BrushOverlay, BrushSettingsWidget, smooth contour extraction
βββ tools.py # Phase 3+4 β DrawingCanvas with all annotation tools
βββ mask.py # MaskGenerator, MaskPreviewWidget
βββ widgets.py # ThumbnailStrip, ZoomWidget, ClassManager, ToolbarWidget, PresetImportDialog
βββ export.py # YOLO, COCO, VOC, mask PNG export
βββ session.py # Session save/load with zlib compression and PNG-encoded brush masks
βββ presets.py # Built-in class presets: IDD, Cityscapes, COCO, Pascal VOC, ADE20K
βββ main.py # MainWindow, application-level shortcuts, AI signal bridges
βββ ai/
βββ __init__.py # Sets YOLO_OFFLINE env vars before any ultralytics import
βββ suggestion.py # Suggestion dataclass (pending AI annotation)
βββ sam_engine.py # SamEngine β SAM 2 wrapper with background thread loading
βββ yolo_engine.py # YoloEngine β YOLO inference wrapper
βββ ai_toolbar.py # AiToolbar dock widget with spinner, model status, mode buttons
- Python 3.11+
- Windows 10/11 (developed and tested on Windows)
- Visual C++ Redistributables 2015-2022 (download)
# Clone the repository
git clone https://github.com/yourusername/labelapp.git
cd labelapp
# Create and activate virtual environment
python -m venv venv
venv\Scripts\activate
# Install dependencies
pip install -r requirements.txtPyQt6
opencv-python
Pillow
numpy
ultralytics
torch
torchvision
openvino(Work in progress to implement support for Intel GPUs)
NVIDIA GPU users: Install CUDA-enabled PyTorch from pytorch.org before running pip install.
# Activate venv
venv\Scripts\activate
# Run the app
python -m labelapp.run- Click π Open Folder and select a folder of images
- Images appear in the thumbnail strip on the left β click any to load it
- Select a tool from the toolbar or press its shortcut key
- Draw annotations on the canvas
- Press
Ctrl+Sto save your session
Click and drag to draw a box. The box is stored in normalized YOLO format (x_center, y_center, width, height, all 0β1).
Click to place points one by one. Right-click or double-click to close the polygon. Press Escape to cancel.
Click and drag to draw a free-form outline. Release the mouse to auto-simplify with Douglas-Peucker and commit.
Paint a filled region over the object. The brush overlay appears in the active class color.
- Use the Brush Settings dock (appears automatically) to adjust size (1β120px) and opacity
- Press
Eto toggle the eraser and remove overflow areas - Press Enter to convert the painted region into a smooth polygon annotation
- Click π Clear brush mask to start over
- Switch to Select tool (
V) - Double-click any existing polygon or SAM mask
- The annotation loads into the brush overlay with the eraser active
- Paint over the parts you want to remove
- Press Enter to commit the corrected polygon, or Escape to cancel
Click any annotation to select it (highlighted outline). Drag to reposition. The new position is written back to the store on mouse release.
- Open the AI Tools dock on the left
- Select a model variant from the dropdown:
- SAM2-tiny (~40 MB) β fastest
- SAM2-small (~180 MB) β recommended
- SAM2-base (~310 MB)
- SAM2-large (~900 MB) β most accurate
- Click β¬ Load / download β weights download automatically on first run and are cached in
~/.cache/ultralytics/ - Or click π Browse .ptβ¦ to load a file you already have on disk
- An animated spinner shows loading progress with staged status messages
- Click β Point in the AI Tools dock or press
S - Left-click the object to add a foreground point (cyan dot)
- Shift+click to add a background point (red dot) to refine the mask
- The segmentation suggestion appears as a cyan dashed overlay
- Press Enter to accept, Escape to reject
- Click β¬ Box in the AI Tools dock or press
X - Draw a box around the object
- SAM segments the best match inside the box
- Press Enter to accept, Escape to reject
- Click Browse .pt⦠in the YOLO section and select a YOLO model file
- Adjust the Confidence slider (default 0.25)
- Click βΆ Run YOLO on image
- All detections appear as amber dashed overlays with confidence scores
- Click β Accept all or press
Ctrl+Ato commit all suggestions - Click β Reject all or press
Ctrl+Rto discard them
SAM point click β cyan mask appears
β Enter to accept β becomes polygon annotation
β Double-click the polygon β enters brush edit mode
β Erase the parts SAM got wrong
β Enter to commit the correction
The Mask Preview dock updates in real time as you annotate.
| Setting | Options | Description |
|---|---|---|
| Type | Semantic / Instance | Semantic: same class = same color. Instance: each annotation gets a unique color |
| Format | Color / Grayscale | Color: RGB class/instance colors. Grayscale: pixel value = class_id or instance index |
| Opacity | 20β100% | Controls overlay transparency in the preview |
Click πΎ Save mask PNGβ¦ to save the current preview as a PNG file. When saving grayscale masks you can choose between raw label values (for training) or brightness-scaled values (for visualization).
Access via the Export dock (tabbed with Mask Preview).
| Format | Description |
|---|---|
| YOLO .txt | One file per image, normalized class x_center y_center width height |
| COCO JSON | Instance segmentation with polygon segmentation arrays and bounding boxes |
| Mask PNG (current) | PNG mask for the currently displayed image |
| Mask PNG (all) | Batch export masks for every annotated image in the session |
LabelApp automatically saves your session every time you switch images. You can also save, load, and clear sessions manually.
| Action | How |
|---|---|
| Auto-save | Happens on every image switch |
| Manual save | Ctrl+S or πΎ Save Session button |
| Load session | π Load Session button β restores folder, classes, all annotations, and brush masks |
| Clear session | π Clear Session button |
- Last opened folder path
- All label classes with their names and colors
- All annotations (bounding boxes and polygons) for every image
- Brush mask overlays (stored as base64-encoded PNG, ~100Γ smaller than raw arrays)
- Last active image and class selection
Click ⬠Import preset⦠in the Classes panel to open the preset dialog.
Paste class names (one per line or as a Python list) and an optional RGB palette in the Paste names + palette dialog:
# Names β one per line or Python list
road
sidewalk
building
# Palette β list of [R, G, B] rows (optional, auto-generated if omitted)
[[128, 64, 128], [244, 35, 232], [70, 70, 70]]from labelapp.presets import classes_from_raw
import numpy as np
MY_CLASSES = ["cat", "dog", "bird"]
MY_PALETTE = np.array([[255,0,0],[0,255,0],[0,0,255]], dtype=np.uint8)
my_classes = classes_from_raw(MY_CLASSES, MY_PALETTE)All shortcuts work application-wide regardless of which panel has focus.
| Key | Tool |
|---|---|
V |
Select / move |
B |
Bounding box |
P |
Polygon |
F2 |
Freehand |
G |
Brush |
S |
SAM 2 point |
X |
SAM 2 box |
| Key | Action |
|---|---|
F |
Fit image to view |
+ / = |
Zoom in |
- |
Zoom out |
Scroll wheel |
Zoom in / out |
Space + drag |
Pan canvas |
Middle-click drag |
Pan canvas |
| Key | Action |
|---|---|
Enter |
Accept suggestions / commit brush / close polygon |
Escape |
Reject suggestions / abort drawing |
Delete |
Delete selected annotation |
Ctrl+Z |
Undo |
Ctrl+Y / Ctrl+Shift+Z |
Redo |
E |
Toggle eraser (brush mode only) |
Double-click annotation |
Enter mask edit mode |
| Key | Action |
|---|---|
β / D |
Next image |
β / A |
Previous image |
Ctrl+S |
Save session |
Ctrl+A |
Accept all AI suggestions |
Ctrl+R |
Reject all AI suggestions |