Skip to content

Commit c3a2911

Browse files
committed
- support sam box prompt
1 parent 2e76228 commit c3a2911

File tree

10 files changed

+350
-145
lines changed

10 files changed

+350
-145
lines changed

ISAT/configs.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ class STATUSMode(Enum):
3737
class DRAWMode(Enum):
3838
POLYGON = 0
3939
SEGMENTANYTHING = 1
40+
SEGMENTANYTHING_BOX = 2
4041

4142
class CLICKMode(Enum):
4243
POSITIVE = 0

ISAT/icons.qrc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<RCC>
22
<qresource prefix="icon">
3+
<file>../icons/小矩形_rectangle-small.svg</file>
34
<file>../icons/关闭-小_close-small.svg</file>
45
<file>../icons/校验-小_check-small.svg</file>
56
<file>../icons/play-1.svg</file>

ISAT/icons_rc.py

Lines changed: 157 additions & 126 deletions
Large diffs are not rendered by default.

ISAT/software.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ label:
2424
software:
2525
auto_save: false
2626
contour_mode: external
27-
language: zh
27+
language: en
2828
mask_alpha: 0.6
2929
show_edge: true
3030
show_prompt: true

ISAT/ui/MainWindow.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,11 @@ def setupUi(self, MainWindow):
362362
icon35.addPixmap(QtGui.QPixmap(":/icon/icons/视频_video-two.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
363363
self.actionVideo_to_frames.setIcon(icon35)
364364
self.actionVideo_to_frames.setObjectName("actionVideo_to_frames")
365+
self.actionSegment_anything_box = QtWidgets.QAction(MainWindow)
366+
icon36 = QtGui.QIcon()
367+
icon36.addPixmap(QtGui.QPixmap(":/icon/icons/小矩形_rectangle-small.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
368+
self.actionSegment_anything_box.setIcon(icon36)
369+
self.actionSegment_anything_box.setObjectName("actionSegment_anything_box")
365370
self.menuFile.addAction(self.actionOpen_dir)
366371
self.menuFile.addAction(self.actionSave_dir)
367372
self.menuFile.addSeparator()
@@ -388,6 +393,7 @@ def setupUi(self, MainWindow):
388393
self.menuTools.addAction(self.actionAuto_segment)
389394
self.menuTools.addAction(self.actionAnno_validator)
390395
self.menuEdit.addAction(self.actionSegment_anything)
396+
self.menuEdit.addAction(self.actionSegment_anything_box)
391397
self.menuEdit.addAction(self.actionPolygon)
392398
self.menuEdit.addSeparator()
393399
self.menuEdit.addAction(self.actionVideo_segment)
@@ -428,6 +434,7 @@ def setupUi(self, MainWindow):
428434
self.toolBar.addAction(self.actionNext)
429435
self.toolBar.addSeparator()
430436
self.toolBar.addAction(self.actionSegment_anything)
437+
self.toolBar.addAction(self.actionSegment_anything_box)
431438
self.toolBar.addAction(self.actionPolygon)
432439
self.toolBar.addSeparator()
433440
self.toolBar.addAction(self.actionVideo_segment_once)
@@ -507,8 +514,8 @@ def retranslateUi(self, MainWindow):
507514
self.actionNext.setShortcut(_translate("MainWindow", "D"))
508515
self.actionShortcut.setText(_translate("MainWindow", "Shortcut"))
509516
self.actionAbout.setText(_translate("MainWindow", "About"))
510-
self.actionSegment_anything.setText(_translate("MainWindow", "Segment anything"))
511-
self.actionSegment_anything.setToolTip(_translate("MainWindow", "Segment anything"))
517+
self.actionSegment_anything.setText(_translate("MainWindow", "Segment anything point"))
518+
self.actionSegment_anything.setToolTip(_translate("MainWindow", "Segment anything point"))
512519
self.actionSegment_anything.setStatusTip(_translate("MainWindow", "Quick annotate using Segment anything."))
513520
self.actionSegment_anything.setShortcut(_translate("MainWindow", "Q"))
514521
self.actionDelete.setText(_translate("MainWindow", "Delete"))
@@ -588,4 +595,6 @@ def retranslateUi(self, MainWindow):
588595
self.actionVideo_segment_five_times.setText(_translate("MainWindow", "Video segment five times"))
589596
self.actionVideo_segment_five_times.setStatusTip(_translate("MainWindow", "Video segment next five frames.(only support sam2 model)"))
590597
self.actionVideo_to_frames.setText(_translate("MainWindow", "Video to frames"))
591-
598+
self.actionSegment_anything_box.setText(_translate("MainWindow", "Segment anything box"))
599+
self.actionSegment_anything_box.setStatusTip(_translate("MainWindow", "Quick annotate using Segment anything."))
600+
self.actionSegment_anything_box.setShortcut(_translate("MainWindow", "W"))

ISAT/ui/MainWindow.ui

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@
167167
<string>Edit</string>
168168
</property>
169169
<addaction name="actionSegment_anything"/>
170+
<addaction name="actionSegment_anything_box"/>
170171
<addaction name="actionPolygon"/>
171172
<addaction name="separator"/>
172173
<addaction name="actionVideo_segment"/>
@@ -266,6 +267,7 @@
266267
<addaction name="actionNext"/>
267268
<addaction name="separator"/>
268269
<addaction name="actionSegment_anything"/>
270+
<addaction name="actionSegment_anything_box"/>
269271
<addaction name="actionPolygon"/>
270272
<addaction name="separator"/>
271273
<addaction name="actionVideo_segment_once"/>
@@ -528,10 +530,10 @@
528530
<normaloff>:/icon/icons/M_Favicon.ico</normaloff>:/icon/icons/M_Favicon.ico</iconset>
529531
</property>
530532
<property name="text">
531-
<string>Segment anything</string>
533+
<string>Segment anything point</string>
532534
</property>
533535
<property name="toolTip">
534-
<string>Segment anything</string>
536+
<string>Segment anything point</string>
535537
</property>
536538
<property name="statusTip">
537539
<string>Quick annotate using Segment anything.</string>
@@ -993,6 +995,21 @@
993995
<string>Video to frames</string>
994996
</property>
995997
</action>
998+
<action name="actionSegment_anything_box">
999+
<property name="icon">
1000+
<iconset resource="../icons.qrc">
1001+
<normaloff>:/icon/icons/小矩形_rectangle-small.svg</normaloff>:/icon/icons/小矩形_rectangle-small.svg</iconset>
1002+
</property>
1003+
<property name="text">
1004+
<string>Segment anything box</string>
1005+
</property>
1006+
<property name="statusTip">
1007+
<string>Quick annotate using Segment anything.</string>
1008+
</property>
1009+
<property name="shortcut">
1010+
<string>W</string>
1011+
</property>
1012+
</action>
9961013
</widget>
9971014
<resources>
9981015
<include location="../icons.qrc"/>

ISAT/widgets/canvas.py

Lines changed: 55 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# @Author : LG
33

44
from PyQt5 import QtWidgets, QtGui, QtCore
5-
from ISAT.widgets.polygon import Polygon, Vertex, PromptPoint, Line
5+
from ISAT.widgets.polygon import Polygon, Vertex, PromptPoint, Line, Rect
66
from ISAT.configs import STATUSMode, CLICKMode, DRAWMode, CONTOURMode
77
import numpy as np
88
import cv2
@@ -18,6 +18,7 @@ def __init__(self, mainwindow):
1818
self.mask_item: QtWidgets.QGraphicsPixmapItem = None
1919
self.image_data = None
2020
self.current_graph: Polygon = None
21+
self.current_sam_rect: Rect = None
2122
self.current_line: Line = None
2223
self.mode = STATUSMode.VIEW
2324
self.click = CLICKMode.POSITIVE
@@ -82,6 +83,7 @@ def change_mode_to_create(self):
8283
self.mainwindow.actionNext.setEnabled(False)
8384

8485
self.mainwindow.actionSegment_anything.setEnabled(False)
86+
self.mainwindow.actionSegment_anything_box.setEnabled(False)
8587
self.mainwindow.actionPolygon.setEnabled(False)
8688
self.mainwindow.actionBackspace.setEnabled(True)
8789
self.mainwindow.actionFinish.setEnabled(True)
@@ -157,6 +159,7 @@ def change_mode_to_edit(self):
157159
self.mainwindow.actionNext.setEnabled(False)
158160

159161
self.mainwindow.actionSegment_anything.setEnabled(False)
162+
self.mainwindow.actionSegment_anything_box.setEnabled(False)
160163
self.mainwindow.actionPolygon.setEnabled(False)
161164
self.mainwindow.actionBackspace.setEnabled(False)
162165
self.mainwindow.actionFinish.setEnabled(False)
@@ -198,6 +201,7 @@ def change_mode_to_repaint(self):
198201
self.mainwindow.actionNext.setEnabled(False)
199202

200203
self.mainwindow.actionSegment_anything.setEnabled(False)
204+
self.mainwindow.actionSegment_anything_box.setEnabled(False)
201205
self.mainwindow.actionPolygon.setEnabled(False)
202206
self.mainwindow.actionBackspace.setEnabled(True)
203207
self.mainwindow.actionFinish.setEnabled(False)
@@ -242,6 +246,10 @@ def start_segment_anything(self):
242246
self.draw_mode = DRAWMode.SEGMENTANYTHING
243247
self.start_draw()
244248

249+
def start_segment_anything_box(self):
250+
self.draw_mode = DRAWMode.SEGMENTANYTHING_BOX
251+
self.start_draw()
252+
245253
def start_draw_polygon(self):
246254
self.draw_mode = DRAWMode.POLYGON
247255
self.start_draw()
@@ -269,7 +277,7 @@ def finish_draw(self):
269277
is_crowd = False
270278
note = ''
271279

272-
if self.draw_mode == DRAWMode.SEGMENTANYTHING:
280+
if self.draw_mode == DRAWMode.SEGMENTANYTHING or self.draw_mode == DRAWMode.SEGMENTANYTHING_BOX:
273281
# mask to polygon
274282
# --------------
275283
if self.masks is not None:
@@ -378,6 +386,12 @@ def finish_draw(self):
378386
self.mainwindow.annos_dock_widget.update_listwidget()
379387

380388
self.current_graph = None
389+
390+
if self.current_sam_rect is not None:
391+
self.current_sam_rect.delete()
392+
self.removeItem(self.current_sam_rect)
393+
self.current_sam_rect = None
394+
381395
self.change_mode_to_view()
382396

383397
# mask清空
@@ -406,6 +420,11 @@ def cancel_draw(self):
406420
for item in self.selectedItems():
407421
item.setSelected(False)
408422

423+
if self.current_sam_rect is not None:
424+
self.current_sam_rect.delete()
425+
self.removeItem(self.current_sam_rect)
426+
self.current_sam_rect = None
427+
409428
self.change_mode_to_view()
410429

411430
self.click_points.clear()
@@ -763,6 +782,14 @@ def mousePressEvent(self, event: 'QtWidgets.QGraphicsSceneMouseEvent'):
763782
self.prompt_points.append(prompt_point)
764783
self.addItem(prompt_point)
765784

785+
elif self.draw_mode == DRAWMode.SEGMENTANYTHING_BOX: # sam 矩形框提示
786+
if self.current_sam_rect is None:
787+
self.current_sam_rect = Rect()
788+
self.current_sam_rect.setZValue(2)
789+
self.addItem(self.current_sam_rect)
790+
self.current_sam_rect.addPoint(QtCore.QPointF(sceneX, sceneY))
791+
self.current_sam_rect.addPoint(QtCore.QPointF(sceneX, sceneY))
792+
766793
elif self.draw_mode == DRAWMode.POLYGON:
767794
# 移除随鼠标移动的点
768795
self.current_graph.removePoint(len(self.current_graph.points) - 1)
@@ -877,6 +904,10 @@ def mouseMoveEvent(self, event: 'QtWidgets.QGraphicsSceneMouseEvent'):
877904
if self.draw_mode == DRAWMode.POLYGON:
878905
# 随鼠标位置实时更新多边形
879906
self.current_graph.movePoint(len(self.current_graph.points) - 1, pos)
907+
if self.draw_mode == DRAWMode.SEGMENTANYTHING_BOX:
908+
if self.current_sam_rect is not None:
909+
self.current_sam_rect.movePoint(len(self.current_sam_rect.points) - 1, pos)
910+
self.update_mask()
880911

881912
if self.mode == STATUSMode.REPAINT:
882913
self.current_line.movePoint(len(self.current_line.points) - 1, pos)
@@ -946,6 +977,23 @@ def update_mask(self):
946977

947978
if len(self.click_points) > 0 and len(self.click_points_mode) > 0:
948979
masks = self.mainwindow.segany.predict_with_point_prompt(self.click_points, self.click_points_mode)
980+
self.masks = masks
981+
color = np.array([0, 0, 255])
982+
h, w = masks.shape[-2:]
983+
mask_image = masks.reshape(h, w, 1) * color.reshape(1, 1, -1)
984+
mask_image = mask_image.astype("uint8")
985+
mask_image = cv2.cvtColor(mask_image, cv2.COLOR_BGR2RGB)
986+
mask_image = cv2.addWeighted(self.image_data, self.mask_alpha, mask_image, 1, 0)
987+
elif self.current_sam_rect is not None:
988+
point1 = self.current_sam_rect.points[0]
989+
point2 = self.current_sam_rect.points[1]
990+
box = np.array([min(point1.x(), point2.x()),
991+
min(point1.y(), point2.y()),
992+
max(point1.x(), point2.x()),
993+
max(point1.y(), point2.y()),
994+
])
995+
masks = self.mainwindow.segany.predict_with_box_prompt(box)
996+
949997
self.masks = masks
950998
color = np.array([0, 0, 255])
951999
h, w = masks.shape[-2:]
@@ -954,19 +1002,14 @@ def update_mask(self):
9541002
mask_image = cv2.cvtColor(mask_image, cv2.COLOR_BGR2RGB)
9551003
# 这里通过调整原始图像的权重self.mask_alpha,来调整mask的明显程度。
9561004
mask_image = cv2.addWeighted(self.image_data, self.mask_alpha, mask_image, 1, 0)
957-
mask_image = QtGui.QImage(mask_image[:], mask_image.shape[1], mask_image.shape[0], mask_image.shape[1] * 3,
958-
QtGui.QImage.Format_RGB888)
959-
mask_pixmap = QtGui.QPixmap(mask_image)
960-
if self.mask_item is not None:
961-
self.mask_item.setPixmap(mask_pixmap)
9621005
else:
9631006
mask_image = np.zeros(self.image_data.shape, dtype=np.uint8)
9641007
mask_image = cv2.addWeighted(self.image_data, 1, mask_image, 0, 0)
965-
mask_image = QtGui.QImage(mask_image[:], mask_image.shape[1], mask_image.shape[0], mask_image.shape[1] * 3,
966-
QtGui.QImage.Format_RGB888)
967-
mask_pixmap = QtGui.QPixmap(mask_image)
968-
if self.mask_item is not None:
969-
self.mask_item.setPixmap(mask_pixmap)
1008+
mask_image = QtGui.QImage(mask_image[:], mask_image.shape[1], mask_image.shape[0], mask_image.shape[1] * 3,
1009+
QtGui.QImage.Format_RGB888)
1010+
mask_pixmap = QtGui.QPixmap(mask_image)
1011+
if self.mask_item is not None:
1012+
self.mask_item.setPixmap(mask_pixmap)
9701013

9711014
def backspace(self):
9721015
if self.mode == STATUSMode.CREATE:

ISAT/widgets/mainwindow.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ def init_segment_anything(self, model_name=None):
405405
return
406406
# 等待sam线程完成
407407
self.actionSegment_anything.setEnabled(False)
408+
self.actionSegment_anything_box.setEnabled(False)
408409
try:
409410
self.seganythread.wait()
410411
self.seganythread.results_dict.clear()
@@ -539,6 +540,7 @@ def SeganyEnabled(self):
539540
"""
540541
if not self.use_segment_anything:
541542
self.actionSegment_anything.setEnabled(False)
543+
self.actionSegment_anything_box.setEnabled(False)
542544
return
543545

544546
results = self.seganythread.results_dict.get(self.current_index, {})
@@ -560,9 +562,11 @@ def SeganyEnabled(self):
560562
self.segany.predictor_with_point_prompt._is_image_set = True
561563

562564
self.actionSegment_anything.setEnabled(True)
565+
self.actionSegment_anything_box.setEnabled(True)
563566
else:
564567
self.segany.predictor_with_point_prompt.reset_image()
565568
self.actionSegment_anything.setEnabled(False)
569+
self.actionSegment_anything_box.setEnabled(False)
566570

567571
def seg_video_start(self, max_frame_num_to_track=None):
568572
if self.current_index == None:
@@ -1161,6 +1165,7 @@ def change_bit_map_to_semantic(self):
11611165
self.annos_dock_widget.listWidget.setEnabled(False)
11621166
self.annos_dock_widget.checkBox_visible.setEnabled(False)
11631167
self.actionSegment_anything.setEnabled(False)
1168+
self.actionSegment_anything_box.setEnabled(False)
11641169
self.actionVideo_segment.setEnabled(False)
11651170
self.actionVideo_segment_once.setEnabled(False)
11661171
self.actionVideo_segment_five_times.setEnabled(False)
@@ -1189,6 +1194,7 @@ def change_bit_map_to_instance(self):
11891194
self.annos_dock_widget.listWidget.setEnabled(False)
11901195
self.annos_dock_widget.checkBox_visible.setEnabled(False)
11911196
self.actionSegment_anything.setEnabled(False)
1197+
self.actionSegment_anything_box.setEnabled(False)
11921198
self.actionVideo_segment.setEnabled(False)
11931199
self.actionVideo_segment_once.setEnabled(False)
11941200
self.actionVideo_segment_five_times.setEnabled(False)
@@ -1425,6 +1431,7 @@ def init_connect(self):
14251431
self.actionExit.triggered.connect(self.exit)
14261432

14271433
self.actionSegment_anything.triggered.connect(self.scene.start_segment_anything)
1434+
self.actionSegment_anything_box.triggered.connect(self.scene.start_segment_anything_box)
14281435
self.actionPolygon.triggered.connect(self.scene.start_draw_polygon)
14291436
self.actionCancel.triggered.connect(self.scene.cancel_draw)
14301437
self.actionBackspace.triggered.connect(self.scene.backspace)
@@ -1471,6 +1478,7 @@ def reset_action(self):
14711478
self.actionPrev.setEnabled(False)
14721479
self.actionNext.setEnabled(False)
14731480
self.actionSegment_anything.setEnabled(False)
1481+
self.actionSegment_anything_box.setEnabled(False)
14741482
self.actionPolygon.setEnabled(False)
14751483
self.actionVideo_segment.setEnabled(False)
14761484
self.actionVideo_segment_once.setEnabled(False)

0 commit comments

Comments
 (0)