|
@@ -46,7 +46,6 @@ LABEL_COLORMAP = imgviz.label_colormap()
|
|
|
|
|
|
|
|
|
|
class MainWindow(QtWidgets.QMainWindow):
|
|
class MainWindow(QtWidgets.QMainWindow):
|
|
-
|
|
|
|
FIT_WINDOW, FIT_WIDTH, MANUAL_ZOOM = 0, 1, 2
|
|
FIT_WINDOW, FIT_WIDTH, MANUAL_ZOOM = 0, 1, 2
|
|
|
|
|
|
def __init__(
|
|
def __init__(
|
|
@@ -58,9 +57,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
output_dir=None,
|
|
output_dir=None,
|
|
):
|
|
):
|
|
if output is not None:
|
|
if output is not None:
|
|
- logger.warning(
|
|
|
|
- "argument output is deprecated, use output_file instead"
|
|
|
|
- )
|
|
|
|
|
|
+ logger.warning("argument output is deprecated, use output_file instead")
|
|
if output_file is None:
|
|
if output_file is None:
|
|
output_file = output
|
|
output_file = output
|
|
|
|
|
|
@@ -125,17 +122,14 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
self.labelList.itemDoubleClicked.connect(self.editLabel)
|
|
self.labelList.itemDoubleClicked.connect(self.editLabel)
|
|
self.labelList.itemChanged.connect(self.labelItemChanged)
|
|
self.labelList.itemChanged.connect(self.labelItemChanged)
|
|
self.labelList.itemDropped.connect(self.labelOrderChanged)
|
|
self.labelList.itemDropped.connect(self.labelOrderChanged)
|
|
- self.shape_dock = QtWidgets.QDockWidget(
|
|
|
|
- self.tr("Polygon Labels"), self
|
|
|
|
- )
|
|
|
|
|
|
+ self.shape_dock = QtWidgets.QDockWidget(self.tr("Polygon Labels"), self)
|
|
self.shape_dock.setObjectName("Labels")
|
|
self.shape_dock.setObjectName("Labels")
|
|
self.shape_dock.setWidget(self.labelList)
|
|
self.shape_dock.setWidget(self.labelList)
|
|
|
|
|
|
self.uniqLabelList = UniqueLabelQListWidget()
|
|
self.uniqLabelList = UniqueLabelQListWidget()
|
|
self.uniqLabelList.setToolTip(
|
|
self.uniqLabelList.setToolTip(
|
|
self.tr(
|
|
self.tr(
|
|
- "Select label to start annotating for it. "
|
|
|
|
- "Press 'Esc' to deselect."
|
|
|
|
|
|
+ "Select label to start annotating for it. " "Press 'Esc' to deselect."
|
|
)
|
|
)
|
|
)
|
|
)
|
|
if self._config["labels"]:
|
|
if self._config["labels"]:
|
|
@@ -152,9 +146,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
self.fileSearch.setPlaceholderText(self.tr("Search Filename"))
|
|
self.fileSearch.setPlaceholderText(self.tr("Search Filename"))
|
|
self.fileSearch.textChanged.connect(self.fileSearchChanged)
|
|
self.fileSearch.textChanged.connect(self.fileSearchChanged)
|
|
self.fileListWidget = QtWidgets.QListWidget()
|
|
self.fileListWidget = QtWidgets.QListWidget()
|
|
- self.fileListWidget.itemSelectionChanged.connect(
|
|
|
|
- self.fileSelectionChanged
|
|
|
|
- )
|
|
|
|
|
|
+ self.fileListWidget.itemSelectionChanged.connect(self.fileSelectionChanged)
|
|
fileListLayout = QtWidgets.QVBoxLayout()
|
|
fileListLayout = QtWidgets.QVBoxLayout()
|
|
fileListLayout.setContentsMargins(0, 0, 0, 0)
|
|
fileListLayout.setContentsMargins(0, 0, 0, 0)
|
|
fileListLayout.setSpacing(0)
|
|
fileListLayout.setSpacing(0)
|
|
@@ -611,9 +603,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
labelMenu = QtWidgets.QMenu()
|
|
labelMenu = QtWidgets.QMenu()
|
|
utils.addActions(labelMenu, (edit, delete))
|
|
utils.addActions(labelMenu, (edit, delete))
|
|
self.labelList.setContextMenuPolicy(Qt.CustomContextMenu)
|
|
self.labelList.setContextMenuPolicy(Qt.CustomContextMenu)
|
|
- self.labelList.customContextMenuRequested.connect(
|
|
|
|
- self.popLabelListMenu
|
|
|
|
- )
|
|
|
|
|
|
+ self.labelList.customContextMenuRequested.connect(self.popLabelListMenu)
|
|
|
|
|
|
# Store actions for further handling.
|
|
# Store actions for further handling.
|
|
self.actions = utils.struct(
|
|
self.actions = utils.struct(
|
|
@@ -782,9 +772,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
selectAiModel.defaultWidget().layout().addWidget(selectAiModelLabel)
|
|
selectAiModel.defaultWidget().layout().addWidget(selectAiModelLabel)
|
|
#
|
|
#
|
|
self._selectAiModelComboBox = QtWidgets.QComboBox()
|
|
self._selectAiModelComboBox = QtWidgets.QComboBox()
|
|
- selectAiModel.defaultWidget().layout().addWidget(
|
|
|
|
- self._selectAiModelComboBox
|
|
|
|
- )
|
|
|
|
|
|
+ selectAiModel.defaultWidget().layout().addWidget(self._selectAiModelComboBox)
|
|
model_names = [model.name for model in MODELS]
|
|
model_names = [model.name for model in MODELS]
|
|
self._selectAiModelComboBox.addItems(model_names)
|
|
self._selectAiModelComboBox.addItems(model_names)
|
|
if self._config["ai"]["default"] in model_names:
|
|
if self._config["ai"]["default"] in model_names:
|
|
@@ -1302,9 +1290,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
description=s.description,
|
|
description=s.description,
|
|
shape_type=s.shape_type,
|
|
shape_type=s.shape_type,
|
|
flags=s.flags,
|
|
flags=s.flags,
|
|
- mask=None
|
|
|
|
- if s.mask is None
|
|
|
|
- else utils.img_arr_to_b64(s.mask),
|
|
|
|
|
|
+ mask=None if s.mask is None else utils.img_arr_to_b64(s.mask),
|
|
)
|
|
)
|
|
)
|
|
)
|
|
return data
|
|
return data
|
|
@@ -1332,9 +1318,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
flags=flags,
|
|
flags=flags,
|
|
)
|
|
)
|
|
self.labelFile = lf
|
|
self.labelFile = lf
|
|
- items = self.fileListWidget.findItems(
|
|
|
|
- self.imagePath, Qt.MatchExactly
|
|
|
|
- )
|
|
|
|
|
|
+ items = self.fileListWidget.findItems(self.imagePath, Qt.MatchExactly)
|
|
if len(items) > 0:
|
|
if len(items) > 0:
|
|
if len(items) != 1:
|
|
if len(items) != 1:
|
|
raise RuntimeError("There are duplicate files.")
|
|
raise RuntimeError("There are duplicate files.")
|
|
@@ -1490,9 +1474,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
self.actions.keepPrevScale.setChecked(enabled)
|
|
self.actions.keepPrevScale.setChecked(enabled)
|
|
|
|
|
|
def onNewBrightnessContrast(self, qimage):
|
|
def onNewBrightnessContrast(self, qimage):
|
|
- self.canvas.loadPixmap(
|
|
|
|
- QtGui.QPixmap.fromImage(qimage), clear_shapes=False
|
|
|
|
- )
|
|
|
|
|
|
+ self.canvas.loadPixmap(QtGui.QPixmap.fromImage(qimage), clear_shapes=False)
|
|
|
|
|
|
def brightnessContrast(self, value):
|
|
def brightnessContrast(self, value):
|
|
dialog = BrightnessContrastDialog(
|
|
dialog = BrightnessContrastDialog(
|
|
@@ -1539,16 +1521,12 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
)
|
|
)
|
|
return False
|
|
return False
|
|
# assumes same name, but json extension
|
|
# assumes same name, but json extension
|
|
- self.status(
|
|
|
|
- str(self.tr("Loading %s...")) % osp.basename(str(filename))
|
|
|
|
- )
|
|
|
|
|
|
+ self.status(str(self.tr("Loading %s...")) % osp.basename(str(filename)))
|
|
label_file = osp.splitext(filename)[0] + ".json"
|
|
label_file = osp.splitext(filename)[0] + ".json"
|
|
if self.output_dir:
|
|
if self.output_dir:
|
|
label_file_without_path = osp.basename(label_file)
|
|
label_file_without_path = osp.basename(label_file)
|
|
label_file = osp.join(self.output_dir, label_file_without_path)
|
|
label_file = osp.join(self.output_dir, label_file_without_path)
|
|
- if QtCore.QFile.exists(label_file) and LabelFile.is_label_file(
|
|
|
|
- label_file
|
|
|
|
- ):
|
|
|
|
|
|
+ if QtCore.QFile.exists(label_file) and LabelFile.is_label_file(label_file):
|
|
try:
|
|
try:
|
|
self.labelFile = LabelFile(label_file)
|
|
self.labelFile = LabelFile(label_file)
|
|
except LabelFileError as e:
|
|
except LabelFileError as e:
|
|
@@ -1695,9 +1673,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
def closeEvent(self, event):
|
|
def closeEvent(self, event):
|
|
if not self.mayContinue():
|
|
if not self.mayContinue():
|
|
event.ignore()
|
|
event.ignore()
|
|
- self.settings.setValue(
|
|
|
|
- "filename", self.filename if self.filename else ""
|
|
|
|
- )
|
|
|
|
|
|
+ self.settings.setValue("filename", self.filename if self.filename else "")
|
|
self.settings.setValue("window/size", self.size())
|
|
self.settings.setValue("window/size", self.size())
|
|
self.settings.setValue("window/position", self.pos())
|
|
self.settings.setValue("window/position", self.pos())
|
|
self.settings.setValue("window/state", self.saveState())
|
|
self.settings.setValue("window/state", self.saveState())
|
|
@@ -1839,9 +1815,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
|
|
|
if current_filename in self.imageList:
|
|
if current_filename in self.imageList:
|
|
# retain currently selected file
|
|
# retain currently selected file
|
|
- self.fileListWidget.setCurrentRow(
|
|
|
|
- self.imageList.index(current_filename)
|
|
|
|
- )
|
|
|
|
|
|
+ self.fileListWidget.setCurrentRow(self.imageList.index(current_filename))
|
|
self.fileListWidget.repaint()
|
|
self.fileListWidget.repaint()
|
|
|
|
|
|
def saveFile(self, _value=False):
|
|
def saveFile(self, _value=False):
|
|
@@ -1863,13 +1837,9 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
caption = self.tr("%s - Choose File") % __appname__
|
|
caption = self.tr("%s - Choose File") % __appname__
|
|
filters = self.tr("Label files (*%s)") % LabelFile.suffix
|
|
filters = self.tr("Label files (*%s)") % LabelFile.suffix
|
|
if self.output_dir:
|
|
if self.output_dir:
|
|
- dlg = QtWidgets.QFileDialog(
|
|
|
|
- self, caption, self.output_dir, filters
|
|
|
|
- )
|
|
|
|
|
|
+ dlg = QtWidgets.QFileDialog(self, caption, self.output_dir, filters)
|
|
else:
|
|
else:
|
|
- dlg = QtWidgets.QFileDialog(
|
|
|
|
- self, caption, self.currentPath(), filters
|
|
|
|
- )
|
|
|
|
|
|
+ dlg = QtWidgets.QFileDialog(self, caption, self.currentPath(), filters)
|
|
dlg.setDefaultSuffix(LabelFile.suffix[1:])
|
|
dlg.setDefaultSuffix(LabelFile.suffix[1:])
|
|
dlg.setAcceptMode(QtWidgets.QFileDialog.AcceptSave)
|
|
dlg.setAcceptMode(QtWidgets.QFileDialog.AcceptSave)
|
|
dlg.setOption(QtWidgets.QFileDialog.DontConfirmOverwrite, False)
|
|
dlg.setOption(QtWidgets.QFileDialog.DontConfirmOverwrite, False)
|
|
@@ -1918,8 +1888,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
def deleteFile(self):
|
|
def deleteFile(self):
|
|
mb = QtWidgets.QMessageBox
|
|
mb = QtWidgets.QMessageBox
|
|
msg = self.tr(
|
|
msg = self.tr(
|
|
- "You are about to permanently delete this label file, "
|
|
|
|
- "proceed anyway?"
|
|
|
|
|
|
+ "You are about to permanently delete this label file, " "proceed anyway?"
|
|
)
|
|
)
|
|
answer = mb.warning(self, self.tr("Attention"), msg, mb.Yes | mb.No)
|
|
answer = mb.warning(self, self.tr("Attention"), msg, mb.Yes | mb.No)
|
|
if answer != mb.Yes:
|
|
if answer != mb.Yes:
|
|
@@ -1956,9 +1925,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
if not self.dirty:
|
|
if not self.dirty:
|
|
return True
|
|
return True
|
|
mb = QtWidgets.QMessageBox
|
|
mb = QtWidgets.QMessageBox
|
|
- msg = self.tr('Save annotations to "{}" before closing?').format(
|
|
|
|
- self.filename
|
|
|
|
- )
|
|
|
|
|
|
+ msg = self.tr('Save annotations to "{}" before closing?').format(self.filename)
|
|
answer = mb.question(
|
|
answer = mb.question(
|
|
self,
|
|
self,
|
|
self.tr("Save annotations?"),
|
|
self.tr("Save annotations?"),
|
|
@@ -1999,8 +1966,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
def deleteSelectedShape(self):
|
|
def deleteSelectedShape(self):
|
|
yes, no = QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No
|
|
yes, no = QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No
|
|
msg = self.tr(
|
|
msg = self.tr(
|
|
- "You are about to permanently delete {} polygons, "
|
|
|
|
- "proceed anyway?"
|
|
|
|
|
|
+ "You are about to permanently delete {} polygons, " "proceed anyway?"
|
|
).format(len(self.canvas.selectedShapes))
|
|
).format(len(self.canvas.selectedShapes))
|
|
if yes == QtWidgets.QMessageBox.warning(
|
|
if yes == QtWidgets.QMessageBox.warning(
|
|
self, self.tr("Attention"), msg, yes | no, yes
|
|
self, self.tr("Attention"), msg, yes | no, yes
|
|
@@ -2030,9 +1996,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
if self.lastOpenDir and osp.exists(self.lastOpenDir):
|
|
if self.lastOpenDir and osp.exists(self.lastOpenDir):
|
|
defaultOpenDirPath = self.lastOpenDir
|
|
defaultOpenDirPath = self.lastOpenDir
|
|
else:
|
|
else:
|
|
- defaultOpenDirPath = (
|
|
|
|
- osp.dirname(self.filename) if self.filename else "."
|
|
|
|
- )
|
|
|
|
|
|
+ defaultOpenDirPath = osp.dirname(self.filename) if self.filename else "."
|
|
|
|
|
|
targetDirPath = str(
|
|
targetDirPath = str(
|
|
QtWidgets.QFileDialog.getExistingDirectory(
|
|
QtWidgets.QFileDialog.getExistingDirectory(
|
|
@@ -2061,9 +2025,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
|
|
|
|
self.filename = None
|
|
self.filename = None
|
|
for file in imageFiles:
|
|
for file in imageFiles:
|
|
- if file in self.imageList or not file.lower().endswith(
|
|
|
|
- tuple(extensions)
|
|
|
|
- ):
|
|
|
|
|
|
+ if file in self.imageList or not file.lower().endswith(tuple(extensions)):
|
|
continue
|
|
continue
|
|
label_file = osp.splitext(file)[0] + ".json"
|
|
label_file = osp.splitext(file)[0] + ".json"
|
|
if self.output_dir:
|
|
if self.output_dir:
|
|
@@ -2071,9 +2033,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
label_file = osp.join(self.output_dir, label_file_without_path)
|
|
label_file = osp.join(self.output_dir, label_file_without_path)
|
|
item = QtWidgets.QListWidgetItem(file)
|
|
item = QtWidgets.QListWidgetItem(file)
|
|
item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
|
|
item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
|
|
- if QtCore.QFile.exists(label_file) and LabelFile.is_label_file(
|
|
|
|
- label_file
|
|
|
|
- ):
|
|
|
|
|
|
+ if QtCore.QFile.exists(label_file) and LabelFile.is_label_file(label_file):
|
|
item.setCheckState(Qt.Checked)
|
|
item.setCheckState(Qt.Checked)
|
|
else:
|
|
else:
|
|
item.setCheckState(Qt.Unchecked)
|
|
item.setCheckState(Qt.Unchecked)
|
|
@@ -2104,9 +2064,7 @@ class MainWindow(QtWidgets.QMainWindow):
|
|
label_file = osp.join(self.output_dir, label_file_without_path)
|
|
label_file = osp.join(self.output_dir, label_file_without_path)
|
|
item = QtWidgets.QListWidgetItem(filename)
|
|
item = QtWidgets.QListWidgetItem(filename)
|
|
item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
|
|
item.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
|
|
- if QtCore.QFile.exists(label_file) and LabelFile.is_label_file(
|
|
|
|
- label_file
|
|
|
|
- ):
|
|
|
|
|
|
+ if QtCore.QFile.exists(label_file) and LabelFile.is_label_file(label_file):
|
|
item.setCheckState(Qt.Checked)
|
|
item.setCheckState(Qt.Checked)
|
|
else:
|
|
else:
|
|
item.setCheckState(Qt.Unchecked)
|
|
item.setCheckState(Qt.Unchecked)
|