lazylabel-gui 1.1.9__tar.gz → 1.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. {lazylabel_gui-1.1.9/src/lazylabel_gui.egg-info → lazylabel_gui-1.2.1}/PKG-INFO +56 -96
  2. lazylabel_gui-1.2.1/README.md +145 -0
  3. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/pyproject.toml +1 -1
  4. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/config/hotkeys.py +2 -2
  5. lazylabel_gui-1.2.1/src/lazylabel/core/model_manager.py +183 -0
  6. lazylabel_gui-1.2.1/src/lazylabel/models/sam2_model.py +223 -0
  7. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/models/sam_model.py +25 -3
  8. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/ui/control_panel.py +37 -2
  9. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/ui/main_window.py +438 -33
  10. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1/src/lazylabel_gui.egg-info}/PKG-INFO +56 -96
  11. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel_gui.egg-info/SOURCES.txt +1 -0
  12. lazylabel_gui-1.1.9/README.md +0 -185
  13. lazylabel_gui-1.1.9/src/lazylabel/core/model_manager.py +0 -108
  14. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/LICENSE +0 -0
  15. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/setup.cfg +0 -0
  16. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/__init__.py +0 -0
  17. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/__main__.py +0 -0
  18. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/config/__init__.py +0 -0
  19. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/config/paths.py +0 -0
  20. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/config/settings.py +0 -0
  21. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/core/__init__.py +0 -0
  22. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/core/file_manager.py +0 -0
  23. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/core/segment_manager.py +0 -0
  24. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/main.py +0 -0
  25. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/models/__init__.py +0 -0
  26. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/ui/__init__.py +0 -0
  27. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/ui/editable_vertex.py +0 -0
  28. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/ui/hotkey_dialog.py +0 -0
  29. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/ui/hoverable_pixelmap_item.py +0 -0
  30. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/ui/hoverable_polygon_item.py +0 -0
  31. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/ui/numeric_table_widget_item.py +0 -0
  32. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/ui/photo_viewer.py +0 -0
  33. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/ui/reorderable_class_table.py +0 -0
  34. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/ui/right_panel.py +0 -0
  35. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/ui/widgets/__init__.py +0 -0
  36. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/ui/widgets/adjustments_widget.py +0 -0
  37. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/ui/widgets/border_crop_widget.py +0 -0
  38. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/ui/widgets/channel_threshold_widget.py +0 -0
  39. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/ui/widgets/fft_threshold_widget.py +0 -0
  40. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/ui/widgets/fragment_threshold_widget.py +0 -0
  41. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/ui/widgets/model_selection_widget.py +0 -0
  42. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/ui/widgets/settings_widget.py +0 -0
  43. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/ui/widgets/status_bar.py +0 -0
  44. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/utils/__init__.py +0 -0
  45. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/utils/custom_file_system_model.py +0 -0
  46. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/utils/logger.py +0 -0
  47. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel/utils/utils.py +0 -0
  48. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel_gui.egg-info/dependency_links.txt +0 -0
  49. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel_gui.egg-info/entry_points.txt +0 -0
  50. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel_gui.egg-info/requires.txt +0 -0
  51. {lazylabel_gui-1.1.9 → lazylabel_gui-1.2.1}/src/lazylabel_gui.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lazylabel-gui
3
- Version: 1.1.9
3
+ Version: 1.2.1
4
4
  Summary: An image segmentation GUI for generating ML ready mask tensors and annotations.
5
5
  Author-email: "Deniz N. Cakan" <deniz.n.cakan@gmail.com>
6
6
  License: MIT License
@@ -57,7 +57,7 @@ Dynamic: license-file
57
57
 
58
58
  **AI-Assisted Image Segmentation Made Simple**
59
59
 
60
- LazyLabel combines Meta's Segment Anything Model (SAM) with intuitive editing tools for fast, precise image labeling. Perfect for machine learning datasets, computer vision research, and annotation workflows.
60
+ LazyLabel combines Meta's Segment Anything Model (SAM) with intuitive editing tools for fast, precise image labeling. Perfect for machine learning datasets and computer vision research.
61
61
 
62
62
  ![LazyLabel Screenshot](https://raw.githubusercontent.com/dnzckn/LazyLabel/main/src/lazylabel/demo_pictures/gui.PNG)
63
63
 
@@ -71,67 +71,57 @@ pip install lazylabel-gui
71
71
  lazylabel-gui
72
72
  ```
73
73
 
74
+ ### Optional: SAM-2 Support
75
+ For advanced SAM-2 models, install manually:
76
+ ```bash
77
+ pip install git+https://github.com/facebookresearch/sam2.git
78
+ ```
79
+ *Note: SAM-2 is optional - LazyLabel works with SAM 1.0 models by default*
80
+
74
81
  ### Usage
75
82
  1. **Open Folder** → Select your image directory
76
83
  2. **Click on image** → AI generates instant masks
77
- 3. **Fine-tune** → Edit polygons, merge segments, adjust classes
84
+ 3. **Fine-tune** → Edit polygons, merge segments
78
85
  4. **Export** → Clean `.npz` files ready for ML training
79
86
 
80
87
  ---
81
88
 
82
89
  ## ✨ Key Features
83
90
 
84
- ### **🧠 AI-Powered Segmentation**
85
- - **One-click masking** with Meta's SAM model
86
- - **Smart prompting** via positive/negative points
87
- - **Fragment filtering** to remove small artifacts
88
- - **Multiple model support** (VIT-H, VIT-L, VIT-B)
89
-
90
- ### **🎨 Advanced Editing**
91
- - **Polygon drawing** with full vertex control
92
- - **Bounding box** annotation mode
93
- - **Shape merging** and class assignment
94
- - **Edit mode** for precision adjustments
95
-
96
- ### **⚡ Productivity Tools**
97
- - **Image adjustments** (brightness, contrast, gamma)
98
- - **Customizable hotkeys** for all functions
99
- - **Undo/redo** with full history
100
- - **Auto-save** and session persistence
101
-
102
- ### **📊 ML-Ready Outputs**
103
- - **One-hot encoded** `.npz` format
104
- - **Clean class separation** with shape `(H, W, Classes)`
105
- - **Batch processing** support
106
- - **Existing mask loading** for iterative work
91
+ - **🧠 One-click AI segmentation** with Meta's SAM and SAM2 models
92
+ - **🎨 Manual polygon drawing** with full vertex control
93
+ - **⚡ Smart editing tools** - merge segments, adjust class names, and class order
94
+ - **📊 ML-ready exports** - One-hot encoded `.npz` format and `.json` for YOLO format
95
+ - **🔧 Image enhancement** - brightness, contrast, gamma adjustment
96
+ - **🔍 Image viewer** - zoom, pan, brightness, contrast, and gamma adjustment
97
+ - **✂️ Edge cropping** - define custom crop areas to focus on specific regions
98
+ - **🔄 Undo/Redo** - full history of all actions
99
+ - **💾 Auto-saving** - Automatic saving of your labels when navigating between images
100
+ - **🎛️ Advanced filtering** - FFT thresholding and color channel thresholding
101
+ - **⌨️ Customizable hotkeys** for all functions
107
102
 
108
103
  ---
109
104
 
110
- ## ⌨️ Essential Controls
111
-
112
- | Mode | Key | Action |
113
- |------|-----|--------|
114
- | **AI Segmentation** | `1` | Point mode for SAM |
115
- | | `Left Click` | Add positive point |
116
- | | `Right Click` | Add negative point |
117
- | | `Space` | Save segment |
118
- | **Manual Drawing** | `2` | Polygon mode |
119
- | | `Left Click` | Add vertex |
120
- | | `Enter` | Close polygon |
121
- | **Editing** | `E` | Selection mode |
122
- | | `R` | Edit selected shapes |
123
- | | `M` | Merge selected segments |
124
- | **Navigation** | `Q` | Pan mode |
125
- | | `W/A/S/D` | Pan image |
126
- | | `Scroll` | Zoom in/out |
127
-
128
- **💡 All hotkeys are customizable** - Click "Hotkeys" button to personalize shortcuts
105
+ ## ⌨️ Essential Hotkeys
106
+
107
+ | Action | Key | Description |
108
+ |--------|-----|-------------|
109
+ | **AI Mode** | `1` | Point-click segmentation |
110
+ | **Draw Mode** | `2` | Manual polygon drawing |
111
+ | **Edit Mode** | `E` | Select and modify shapes |
112
+ | **Save Segment** | `Space` | Confirm current mask |
113
+ | **Merge** | `M` | Combine selected segments |
114
+ | **Pan** | `Q` + drag | Navigate large images |
115
+ | **Positive Point** | `Left Click` | Add to segment |
116
+ | **Negative Point** | `Right Click` | Remove from segment |
117
+
118
+ 💡 **All hotkeys customizable** - Click "Hotkeys" button to personalize
129
119
 
130
120
  ---
131
121
 
132
122
  ## 📦 Output Format
133
123
 
134
- LazyLabel exports clean, ML-ready data:
124
+ Perfect for ML training - clean, structured data:
135
125
 
136
126
  ```python
137
127
  import numpy as np
@@ -141,41 +131,24 @@ data = np.load('your_image.npz')
141
131
  mask = data['mask'] # Shape: (height, width, num_classes)
142
132
 
143
133
  # Each channel is a binary mask for one class
144
- class_0_mask = mask[:, :, 0] # Binary mask for class 0
145
- class_1_mask = mask[:, :, 1] # Binary mask for class 1
146
- # ... and so on
134
+ class_0_mask = mask[:, :, 0] # Background
135
+ class_1_mask = mask[:, :, 1] # Object type 1
136
+ class_2_mask = mask[:, :, 2] # Object type 2
147
137
  ```
148
138
 
149
- **Perfect for:**
150
- - Semantic segmentation training
151
- - Instance segmentation datasets
139
+
140
+ **Ideal for:**
141
+ - Semantic segmentation datasets
142
+ - Instance segmentation training
152
143
  - Computer vision research
153
144
  - Automated annotation pipelines
154
145
 
155
146
  ---
156
147
 
157
- ## 🛠️ Advanced Features
158
-
159
- ### **Image Enhancement**
160
- - **Brightness/Contrast** adjustment sliders
161
- - **Gamma correction** for better visibility
162
- - **Live preview** of adjustments
163
- - **SAM integration** with adjusted images
164
-
165
- ### **Smart Filtering**
166
- - **Fragment threshold** removes small segments
167
- - **Size-based filtering** (0-100% of largest segment)
168
- - **Quality control** for clean annotations
169
-
170
- ### **Professional Workflow**
171
- - **Class management** with custom aliases
172
- - **Segment organization** with sortable tables
173
- - **Batch export** for large datasets
174
- - **Model switching** without restart
148
+ ## 🛠️ Development
175
149
 
176
- ---
177
-
178
- ## 🏗️ Development
150
+ **Requirements:** Python 3.10+
151
+ **2.5GB** disk space for SAM model (auto-downloaded)
179
152
 
180
153
  ### Installation from Source
181
154
  ```bash
@@ -185,38 +158,26 @@ pip install -e .
185
158
  lazylabel-gui
186
159
  ```
187
160
 
188
- ### Code Quality & Testing
161
+ ### Testing & Quality
189
162
  ```bash
190
- # Linting & formatting
191
- ruff check . && ruff format .
192
-
193
- # Run tests with coverage
163
+ # Run full test suite
194
164
  python -m pytest --cov=lazylabel --cov-report=html
195
165
 
196
- # All tests pass with 60%+ coverage
166
+ # Code formatting & linting
167
+ ruff check . && ruff format .
197
168
  ```
198
169
 
199
170
  ### Architecture
200
- - **Modular design** with clean separation of concerns
201
- - **Signal-based communication** between components
171
+ - **Modular design** with clean component separation
172
+ - **Signal-based communication** between UI elements
202
173
  - **Extensible model system** for new SAM variants
203
- - **Comprehensive test suite** with 95% speed optimization
204
-
205
- ---
206
-
207
- ## 📋 Requirements
208
-
209
- - **Python 3.10+**
210
- - **OpenCV** for image processing
211
- - **PyQt6** for GUI
212
- - **NumPy** for data handling
213
- - **2.5GB** disk space for SAM model (auto-downloaded)
174
+ - **Comprehensive test suite** (150+ tests, 60%+ coverage)
214
175
 
215
176
  ---
216
177
 
217
178
  ## 🤝 Contributing
218
179
 
219
- LazyLabel welcomes contributions! Check out our:
180
+ LazyLabel welcomes contributions! Check out:
220
181
  - [Architecture Guide](src/lazylabel/ARCHITECTURE.md) for technical details
221
182
  - [Hotkey System](src/lazylabel/HOTKEY_FEATURE.md) for customization
222
183
  - Issues page for feature requests and bug reports
@@ -225,9 +186,8 @@ LazyLabel welcomes contributions! Check out our:
225
186
 
226
187
  ## 🙏 Acknowledgments
227
188
 
228
- LazyLabel was inspired by and builds upon the excellent work of:
229
- - [LabelMe](https://github.com/wkentaro/labelme) - The pioneering open-source image annotation tool
230
- - [Segment-Anything-UI](https://github.com/branislavhesko/segment-anything-ui) - Early SAM integration concepts
189
+ - [LabelMe](https://github.com/wkentaro/labelme)
190
+ - [Segment-Anything-UI](https://github.com/branislavhesko/segment-anything-ui)
231
191
 
232
192
  ---
233
193
 
@@ -0,0 +1,145 @@
1
+ # <img src="https://raw.githubusercontent.com/dnzckn/LazyLabel/main/src/lazylabel/demo_pictures/logo2.png" alt="LazyLabel Logo" style="height:60px; vertical-align:middle;" /> <img src="https://raw.githubusercontent.com/dnzckn/LazyLabel/main/src/lazylabel/demo_pictures/logo_black.png" alt="LazyLabel Cursive" style="height:60px; vertical-align:middle;" />
2
+
3
+ **AI-Assisted Image Segmentation Made Simple**
4
+
5
+ LazyLabel combines Meta's Segment Anything Model (SAM) with intuitive editing tools for fast, precise image labeling. Perfect for machine learning datasets and computer vision research.
6
+
7
+ ![LazyLabel Screenshot](https://raw.githubusercontent.com/dnzckn/LazyLabel/main/src/lazylabel/demo_pictures/gui.PNG)
8
+
9
+ ---
10
+
11
+ ## 🚀 Quick Start
12
+
13
+ ### Installation
14
+ ```bash
15
+ pip install lazylabel-gui
16
+ lazylabel-gui
17
+ ```
18
+
19
+ ### Optional: SAM-2 Support
20
+ For advanced SAM-2 models, install manually:
21
+ ```bash
22
+ pip install git+https://github.com/facebookresearch/sam2.git
23
+ ```
24
+ *Note: SAM-2 is optional - LazyLabel works with SAM 1.0 models by default*
25
+
26
+ ### Usage
27
+ 1. **Open Folder** → Select your image directory
28
+ 2. **Click on image** → AI generates instant masks
29
+ 3. **Fine-tune** → Edit polygons, merge segments
30
+ 4. **Export** → Clean `.npz` files ready for ML training
31
+
32
+ ---
33
+
34
+ ## ✨ Key Features
35
+
36
+ - **🧠 One-click AI segmentation** with Meta's SAM and SAM2 models
37
+ - **🎨 Manual polygon drawing** with full vertex control
38
+ - **⚡ Smart editing tools** - merge segments, adjust class names, and class order
39
+ - **📊 ML-ready exports** - One-hot encoded `.npz` format and `.json` for YOLO format
40
+ - **🔧 Image enhancement** - brightness, contrast, gamma adjustment
41
+ - **🔍 Image viewer** - zoom, pan, brightness, contrast, and gamma adjustment
42
+ - **✂️ Edge cropping** - define custom crop areas to focus on specific regions
43
+ - **🔄 Undo/Redo** - full history of all actions
44
+ - **💾 Auto-saving** - Automatic saving of your labels when navigating between images
45
+ - **🎛️ Advanced filtering** - FFT thresholding and color channel thresholding
46
+ - **⌨️ Customizable hotkeys** for all functions
47
+
48
+ ---
49
+
50
+ ## ⌨️ Essential Hotkeys
51
+
52
+ | Action | Key | Description |
53
+ |--------|-----|-------------|
54
+ | **AI Mode** | `1` | Point-click segmentation |
55
+ | **Draw Mode** | `2` | Manual polygon drawing |
56
+ | **Edit Mode** | `E` | Select and modify shapes |
57
+ | **Save Segment** | `Space` | Confirm current mask |
58
+ | **Merge** | `M` | Combine selected segments |
59
+ | **Pan** | `Q` + drag | Navigate large images |
60
+ | **Positive Point** | `Left Click` | Add to segment |
61
+ | **Negative Point** | `Right Click` | Remove from segment |
62
+
63
+ 💡 **All hotkeys customizable** - Click "Hotkeys" button to personalize
64
+
65
+ ---
66
+
67
+ ## 📦 Output Format
68
+
69
+ Perfect for ML training - clean, structured data:
70
+
71
+ ```python
72
+ import numpy as np
73
+
74
+ # Load your labeled data
75
+ data = np.load('your_image.npz')
76
+ mask = data['mask'] # Shape: (height, width, num_classes)
77
+
78
+ # Each channel is a binary mask for one class
79
+ class_0_mask = mask[:, :, 0] # Background
80
+ class_1_mask = mask[:, :, 1] # Object type 1
81
+ class_2_mask = mask[:, :, 2] # Object type 2
82
+ ```
83
+
84
+
85
+ **Ideal for:**
86
+ - Semantic segmentation datasets
87
+ - Instance segmentation training
88
+ - Computer vision research
89
+ - Automated annotation pipelines
90
+
91
+ ---
92
+
93
+ ## 🛠️ Development
94
+
95
+ **Requirements:** Python 3.10+
96
+ **2.5GB** disk space for SAM model (auto-downloaded)
97
+
98
+ ### Installation from Source
99
+ ```bash
100
+ git clone https://github.com/dnzckn/LazyLabel.git
101
+ cd LazyLabel
102
+ pip install -e .
103
+ lazylabel-gui
104
+ ```
105
+
106
+ ### Testing & Quality
107
+ ```bash
108
+ # Run full test suite
109
+ python -m pytest --cov=lazylabel --cov-report=html
110
+
111
+ # Code formatting & linting
112
+ ruff check . && ruff format .
113
+ ```
114
+
115
+ ### Architecture
116
+ - **Modular design** with clean component separation
117
+ - **Signal-based communication** between UI elements
118
+ - **Extensible model system** for new SAM variants
119
+ - **Comprehensive test suite** (150+ tests, 60%+ coverage)
120
+
121
+ ---
122
+
123
+ ## 🤝 Contributing
124
+
125
+ LazyLabel welcomes contributions! Check out:
126
+ - [Architecture Guide](src/lazylabel/ARCHITECTURE.md) for technical details
127
+ - [Hotkey System](src/lazylabel/HOTKEY_FEATURE.md) for customization
128
+ - Issues page for feature requests and bug reports
129
+
130
+ ---
131
+
132
+ ## 🙏 Acknowledgments
133
+
134
+ - [LabelMe](https://github.com/wkentaro/labelme)
135
+ - [Segment-Anything-UI](https://github.com/branislavhesko/segment-anything-ui)
136
+
137
+ ---
138
+
139
+ ## ☕ Support
140
+
141
+ If LazyLabel saves you time on annotation tasks, [consider supporting the project!](https://buymeacoffee.com/dnzckn)
142
+
143
+ ---
144
+
145
+ **Made with ❤️ for the computer vision community**
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "lazylabel-gui"
7
- version = "1.1.9"
7
+ version = "1.2.1"
8
8
  authors = [
9
9
  { name="Deniz N. Cakan", email="deniz.n.cakan@gmail.com" },
10
10
  ]
@@ -44,7 +44,7 @@ class HotkeyManager:
44
44
  ),
45
45
  HotkeyAction("fit_view", "Fit View", ".", category="Navigation"),
46
46
  # Modes
47
- HotkeyAction("sam_mode", "Point Mode (SAM)", "1", category="Modes"),
47
+ HotkeyAction("sam_mode", "AI Mode (Points + Box)", "1", category="Modes"),
48
48
  HotkeyAction("polygon_mode", "Polygon Mode", "2", category="Modes"),
49
49
  HotkeyAction("bbox_mode", "Bounding Box Mode", "3", category="Modes"),
50
50
  HotkeyAction("selection_mode", "Selection Mode", "E", category="Modes"),
@@ -95,7 +95,7 @@ class HotkeyManager:
95
95
  # Mouse-related (cannot be reassigned)
96
96
  HotkeyAction(
97
97
  "left_click",
98
- "Add Positive Point / Select",
98
+ "AI: Point (click) / Box (drag) / Select",
99
99
  "Left Click",
100
100
  category="Mouse",
101
101
  mouse_related=True,
@@ -0,0 +1,183 @@
1
+ """Model management functionality."""
2
+
3
+ import os
4
+ from collections.abc import Callable
5
+
6
+ from ..config import Paths
7
+ from ..models.sam_model import SamModel
8
+ from ..utils.logger import logger
9
+
10
+ # Optional SAM-2 support
11
+ try:
12
+ from ..models.sam2_model import Sam2Model
13
+
14
+ SAM2_AVAILABLE = True
15
+ except ImportError:
16
+ logger.info(
17
+ "SAM-2 not available. Install with: pip install git+https://github.com/facebookresearch/sam2.git"
18
+ )
19
+ Sam2Model = None
20
+ SAM2_AVAILABLE = False
21
+
22
+
23
+ class ModelManager:
24
+ """Manages SAM model loading and selection."""
25
+
26
+ def __init__(self, paths: Paths):
27
+ self.paths = paths
28
+ self.sam_model: SamModel | None = None
29
+ self.current_models_folder: str | None = None
30
+ self.on_model_changed: Callable[[str], None] | None = None
31
+
32
+ def initialize_default_model(self, model_type: str = "vit_h") -> SamModel | None:
33
+ """Initialize the default SAM model.
34
+
35
+ Returns:
36
+ SamModel instance if successful, None if failed
37
+ """
38
+ try:
39
+ logger.info(f"Step 4/8: Loading {model_type.upper()} model...")
40
+ self.sam_model = SamModel(model_type=model_type)
41
+ self.current_models_folder = str(self.paths.models_dir)
42
+ return self.sam_model
43
+ except Exception as e:
44
+ logger.error(f"Step 4/8: Failed to initialize default model: {e}")
45
+ self.sam_model = None
46
+ return None
47
+
48
+ def get_available_models(self, folder_path: str) -> list[tuple[str, str]]:
49
+ """Get list of available .pth models in folder.
50
+
51
+ Returns:
52
+ List of (display_name, full_path) tuples
53
+ """
54
+ pth_files = []
55
+ for root, _dirs, files in os.walk(folder_path):
56
+ for file in files:
57
+ if file.lower().endswith(".pth") or file.lower().endswith(".pt"):
58
+ full_path = os.path.join(root, file)
59
+ rel_path = os.path.relpath(full_path, folder_path)
60
+ pth_files.append((rel_path, full_path))
61
+
62
+ return sorted(pth_files, key=lambda x: x[0])
63
+
64
+ def detect_model_type(self, model_path: str) -> str:
65
+ """Detect model type from filename."""
66
+ filename = os.path.basename(model_path).lower()
67
+
68
+ # Check if it's a SAM2 model
69
+ if self._is_sam2_model(model_path):
70
+ if "tiny" in filename or "_t" in filename:
71
+ return "sam2_tiny"
72
+ elif "small" in filename or "_s" in filename:
73
+ return "sam2_small"
74
+ elif "base_plus" in filename or "_b+" in filename:
75
+ return "sam2_base_plus"
76
+ elif "large" in filename or "_l" in filename:
77
+ return "sam2_large"
78
+ else:
79
+ return "sam2_large" # default for SAM2
80
+ else:
81
+ # Original SAM model types
82
+ if "vit_l" in filename or "large" in filename:
83
+ return "vit_l"
84
+ elif "vit_b" in filename or "base" in filename:
85
+ return "vit_b"
86
+ elif "vit_h" in filename or "huge" in filename:
87
+ return "vit_h"
88
+ return "vit_h" # default for SAM1
89
+
90
+ def _is_sam2_model(self, model_path: str) -> bool:
91
+ """Check if the model is a SAM2 model based on filename patterns."""
92
+ filename = os.path.basename(model_path).lower()
93
+ sam2_indicators = ["sam2", "sam2.1", "hiera", "_t.", "_s.", "_b+.", "_l."]
94
+ return any(indicator in filename for indicator in sam2_indicators)
95
+
96
+ def load_custom_model(self, model_path: str) -> bool:
97
+ """Load a custom model from path.
98
+
99
+ Returns:
100
+ True if successful, False otherwise
101
+ """
102
+ if not os.path.exists(model_path):
103
+ return False
104
+
105
+ model_type = self.detect_model_type(model_path)
106
+
107
+ try:
108
+ # Clear existing model from memory
109
+ if self.sam_model is not None:
110
+ del self.sam_model
111
+ import torch
112
+
113
+ torch.cuda.empty_cache() if torch.cuda.is_available() else None
114
+
115
+ # Create appropriate model instance
116
+ if self._is_sam2_model(model_path):
117
+ if not SAM2_AVAILABLE:
118
+ logger.warning(
119
+ f"SAM-2 model detected but SAM-2 not installed: {model_path}"
120
+ )
121
+ logger.info(
122
+ "Install SAM-2 with: pip install git+https://github.com/facebookresearch/sam2.git"
123
+ )
124
+ return False
125
+
126
+ logger.info(f"Loading SAM2 model: {model_type}")
127
+ self.sam_model = Sam2Model(model_path)
128
+ else:
129
+ logger.info(f"Loading SAM1 model: {model_type}")
130
+ # Convert SAM2 model types back to SAM1 types for compatibility
131
+ sam1_model_type = model_type
132
+ if model_type.startswith("sam2_"):
133
+ type_mapping = {
134
+ "sam2_tiny": "vit_b",
135
+ "sam2_small": "vit_b",
136
+ "sam2_base_plus": "vit_l",
137
+ "sam2_large": "vit_h",
138
+ }
139
+ sam1_model_type = type_mapping.get(model_type, "vit_h")
140
+
141
+ # Create SAM1 model with custom path
142
+ self.sam_model = SamModel(
143
+ model_type=sam1_model_type, custom_model_path=model_path
144
+ )
145
+
146
+ success = self.sam_model.is_loaded
147
+
148
+ if success and self.on_model_changed:
149
+ model_name = os.path.basename(model_path)
150
+ self.on_model_changed(f"Current: {model_name}")
151
+
152
+ return success
153
+
154
+ except Exception as e:
155
+ logger.error(f"Failed to load custom model: {e}")
156
+ self.sam_model = None
157
+ return False
158
+
159
+ def set_models_folder(self, folder_path: str) -> None:
160
+ """Set the current models folder."""
161
+ self.current_models_folder = folder_path
162
+
163
+ def get_models_folder(self) -> str | None:
164
+ """Get the current models folder."""
165
+ return self.current_models_folder
166
+
167
+ def is_model_available(self) -> bool:
168
+ """Check if a SAM model is loaded and available."""
169
+ return self.sam_model is not None and getattr(
170
+ self.sam_model, "is_loaded", False
171
+ )
172
+
173
+ def set_image_from_path(self, image_path: str) -> bool:
174
+ """Set image for SAM model from file path."""
175
+ if not self.is_model_available():
176
+ return False
177
+ return self.sam_model.set_image_from_path(image_path)
178
+
179
+ def set_image_from_array(self, image_array) -> bool:
180
+ """Set image for SAM model from numpy array."""
181
+ if not self.is_model_available():
182
+ return False
183
+ return self.sam_model.set_image_from_array(image_array)