A quick-and-dirty PyQt5-based image annotation tool for creating bounding box annotations, designed for machine learning training data preparation.
- Interactive Image Annotation: Draw bounding boxes directly on images with mouse interactions
- Multi-tab Interface: Separate configuration and annotation workspaces
- File Management: Browse and select image directories with support for JPG, JPEG, PNG, BMP, TIFF, WebP, and GIF formats
- Class Management: Define and manage object classes for annotations with search/filter
- Zoom and Pan: Zoom in/out (+/- keys or Ctrl+scroll) and pan (middle-click drag) for detailed annotation
- Multiple Export Formats: Export annotations to YOLO, COCO, or native GRC JSON format
- Batch Processing: Export all annotations to a chosen format in one operation
- Annotation Statistics: Track progress with statistics showing total images, annotated count, and class distribution
- Undo/Redo: Full undo/redo support for annotation changes
- Keyboard Shortcuts: Efficient workflow with keyboard navigation and actions
- Cross-platform: Works on Windows, macOS, and Linux
- Python 3.8 or higher
- UV - Fast Python package installer and resolver
-
Clone the repository:
git clone <repository-url> cd ml-grc
-
Install UV (if not already installed):
# macOS/Linux curl -LsSf https://astral.sh/uv/install.sh | sh # Windows (PowerShell) powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
-
Setup environment and install dependencies:
make setup
Or manually:
uv venv uv pip install -e ".[dev]" -
Run the application:
make dev
Or:
uv run python -m grc.main
-
Configure your workspace:
- Click on the "Configure" tab
- Use the "Files" section to select a directory containing your images
- Use the "Classes" section to load or define your object classes
-
Start annotating:
- Switch to the "Annotate" tab
- The image viewer will display your images
- Click and drag to create bounding boxes
- Use the control panel to navigate between images and select classes
- Open Directory: Click "Open" in the Files section to select a directory containing your images
- Supported Formats: JPG, JPEG, PNG, BMP, TIFF, WebP, GIF
- File List: View all available images in a tree structure
- Load Classes: Click "Open" in the Classes section to load class definitions from text files
- Class Structure: Each class should be defined with an ID and name
- Progress Tracking: View total images, annotated images, and annotation count
- Class Distribution: See breakdown of annotations by class
- Refresh: Click "Refresh Statistics" to update progress
- Batch Export: Export all annotations to YOLO or COCO format at once
- Format Selection: Choose target format from dropdown
- Drawing Bounding Boxes:
- Click and drag to create rectangular annotations
- Minimum area threshold prevents accidental tiny annotations
- Selecting Boxes: Click on existing bounding boxes to select them
- Visual Feedback: Selected boxes appear with different opacity
- Previous/Next: Navigate between images in your dataset
- Class Selection: Choose the current class for new annotations using the dropdown
Navigation:
←/A: Previous image→/D: Next image
Annotations:
Delete: Delete selected boxesCtrl+Z: Undo last annotation changeCtrl+Y: Redo last undone change
Saving:
S: Save annotations for current imageR: Reload annotations from disk
Zoom & Pan:
+/=: Zoom in-/_: Zoom out0: Reset zoomCtrl+Scroll: Zoom in/outMiddle-click drag: Pan image
Mouse Interactions:
- Left-click drag : Create new bounding box
- Click : Select existing bounding box
- Ctrl+Click : Multi-select bounding boxes
- Crosshair Cursor : Indicates annotation mode
The application uses a multi-threaded architecture for smooth performance:
- Main Thread: Handles UI interactions and user input
- Render Thread: Manages image rendering and annotation overlays
- Thread Safety: Uses mutexes and signals for safe inter-thread communication
ml-grc/
├── src/grc/ # Main package
│ ├── core/ # Core application logic
│ │ ├── app.py # Main App class
│ │ ├── state.py # Application state management
│ │ ├── annotation_formats.py # Format handling (YOLO, COCO, GRC)
│ │ └── bounding_box.py # BoundingBox data model
│ ├── widgets/ # UI components
│ │ ├── image_widget.py # Core image display and annotation logic
│ │ ├── image_controls.py # Navigation, zoom, and action controls
│ │ ├── table_widget.py # Tab-based interface layout
│ │ ├── file_list_widget.py # File browser and management
│ │ ├── class_list_widget.py # Class definition management
│ │ ├── status_bar.py # Modern status bar with info display
│ │ ├── styles.py # Dark theme styling and color palette
│ │ ├── stats_widget.py # Annotation statistics display
│ │ └── batch_widget.py # Batch export functionality
│ ├── utils/ # Utility functions
│ ├── config/ # Configuration management
│ └── main.py # Application entry point
├── tests/ # Test files
│ ├── test_annotation_system.py # Annotation and format tests
│ ├── test_ui_components.py # UI component tests
│ └── test_core_system.py # Core functionality tests
├── pyproject.toml # Project configuration (UV, Ruff, dependencies)
├── Makefile # Development commands
└── README.md # This file
- PyQt5: GUI framework
- NumPy: Numerical operations
- OpenCV: Image processing
- Pillow: Image handling
- SciPy: Scientific computing
make setup # Create virtual environment and install dependencies
make dev # Start the GRC application
make lint # Run Ruff linter to check code
make format # Run Ruff formatter to format code
make check # Run both lint and format check
make test # Run the test suite
make clean # Remove virtual environment and cache filesThis project uses Ruff for linting and formatting:
# Check for issues
make lint
# Auto-format code
make format
# Check formatting without changes
make checkConfiguration is in pyproject.toml under [tool.ruff].
- Run
make setupto install dependencies - Run
make devto start the application - The application will start with a default window size of 1280x800
- Window Size: Modify the geometry settings in
app.py(default: 1280x800) - Theme Colors: Edit
src/grc/widgets/styles.pyto customize the color palette - Supported Formats: Update the
allowed_extensionslist infile_list_widget.py - Minimum Box Size: Adjust the area threshold in
image_widget.py
The application uses a carefully selected dark theme with the following key colors:
| Element | Color | Usage |
|---|---|---|
| Background | #1a1a2e |
Main window background |
| Surface | #16213e |
Panels, cards, group boxes |
| Surface Dark | #0f0f23 |
Input fields, lists |
| Border | #2d2d44 |
Subtle separators |
| Text | #ccd6f6 |
Primary text color |
| Text Muted | #8892b0 |
Secondary text, labels |
| Accent | #64ffda |
Highlights, selection, active states |
| Danger | #ff6b6b |
Destructive actions, warnings |
To customize, edit src/grc/widgets/styles.py and modify the COLORS dictionary or MODERN_DARK_THEME stylesheet.
- RAM: Minimum 4GB recommended
- Storage: Varies based on image dataset size
- Display: Minimum 1024x768 resolution
- Fork the repository
- Create a feature branch
- Make your changes
- Test thoroughly
- Submit a pull request
MIT - Do with it whatever you want.
- Auto-save functionality
- Polygon and segmentation annotation support
- Image filtering and search capabilities
- Collaborative annotation features
- Custom annotation attributes and metadata
- Integration with cloud storage services