diff --git a/isat.yaml b/isat.yaml index bec54bb..6ea21f0 100644 --- a/isat.yaml +++ b/isat.yaml @@ -1,4 +1,4 @@ -contour_mode: all +contour_mode: external label: - color: '#000000' name: __background__ @@ -21,4 +21,4 @@ label: - color: '#5c3566' name: fence language: en -mask_alpha: 0.5 +mask_alpha: 0.6 diff --git a/main.py b/main.py index cea8269..6791910 100644 --- a/main.py +++ b/main.py @@ -12,5 +12,5 @@ if __name__ == '__main__': app = QtWidgets.QApplication(['']) mainwindow = MainWindow() mainwindow.show() - sys.exit(app.exec()) + sys.exit(app.exec_()) diff --git a/ui/MainWindow.py b/ui/MainWindow.py index 656819d..0930472 100644 --- a/ui/MainWindow.py +++ b/ui/MainWindow.py @@ -487,12 +487,12 @@ class Ui_MainWindow(object): self.actionTo_LabelMe.setToolTip(_translate("MainWindow", "Convert ISAT to LabelMe")) self.actionTo_LabelMe.setStatusTip(_translate("MainWindow", "Convert ISAT jsons to LabelMe jsons.")) self.actionContour_Max_only.setText(_translate("MainWindow", "Max only")) - self.actionContour_Max_only.setStatusTip(_translate("MainWindow", "Contour save max only.")) - self.actionContour_Max_only.setWhatsThis(_translate("MainWindow", "Contour save max only.")) + self.actionContour_Max_only.setStatusTip(_translate("MainWindow", "Max contour save only.")) + self.actionContour_Max_only.setWhatsThis(_translate("MainWindow", "Max contour save only.")) self.actionContour_External.setText(_translate("MainWindow", "External")) - self.actionContour_External.setStatusTip(_translate("MainWindow", "Contour save external only.")) - self.actionContour_External.setWhatsThis(_translate("MainWindow", "Contour save external only.")) + self.actionContour_External.setStatusTip(_translate("MainWindow", "External contour save only.")) + self.actionContour_External.setWhatsThis(_translate("MainWindow", "External contour save only.")) self.actionContour_All.setText(_translate("MainWindow", "All")) - self.actionContour_All.setStatusTip(_translate("MainWindow", "Contour save all.")) - self.actionContour_All.setWhatsThis(_translate("MainWindow", "Contour save all.")) + self.actionContour_All.setStatusTip(_translate("MainWindow", "All contour save.")) + self.actionContour_All.setWhatsThis(_translate("MainWindow", "All contour save.")) import icons_rc diff --git a/ui/MainWindow.ui b/ui/MainWindow.ui index 481b280..210e37b 100644 --- a/ui/MainWindow.ui +++ b/ui/MainWindow.ui @@ -803,10 +803,10 @@ Max only - Contour save max only. + Max contour save only. - Contour save max only. + Max contour save only. @@ -823,10 +823,10 @@ External - Contour save external only. + External contour save only. - Contour save external only. + External contour save only. @@ -843,10 +843,10 @@ All - Contour save all. + All contour save. - Contour save all. + All contour save. diff --git a/ui/anno_dock.py b/ui/anno_dock.py index 7f653f3..cf9be55 100644 --- a/ui/anno_dock.py +++ b/ui/anno_dock.py @@ -1,5 +1,7 @@ # -*- coding: utf-8 -*- +# Form implementation generated from reading ui file '/home/super/PycharmProjects/ISAT_with_segment_anything/ui/anno_dock.ui' +# # Created by: PyQt5 UI code generator 5.15.7 # # WARNING: Any manual changes made to this file will be lost when pyuic5 is @@ -12,7 +14,7 @@ from PyQt5 import QtCore, QtGui, QtWidgets class Ui_Form(object): def setupUi(self, Form): Form.setObjectName("Form") - Form.resize(250, 302) + Form.resize(339, 302) self.verticalLayout = QtWidgets.QVBoxLayout(Form) self.verticalLayout.setContentsMargins(2, 2, 2, 2) self.verticalLayout.setSpacing(0) @@ -23,17 +25,37 @@ class Ui_Form(object): self.horizontalLayout.setContentsMargins(-1, -1, -1, 0) self.horizontalLayout.setObjectName("horizontalLayout") self.checkBox_visible = QtWidgets.QCheckBox(self.widget) + self.checkBox_visible.setMaximumSize(QtCore.QSize(120, 16777215)) self.checkBox_visible.setObjectName("checkBox_visible") self.horizontalLayout.addWidget(self.checkBox_visible) + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) + self.horizontalLayout.addItem(spacerItem) self.comboBox_group_select = QtWidgets.QComboBox(self.widget) + self.comboBox_group_select.setMaximumSize(QtCore.QSize(60, 16777215)) self.comboBox_group_select.setObjectName("comboBox_group_select") self.horizontalLayout.addWidget(self.comboBox_group_select) self.button_prev_group = QtWidgets.QPushButton(self.widget) + self.button_prev_group.setMaximumSize(QtCore.QSize(25, 16777215)) + self.button_prev_group.setText("") + icon = QtGui.QIcon() + icon.addPixmap(QtGui.QPixmap(":/icon/icons/上一步_back.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.button_prev_group.setIcon(icon) self.button_prev_group.setObjectName("button_prev_group") self.horizontalLayout.addWidget(self.button_prev_group) self.button_next_group = QtWidgets.QPushButton(self.widget) + self.button_next_group.setMaximumSize(QtCore.QSize(25, 16777215)) + self.button_next_group.setText("") + icon1 = QtGui.QIcon() + icon1.addPixmap(QtGui.QPixmap(":/icon/icons/下一步_next.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off) + self.button_next_group.setIcon(icon1) self.button_next_group.setObjectName("button_next_group") self.horizontalLayout.addWidget(self.button_next_group) + self.label = QtWidgets.QLabel(self.widget) + self.label.setMinimumSize(QtCore.QSize(3, 0)) + self.label.setMaximumSize(QtCore.QSize(3, 16777215)) + self.label.setText("") + self.label.setObjectName("label") + self.horizontalLayout.addWidget(self.label) self.verticalLayout.addWidget(self.widget) self.listWidget = QtWidgets.QListWidget(Form) self.listWidget.setObjectName("listWidget") @@ -46,5 +68,4 @@ class Ui_Form(object): _translate = QtCore.QCoreApplication.translate Form.setWindowTitle(_translate("Form", "Form")) self.checkBox_visible.setText(_translate("Form", "Visible")) - self.button_prev_group.setText(_translate("Form", "Previous")) - self.button_next_group.setText(_translate("Form", "Next")) +import icons_rc diff --git a/ui/anno_dock.ui b/ui/anno_dock.ui index 119d32d..90b0f5c 100644 --- a/ui/anno_dock.ui +++ b/ui/anno_dock.ui @@ -6,7 +6,7 @@ 0 0 - 250 + 339 302 @@ -37,25 +37,90 @@ + + + 120 + 16777215 + + Visible - + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 60 + 16777215 + + + + + + 25 + 16777215 + + - Previous + + + + + :/icon/icons/上一步_back.svg:/icon/icons/上一步_back.svg + + + 25 + 16777215 + + - Next + + + + + :/icon/icons/下一步_next.svg:/icon/icons/下一步_next.svg + + + + + + + + 3 + 0 + + + + + 3 + 16777215 + + + + @@ -67,6 +132,8 @@ - + + + diff --git a/ui/zh_CN.qm b/ui/zh_CN.qm index c8c4471..a2527a3 100644 Binary files a/ui/zh_CN.qm and b/ui/zh_CN.qm differ diff --git a/ui/zh_CN.ts b/ui/zh_CN.ts index f170f95..cea0114 100644 --- a/ui/zh_CN.ts +++ b/ui/zh_CN.ts @@ -526,7 +526,7 @@ p, li { white-space: pre-wrap; } Form - + Form @@ -571,7 +571,7 @@ p, li { white-space: pre-wrap; } 跳转到指定图片. - + Visible 显示/隐藏 @@ -579,52 +579,52 @@ p, li { white-space: pre-wrap; } MainWindow - + ISAT ISAT 图片分割标注工具 - + File 文件 - + View 视图 - + Help 帮助 - + Tools 工具 - + Edit 编辑 - + toolBar 工具栏 - + Info 图片信息 Labels - 标签列表 + 标签列表 - + Files 文件列表 @@ -639,32 +639,32 @@ p, li { white-space: pre-wrap; } 打开图片文件夹 - + Zoom in 放大 - + Zoom out 缩小 - + Fit window 适应窗口 - + F - + Setting 设置 - + Exit 退出 @@ -674,12 +674,12 @@ p, li { white-space: pre-wrap; } 标签保存位置 - + Save 保存 - + S @@ -689,12 +689,12 @@ p, li { white-space: pre-wrap; } 上一张 - + Prev image 上一张图片 - + A @@ -704,17 +704,17 @@ p, li { white-space: pre-wrap; } 下一张 - + Next image 下一张图片 - + D - + About 关于 @@ -729,72 +729,72 @@ p, li { white-space: pre-wrap; } 创建多边形 - + C - + Delete 删除 - + Delete polygon 删除多边形 - + Del - + Bit map 位图 - + Space - + Edit polygon 编辑多边形 - + E - + To top 置顶 - + Move polygon to top layer 移动多边形到顶层 - + T - + To bottom 置底 - + Move polygon to bottom layer 移动多边形到底层 - + B @@ -809,12 +809,12 @@ p, li { white-space: pre-wrap; } 将ISAT标注文件转换为png图片. - + Laguage 语言 - + Shortcut 快捷键 @@ -824,52 +824,52 @@ p, li { white-space: pre-wrap; } 中文 - + English - + 中文 - + Images dir 图片文件夹 - + Open images dir. 打开图片文件夹. - + Zoom in. 放大. - + Zoom out. 缩小. - + Fit window. 适应窗口. - + Label dir 标签文件夹 - + Open label dir. 打开标签文件夹. - + Save annotation. 保存. @@ -884,7 +884,7 @@ p, li { white-space: pre-wrap; } 打开上一张图片. - + Next image. 下一张图片. @@ -894,142 +894,142 @@ p, li { white-space: pre-wrap; } 打开下一张图片. - + Delete polygon. 删除多边形. - + Show instance or segmeent state. 显示语义与实例结果. - + Edit polygon attribute. 编辑多边形属性. - + Move polygon to top layer. 将多边形移动到最上层. - + Move polygon to bottom layer. 将多边形移动到最下层. - + Setting. 设置. - + Exit. 退出. - + Prev image. 前一张图片. - + Segment anything - + Quick annotate using Segment anything. 使用Segment anything进行快速标注. - + Q - + Backspace 回退 - + Backspace. 回退. - + Z - + Cancel 取消 - + Annotate canceled 标注取消 - + Annotate canceled. 标注取消. - + Esc - + Finish 完成 - + Annotate finished 标注完成 - + Annotate finished. 标注完成. - + Polygon 多边形 - + Draw polygon 绘制多边形 - + Accurately annotate by drawing polygon. 通过手动绘制多边形,进行精细标注. - + Visible 显示/隐藏 - + V - + To VOC - + Convert ISAT to VOC ISAT转VOC @@ -1039,54 +1039,114 @@ p, li { white-space: pre-wrap; } 将ISAT格式json转换为VOC单通道png。 - + To COCO - + Convert ISAT to COCO ISAT转COCO - + Convert ISAT jsons to COCO json. 将ISAT格式json转换为COCO格式json。 - + From COCO - + Convert COCO to ISAT COCO转ISAT - + Convert COCO json to ISAT jsons. 将COCO格式json转换为ISAT格式json。 - + Convert ISAT jsons to VOC png images. 将ISAT格式json转换为VOC单通道png图片。 - + To LabelMe - + Convert ISAT to LabelMe ISAT转LabelMe - + Convert ISAT jsons to LabelMe jsons. 将ISAT格式json转换为LabelMe格式json。 + + + Mode + 模式 + + + + Contour mode + 轮廓模式 + + + + SAM + + + + + Annos + 标注 + + + + Categories + 类别 + + + + Visible. + 显示/隐藏. + + + + Max only + 只保存最大轮廓 + + + + Max contour save only. + 只保存最大轮廓. + + + + External + 只保存外轮廓 + + + + External contour save only. + 只保存外轮廓. + + + + All + 保存所有轮廓 + + + + All contour save. + 保存所有轮廓. + diff --git a/widgets/annos_dock_widget.py b/widgets/annos_dock_widget.py index bdc85c4..b044b6e 100644 --- a/widgets/annos_dock_widget.py +++ b/widgets/annos_dock_widget.py @@ -20,6 +20,9 @@ class AnnosDockWidget(QtWidgets.QWidget, Ui_Form): self.comboBox_group_select.currentIndexChanged.connect(self.set_group_polygon_visible) self.button_next_group.clicked.connect(self.go_to_next_group) self.button_prev_group.clicked.connect(self.go_to_prev_group) + self.comboBox_group_select.setStatusTip('Select polygons by group.') + self.button_prev_group.setStatusTip('Prev group.') + self.button_next_group.setStatusTip('Next group.') self.listWidget.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.CustomContextMenu) self.listWidget.customContextMenuRequested.connect( @@ -50,8 +53,10 @@ class AnnosDockWidget(QtWidgets.QWidget, Ui_Form): category = QtWidgets.QLabel(polygon.category) group = QtWidgets.QLabel('{}'.format(polygon.group)) - + group.setFixedWidth(50) note = QtWidgets.QLabel('{}'.format(polygon.note)) + note.setToolTip(polygon.note) + note.setFixedWidth(46) label_iscrowd = QtWidgets.QLabel() label_iscrowd.setFixedWidth(3) @@ -61,7 +66,7 @@ class AnnosDockWidget(QtWidgets.QWidget, Ui_Form): layout.addWidget(category) layout.addWidget(group) layout.addWidget(note) - layout.addWidget(label_iscrowd, alignment=QtCore.Qt.AlignmentFlag.AlignRight) + layout.addWidget(label_iscrowd) item_widget.setLayout(layout) return item, item_widget @@ -83,7 +88,8 @@ class AnnosDockWidget(QtWidgets.QWidget, Ui_Form): unique_groups = {polygon.group for polygon in self.mainwindow.polygons} self.comboBox_group_select.clear() self.comboBox_group_select.addItem('All') # add an option to view all groups - self.comboBox_group_select.addItems(sorted(unique_groups, key=lambda s: [int(text) if text.isdigit() else text.lower() for text in re.split(r'(\d+)', s)])) + self.comboBox_group_select.addItems(sorted([str(item) for item in unique_groups], + key=lambda s: [int(t) if t.isdigit() else t for t in re.split(r'(\d+)', s)])) def set_selected(self, polygon): item = self.polygon_item_dict[polygon] @@ -131,16 +137,24 @@ class AnnosDockWidget(QtWidgets.QWidget, Ui_Form): for polygon, item in self.polygon_item_dict.items(): widget = self.listWidget.itemWidget(item) check_box = widget.findChild(QtWidgets.QCheckBox, 'check_box') - - if selected_group == 'All' or polygon.group == selected_group: + if selected_group == '': + return + if selected_group == 'All' or polygon.group == int(selected_group): check_box.setChecked(True) else: check_box.setChecked(False) + self.zoom_to_group() + def zoom_to_group(self): selected_group = self.comboBox_group_select.currentText() - polygons_in_group = [polygon for polygon, item in self.polygon_item_dict.items() - if polygon.group == selected_group] + if selected_group == '': + return + if selected_group == 'All': + polygons_in_group = [polygon for polygon, item in self.polygon_item_dict.items()] + else: + polygons_in_group = [polygon for polygon, item in self.polygon_item_dict.items() + if polygon.group == int(selected_group)] if not polygons_in_group: return min_x = min(min(vertex.x() for vertex in polygon.vertexs) for polygon in polygons_in_group) @@ -157,14 +171,12 @@ class AnnosDockWidget(QtWidgets.QWidget, Ui_Form): if current_index < max_index: self.comboBox_group_select.setCurrentIndex(current_index + 1) self.set_group_polygon_visible() - self.zoom_to_group() def go_to_prev_group(self): current_index = self.comboBox_group_select.currentIndex() if current_index > 0: self.comboBox_group_select.setCurrentIndex(current_index - 1) self.set_group_polygon_visible() - self.zoom_to_group() diff --git a/widgets/canvas.py b/widgets/canvas.py index 166a2a4..e7b4ea6 100644 --- a/widgets/canvas.py +++ b/widgets/canvas.py @@ -515,8 +515,8 @@ class AnnotationView(QtWidgets.QGraphicsView): # 缩放比例 pix_widget = self.transform().scale(factor, factor).mapRect(QtCore.QRectF(0, 0, 1, 1)).width() - if pix_widget > 3 or pix_widget < 0.01: - return + if pix_widget > 30 and factor > 1: return + if pix_widget < 0.01 and factor < 1: return self.scale(factor, factor) if point is not None: diff --git a/widgets/category_choice_dialog.py b/widgets/category_choice_dialog.py index 30e7d1b..7b67494 100644 --- a/widgets/category_choice_dialog.py +++ b/widgets/category_choice_dialog.py @@ -71,7 +71,7 @@ class CategoryChoiceDialog(QtWidgets.QDialog, Ui_Dialog): def apply(self): category = self.lineEdit_category.text() - group = self.lineEdit_group.text() + group = int(self.lineEdit_group.text()) is_crowd = int(self.checkBox_iscrowded.isChecked()) note = self.lineEdit_note.text() if not category: diff --git a/widgets/category_edit_dialog.py b/widgets/category_edit_dialog.py index a6d8ae8..51d6dc1 100644 --- a/widgets/category_edit_dialog.py +++ b/widgets/category_edit_dialog.py @@ -89,7 +89,7 @@ class CategoryEditDialog(QtWidgets.QDialog, Ui_Dialog): def apply(self): category = self.lineEdit_category.text() - group = self.lineEdit_group.text() + group = int(self.lineEdit_group.text()) is_crowd = int(self.checkBox_iscrowded.isChecked()) note = self.lineEdit_note.text() if not category: diff --git a/widgets/mainwindow.py b/widgets/mainwindow.py index 99bad76..fd9b2e7 100644 --- a/widgets/mainwindow.py +++ b/widgets/mainwindow.py @@ -57,7 +57,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): # 标注目标 self.current_label:Annotation = None self.use_segment_anything = False - + self.gpu_resource_thread = None self.init_ui() self.reload_cfg() @@ -65,6 +65,7 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): self.reset_action() def init_segment_anything(self, model_name, reload=False): + if model_name == '': self.use_segment_anything = False for name, action in self.pths_actions.items(): @@ -85,18 +86,18 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): self.statusbar.showMessage('Use the checkpoint named {}.'.format(model_name), 3000) for name, action in self.pths_actions.items(): action.setChecked(model_name==name) - if not reload: - if self.use_segment_anything: - if self.segany.device != 'cpu': + if self.use_segment_anything: + if self.segany.device != 'cpu': + if self.gpu_resource_thread is None: self.gpu_resource_thread = GPUResource_Thread() self.gpu_resource_thread.message.connect(self.labelGPUResource.setText) self.gpu_resource_thread.start() - else: - self.labelGPUResource.setText('cpu') else: - self.labelGPUResource.setText('segment anything unused.') + self.labelGPUResource.setText('cpu') + else: + self.labelGPUResource.setText('segment anything unused.') - if reload and self.current_index is not None: + if self.current_index is not None: self.show_image(self.current_index) def init_ui(self): diff --git a/widgets/polygon.py b/widgets/polygon.py index 2699b9a..0b2173d 100644 --- a/widgets/polygon.py +++ b/widgets/polygon.py @@ -191,6 +191,8 @@ class Polygon(QtWidgets.QGraphicsPolygonItem): def set_drawed(self, category, group, iscrowd, note, color:QtGui.QColor, layer=None): self.is_drawing = False self.category = category + if isinstance(group, str): + group = 0 if group == '' else int(group) self.group = group self.iscrowd = iscrowd self.note = note