lazylabel-gui 1.0.0__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.
lazylabel/controls.py ADDED
@@ -0,0 +1,108 @@
1
+ from PyQt6.QtWidgets import (
2
+ QWidget,
3
+ QVBoxLayout,
4
+ QPushButton,
5
+ QLabel,
6
+ QFrame,
7
+ QTableWidget,
8
+ QTreeView,
9
+ QAbstractItemView,
10
+ QHBoxLayout,
11
+ QComboBox,
12
+ QHeaderView,
13
+ )
14
+ from PyQt6.QtCore import Qt
15
+ from .reorderable_class_table import ReorderableClassTable
16
+
17
+
18
+ class ControlPanel(QWidget):
19
+ def __init__(self, parent=None):
20
+ super().__init__(parent)
21
+ layout = QVBoxLayout(self)
22
+ layout.setAlignment(Qt.AlignmentFlag.AlignTop)
23
+ self.mode_label = QLabel("Mode: Points")
24
+ font = self.mode_label.font()
25
+ font.setPointSize(14)
26
+ font.setBold(True)
27
+ self.mode_label.setFont(font)
28
+ layout.addWidget(self.mode_label)
29
+ self.btn_sam_mode = QPushButton("Point Mode (1)")
30
+ self.btn_polygon_mode = QPushButton("Polygon Mode (2)")
31
+ self.btn_selection_mode = QPushButton("Selection Mode (E)")
32
+ layout.addWidget(self.btn_sam_mode)
33
+ layout.addWidget(self.btn_polygon_mode)
34
+ layout.addWidget(self.btn_selection_mode)
35
+ layout.addSpacing(20)
36
+ line1 = QFrame()
37
+ line1.setFrameShape(QFrame.Shape.HLine)
38
+ layout.addWidget(line1)
39
+ layout.addSpacing(10)
40
+ self.btn_clear_points = QPushButton("Clear Clicks (C)")
41
+ layout.addWidget(self.btn_clear_points)
42
+ layout.addStretch()
43
+ self.device_label = QLabel("Device: Unknown")
44
+ layout.addWidget(self.device_label)
45
+ self.setFixedWidth(250)
46
+
47
+
48
+ class RightPanel(QWidget):
49
+ def __init__(self, parent=None):
50
+ super().__init__(parent)
51
+ layout = QVBoxLayout(self)
52
+
53
+ # File Explorer
54
+ file_explorer_layout = QVBoxLayout()
55
+ self.btn_open_folder = QPushButton("Open Image Folder")
56
+ self.file_tree = QTreeView()
57
+ file_explorer_layout.addWidget(self.btn_open_folder)
58
+ file_explorer_layout.addWidget(self.file_tree)
59
+ layout.addLayout(file_explorer_layout)
60
+
61
+ # Status Label
62
+ self.status_label = QLabel("")
63
+ self.status_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
64
+ layout.addWidget(self.status_label)
65
+
66
+ # Segment Table
67
+ segment_layout = QVBoxLayout()
68
+ class_filter_layout = QHBoxLayout()
69
+ class_filter_layout.addWidget(QLabel("Filter Class:"))
70
+ self.class_filter_combo = QComboBox()
71
+ class_filter_layout.addWidget(self.class_filter_combo)
72
+ segment_layout.addLayout(class_filter_layout)
73
+
74
+ self.segment_table = QTableWidget()
75
+ self.segment_table.setColumnCount(3)
76
+ self.segment_table.setHorizontalHeaderLabels(["Index", "Class", "Type"])
77
+ self.segment_table.horizontalHeader().setSectionResizeMode(
78
+ QHeaderView.ResizeMode.Stretch
79
+ )
80
+ self.segment_table.setSelectionBehavior(
81
+ QAbstractItemView.SelectionBehavior.SelectRows
82
+ )
83
+ self.segment_table.setSortingEnabled(True)
84
+ segment_layout.addWidget(self.segment_table)
85
+
86
+ segment_action_layout = QHBoxLayout()
87
+ self.btn_merge_selection = QPushButton("Merge to Class")
88
+ self.btn_delete_selection = QPushButton("Delete")
89
+ segment_action_layout.addWidget(self.btn_merge_selection)
90
+ segment_action_layout.addWidget(self.btn_delete_selection)
91
+ segment_layout.addLayout(segment_action_layout)
92
+ layout.addLayout(segment_layout, 2)
93
+
94
+ # Class Table
95
+ class_layout = QVBoxLayout()
96
+ class_layout.addWidget(QLabel("Class Order:"))
97
+ self.class_table = ReorderableClassTable()
98
+ self.class_table.setColumnCount(1)
99
+ self.class_table.setHorizontalHeaderLabels(["Class ID"])
100
+ self.class_table.horizontalHeader().setSectionResizeMode(
101
+ QHeaderView.ResizeMode.Stretch
102
+ )
103
+ class_layout.addWidget(self.class_table)
104
+ self.btn_reassign_classes = QPushButton("Reassign Class IDs")
105
+ class_layout.addWidget(self.btn_reassign_classes)
106
+ layout.addLayout(class_layout, 1)
107
+
108
+ self.setFixedWidth(350)
@@ -0,0 +1,57 @@
1
+ import os
2
+ from PyQt6.QtCore import Qt, QModelIndex, QDir
3
+ from PyQt6.QtGui import QFileSystemModel, QBrush, QColor
4
+
5
+
6
+ class CustomFileSystemModel(QFileSystemModel):
7
+ def __init__(self, parent=None):
8
+ super().__init__(parent)
9
+ self.setFilter(QDir.Filter.NoDotAndDotDot | QDir.Filter.Files)
10
+ self.setNameFilterDisables(False)
11
+ self.setNameFilters(["*.png", "*.jpg", "*.jpeg", "*.tiff"])
12
+ self.highlighted_path = None
13
+
14
+ def set_highlighted_path(self, path):
15
+ self.highlighted_path = path
16
+
17
+ def columnCount(self, parent: QModelIndex = QModelIndex()) -> int:
18
+ return 2
19
+
20
+ def headerData(
21
+ self,
22
+ section: int,
23
+ orientation: Qt.Orientation,
24
+ role: int = Qt.ItemDataRole.DisplayRole,
25
+ ):
26
+ if (
27
+ orientation == Qt.Orientation.Horizontal
28
+ and role == Qt.ItemDataRole.DisplayRole
29
+ ):
30
+ if section == 0:
31
+ return "File Name"
32
+ if section == 1:
33
+ return "Mask"
34
+ return super().headerData(section, orientation, role)
35
+
36
+ def data(self, index: QModelIndex, role: int = Qt.ItemDataRole.DisplayRole):
37
+ if not index.isValid():
38
+ return None
39
+
40
+ # Handle the temporary highlight for saving
41
+ if role == Qt.ItemDataRole.BackgroundRole:
42
+ filePath = self.filePath(index)
43
+ if filePath == self.highlighted_path:
44
+ return QBrush(QColor("yellow"))
45
+
46
+ if index.column() == 1:
47
+ if role == Qt.ItemDataRole.CheckStateRole:
48
+ filePath = self.filePath(index.siblingAtColumn(0))
49
+ mask_path = os.path.splitext(filePath)[0] + ".npz"
50
+ return (
51
+ Qt.CheckState.Checked
52
+ if os.path.exists(mask_path)
53
+ else Qt.CheckState.Unchecked
54
+ )
55
+ return None
56
+
57
+ return super().data(index, role)
@@ -0,0 +1,25 @@
1
+ from PyQt6.QtWidgets import QGraphicsEllipseItem, QGraphicsItem
2
+ from PyQt6.QtCore import Qt
3
+ from PyQt6.QtGui import QBrush, QPen
4
+
5
+
6
+ class EditableVertexItem(QGraphicsEllipseItem):
7
+ def __init__(self, main_window, segment_index, vertex_index, x, y, w, h):
8
+ super().__init__(x, y, w, h)
9
+ self.main_window = main_window
10
+ self.segment_index = segment_index
11
+ self.vertex_index = vertex_index
12
+
13
+ self.setZValue(200)
14
+ self.setBrush(QBrush(Qt.GlobalColor.cyan))
15
+ self.setPen(QPen(Qt.GlobalColor.white, 1))
16
+ self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemIsMovable)
17
+ self.setFlag(QGraphicsItem.GraphicsItemFlag.ItemSendsGeometryChanges)
18
+
19
+ def itemChange(self, change, value):
20
+ if change == QGraphicsItem.GraphicsItemChange.ItemPositionHasChanged:
21
+ new_pos = value
22
+ self.main_window.update_vertex_pos(
23
+ self.segment_index, self.vertex_index, new_pos
24
+ )
25
+ return super().itemChange(change, value)
@@ -0,0 +1,23 @@
1
+ from PyQt6.QtWidgets import QGraphicsPolygonItem
2
+ from PyQt6.QtGui import QBrush
3
+
4
+
5
+ class HoverablePolygonItem(QGraphicsPolygonItem):
6
+ def __init__(self, polygon, parent=None):
7
+ super().__init__(polygon, parent)
8
+ self.setAcceptHoverEvents(True)
9
+ self.default_brush = QBrush()
10
+ self.hover_brush = QBrush()
11
+
12
+ def set_brushes(self, default_brush, hover_brush):
13
+ self.default_brush = default_brush
14
+ self.hover_brush = hover_brush
15
+ self.setBrush(self.default_brush)
16
+
17
+ def hoverEnterEvent(self, event):
18
+ self.setBrush(self.hover_brush)
19
+ super().hoverEnterEvent(event)
20
+
21
+ def hoverLeaveEvent(self, event):
22
+ self.setBrush(self.default_brush)
23
+ super().hoverLeaveEvent(event)