lazylabel-gui 1.1.4__py3-none-any.whl → 1.1.6__py3-none-any.whl

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.
@@ -1,113 +1,125 @@
1
- """Settings widget for save options."""
2
-
3
- from PyQt6.QtCore import pyqtSignal
4
- from PyQt6.QtWidgets import QCheckBox, QGroupBox, QVBoxLayout, QWidget
5
-
6
-
7
- class SettingsWidget(QWidget):
8
- """Widget for application settings."""
9
-
10
- settings_changed = pyqtSignal()
11
-
12
- def __init__(self, parent=None):
13
- super().__init__(parent)
14
- self._setup_ui()
15
- self._connect_signals()
16
-
17
- def _setup_ui(self):
18
- """Setup the UI layout."""
19
- group = QGroupBox("Settings")
20
- layout = QVBoxLayout(group)
21
-
22
- # Auto-save
23
- self.chk_auto_save = QCheckBox("Auto-Save on Navigate")
24
- self.chk_auto_save.setToolTip(
25
- "Automatically save work when using arrow keys to change images."
26
- )
27
- self.chk_auto_save.setChecked(True)
28
- layout.addWidget(self.chk_auto_save)
29
-
30
- # Save NPZ
31
- self.chk_save_npz = QCheckBox("Save .npz")
32
- self.chk_save_npz.setChecked(True)
33
- self.chk_save_npz.setToolTip(
34
- "Save the final mask as a compressed NumPy NPZ file."
35
- )
36
- layout.addWidget(self.chk_save_npz)
37
-
38
- # Save TXT
39
- self.chk_save_txt = QCheckBox("Save .txt")
40
- self.chk_save_txt.setChecked(True)
41
- self.chk_save_txt.setToolTip(
42
- "Save bounding box annotations in YOLO TXT format."
43
- )
44
- layout.addWidget(self.chk_save_txt)
45
-
46
- # YOLO with aliases
47
- self.chk_yolo_use_alias = QCheckBox("Save YOLO with Class Aliases")
48
- self.chk_yolo_use_alias.setToolTip(
49
- "If checked, saves YOLO .txt files using class alias names instead of numeric IDs.\n"
50
- "This is useful when a separate .yaml or .names file defines the classes."
51
- )
52
- self.chk_yolo_use_alias.setChecked(True)
53
- layout.addWidget(self.chk_yolo_use_alias)
54
-
55
- # Save class aliases
56
- self.chk_save_class_aliases = QCheckBox("Save Class Aliases (.json)")
57
- self.chk_save_class_aliases.setToolTip(
58
- "Save class aliases to a companion JSON file."
59
- )
60
- self.chk_save_class_aliases.setChecked(False)
61
- layout.addWidget(self.chk_save_class_aliases)
62
-
63
- # Main layout
64
- main_layout = QVBoxLayout(self)
65
- main_layout.setContentsMargins(0, 0, 0, 0)
66
- main_layout.addWidget(group)
67
-
68
- def _connect_signals(self):
69
- """Connect internal signals."""
70
- self.chk_save_npz.stateChanged.connect(self._handle_save_checkbox_change)
71
- self.chk_save_txt.stateChanged.connect(self._handle_save_checkbox_change)
72
-
73
- # Connect all checkboxes to settings changed signal
74
- for checkbox in [
75
- self.chk_auto_save,
76
- self.chk_save_npz,
77
- self.chk_save_txt,
78
- self.chk_yolo_use_alias,
79
- self.chk_save_class_aliases,
80
- ]:
81
- checkbox.stateChanged.connect(self.settings_changed)
82
-
83
- def _handle_save_checkbox_change(self):
84
- """Ensure at least one save format is selected."""
85
- is_npz_checked = self.chk_save_npz.isChecked()
86
- is_txt_checked = self.chk_save_txt.isChecked()
87
-
88
- if not is_npz_checked and not is_txt_checked:
89
- sender = self.sender()
90
- if sender == self.chk_save_npz:
91
- self.chk_save_txt.setChecked(True)
92
- else:
93
- self.chk_save_npz.setChecked(True)
94
-
95
- def get_settings(self):
96
- """Get current settings as dictionary."""
97
- return {
98
- "auto_save": self.chk_auto_save.isChecked(),
99
- "save_npz": self.chk_save_npz.isChecked(),
100
- "save_txt": self.chk_save_txt.isChecked(),
101
- "yolo_use_alias": self.chk_yolo_use_alias.isChecked(),
102
- "save_class_aliases": self.chk_save_class_aliases.isChecked(),
103
- }
104
-
105
- def set_settings(self, settings):
106
- """Set settings from dictionary."""
107
- self.chk_auto_save.setChecked(settings.get("auto_save", True))
108
- self.chk_save_npz.setChecked(settings.get("save_npz", True))
109
- self.chk_save_txt.setChecked(settings.get("save_txt", True))
110
- self.chk_yolo_use_alias.setChecked(settings.get("yolo_use_alias", True))
111
- self.chk_save_class_aliases.setChecked(
112
- settings.get("save_class_aliases", False)
113
- )
1
+ """Settings widget for save options."""
2
+
3
+ from PyQt6.QtCore import pyqtSignal
4
+ from PyQt6.QtWidgets import QCheckBox, QGroupBox, QVBoxLayout, QWidget
5
+
6
+
7
+ class SettingsWidget(QWidget):
8
+ """Widget for application settings."""
9
+
10
+ settings_changed = pyqtSignal()
11
+
12
+ def __init__(self, parent=None):
13
+ super().__init__(parent)
14
+ self._setup_ui()
15
+ self._connect_signals()
16
+
17
+ def _setup_ui(self):
18
+ """Setup the UI layout."""
19
+ group = QGroupBox("Settings")
20
+ layout = QVBoxLayout(group)
21
+
22
+ # Auto-save
23
+ self.chk_auto_save = QCheckBox("Auto-Save on Navigate")
24
+ self.chk_auto_save.setToolTip(
25
+ "Automatically save work when using arrow keys to change images."
26
+ )
27
+ self.chk_auto_save.setChecked(True)
28
+ layout.addWidget(self.chk_auto_save)
29
+
30
+ # Save NPZ
31
+ self.chk_save_npz = QCheckBox("Save .npz")
32
+ self.chk_save_npz.setChecked(True)
33
+ self.chk_save_npz.setToolTip(
34
+ "Save the final mask as a compressed NumPy NPZ file."
35
+ )
36
+ layout.addWidget(self.chk_save_npz)
37
+
38
+ # Save TXT
39
+ self.chk_save_txt = QCheckBox("Save .txt")
40
+ self.chk_save_txt.setChecked(True)
41
+ self.chk_save_txt.setToolTip(
42
+ "Save bounding box annotations in YOLO TXT format."
43
+ )
44
+ layout.addWidget(self.chk_save_txt)
45
+
46
+ # YOLO with aliases
47
+ self.chk_yolo_use_alias = QCheckBox("Save YOLO with Class Aliases")
48
+ self.chk_yolo_use_alias.setToolTip(
49
+ "If checked, saves YOLO .txt files using class alias names instead of numeric IDs.\n"
50
+ "This is useful when a separate .yaml or .names file defines the classes."
51
+ )
52
+ self.chk_yolo_use_alias.setChecked(True)
53
+ layout.addWidget(self.chk_yolo_use_alias)
54
+
55
+ # Save class aliases
56
+ self.chk_save_class_aliases = QCheckBox("Save Class Aliases (.json)")
57
+ self.chk_save_class_aliases.setToolTip(
58
+ "Save class aliases to a companion JSON file."
59
+ )
60
+ self.chk_save_class_aliases.setChecked(False)
61
+ layout.addWidget(self.chk_save_class_aliases)
62
+
63
+ # Operate on View
64
+ self.chk_operate_on_view = QCheckBox("Operate On View")
65
+ self.chk_operate_on_view.setToolTip(
66
+ "If checked, SAM model will operate on the currently displayed (adjusted) image.\n"
67
+ "Otherwise, it operates on the original image."
68
+ )
69
+ self.chk_operate_on_view.setChecked(False)
70
+ layout.addWidget(self.chk_operate_on_view)
71
+
72
+ # Main layout
73
+ main_layout = QVBoxLayout(self)
74
+ main_layout.setContentsMargins(0, 0, 0, 0)
75
+ main_layout.addWidget(group)
76
+
77
+ def _connect_signals(self):
78
+ """Connect internal signals."""
79
+ self.chk_save_npz.stateChanged.connect(self._handle_save_checkbox_change)
80
+ self.chk_save_txt.stateChanged.connect(self._handle_save_checkbox_change)
81
+
82
+ # Connect all checkboxes to settings changed signal
83
+ for checkbox in [
84
+ self.chk_auto_save,
85
+ self.chk_save_npz,
86
+ self.chk_save_txt,
87
+ self.chk_yolo_use_alias,
88
+ self.chk_save_class_aliases,
89
+ self.chk_operate_on_view,
90
+ ]:
91
+ checkbox.stateChanged.connect(self.settings_changed)
92
+
93
+ def _handle_save_checkbox_change(self):
94
+ """Ensure at least one save format is selected."""
95
+ is_npz_checked = self.chk_save_npz.isChecked()
96
+ is_txt_checked = self.chk_save_txt.isChecked()
97
+
98
+ if not is_npz_checked and not is_txt_checked:
99
+ sender = self.sender()
100
+ if sender == self.chk_save_npz:
101
+ self.chk_save_txt.setChecked(True)
102
+ else:
103
+ self.chk_save_npz.setChecked(True)
104
+
105
+ def get_settings(self):
106
+ """Get current settings as dictionary."""
107
+ return {
108
+ "auto_save": self.chk_auto_save.isChecked(),
109
+ "save_npz": self.chk_save_npz.isChecked(),
110
+ "save_txt": self.chk_save_txt.isChecked(),
111
+ "yolo_use_alias": self.chk_yolo_use_alias.isChecked(),
112
+ "save_class_aliases": self.chk_save_class_aliases.isChecked(),
113
+ "operate_on_view": self.chk_operate_on_view.isChecked(),
114
+ }
115
+
116
+ def set_settings(self, settings):
117
+ """Set settings from dictionary."""
118
+ self.chk_auto_save.setChecked(settings.get("auto_save", True))
119
+ self.chk_save_npz.setChecked(settings.get("save_npz", True))
120
+ self.chk_save_txt.setChecked(settings.get("save_txt", True))
121
+ self.chk_yolo_use_alias.setChecked(settings.get("yolo_use_alias", True))
122
+ self.chk_save_class_aliases.setChecked(
123
+ settings.get("save_class_aliases", False)
124
+ )
125
+ self.chk_operate_on_view.setChecked(settings.get("operate_on_view", False))
@@ -0,0 +1,45 @@
1
+ import logging
2
+ import os
3
+
4
+
5
+ def setup_logging(log_file="lazylabel.log", level=logging.INFO):
6
+ """
7
+ Sets up the logging configuration for the application.
8
+
9
+ Args:
10
+ log_file (str): The name of the log file.
11
+ level (int): The logging level (e.g., logging.INFO, logging.DEBUG).
12
+ """
13
+ log_dir = os.path.join(os.path.expanduser("~"), ".lazylabel", "logs")
14
+ os.makedirs(log_dir, exist_ok=True)
15
+ log_path = os.path.join(log_dir, log_file)
16
+
17
+ # Create a logger
18
+ logger = logging.getLogger("lazylabel")
19
+ logger.setLevel(level)
20
+
21
+ # Create handlers
22
+ # Console handler
23
+ c_handler = logging.StreamHandler()
24
+ c_handler.setLevel(level)
25
+
26
+ # File handler
27
+ f_handler = logging.FileHandler(log_path)
28
+ f_handler.setLevel(level)
29
+
30
+ # Create formatters and add it to handlers
31
+ c_format = logging.Formatter("%(levelname)s: %(message)s")
32
+ f_format = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
33
+ c_handler.setFormatter(c_format)
34
+ f_handler.setFormatter(f_format)
35
+
36
+ # Add handlers to the logger
37
+ if not logger.handlers: # Avoid adding handlers multiple times
38
+ logger.addHandler(c_handler)
39
+ logger.addHandler(f_handler)
40
+
41
+ return logger
42
+
43
+
44
+ # Initialize logger for the application
45
+ logger = setup_logging()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: lazylabel-gui
3
- Version: 1.1.4
3
+ Version: 1.1.6
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
@@ -139,6 +139,7 @@ Inspired by [LabelMe](https://github.com/wkentaro/labelme?tab=readme-ov-file#ins
139
139
  |---|---|
140
140
  | `1` | Enter **Point Mode** (for AI segmentation). |
141
141
  | `2` | Enter **Polygon Drawing Mode**. |
142
+ | `3` | Enter **Bounding Box Mode**. |
142
143
  | `E` | Toggle **Selection Mode** to select existing segments. |
143
144
  | `R` | Enter **Edit Mode** for selected polygons (drag shape or vertices). |
144
145
  | `Q` | Toggle **Pan Mode** (click and drag the image). |
@@ -1,37 +1,39 @@
1
1
  lazylabel/__init__.py,sha256=0yitHZYNNuF4Rqj7cqE0TrfDV8zhzKD3A5W1vOymHK4,199
2
- lazylabel/main.py,sha256=AQ-SKj8korOa2rKviFaA1kC-c03VPmVN2xU2qk36764,768
2
+ lazylabel/__main__.py,sha256=5IWklQrNkzeMH6rchzZxxoeSnZlkz-HRiPWXqjjj2yA,139
3
+ lazylabel/main.py,sha256=8NkDYawiSRavXv35Lh2nYAz88EYVt8jrJXYZsk6EE7M,849
3
4
  lazylabel/config/__init__.py,sha256=TnDXH0yx0zy97FfjpiVPHleMgMrM5YwWrUbvevSNJjg,263
4
5
  lazylabel/config/hotkeys.py,sha256=bbHPpCNokwgH0EX74vGcNdn3RoyVZNVr-is6us-7J3M,7990
5
6
  lazylabel/config/paths.py,sha256=ZVKbtaNOxmYO4l6JgsY-8DXaE_jaJfDg2RQJJn3-5nw,1275
6
- lazylabel/config/settings.py,sha256=Ud27cSadJ7M4l30XN0KrxZ3ixAOPXTUhj-SvvanMjaI,1787
7
+ lazylabel/config/settings.py,sha256=0muOT64zBr9Tn-JbyYRPf9xX760-X84ov93m56SpSHA,1898
7
8
  lazylabel/core/__init__.py,sha256=FmRjop_uIBSJwKMGhaZ-3Iwu34LkoxTuD-hnq5vbTSY,232
8
- lazylabel/core/file_manager.py,sha256=Blo55jXW-uGVLrreGRmlHUtK2yTbyj3jsTKkfjD0z7k,4796
9
- lazylabel/core/model_manager.py,sha256=P3IahI0xUk6-F7Y5U4r5RpnUQSelJqX2KBtcmUGNeNY,3368
10
- lazylabel/core/segment_manager.py,sha256=1lABdVdaa69_RPKx6ftYKJh7lNWCanodTsh7Utrpn2Q,6477
9
+ lazylabel/core/file_manager.py,sha256=I8josIoPtRYQXcaBZbC5fb5zqCxbFlTVitkbKjyOz70,4715
10
+ lazylabel/core/model_manager.py,sha256=PZj8YPLOacn_TnFcnPDY3stqapsT4B9mUYqJ500gCtM,3326
11
+ lazylabel/core/segment_manager.py,sha256=M6kHcYeiub3WqL01NElCvKOc2GNmf72LUM1W8XwSaxc,6465
11
12
  lazylabel/models/__init__.py,sha256=fIlk_0DuZfiClcm0XlZdimeHzunQwBmTMI4PcGsaymw,91
12
- lazylabel/models/sam_model.py,sha256=89v99hpD0ngAAQKiuRyIib0E-5u9zTDJcubtmxxG-PM,7878
13
+ lazylabel/models/sam_model.py,sha256=anh4XMkoX8U5MCZHV5HqN0x8iVnRYi50rcXFt6LdFCQ,8020
13
14
  lazylabel/ui/__init__.py,sha256=4qDIh9y6tABPmD8MAMGZn_G7oSRyrcHt2HkjoWgbGH4,268
14
- lazylabel/ui/control_panel.py,sha256=UlETN2IZv1l2xiaWPQvdalaK_f9YQf9iiB1Jb_EEgfs,9260
15
- lazylabel/ui/editable_vertex.py,sha256=xzc5QdFJJXiy035C3HgR4ph-tuJu8245l-Ar7aBvVv8,2399
16
- lazylabel/ui/hotkey_dialog.py,sha256=ZlZoPvY822ke8YkbCy22o2RUjxtkXSoEOg8eVETIKpQ,15118
15
+ lazylabel/ui/control_panel.py,sha256=ZYclv2G1-HR_pg-b-4heU8hsKfE35jggLvcmJ3clHZA,10471
16
+ lazylabel/ui/editable_vertex.py,sha256=nAFC2UuFfbvMbGBbAiLWA77cS5-Hn3a08xe1_QLz2yk,2449
17
+ lazylabel/ui/hotkey_dialog.py,sha256=U_B76HLOxWdWkfA4d2XgRUaZTJPAAE_m5fmwf7Rh-5Y,14743
17
18
  lazylabel/ui/hoverable_pixelmap_item.py,sha256=kJFOp7WXiyHpNf7l73TZjiob85jgP30b5MZvu_z5L3c,728
18
19
  lazylabel/ui/hoverable_polygon_item.py,sha256=aclUwd0P8H8xbcep6GwhnfaVs1zSkqeZKAL-xeDyMiU,1222
19
- lazylabel/ui/main_window.py,sha256=ta3nzb6MWG-eLexlGKBc3oKtlsF9HpI-q1SvlrA-W2o,78623
20
+ lazylabel/ui/main_window.py,sha256=zuszmw41849OXjBwVBc0TnBeuU4HZOJsJEurrzb_qbI,83764
20
21
  lazylabel/ui/numeric_table_widget_item.py,sha256=dQUlIFu9syCxTGAHVIlmbgkI7aJ3f3wmDPBz1AGK9Bg,283
21
- lazylabel/ui/photo_viewer.py,sha256=4n2zSpFAnausCoIU-wwWDHDo6vsNp_RGIkhDyhuM2_A,1997
22
+ lazylabel/ui/photo_viewer.py,sha256=f93Mn9ajR2CYakJbbhhHvD5blKrwiGq3ZYgro-k2npc,4217
22
23
  lazylabel/ui/reorderable_class_table.py,sha256=sxHhQre5O_MXLDFgKnw43QnvXXoqn5xRKMGitgO7muI,2371
23
24
  lazylabel/ui/right_panel.py,sha256=-PeXcu7Lr-xhZniBMvWLDPiFb_RAHYAcILyw8fPJs6I,13139
24
25
  lazylabel/ui/widgets/__init__.py,sha256=bYjLRTqWdi4hcPfSSXmXuT-0c5Aee7HnnQurv_k5bfY,314
25
- lazylabel/ui/widgets/adjustments_widget.py,sha256=xM43q1khpvRIHslPfI6bukzjx9J0mPgHUdNKCmp3rtM,3912
26
+ lazylabel/ui/widgets/adjustments_widget.py,sha256=CJXtq19hfy12ggCA3_RMwETKNnVAQsn-rT_lIYxpAT4,13458
26
27
  lazylabel/ui/widgets/model_selection_widget.py,sha256=kMPaBMfdfnEVH-Be1d5OxLEuioO0c04FZT1Hr904axM,3497
27
- lazylabel/ui/widgets/settings_widget.py,sha256=2T7A5t1g9oIRx6KsxWk--Reuft9DYeqH1rRI9ME18HQ,4347
28
+ lazylabel/ui/widgets/settings_widget.py,sha256=qxVCiTYMQee95pE_FkFUXMCsmuo85LYdKeQYaCTrRVc,4829
28
29
  lazylabel/ui/widgets/status_bar.py,sha256=wTbMQNEOBfmtNj8EVFZS_lxgaemu-CbRXeZzEQDaVz8,4014
29
30
  lazylabel/utils/__init__.py,sha256=V6IR5Gim-39HgM2NyTVT-n8gy3mjilCSFW9y0owN5nc,179
30
31
  lazylabel/utils/custom_file_system_model.py,sha256=-3EimlybvevH6bvqBE0qdFnLADVtayylmkntxPXK0Bk,4869
32
+ lazylabel/utils/logger.py,sha256=R7z6ifgA-NY-9ZbLlNH0i19zzwXndJ_gkG2J1zpVEhg,1306
31
33
  lazylabel/utils/utils.py,sha256=sYSCoXL27OaLgOZaUkCAhgmKZ7YfhR3Cc5F8nDIa3Ig,414
32
- lazylabel_gui-1.1.4.dist-info/licenses/LICENSE,sha256=kSDEIgrWAPd1u2UFGGpC9X71dhzrlzBFs8hbDlENnGE,1092
33
- lazylabel_gui-1.1.4.dist-info/METADATA,sha256=hYVIAtM7vZNaJ8-0QOnFtNyaK3UpScgswNyJuaiJaFE,9506
34
- lazylabel_gui-1.1.4.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
35
- lazylabel_gui-1.1.4.dist-info/entry_points.txt,sha256=Hd0WwEG9OPTa_ziYjiD0aRh7R6Fupt-wdQ3sspdc1mM,54
36
- lazylabel_gui-1.1.4.dist-info/top_level.txt,sha256=YN4uIyrpDBq1wiJaBuZLDipIzyZY0jqJOmmXiPIOUkU,10
37
- lazylabel_gui-1.1.4.dist-info/RECORD,,
34
+ lazylabel_gui-1.1.6.dist-info/licenses/LICENSE,sha256=kSDEIgrWAPd1u2UFGGpC9X71dhzrlzBFs8hbDlENnGE,1092
35
+ lazylabel_gui-1.1.6.dist-info/METADATA,sha256=6zAAWlFPc61dOus5FGTAeEp4AlwNnbUjQsmHHwSgATQ,9546
36
+ lazylabel_gui-1.1.6.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
37
+ lazylabel_gui-1.1.6.dist-info/entry_points.txt,sha256=Hd0WwEG9OPTa_ziYjiD0aRh7R6Fupt-wdQ3sspdc1mM,54
38
+ lazylabel_gui-1.1.6.dist-info/top_level.txt,sha256=YN4uIyrpDBq1wiJaBuZLDipIzyZY0jqJOmmXiPIOUkU,10
39
+ lazylabel_gui-1.1.6.dist-info/RECORD,,