Smart Polygon Annotation with Universal AI Plugin Support
A professional Qt6-based desktop application for creating polygon annotations for computer vision training datasets. Features a universal AI plugin system that integrates with any AI detection framework.
- Overview
- Key Features
- Requirements
- Building from Source
- Running the Application
- Application Settings
- AI Plugin System
- Batch Detection Workflow
- Available Plugins
- Usage Guide
- Keyboard Shortcuts
- Annotation Format
- Troubleshooting
- License
- Contributing
PolySeg is designed for ML engineers, data scientists, and researchers who need to create high-quality polygon annotations for training computer vision models. The application combines efficient manual annotation tools with AI-assisted automation.
- Manual Annotation: Draw precise polygon masks around objects in images
- AI-Assisted Annotation: Use any AI model to auto-detect objects, then review and refine
- Dataset Management: Organize images with train/val/test splits
- Quality Control: Two-tier review system ensures only verified annotations enter training
- Machine Learning Engineers building object detection/segmentation models
- Data Scientists preparing training datasets
- Research teams needing annotated ground truth data
- Anyone creating polygon-based annotations for computer vision
- Interactive polygon drawing - Point-and-click with drag-and-drop editing
- Universal AI Plugin System - Integrate ANY AI detection framework or custom model
- Cloud Storage Integration - One-click project creation in OneDrive, Google Drive, Dropbox, etc.
- Train/Val/Test Split Management - Automatic split assignment with model version tracking
- Undo/Redo System - Full history with Ctrl+Z/Ctrl+Y support (50 levels)
- Copy/Paste Polygons - Copy annotations between images with Ctrl+C/Ctrl+V
- Class Navigation - Quick switching with Tab/Shift+Tab and number keys 1-9
- Customizable Shortcuts - Edit any keyboard shortcut to match your workflow
- Multi-polygon & classes - Unlimited polygons per image with color-coded classes
- Project management - Organized
.polysegprojects with auto-save - Zoom & navigation - Zoom controls + keyboard shortcuts for image navigation
- Export formats - Normalized segmentation format, bounding boxes, COCO JSON
- Selection & editing - Click to select, drag points, delete polygons
- Image formats - PNG, JPG, BMP, TIFF support
| Component | Requirement |
|---|---|
| Operating System | Linux, Windows, macOS |
| RAM | 4 GB minimum, 8 GB recommended |
| Disk Space | 100 MB for application + space for images |
| Display | 1280x720 minimum resolution |
- Qt Framework: 6.5.3 or later
- Compiler: C++17 compatible (GCC, Clang, MSVC)
- Build System: qmake
- Optional: clang-format and clang-tidy (for development)
Linux (Ubuntu/Debian):
sudo apt-get update
sudo apt-get install -y qt6-base-dev qt6-tools-dev-toolsLinux (Fedora):
sudo dnf install qt6-qtbase-devel qt6-qttools-develLinux (Arch):
sudo pacman -S qt6-base qt6-toolsmacOS (Homebrew):
brew install qt@6Windows:
- Download Qt installer from qt.io/download
- Run the installer and select Qt 6.5.3 with MSVC compiler
- Add Qt bin directory to PATH (e.g.,
C:\Qt\6.5.3\msvc2019_64\bin)
To use AI-assisted annotation, you need:
- Python: 3.8 or later
- AI Framework: PyTorch, TensorFlow, ONNX Runtime, or other
- Environment: Native Python, virtualenv, conda, or Docker
# Clone the repository
git clone https://github.com/lstachowicz/PolySeg.git
cd PolySeg
# Build with qmake
qmake PolySeg.pro
make
# Run the application
./PolySegFormat code using clang-format:
clang-format -i src/*.cpp src/*.hRun static analysis with clang-tidy:
clang-tidy src/*.cpp -- -I/path/to/qt/include- Run
./PolySeg(Linux/macOS) orPolySeg.exe(Windows) - Create a new project: File → New Project
- Choose project location and name
- Copy images to the
images/folder within your project
A PolySeg project has the following structure:
MyProject/
├── MyProject.polyseg # Project configuration (JSON)
├── images/ # Source images (JPG, PNG, BMP, TIFF)
├── labels/ # Annotation files
│ ├── image_001.txt # Approved annotations (for training)
│ └── image_002.meta # Pending AI detections (for review)
├── splits/ # Train/val/test lists (if enabled)
│ ├── train.txt
│ ├── val.txt
│ └── test.txt
└── models/ # Trained model files
Access settings via Tools → Project Settings. Settings are organized into four tabs.
| Setting | Description |
|---|---|
| Project Name | Display name for your project |
| Annotation Type | Polygon (segmentation) or Bounding Box (detection) |
| Setting | Description | Default |
|---|---|---|
| Enable auto-save | Automatically save annotations while working | Enabled |
| Auto-save interval | Seconds between saves (10-300) | 30 seconds |
Define object classes with unique colors:
- Add/Edit/Remove classes
- Reorder with up/down arrows (affects keyboard shortcuts 1-9)
- First 9 classes accessible via number keys
| Folder | Default | Description |
|---|---|---|
| Images Folder | images/ |
Source images location |
| Labels Folder | labels/ |
Annotation output location |
Automatically crop images during loading to remove unwanted areas.
| Setting | Description |
|---|---|
| Enable cropping | Apply crop to all loaded images |
| X (left) | Left edge position in pixels |
| Y (top) | Top edge position in pixels |
| Width | Crop width (0 = full width) |
| Height | Crop height (0 = full height) |
Use cases: Remove camera timestamps, UI overlays, or watermarks.
Generate meaningful filename prefixes based on source directory structure.
Settings:
- Base Path to Strip: Root directory to remove from file paths
- Folders to Skip: List of folder names to exclude from prefix
Example:
Source: /data/Projects/BMP/RawData/Location_A/photo.jpg
Base Path: /data/Projects
Skip Folders: BMP, RawData
Result: Location_A_photo.jpg
More Examples:
| Use Case | Base Path | Skip Folders | Result Pattern |
|---|---|---|---|
| Simple | /home/user/Images |
(none) | subfolder_image.jpg |
| Medical | /mnt/Medical_Scans |
Raw_Data |
Patient_001_CT_slice.jpg |
| Multi-Camera | /recordings/2024 |
raw_footage |
Camera_Front_frame.jpg |
| Time-Series | /timelapse/Project |
backup |
2024_Q1_January_site.jpg |
Default: jpg, jpeg, png, bmp, tiff
Custom examples: dcm, nii, nrrd (medical), raw, cr2, nef (raw), webp, avif (web)
| Setting | Options | Description |
|---|---|---|
| Export Format | Segmentation, Bounding Box, COCO JSON | Output format |
| Normalize coordinates | Yes/No | Convert to 0.0-1.0 range |
| Coordinate Precision | 0-10 | Decimal places (default: 6) |
| Field | Description | Example |
|---|---|---|
| Enable AI Plugin | Activate plugin functionality | Checked |
| Plugin Name | Display name | "AI Plugin Segmentation" |
| Env Setup | Environment activation (optional) | source venv/bin/activate |
| Command | Program to execute | python3, docker, bash |
| Script Path | Path to plugin script | ./plugins/model_plugin.py |
| Detect Args | Detection arguments | detect --image {image} --model {model} |
| Train Args | Training arguments (optional) | train --data {project} --epochs {epochs} |
Custom settings available as {key} variables:
| Key | Example Value | Usage |
|---|---|---|
model |
./models/best.pt |
{model} in args |
confidence |
0.25 |
{confidence} in args |
device |
cuda |
{device} in args |
epochs |
100 |
{epochs} in args |
Automatic splitting of images for proper ML workflows.
| Setting | Description | Default |
|---|---|---|
| Enable splits | Activate split assignment | Disabled |
| Train ratio | Training data percentage | 70% |
| Val ratio | Validation data percentage | 20% |
| Test ratio | Test data percentage | 10% |
| Random Seed | UUID for deterministic assignment | Auto-generated |
How It Works:
- Each image filename is hashed (MD5) with the seed
- Hash determines split assignment (deterministic)
- New images are assigned to maintain target ratios
- Existing assignments never change (immutable)
Live Statistics Display:
Target: 70/20/10% | Actual: 71/19/10% (T:142 V:38 Te:20)
Reset Splits:
- Archives old models to
models_old_TIMESTAMP/ - Generates new random seed
- Reassigns all images
Track trained model versions with metadata:
| Column | Description |
|---|---|
| Name | Model identifier (e.g., "v1.0_baseline") |
| Date | Training completion date |
| Images Count | Number of training images |
| Path | Model file location |
| Notes | Hyperparameters, metrics, etc. |
Actions: Add Model, Edit Notes, Compare Models, Remove Entry
Configure keyboard shortcuts for all actions. Default shortcuts can be customized to match your workflow.
PolySeg uses a universal plugin architecture that works with ANY AI framework:
PolySeg (C++/Qt) ←→ subprocess ←→ Plugin (Python/other)
JSON
Key Features:
- Framework agnostic: Works with PyTorch, TensorFlow, ONNX, etc.
- Zero dependencies: PolySeg does NOT link to AI libraries
- Simple protocol: JSON-based stdin/stdout communication
- Flexible deployment: Native Python, Docker, virtualenv, conda
Command: python3
Script Path: ./plugins/model_plugin.py
Detect Args: detect --image {image} --model {model} --conf {confidence}
Command: bash
Script Path: -c "source venv/bin/activate && python ./plugins/model_plugin.py"
Detect Args: detect --image {image} --model {model}
Command: conda
Script Path: run -n myenv python ./plugins/model_plugin.py
Detect Args: detect --image {image}
Command: docker
Script Path: exec -i ai_container python /app/model_plugin.py
Detect Args: detect --image /app/data/{image_name} --model {model}
python3 ./plugins/model_plugin.py detect \
--image /path/to/image.jpg \
--model ./models/model.pt \
--confidence 0.25Success:
{
"status": "success",
"detections": [
{
"class": "person",
"confidence": 0.89,
"points": [
[0.1, 0.2],
[0.15, 0.18],
[0.2, 0.22]
]
}
]
}Coordinates are normalized (0.0 - 1.0):
x = pixel_x / image_widthy = pixel_y / image_height
Error:
{
"status": "error",
"message": "Model not found: model.pt"
}PolySeg automatically substitutes variables in {braces}:
| Variable | Description | Example |
|---|---|---|
{image} |
Current image path | /path/to/project/images/photo.jpg |
{project} |
Project directory | /path/to/project |
{splits} |
Splits directory | /path/to/project/splits |
{train_count} |
Training images count | 142 |
{val_count} |
Validation images count | 45 |
{test_count} |
Test images count | 21 |
{key} |
Any custom setting | Value from Plugin Settings |
| Environment | Command | Script Path |
|---|---|---|
| Native Python | python3 |
./plugins/script.py |
| Docker | docker |
exec -i container python /app/script.py |
| Virtual env | bash |
-c "source venv/bin/activate && python ./plugins/script.py" |
| Conda | conda |
run -n env_name python ./plugins/script.py |
| Poetry | poetry |
run python ./plugins/script.py |
| Pipenv | pipenv |
run python ./plugins/script.py |
Process hundreds of images automatically with AI, then review and approve.
PolySeg uses a two-tier system to ensure data quality:
AI Detection → .meta (pending review) → .txt (approved for training)
| File | Status | Used for Training | Editable |
|---|---|---|---|
.txt |
Approved | Yes | Yes |
.meta |
Pending | No | Yes (before approve) |
| (none) | Not annotated | No | Yes (manual) |
Step 1: Setup (One Time)
Tools → Configure Plugin
Configure your AI plugin (see AI Plugin System section).
Step 2: Run Batch Detection
Tools → Batch Detect All (Ctrl+Shift+D)
- AI processes every image in
project/images/ - Results saved to
.metafiles - Images auto-assigned to train/val/test splits (if enabled)
- Skips images with existing
.txt(already approved)
Step 3: Review Detections
Tools → Review → Next Unreviewed (Ctrl+U)
Review Loop:
- Load: Image with AI detections loads automatically
- Inspect: Check polygon accuracy and class labels
- Edit: Drag points, delete incorrect polygons, add missing ones
- Decide:
- Approve (Ctrl+Enter): Saves to
.txt, ready for training - Reject (Ctrl+Backspace): Deletes
.meta, clears canvas
- Approve (Ctrl+Enter): Saves to
- Repeat: Continue until "All images reviewed!"
500 images to annotate:
| Method | Time per Image | Total Time |
|---|---|---|
| Manual annotation | 2-5 minutes | 16-40 hours |
| Batch + Review | 20-30 seconds | 2.5-4 hours |
Time saved: 80-90%
DO:
- Review in batches (50-100 images per session)
- Edit detections before approving
- Use high confidence (0.7+) for first pass
- Approve quickly when detections are good
DON'T:
- Blindly approve all detections
- Use
.metafiles for training - Skip the review process
| Plugin | License | Speed | Accuracy | Best For |
|---|---|---|---|---|
| Detectron2 | Apache 2.0 | Slow | Very High | Research, highest accuracy |
| SMP | MIT | Medium | High | Flexible experimentation |
License: Apache 2.0
Installation:
Create a virtual environment in your project's plugin/ directory:
# Navigate to your project's plugin directory
cd /path/to/your/project/plugin
# Create virtual environment
python3 -m venv detectron2_venv
# Activate the environment
source detectron2_venv/bin/activate
# Install dependencies from requirements file
# IMPORTANT: Use --no-build-isolation to prevent detectron2 from creating its own venv
pip install -r /path/to/PolySeg/examples/plugins/requirements/detectron2.txt --no-build-isolation
# Deactivate when done
deactivateCopy the plugin script:
cp /path/to/PolySeg/examples/plugins/detectron2_plugin.py /path/to/your/project/plugin/Configuration in PolySeg:
Enable AI Plugin: ✓
Plugin Name: Detectron2 Mask R-CNN
Env Setup: source plugin/detectron2_venv/bin/activate
Command: python3
Script Path: plugin/detectron2_plugin.py
Detect Args: detect --image {image} --config {config} --model {model} --conf {confidence}
Settings:
config: COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml
model: models/my_model/model_final.pth
confidence: 0.5
Available Models:
mask_rcnn_R_50_FPN_3x- ResNet-50 backbonemask_rcnn_R_101_FPN_3x- ResNet-101 (more accurate)pointrend_rcnn_R_50_FPN_3x_coco- Better boundary qualitycascade_mask_rcnn_R_50_FPN_3x- Highest accuracy
License: MIT
Installation:
Create a virtual environment in your project's plugin/ directory:
# Navigate to your project's plugin directory
cd /path/to/your/project/plugin
# Create virtual environment
python3 -m venv smp_venv
# Activate the environment
source smp_venv/bin/activate
# Install dependencies from requirements file
pip install -r /path/to/PolySeg/examples/plugins/requirements/smp.txt
# Deactivate when done
deactivateCopy the plugin script:
cp /path/to/PolySeg/examples/plugins/smp_plugin.py /path/to/your/project/plugin/Configuration in PolySeg:
Enable AI Plugin: ✓
Plugin Name: SMP Segmentation
Env Setup: source plugin/smp_venv/bin/activate
Command: python3
Script Path: plugin/smp_plugin.py
Detect Args: detect --image {image} --architecture {architecture} --encoder {encoder} --weights {model} --conf {confidence} --classes {classes}
Train Args: train --dataset {project}/data.yaml --output {model} --architecture {architecture} --encoder {encoder} --epochs {epochs} --batch-size {batch_size} --lr {lr} --img-size {img_size} --classes {classes}
Settings:
architecture: Unet
encoder: resnet34
model: models/best.pt
confidence: 0.5
classes: 1
epochs: 50
batch_size: 4
lr: 0.0001
img_size: 512
Architectures: Unet, UnetPlusPlus, MAnet, Linknet, FPN, PSPNet, DeepLabV3, DeepLabV3Plus, PAN
Encoders: resnet18, resnet34, resnet50, resnet101, efficientnet-b0 to b7, mobilenet_v2, timm-mobilenetv3_large_100
Any plugin must:
- Accept command-line arguments for image path, model, etc.
- Output JSON to stdout with detections
- Use normalized coordinates (0.0 - 1.0)
- Handle errors gracefully
Minimal Example:
#!/usr/bin/env python3
import json
import sys
def detect(image_path):
# Your AI detection logic here
detections = [
{
"class": "person",
"confidence": 0.89,
"points": [[0.1, 0.2], [0.15, 0.18], [0.2, 0.22]]
}
]
print(json.dumps({
"status": "success",
"detections": detections
}))
if __name__ == "__main__":
if len(sys.argv) < 2:
print(json.dumps({"status": "error", "message": "No image provided"}))
sys.exit(1)
detect(sys.argv[1])Supported Environments:
- Native Python, Docker, virtualenv, conda
- Bash scripts, Node.js, compiled binaries
- Any executable that outputs JSON
- Create Project: File → New Project
- Add Images: Copy images to
YourProject/images/ - Select Class: Choose from dropdown or create new (Ctrl+M)
- Draw Polygon: Click to add points around object
- Edit Points: Drag to adjust, Ctrl+Click to insert/delete
- Finish: Press
Enteror double-click - Navigate: Ctrl+Right/Left for next/previous image
- Save: Auto-saves on navigation, or Ctrl+S
Single Image:
- Configure Plugin (Tools → Configure Plugin) - one-time setup
- Load any image
- Run detection (Ctrl+D or Tools → Auto Detect)
- Review and edit AI-generated polygons
- Save (auto or Ctrl+S)
Batch Processing:
- Configure Plugin - one-time setup
- Run batch detection (Ctrl+Shift+D)
- Review loop: Ctrl+U → Edit → Ctrl+Enter (approve) or Ctrl+Backspace (reject)
- Repeat until all reviewed
- Train model on approved
.txtfiles only
| Shortcut | Action |
|---|---|
Right |
Next image |
Left |
Previous image |
Home |
First image |
End |
Last image |
| Shortcut | Action |
|---|---|
Enter |
Finish polygon |
Esc |
Cancel / Deselect |
Del |
Delete selected |
Ctrl+Z |
Undo |
Ctrl+Y |
Redo |
Ctrl+C |
Copy selected polygon |
Ctrl+V |
Paste polygon |
| Shortcut | Action |
|---|---|
Tab |
Next class |
Shift+Tab |
Previous class |
1-9 |
Quick select class |
Ctrl+M |
Manage classes |
| Shortcut | Action |
|---|---|
Ctrl+D |
AI auto-detect (single image) |
Ctrl+Shift+D |
Batch detect all images |
Ctrl+U |
Next unreviewed image |
Ctrl+Enter |
Approve & save annotations |
Ctrl+Backspace |
Reject & clear AI detections |
| Shortcut | Action |
|---|---|
Ctrl+N |
New project |
Ctrl+S |
Save annotations |
Exported .txt files (in labels/ folder):
class_id x1 y1 x2 y2 x3 y3 ...
All coordinates normalized to [0.0, 1.0] range.
Example:
0 0.123456 0.234567 0.345678 0.456789 0.234567 0.567890
1 0.500000 0.300000 0.550000 0.280000 0.600000 0.320000
Check:
- File permissions on
.polysegfile - Disk space available
- Project file not read-only
Solution: Close and reopen project
Check:
- Plugin enabled checkbox is checked
- Command path is correct (
python3vspython) - Script path is valid (relative to project dir)
- Plugin settings contain required values
Debug: Run plugin command manually in terminal:
python3 ./plugins/model_plugin.py detect --image test.jpg --model model.pt --conf 0.25Check:
- Confidence threshold not too high (try 0.15)
- Model matches your object classes
- Image loading correctly
Cause: No images in project yet
Solution: Copy images to images/ folder, then reopen settings
Cause: All images already have .txt files
Solution: Delete .txt files to re-detect
Solutions:
- Reduce batch size:
--batch 8or--batch 4 - Use smaller model
- Use CPU:
--device cpu
Check:
- Volume mounts are correct
- Container is running (
docker ps) - GPU access with
--gpus all
PolySeg Application Code: MIT License - see LICENSE for details
Third-Party Components: See THIRD-PARTY-LICENSES.md and NOTICE for Qt Framework and other dependencies
PolySeg does NOT impose licensing on plugins. Your plugins can use any license you choose.
Note: Some AI frameworks have restrictive licenses:
- AGPL-3.0 (YOLOv11): Keep plugin code separate from PolySeg core
- GPL-3.0: May require separate repositories
MIT and Apache 2.0 licensed plugins can be freely integrated.
This application is built with:
- Qt Framework 6.5.3 - LGPL v3 License (https://www.qt.io/)
- Qt is dynamically linked, allowing users to replace libraries under LGPL v3 terms
Contributions are welcome! Please feel free to submit a Pull Request.
Areas for contribution:
- New plugin implementations
- Documentation improvements
- Bug fixes
- Feature requests
- Report bugs or request features via GitHub Issues
- Star the repository if this tool helps you
Lukasz Stachowicz
Perfect for creating training datasets for computer vision models requiring polygon-based ground truth annotations.