New functions like batch move, delete, withdraw with redundant codes
This commit is contained in:
parent
0ae2b779ce
commit
ecf8b569d8
|
@ -206,7 +206,7 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.labelList = EditInList()
|
self.labelList = EditInList()
|
||||||
labelListContainer = QWidget()
|
labelListContainer = QWidget()
|
||||||
labelListContainer.setLayout(listLayout)
|
labelListContainer.setLayout(listLayout)
|
||||||
self.labelList.itemActivated.connect(self.labelSelectionChanged)
|
# self.labelList.itemActivated.connect(self.labelSelectionChanged)
|
||||||
self.labelList.itemSelectionChanged.connect(self.labelSelectionChanged)
|
self.labelList.itemSelectionChanged.connect(self.labelSelectionChanged)
|
||||||
self.labelList.clicked.connect(self.labelList.item_clicked)
|
self.labelList.clicked.connect(self.labelList.item_clicked)
|
||||||
# Connect to itemChanged to detect checkbox changes.
|
# Connect to itemChanged to detect checkbox changes.
|
||||||
|
@ -444,7 +444,7 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
'Ctrl+R', 'reRec', getStr('singleRe'), enabled=False)
|
'Ctrl+R', 'reRec', getStr('singleRe'), enabled=False)
|
||||||
|
|
||||||
createpoly = action(getStr('creatPolygon'), self.createPolygon,
|
createpoly = action(getStr('creatPolygon'), self.createPolygon,
|
||||||
'q', 'new', 'Creat Polygon', enabled=True)
|
'q', 'new', getStr('creatPolygon'), enabled=True)
|
||||||
|
|
||||||
saveRec = action(getStr('saveRec'), self.saveRecResult,
|
saveRec = action(getStr('saveRec'), self.saveRecResult,
|
||||||
'', 'save', getStr('saveRec'), enabled=False)
|
'', 'save', getStr('saveRec'), enabled=False)
|
||||||
|
@ -452,6 +452,12 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
saveLabel = action(getStr('saveLabel'), self.saveLabelFile, #
|
saveLabel = action(getStr('saveLabel'), self.saveLabelFile, #
|
||||||
'Ctrl+S', 'save', getStr('saveLabel'), enabled=False)
|
'Ctrl+S', 'save', getStr('saveLabel'), enabled=False)
|
||||||
|
|
||||||
|
undoLastPoint = action(getStr("undoLastPoint"), self.canvas.undoLastPoint,
|
||||||
|
'Ctrl+Z', "undo", "Undo last drawn point", enabled=False)
|
||||||
|
|
||||||
|
undo = action(getStr("undo"), self.undoShapeEdit,
|
||||||
|
'Ctrl+Z', "undo", "Undo last add and edit of shape", enabled=False)
|
||||||
|
|
||||||
self.editButton.setDefaultAction(edit)
|
self.editButton.setDefaultAction(edit)
|
||||||
self.newButton.setDefaultAction(create)
|
self.newButton.setDefaultAction(create)
|
||||||
self.DelButton.setDefaultAction(deleteImg)
|
self.DelButton.setDefaultAction(deleteImg)
|
||||||
|
@ -512,10 +518,11 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
zoom=zoom, zoomIn=zoomIn, zoomOut=zoomOut, zoomOrg=zoomOrg,
|
zoom=zoom, zoomIn=zoomIn, zoomOut=zoomOut, zoomOrg=zoomOrg,
|
||||||
fitWindow=fitWindow, fitWidth=fitWidth,
|
fitWindow=fitWindow, fitWidth=fitWidth,
|
||||||
zoomActions=zoomActions, saveLabel=saveLabel,
|
zoomActions=zoomActions, saveLabel=saveLabel,
|
||||||
|
undo=undo, undoLastPoint=undoLastPoint,
|
||||||
fileMenuActions=(
|
fileMenuActions=(
|
||||||
opendir, saveLabel, resetAll, quit),
|
opendir, saveLabel, resetAll, quit),
|
||||||
beginner=(), advanced=(),
|
beginner=(), advanced=(),
|
||||||
editMenu=(createpoly, edit, copy, delete,singleRere,
|
editMenu=(createpoly, edit, copy, delete,singleRere,None, undo, undoLastPoint,
|
||||||
None, color1, self.drawSquaresOption),
|
None, color1, self.drawSquaresOption),
|
||||||
beginnerContext=(create, edit, copy, delete, singleRere),
|
beginnerContext=(create, edit, copy, delete, singleRere),
|
||||||
advancedContext=(createMode, editMode, edit, copy,
|
advancedContext=(createMode, editMode, edit, copy,
|
||||||
|
@ -549,8 +556,13 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.labelDialogOption.setChecked(settings.get(SETTING_PAINT_LABEL, False))
|
self.labelDialogOption.setChecked(settings.get(SETTING_PAINT_LABEL, False))
|
||||||
self.labelDialogOption.triggered.connect(self.speedChoose)
|
self.labelDialogOption.triggered.connect(self.speedChoose)
|
||||||
|
|
||||||
|
self.autoSaveOption = QAction(getStr('autoSaveMode'), self)
|
||||||
|
self.autoSaveOption.setCheckable(True)
|
||||||
|
self.autoSaveOption.setChecked(settings.get(SETTING_PAINT_LABEL, False))
|
||||||
|
self.autoSaveOption.triggered.connect(self.autoSaveFunc)
|
||||||
|
|
||||||
addActions(self.menus.file,
|
addActions(self.menus.file,
|
||||||
(opendir, None, saveLabel, saveRec, None, resetAll, deleteImg, quit))
|
(opendir, None, saveLabel, saveRec, self.autoSaveOption, None, resetAll, deleteImg, quit))
|
||||||
|
|
||||||
addActions(self.menus.help, (showSteps, showInfo))
|
addActions(self.menus.help, (showSteps, showInfo))
|
||||||
addActions(self.menus.view, (
|
addActions(self.menus.view, (
|
||||||
|
@ -758,6 +770,7 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.canvas.setEditing(False)
|
self.canvas.setEditing(False)
|
||||||
self.canvas.fourpoint = True
|
self.canvas.fourpoint = True
|
||||||
self.actions.create.setEnabled(False)
|
self.actions.create.setEnabled(False)
|
||||||
|
self.actions.undoLastPoint.setEnabled(True)
|
||||||
|
|
||||||
def toggleDrawingSensitive(self, drawing=True):
|
def toggleDrawingSensitive(self, drawing=True):
|
||||||
"""In the middle of drawing, toggling between modes should be disabled."""
|
"""In the middle of drawing, toggling between modes should be disabled."""
|
||||||
|
@ -865,11 +878,21 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.setDirty()
|
self.setDirty()
|
||||||
self.updateComboBox()
|
self.updateComboBox()
|
||||||
|
|
||||||
|
# def updateBoxlist(self):
|
||||||
|
# shape = self.canvas.selectedShape
|
||||||
|
# item = self.shapesToItemsbox[shape] # listitem
|
||||||
|
# text = [(int(p.x()), int(p.y())) for p in shape.points]
|
||||||
|
# item.setText(str(text))
|
||||||
|
# self.setDirty()
|
||||||
|
|
||||||
def updateBoxlist(self):
|
def updateBoxlist(self):
|
||||||
shape = self.canvas.selectedShape
|
#changedShape = self.canvas.selectedShapes
|
||||||
item = self.shapesToItemsbox[shape] # listitem
|
#changedShape.append(self.canvas.hShape) #changedShape: #
|
||||||
text = [(int(p.x()), int(p.y())) for p in shape.points]
|
for shape in self.canvas.selectedShapes+[self.canvas.hShape]:
|
||||||
item.setText(str(text))
|
item = self.shapesToItemsbox[shape] # listitem
|
||||||
|
text = [(int(p.x()), int(p.y())) for p in shape.points]
|
||||||
|
item.setText(str(text))
|
||||||
|
self.actions.undo.setEnabled(True)
|
||||||
self.setDirty()
|
self.setDirty()
|
||||||
|
|
||||||
def indexTo5Files(self, currIndex):
|
def indexTo5Files(self, currIndex):
|
||||||
|
@ -902,23 +925,60 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
if len(self.mImgList) > 0:
|
if len(self.mImgList) > 0:
|
||||||
self.zoomWidget.setValue(self.zoomWidgetValue + self.imgsplider.value())
|
self.zoomWidget.setValue(self.zoomWidgetValue + self.imgsplider.value())
|
||||||
|
|
||||||
# React to canvas signals.
|
# # TODO: UPDATE THIS FUNCTION
|
||||||
def shapeSelectionChanged(self, selected=False):
|
# # React to canvas signals.
|
||||||
if self._noSelectionSlot:
|
# def shapeSelectionChanged(self, selected=False):
|
||||||
self._noSelectionSlot = False
|
# if self._noSelectionSlot:
|
||||||
else:
|
# self._noSelectionSlot = False
|
||||||
shape = self.canvas.selectedShape
|
# else:
|
||||||
if shape:
|
# shape = self.canvas.selectedShape
|
||||||
self.shapesToItems[shape].setSelected(True)
|
# if shape:
|
||||||
self.shapesToItemsbox[shape].setSelected(True) # ADD
|
# self.shapesToItems[shape].setSelected(True)
|
||||||
else:
|
# self.shapesToItemsbox[shape].setSelected(True) # ADD
|
||||||
self.labelList.clearSelection()
|
# else:
|
||||||
self.actions.delete.setEnabled(selected)
|
# self.labelList.clearSelection()
|
||||||
self.actions.copy.setEnabled(selected)
|
# self.actions.delete.setEnabled(selected)
|
||||||
self.actions.edit.setEnabled(selected)
|
# self.actions.copy.setEnabled(selected)
|
||||||
self.actions.shapeLineColor.setEnabled(selected)
|
# self.actions.edit.setEnabled(selected)
|
||||||
self.actions.shapeFillColor.setEnabled(selected)
|
# self.actions.shapeLineColor.setEnabled(selected)
|
||||||
self.actions.singleRere.setEnabled(selected)
|
# self.actions.shapeFillColor.setEnabled(selected)
|
||||||
|
# self.actions.singleRere.setEnabled(selected)
|
||||||
|
|
||||||
|
# def shapeSelectionChanged(self, selected_shapes):
|
||||||
|
# if self._noSelectionSlot:
|
||||||
|
# self._noSelectionSlot = False
|
||||||
|
# else:
|
||||||
|
# if self.canvas.selectedShapes:
|
||||||
|
# for shape in self.canvas.selectedShapes:
|
||||||
|
# self.shapesToItems[shape].setSelected(True)
|
||||||
|
# self.shapesToItemsbox[shape].setSelected(True)
|
||||||
|
# else:
|
||||||
|
# self.labelList.clearSelection()
|
||||||
|
#
|
||||||
|
# n_selected = len(selected_shapes)
|
||||||
|
# self.actions.delete.setEnabled(n_selected)
|
||||||
|
# self.actions.copy.setEnabled(n_selected)
|
||||||
|
# self.actions.edit.setEnabled(n_selected == 1)
|
||||||
|
|
||||||
|
def shapeSelectionChanged(self, selected_shapes):
|
||||||
|
self._noSelectionSlot = True
|
||||||
|
for shape in self.canvas.selectedShapes: # 为何要反选?
|
||||||
|
shape.selected = False
|
||||||
|
self.labelList.clearSelection()
|
||||||
|
self.canvas.selectedShapes = selected_shapes # 这里没有把选择的两个都加入
|
||||||
|
for shape in self.canvas.selectedShapes:
|
||||||
|
shape.selected = True
|
||||||
|
# item = self.labelList.findItemByShape(shape)
|
||||||
|
# self.labelList.selectItem(item)
|
||||||
|
# self.labelList.scrollToItem(item)
|
||||||
|
self.shapesToItems[shape].setSelected(True)
|
||||||
|
self.shapesToItemsbox[shape].setSelected(True) # ADD 是否可以代替selectItem?
|
||||||
|
|
||||||
|
self._noSelectionSlot = False
|
||||||
|
n_selected = len(selected_shapes)
|
||||||
|
self.actions.delete.setEnabled(n_selected)
|
||||||
|
self.actions.copy.setEnabled(n_selected)
|
||||||
|
self.actions.edit.setEnabled(n_selected == 1)
|
||||||
|
|
||||||
def addLabel(self, shape):
|
def addLabel(self, shape):
|
||||||
shape.paintLabel = self.displayLabelOption.isChecked()
|
shape.paintLabel = self.displayLabelOption.isChecked()
|
||||||
|
@ -941,22 +1001,23 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
action.setEnabled(True)
|
action.setEnabled(True)
|
||||||
self.updateComboBox()
|
self.updateComboBox()
|
||||||
|
|
||||||
def remLabel(self, shape):
|
def remLabels(self, shapes):
|
||||||
if shape is None:
|
if shapes is None:
|
||||||
# print('rm empty label')
|
# print('rm empty label')
|
||||||
return
|
return
|
||||||
item = self.shapesToItems[shape]
|
for shape in shapes:
|
||||||
self.labelList.takeItem(self.labelList.row(item))
|
item = self.shapesToItems[shape]
|
||||||
del self.shapesToItems[shape]
|
self.labelList.takeItem(self.labelList.row(item))
|
||||||
del self.itemsToShapes[item]
|
del self.shapesToItems[shape]
|
||||||
self.updateComboBox()
|
del self.itemsToShapes[item]
|
||||||
|
self.updateComboBox()
|
||||||
|
|
||||||
# ADD:
|
# ADD:
|
||||||
item = self.shapesToItemsbox[shape]
|
item = self.shapesToItemsbox[shape]
|
||||||
self.BoxList.takeItem(self.BoxList.row(item))
|
self.BoxList.takeItem(self.BoxList.row(item))
|
||||||
del self.shapesToItemsbox[shape]
|
del self.shapesToItemsbox[shape]
|
||||||
del self.itemsToShapesbox[item]
|
del self.itemsToShapesbox[item]
|
||||||
self.updateComboBox()
|
self.updateComboBox()
|
||||||
|
|
||||||
def loadLabels(self, shapes):
|
def loadLabels(self, shapes):
|
||||||
s = []
|
s = []
|
||||||
|
@ -1001,7 +1062,7 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
item.setText(str([(int(p.x()), int(p.y())) for p in shape.points]))
|
item.setText(str([(int(p.x()), int(p.y())) for p in shape.points]))
|
||||||
self.updateComboBox()
|
self.updateComboBox()
|
||||||
|
|
||||||
def updateComboBox(self):
|
def updateComboBox(self): # TODO:貌似没用
|
||||||
# Get the unique labels and add them to the Combobox.
|
# Get the unique labels and add them to the Combobox.
|
||||||
itemsTextList = [str(self.labelList.item(i).text()) for i in range(self.labelList.count())]
|
itemsTextList = [str(self.labelList.item(i).text()) for i in range(self.labelList.count())]
|
||||||
|
|
||||||
|
@ -1059,21 +1120,47 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.shapeSelectionChanged(True)
|
self.shapeSelectionChanged(True)
|
||||||
|
|
||||||
|
|
||||||
|
# def labelSelectionChanged(self):
|
||||||
|
# item = self.currentItem()
|
||||||
|
# self.labelList.scrollToItem(item, QAbstractItemView.EnsureVisible)
|
||||||
|
# if item and self.canvas.editing():
|
||||||
|
# self._noSelectionSlot = True
|
||||||
|
# self.canvas.selectShape(self.itemsToShapes[item])
|
||||||
|
# shape = self.itemsToShapes[item]
|
||||||
|
|
||||||
def labelSelectionChanged(self):
|
def labelSelectionChanged(self):
|
||||||
item = self.currentItem()
|
if self._noSelectionSlot:
|
||||||
self.labelList.scrollToItem(item, QAbstractItemView.EnsureVisible)
|
return
|
||||||
if item and self.canvas.editing():
|
if self.canvas.editing():
|
||||||
self._noSelectionSlot = True
|
selected_shapes = []
|
||||||
self.canvas.selectShape(self.itemsToShapes[item])
|
for item in self.labelList.selectedItems():
|
||||||
shape = self.itemsToShapes[item]
|
selected_shapes.append(self.itemsToShapes[item])
|
||||||
|
if selected_shapes:
|
||||||
|
self.canvas.selectShapes(selected_shapes)
|
||||||
|
else:
|
||||||
|
self.canvas.deSelectShape()
|
||||||
|
|
||||||
|
|
||||||
|
# def boxSelectionChanged(self):
|
||||||
|
# item = self.currentBox()
|
||||||
|
# self.BoxList.scrollToItem(item, QAbstractItemView.EnsureVisible)
|
||||||
|
# if item and self.canvas.editing():
|
||||||
|
# self._noSelectionSlot = True
|
||||||
|
# self.canvas.selectShape(self.itemsToShapesbox[item])
|
||||||
|
# shape = self.itemsToShapesbox[item]
|
||||||
|
|
||||||
def boxSelectionChanged(self):
|
def boxSelectionChanged(self):
|
||||||
item = self.currentBox()
|
if self._noSelectionSlot:
|
||||||
self.BoxList.scrollToItem(item, QAbstractItemView.EnsureVisible)
|
return
|
||||||
if item and self.canvas.editing():
|
if self.canvas.editing():
|
||||||
self._noSelectionSlot = True
|
selected_shapes = []
|
||||||
self.canvas.selectShape(self.itemsToShapesbox[item])
|
for item in self.labelList.selectedItems():
|
||||||
shape = self.itemsToShapesbox[item]
|
selected_shapes.append(self.itemsToShapesbox[item])
|
||||||
|
if selected_shapes:
|
||||||
|
self.canvas.selectShapes(selected_shapes)
|
||||||
|
else:
|
||||||
|
self.canvas.deSelectShape()
|
||||||
|
|
||||||
|
|
||||||
def labelItemChanged(self, item):
|
def labelItemChanged(self, item):
|
||||||
shape = self.itemsToShapes[item]
|
shape = self.itemsToShapes[item]
|
||||||
|
@ -1113,6 +1200,8 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
if self.beginner(): # Switch to edit mode.
|
if self.beginner(): # Switch to edit mode.
|
||||||
self.canvas.setEditing(True)
|
self.canvas.setEditing(True)
|
||||||
self.actions.create.setEnabled(True)
|
self.actions.create.setEnabled(True)
|
||||||
|
self.actions.undoLastPoint.setEnabled(False)
|
||||||
|
self.actions.undo.setEnabled(True)
|
||||||
else:
|
else:
|
||||||
self.actions.editMode.setEnabled(True)
|
self.actions.editMode.setEnabled(True)
|
||||||
self.setDirty()
|
self.setDirty()
|
||||||
|
@ -1643,7 +1732,8 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.setDirty()
|
self.setDirty()
|
||||||
|
|
||||||
def deleteSelectedShape(self):
|
def deleteSelectedShape(self):
|
||||||
self.remLabel(self.canvas.deleteSelected())
|
self.remLabels(self.canvas.deleteSelected())
|
||||||
|
self.actions.undo.setEnabled(True)
|
||||||
self.setDirty()
|
self.setDirty()
|
||||||
if self.noShapes():
|
if self.noShapes():
|
||||||
for action in self.actions.onShapesPresent:
|
for action in self.actions.onShapesPresent:
|
||||||
|
@ -1914,8 +2004,8 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.savePPlabel()
|
self.savePPlabel()
|
||||||
|
|
||||||
def saveRecResult(self):
|
def saveRecResult(self):
|
||||||
if None in [self.PPlabelpath, self.PPlabel, self.fileStatedict]:
|
if {} in [self.PPlabelpath, self.PPlabel, self.fileStatedict]:
|
||||||
QMessageBox.information(self, "Information", "Save file first")
|
QMessageBox.information(self, "Information", "Check the image first")
|
||||||
return
|
return
|
||||||
|
|
||||||
rec_gt_dir = os.path.dirname(self.PPlabelpath) + '/rec_gt.txt'
|
rec_gt_dir = os.path.dirname(self.PPlabelpath) + '/rec_gt.txt'
|
||||||
|
@ -1953,6 +2043,29 @@ class MainWindow(QMainWindow, WindowMixin):
|
||||||
self.canvas.newShape.disconnect()
|
self.canvas.newShape.disconnect()
|
||||||
self.canvas.newShape.connect(partial(self.newShape, False))
|
self.canvas.newShape.connect(partial(self.newShape, False))
|
||||||
|
|
||||||
|
def autoSaveFunc(self):
|
||||||
|
if self.autoSaveOption.isChecked():
|
||||||
|
self.autoSaveNum = 1 # Real auto_Save
|
||||||
|
print('The program will automatically save once after confirming an image')
|
||||||
|
else:
|
||||||
|
self.autoSaveNum = 5 # Used for backup
|
||||||
|
print('The program will automatically save once after confirming 5 images (default)')
|
||||||
|
|
||||||
|
def undoShapeEdit(self):
|
||||||
|
self.canvas.restoreShape()
|
||||||
|
self.labelList.clear()
|
||||||
|
self.BoxList.clear()
|
||||||
|
self.loadShapes(self.canvas.shapes) # 重新加载
|
||||||
|
self.actions.undo.setEnabled(self.canvas.isShapeRestorable)
|
||||||
|
|
||||||
|
def loadShapes(self, shapes, replace=True):
|
||||||
|
self._noSelectionSlot = True
|
||||||
|
for shape in shapes:
|
||||||
|
self.addLabel(shape)
|
||||||
|
self.labelList.clearSelection()
|
||||||
|
self._noSelectionSlot = False
|
||||||
|
self.canvas.loadShapes(shapes, replace=replace)
|
||||||
|
|
||||||
|
|
||||||
def inverted(color):
|
def inverted(color):
|
||||||
return QColor(*[255 - v for v in color.getRgb()])
|
return QColor(*[255 - v for v in color.getRgb()])
|
||||||
|
@ -1976,7 +2089,7 @@ def get_main_app(argv=[]):
|
||||||
app.setWindowIcon(newIcon("app"))
|
app.setWindowIcon(newIcon("app"))
|
||||||
# Tzutalin 201705+: Accept extra agruments to change predefined class file
|
# Tzutalin 201705+: Accept extra agruments to change predefined class file
|
||||||
argparser = argparse.ArgumentParser()
|
argparser = argparse.ArgumentParser()
|
||||||
argparser.add_argument("--lang", default='en', nargs="?")
|
argparser.add_argument("--lang", default='ch', nargs="?")
|
||||||
argparser.add_argument("--predefined_classes_file",
|
argparser.add_argument("--predefined_classes_file",
|
||||||
default=os.path.join(os.path.dirname(__file__), "data", "predefined_classes.txt"),
|
default=os.path.join(os.path.dirname(__file__), "data", "predefined_classes.txt"),
|
||||||
nargs="?")
|
nargs="?")
|
||||||
|
|
|
@ -37,7 +37,8 @@ class Canvas(QWidget):
|
||||||
zoomRequest = pyqtSignal(int)
|
zoomRequest = pyqtSignal(int)
|
||||||
scrollRequest = pyqtSignal(int, int)
|
scrollRequest = pyqtSignal(int, int)
|
||||||
newShape = pyqtSignal()
|
newShape = pyqtSignal()
|
||||||
selectionChanged = pyqtSignal(bool)
|
# selectionChanged = pyqtSignal(bool)
|
||||||
|
selectionChanged = pyqtSignal(list)
|
||||||
shapeMoved = pyqtSignal()
|
shapeMoved = pyqtSignal()
|
||||||
drawingPolygon = pyqtSignal(bool)
|
drawingPolygon = pyqtSignal(bool)
|
||||||
|
|
||||||
|
@ -51,9 +52,11 @@ class Canvas(QWidget):
|
||||||
# Initialise local state.
|
# Initialise local state.
|
||||||
self.mode = self.EDIT
|
self.mode = self.EDIT
|
||||||
self.shapes = []
|
self.shapes = []
|
||||||
|
self.shapesBackups = []
|
||||||
self.current = None
|
self.current = None
|
||||||
|
self.selectedShapes = []
|
||||||
self.selectedShape = None # save the selected shape here
|
self.selectedShape = None # save the selected shape here
|
||||||
self.selectedShapeCopy = None
|
self.selectedShapesCopy = []
|
||||||
self.drawingLineColor = QColor(0, 0, 255)
|
self.drawingLineColor = QColor(0, 0, 255)
|
||||||
self.drawingRectColor = QColor(0, 0, 255)
|
self.drawingRectColor = QColor(0, 0, 255)
|
||||||
self.line = Shape(line_color=self.drawingLineColor)
|
self.line = Shape(line_color=self.drawingLineColor)
|
||||||
|
@ -77,6 +80,7 @@ class Canvas(QWidget):
|
||||||
self.drawSquare = False
|
self.drawSquare = False
|
||||||
self.fourpoint = True # ADD
|
self.fourpoint = True # ADD
|
||||||
self.pointnum = 0
|
self.pointnum = 0
|
||||||
|
self.movingShape = False
|
||||||
|
|
||||||
#initialisation for panning
|
#initialisation for panning
|
||||||
self.pan_initial_pos = QPoint()
|
self.pan_initial_pos = QPoint()
|
||||||
|
@ -149,37 +153,40 @@ class Canvas(QWidget):
|
||||||
clipped_x = min(max(0, pos.x()), size.width())
|
clipped_x = min(max(0, pos.x()), size.width())
|
||||||
clipped_y = min(max(0, pos.y()), size.height())
|
clipped_y = min(max(0, pos.y()), size.height())
|
||||||
pos = QPointF(clipped_x, clipped_y)
|
pos = QPointF(clipped_x, clipped_y)
|
||||||
elif len(self.current) > 1 and self.closeEnough(pos, self.current[0]) and not self.fourpoint:
|
|
||||||
|
elif len(self.current) > 1 and self.closeEnough(pos, self.current[0]):# and not self.fourpoint:
|
||||||
# Attract line to starting point and colorise to alert the
|
# Attract line to starting point and colorise to alert the
|
||||||
# user:
|
# user:
|
||||||
pos = self.current[0]
|
pos = self.current[0]
|
||||||
color = self.current.line_color
|
color = self.current.line_color
|
||||||
self.overrideCursor(CURSOR_POINT)
|
self.overrideCursor(CURSOR_POINT)
|
||||||
self.current.highlightVertex(0, Shape.NEAR_VERTEX)
|
self.current.highlightVertex(0, Shape.NEAR_VERTEX)
|
||||||
elif ( # ADD
|
# elif ( # ADD # 合并上下代码 内容一样
|
||||||
len(self.current) > 1
|
# len(self.current) > 1
|
||||||
and self.fourpoint
|
# and self.fourpoint
|
||||||
and self.closeEnough(pos, self.current[0])
|
# and self.closeEnough(pos, self.current[0])
|
||||||
):
|
# ):
|
||||||
# Attract line to starting point and
|
# # Attract line to starting point and
|
||||||
# colorise to alert the user.
|
# # colorise to alert the user.
|
||||||
pos = self.current[0]
|
# pos = self.current[0]
|
||||||
self.overrideCursor(CURSOR_POINT)
|
# self.overrideCursor(CURSOR_POINT)
|
||||||
self.current.highlightVertex(0, Shape.NEAR_VERTEX)
|
# self.current.highlightVertex(0, Shape.NEAR_VERTEX)
|
||||||
|
|
||||||
|
|
||||||
if self.drawSquare:
|
if self.drawSquare: # 这部分不同
|
||||||
initPos = self.current[0]
|
# initPos = self.current[0] # 原先代码
|
||||||
minX = initPos.x()
|
# minX = initPos.x()
|
||||||
minY = initPos.y()
|
# minY = initPos.y()
|
||||||
min_size = min(abs(pos.x() - minX), abs(pos.y() - minY))
|
# min_size = min(abs(pos.x() - minX), abs(pos.y() - minY))
|
||||||
directionX = -1 if pos.x() - minX < 0 else 1
|
# directionX = -1 if pos.x() - minX < 0 else 1
|
||||||
directionY = -1 if pos.y() - minY < 0 else 1
|
# directionY = -1 if pos.y() - minY < 0 else 1
|
||||||
self.line[1] = QPointF(minX + directionX * min_size, minY + directionY * min_size)
|
# self.line[1] = QPointF(minX + directionX * min_size, minY + directionY * min_size)
|
||||||
|
|
||||||
|
self.line.points = [self.current[0], pos] # Labelme代码
|
||||||
|
self.line.close()
|
||||||
|
|
||||||
elif self.fourpoint:
|
elif self.fourpoint:
|
||||||
# self.line[self.pointnum] = pos # OLD
|
# self.line[self.pointnum] = pos # OLD
|
||||||
|
|
||||||
self.line[0] = self.current[-1]
|
self.line[0] = self.current[-1]
|
||||||
self.line[1] = pos
|
self.line[1] = pos
|
||||||
|
|
||||||
|
@ -193,15 +200,17 @@ class Canvas(QWidget):
|
||||||
self.prevPoint = pos
|
self.prevPoint = pos
|
||||||
self.repaint()
|
self.repaint()
|
||||||
return
|
return
|
||||||
|
# 一下都相同
|
||||||
# Polygon copy moving.
|
# Polygon copy moving.
|
||||||
if Qt.RightButton & ev.buttons():
|
if Qt.RightButton & ev.buttons():
|
||||||
if self.selectedShapeCopy and self.prevPoint:
|
if self.selectedShapesCopy and self.prevPoint:
|
||||||
self.overrideCursor(CURSOR_MOVE)
|
self.overrideCursor(CURSOR_MOVE)
|
||||||
self.boundedMoveShape(self.selectedShapeCopy, pos)
|
self.boundedMoveShape(self.selectedShapesCopy, pos)
|
||||||
self.repaint()
|
self.repaint()
|
||||||
elif self.selectedShape:
|
elif self.selectedShapes:
|
||||||
self.selectedShapeCopy = self.selectedShape.copy()
|
self.selectedShapesCopy = [
|
||||||
|
s.copy() for s in self.selectedShapes
|
||||||
|
]
|
||||||
self.repaint()
|
self.repaint()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -209,14 +218,16 @@ class Canvas(QWidget):
|
||||||
if Qt.LeftButton & ev.buttons():
|
if Qt.LeftButton & ev.buttons():
|
||||||
if self.selectedVertex():
|
if self.selectedVertex():
|
||||||
self.boundedMoveVertex(pos)
|
self.boundedMoveVertex(pos)
|
||||||
self.shapeMoved.emit()
|
self.shapeMoved.emit() # 同时选中时的移动
|
||||||
self.repaint()
|
self.repaint()
|
||||||
elif self.selectedShape and self.prevPoint:
|
self.movingShape = True
|
||||||
|
elif self.selectedShapes and self.prevPoint:
|
||||||
self.overrideCursor(CURSOR_MOVE)
|
self.overrideCursor(CURSOR_MOVE)
|
||||||
self.boundedMoveShape(self.selectedShape, pos)
|
self.boundedMoveShape(self.selectedShapes, pos)
|
||||||
self.shapeMoved.emit()
|
self.shapeMoved.emit()
|
||||||
self.repaint()
|
self.repaint()
|
||||||
else:
|
self.movingShape = True
|
||||||
|
else: # TODO 这部分是多的
|
||||||
#pan
|
#pan
|
||||||
delta_x = pos.x() - self.pan_initial_pos.x()
|
delta_x = pos.x() - self.pan_initial_pos.x()
|
||||||
delta_y = pos.y() - self.pan_initial_pos.y()
|
delta_y = pos.y() - self.pan_initial_pos.y()
|
||||||
|
@ -237,7 +248,8 @@ class Canvas(QWidget):
|
||||||
if index is not None:
|
if index is not None:
|
||||||
if self.selectedVertex():
|
if self.selectedVertex():
|
||||||
self.hShape.highlightClear()
|
self.hShape.highlightClear()
|
||||||
self.hVertex, self.hShape = index, shape
|
# TODO: Pre部分的变量都没有
|
||||||
|
self.hVertex, self.hShape = index, shape # 倒着来的原因是要更新hShape的值?
|
||||||
shape.highlightVertex(index, shape.MOVE_VERTEX)
|
shape.highlightVertex(index, shape.MOVE_VERTEX)
|
||||||
self.overrideCursor(CURSOR_POINT)
|
self.overrideCursor(CURSOR_POINT)
|
||||||
self.setToolTip("Click & drag to move point")
|
self.setToolTip("Click & drag to move point")
|
||||||
|
@ -263,23 +275,25 @@ class Canvas(QWidget):
|
||||||
|
|
||||||
def mousePressEvent(self, ev):
|
def mousePressEvent(self, ev):
|
||||||
pos = self.transformPos(ev.pos())
|
pos = self.transformPos(ev.pos())
|
||||||
|
|
||||||
if ev.button() == Qt.LeftButton:
|
if ev.button() == Qt.LeftButton:
|
||||||
if self.drawing():
|
if self.drawing():
|
||||||
# self.handleDrawing(pos) # OLD
|
# self.handleDrawing(pos) # OLD
|
||||||
|
if self.current:
|
||||||
|
if self.fourpoint: # ADD IF
|
||||||
if self.current and self.fourpoint: # ADD IF
|
# Add point to existing shape.
|
||||||
# Add point to existing shape.
|
# print('Adding points in mousePressEvent is ', self.line[1])
|
||||||
print('Adding points in mousePressEvent is ', self.line[1])
|
self.current.addPoint(self.line[1])
|
||||||
self.current.addPoint(self.line[1])
|
self.line[0] = self.current[-1]
|
||||||
self.line[0] = self.current[-1]
|
if self.current.isClosed():
|
||||||
if self.current.isClosed():
|
# print('1111')
|
||||||
# print('1111')
|
self.finalise()
|
||||||
|
elif self.drawSquare: # 增加
|
||||||
|
assert len(self.current.points) == 1
|
||||||
|
self.current.points = self.line.points
|
||||||
self.finalise()
|
self.finalise()
|
||||||
elif not self.outOfPixmap(pos):
|
elif not self.outOfPixmap(pos):
|
||||||
# Create new shape.
|
# Create new shape.
|
||||||
self.current = Shape()# self.current = Shape(shape_type=self.createMode)
|
self.current = Shape()# self.current = Shape(shape_type=self.createMode) # TODO: 有可能需要制定类型?
|
||||||
self.current.addPoint(pos)
|
self.current.addPoint(pos)
|
||||||
# if self.createMode == "point":
|
# if self.createMode == "point":
|
||||||
# self.finalise()
|
# self.finalise()
|
||||||
|
@ -291,69 +305,103 @@ class Canvas(QWidget):
|
||||||
self.drawingPolygon.emit(True)
|
self.drawingPolygon.emit(True)
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
|
else: # 改动后可以增加多选框,选点方式从单点变成list
|
||||||
else:
|
# selection = self.selectShapePoint(pos)
|
||||||
selection = self.selectShapePoint(pos)
|
# self.prevPoint = pos
|
||||||
|
#
|
||||||
|
# if selection is None:
|
||||||
|
# #pan
|
||||||
|
# QApplication.setOverrideCursor(QCursor(Qt.OpenHandCursor))
|
||||||
|
# self.pan_initial_pos = pos
|
||||||
|
group_mode = int(ev.modifiers()) == Qt.ControlModifier
|
||||||
|
self.selectShapePoint(pos, multiple_selection_mode=group_mode)
|
||||||
self.prevPoint = pos
|
self.prevPoint = pos
|
||||||
|
self.pan_initial_pos = pos
|
||||||
if selection is None:
|
# self.repaint()
|
||||||
#pan
|
|
||||||
QApplication.setOverrideCursor(QCursor(Qt.OpenHandCursor))
|
|
||||||
self.pan_initial_pos = pos
|
|
||||||
|
|
||||||
elif ev.button() == Qt.RightButton and self.editing():
|
elif ev.button() == Qt.RightButton and self.editing():
|
||||||
self.selectShapePoint(pos)
|
# self.selectShapePoint(pos)
|
||||||
|
# self.prevPoint = pos
|
||||||
|
group_mode = int(ev.modifiers()) == Qt.ControlModifier
|
||||||
|
self.selectShapePoint(pos, multiple_selection_mode=group_mode)
|
||||||
self.prevPoint = pos
|
self.prevPoint = pos
|
||||||
|
# self.repaint() # 只用update?
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def mouseReleaseEvent(self, ev):
|
def mouseReleaseEvent(self, ev):
|
||||||
if ev.button() == Qt.RightButton:
|
if ev.button() == Qt.RightButton:
|
||||||
menu = self.menus[bool(self.selectedShapeCopy)]
|
menu = self.menus[bool(self.selectedShapesCopy)]
|
||||||
self.restoreCursor()
|
self.restoreCursor()
|
||||||
if not menu.exec_(self.mapToGlobal(ev.pos()))\
|
if not menu.exec_(self.mapToGlobal(ev.pos()))\
|
||||||
and self.selectedShapeCopy:
|
and self.selectedShapesCopy:
|
||||||
# Cancel the move by deleting the shadow copy.
|
# Cancel the move by deleting the shadow copy.
|
||||||
self.selectedShapeCopy = None
|
# self.selectedShapeCopy = None
|
||||||
|
self.selectedShapesCopy = []
|
||||||
self.repaint()
|
self.repaint()
|
||||||
elif ev.button() == Qt.LeftButton and self.selectedShape: # OLD
|
# elif ev.button() == Qt.LeftButton and self.selectedShape: # OLD
|
||||||
|
elif ev.button() == Qt.LeftButton and self.selectedShapes:
|
||||||
if self.selectedVertex():
|
if self.selectedVertex():
|
||||||
self.overrideCursor(CURSOR_POINT)
|
self.overrideCursor(CURSOR_POINT)
|
||||||
else:
|
else:
|
||||||
self.overrideCursor(CURSOR_GRAB)
|
self.overrideCursor(CURSOR_GRAB)
|
||||||
|
|
||||||
|
elif ev.button() == Qt.LeftButton and not self.fourpoint: # 暂时去除四点部分的代码
|
||||||
elif ev.button() == Qt.LeftButton and not self.fourpoint:
|
|
||||||
pos = self.transformPos(ev.pos())
|
pos = self.transformPos(ev.pos())
|
||||||
if self.drawing():
|
if self.drawing():
|
||||||
self.handleDrawing(pos)
|
self.handleDrawing(pos) # 关键函数
|
||||||
else:
|
else:
|
||||||
#pan
|
#pan
|
||||||
QApplication.restoreOverrideCursor() # ?
|
QApplication.restoreOverrideCursor() # ?
|
||||||
|
|
||||||
|
if self.movingShape and self.hShape: # 加上之后会移动点会崩 用于撤回
|
||||||
|
index = self.shapes.index(self.hShape)
|
||||||
|
if (
|
||||||
|
self.shapesBackups[-1][index].points # 如果新建的框位置变化
|
||||||
|
!= self.shapes[index].points
|
||||||
|
):
|
||||||
|
self.storeShapes() # 重新backup一下
|
||||||
|
self.shapeMoved.emit() # 连接updateBoxlist
|
||||||
|
|
||||||
|
self.movingShape = False
|
||||||
|
|
||||||
|
|
||||||
def endMove(self, copy=False):
|
def endMove(self, copy=False):
|
||||||
assert self.selectedShape and self.selectedShapeCopy
|
# assert self.selectedShape and self.selectedShapeCopy
|
||||||
shape = self.selectedShapeCopy
|
# shape = self.selectedShapeCopy
|
||||||
#del shape.fill_color
|
#del shape.fill_color
|
||||||
#del shape.line_color
|
#del shape.line_color
|
||||||
|
# if copy:
|
||||||
|
# self.shapes.append(shape)
|
||||||
|
# self.selectedShape.selected = False
|
||||||
|
# self.selectedShape = shape
|
||||||
|
# self.repaint()
|
||||||
|
# else:
|
||||||
|
# self.selectedShape.points = [p for p in shape.points]
|
||||||
|
# self.selectedShapeCopy = None
|
||||||
|
assert self.selectedShapes and self.selectedShapesCopy
|
||||||
|
assert len(self.selectedShapesCopy) == len(self.selectedShapes)
|
||||||
if copy:
|
if copy:
|
||||||
self.shapes.append(shape)
|
for i, shape in enumerate(self.selectedShapesCopy):
|
||||||
self.selectedShape.selected = False
|
self.shapes.append(shape)
|
||||||
self.selectedShape = shape
|
self.selectedShapes[i].selected = False
|
||||||
self.repaint()
|
self.selectedShapes[i] = shape
|
||||||
else:
|
else:
|
||||||
self.selectedShape.points = [p for p in shape.points]
|
for i, shape in enumerate(self.selectedShapesCopy):
|
||||||
self.selectedShapeCopy = None
|
self.selectedShapes[i].points = shape.points
|
||||||
|
self.selectedShapesCopy = []
|
||||||
|
self.repaint()
|
||||||
|
self.storeShapes()
|
||||||
|
return True
|
||||||
|
|
||||||
def hideBackroundShapes(self, value):
|
def hideBackroundShapes(self, value):
|
||||||
self.hideBackround = value
|
self.hideBackround = value
|
||||||
if self.selectedShape:
|
if self.selectedShapes:
|
||||||
# Only hide other shapes if there is a current selection.
|
# Only hide other shapes if there is a current selection.
|
||||||
# Otherwise the user will not be able to select a shape.
|
# Otherwise the user will not be able to select a shape.
|
||||||
self.setHiding(True)
|
self.setHiding(True)
|
||||||
self.repaint()
|
self.repaint()
|
||||||
|
|
||||||
def handleDrawing(self, pos):
|
def handleDrawing(self, pos): # 没有此函数
|
||||||
if self.current and self.current.reachMaxPoints() is False:
|
if self.current and self.current.reachMaxPoints() is False:
|
||||||
if self.fourpoint:
|
if self.fourpoint:
|
||||||
targetPos = self.line[self.pointnum]
|
targetPos = self.line[self.pointnum]
|
||||||
|
@ -399,28 +447,54 @@ class Canvas(QWidget):
|
||||||
self.current.popPoint()
|
self.current.popPoint()
|
||||||
self.finalise()
|
self.finalise()
|
||||||
|
|
||||||
def selectShape(self, shape):
|
def selectShapes(self, shapes):
|
||||||
self.deSelectShape()
|
# self.deSelectShape()
|
||||||
shape.selected = True
|
# shape.selected = True
|
||||||
self.selectedShape = shape
|
# self.selectedShape = shape
|
||||||
|
# self.setHiding()
|
||||||
|
# self.selectionChanged.emit(True)
|
||||||
|
# self.update()
|
||||||
|
for s in shapes: s.seleted = True
|
||||||
self.setHiding()
|
self.setHiding()
|
||||||
self.selectionChanged.emit(True)
|
self.selectionChanged.emit(shapes)
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def selectShapePoint(self, point):
|
# def selectShapePoint(self, point):
|
||||||
|
# """Select the first shape created which contains this point."""
|
||||||
|
# self.deSelectShape()
|
||||||
|
# if self.selectedVertex(): # A vertex is marked for selection.
|
||||||
|
# index, shape = self.hVertex, self.hShape
|
||||||
|
# shape.highlightVertex(index, shape.MOVE_VERTEX)
|
||||||
|
# self.selectShape(shape)
|
||||||
|
# return self.hVertex
|
||||||
|
# for shape in reversed(self.shapes):
|
||||||
|
# if self.isVisible(shape) and shape.containsPoint(point):
|
||||||
|
# self.selectShape(shape) # 函数
|
||||||
|
# self.calculateOffsets(shape, point)
|
||||||
|
# return self.selectedShape
|
||||||
|
# return None
|
||||||
|
|
||||||
|
def selectShapePoint(self, point, multiple_selection_mode):
|
||||||
"""Select the first shape created which contains this point."""
|
"""Select the first shape created which contains this point."""
|
||||||
self.deSelectShape()
|
|
||||||
if self.selectedVertex(): # A vertex is marked for selection.
|
if self.selectedVertex(): # A vertex is marked for selection.
|
||||||
index, shape = self.hVertex, self.hShape
|
index, shape = self.hVertex, self.hShape
|
||||||
shape.highlightVertex(index, shape.MOVE_VERTEX)
|
shape.highlightVertex(index, shape.MOVE_VERTEX) # 突出显示
|
||||||
self.selectShape(shape)
|
|
||||||
return self.hVertex
|
return self.hVertex
|
||||||
for shape in reversed(self.shapes):
|
else:
|
||||||
if self.isVisible(shape) and shape.containsPoint(point):
|
for shape in reversed(self.shapes):
|
||||||
self.selectShape(shape)
|
if self.isVisible(shape) and shape.containsPoint(point):
|
||||||
self.calculateOffsets(shape, point)
|
self.calculateOffsets(shape, point)
|
||||||
return self.selectedShape
|
self.setHiding()
|
||||||
return None
|
if multiple_selection_mode:
|
||||||
|
if shape not in self.selectedShapes: # list TODO:为什么是2个,刚开始应该是1个
|
||||||
|
self.selectionChanged.emit(
|
||||||
|
self.selectedShapes + [shape] # 选择+未选择
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.selectionChanged.emit([shape])
|
||||||
|
return
|
||||||
|
self.deSelectShape()
|
||||||
|
|
||||||
def calculateOffsets(self, shape, point):
|
def calculateOffsets(self, shape, point):
|
||||||
rect = shape.boundingRect()
|
rect = shape.boundingRect()
|
||||||
|
@ -465,22 +539,26 @@ class Canvas(QWidget):
|
||||||
else:
|
else:
|
||||||
shiftPos = pos - point
|
shiftPos = pos - point
|
||||||
|
|
||||||
shape.moveVertexBy(index, shiftPos)
|
if shape[0].x()==shape[3].x() and shape[1].x()==shape[2].x() and shape[0].y()==shape[1].y():
|
||||||
|
shape.moveVertexBy(index, shiftPos)
|
||||||
|
lindex = (index + 1) % 4
|
||||||
|
rindex = (index + 3) % 4
|
||||||
|
lshift = None
|
||||||
|
rshift = None
|
||||||
|
if index % 2 == 0:
|
||||||
|
rshift = QPointF(shiftPos.x(), 0)
|
||||||
|
lshift = QPointF(0, shiftPos.y())
|
||||||
|
else:
|
||||||
|
lshift = QPointF(shiftPos.x(), 0)
|
||||||
|
rshift = QPointF(0, shiftPos.y())
|
||||||
|
shape.moveVertexBy(rindex, rshift)
|
||||||
|
shape.moveVertexBy(lindex, lshift)
|
||||||
|
|
||||||
lindex = (index + 1) % 4
|
|
||||||
rindex = (index + 3) % 4
|
|
||||||
lshift = None
|
|
||||||
rshift = None
|
|
||||||
if index % 2 == 0:
|
|
||||||
rshift = QPointF(shiftPos.x(), 0)
|
|
||||||
lshift = QPointF(0, shiftPos.y())
|
|
||||||
else:
|
else:
|
||||||
lshift = QPointF(shiftPos.x(), 0)
|
shape.moveVertexBy(index, shiftPos)
|
||||||
rshift = QPointF(0, shiftPos.y())
|
|
||||||
shape.moveVertexBy(rindex, rshift)
|
|
||||||
shape.moveVertexBy(lindex, lshift)
|
|
||||||
|
|
||||||
def boundedMoveShape(self, shape, pos):
|
|
||||||
|
def boundedMoveShape(self, shapes, pos):
|
||||||
if self.outOfPixmap(pos):
|
if self.outOfPixmap(pos):
|
||||||
return False # No need to move
|
return False # No need to move
|
||||||
o1 = pos + self.offsets[0]
|
o1 = pos + self.offsets[0]
|
||||||
|
@ -497,36 +575,69 @@ class Canvas(QWidget):
|
||||||
#self.calculateOffsets(self.selectedShape, pos)
|
#self.calculateOffsets(self.selectedShape, pos)
|
||||||
dp = pos - self.prevPoint
|
dp = pos - self.prevPoint
|
||||||
if dp:
|
if dp:
|
||||||
shape.moveBy(dp)
|
for shape in shapes:
|
||||||
|
shape.moveBy(dp)
|
||||||
self.prevPoint = pos
|
self.prevPoint = pos
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def deSelectShape(self):
|
def deSelectShape(self):
|
||||||
if self.selectedShape:
|
# if self.selectedShape:
|
||||||
self.selectedShape.selected = False
|
# self.selectedShape.selected = False
|
||||||
self.selectedShape = None
|
# self.selectedShape = None
|
||||||
|
# self.setHiding(False)
|
||||||
|
# self.selectionChanged.emit(False)
|
||||||
|
# self.update()
|
||||||
|
if self.selectedShapes:
|
||||||
|
# TODO:少了两个清空?
|
||||||
|
for shape in self.selectedShapes: shape.selected=False
|
||||||
self.setHiding(False)
|
self.setHiding(False)
|
||||||
self.selectionChanged.emit(False)
|
self.selectionChanged.emit([])
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
|
# def deleteSelected(self):
|
||||||
|
# if self.selectedShape:
|
||||||
|
# shape = self.selectedShape
|
||||||
|
# self.shapes.remove(self.selectedShape)
|
||||||
|
# self.selectedShape = None
|
||||||
|
# self.update()
|
||||||
|
# return shape
|
||||||
|
|
||||||
def deleteSelected(self):
|
def deleteSelected(self):
|
||||||
if self.selectedShape:
|
deleted_shapes = []
|
||||||
shape = self.selectedShape
|
if self.selectedShapes:
|
||||||
self.shapes.remove(self.selectedShape)
|
#self.storeShapes()
|
||||||
self.selectedShape = None
|
for shape in self.selectedShapes:
|
||||||
|
self.shapes.remove(shape)
|
||||||
|
#self.shapesBackups.append(shape)
|
||||||
|
deleted_shapes.append(shape)
|
||||||
|
self.storeShapes() # 这里应该是先储存
|
||||||
|
self.selectedShapes = []
|
||||||
self.update()
|
self.update()
|
||||||
return shape
|
return deleted_shapes
|
||||||
|
|
||||||
|
def storeShapes(self):
|
||||||
|
shapesBackup = []
|
||||||
|
for shape in self.shapes:
|
||||||
|
shapesBackup.append(shape.copy())
|
||||||
|
if len(self.shapesBackups) >= 10:
|
||||||
|
self.shapesBackups = self.shapesBackups[-9:]
|
||||||
|
self.shapesBackups.append(shapesBackup) # 每删除或保存一次都会backup一次
|
||||||
|
|
||||||
def copySelectedShape(self):
|
def copySelectedShape(self):
|
||||||
if self.selectedShape:
|
# if self.selectedShape:
|
||||||
shape = self.selectedShape.copy()
|
# shape = self.selectedShape.copy()
|
||||||
self.deSelectShape()
|
# self.deSelectShape()
|
||||||
self.shapes.append(shape)
|
# self.shapes.append(shape)
|
||||||
shape.selected = True
|
# shape.selected = True
|
||||||
self.selectedShape = shape
|
# self.selectedShape = shape
|
||||||
self.boundedShiftShape(shape)
|
# self.boundedShiftShape(shape)
|
||||||
return shape
|
# return shape
|
||||||
|
if self.selectedShapes:
|
||||||
|
self.selectedShapesCopy = [s.copy() for s in self.selectedShapes]
|
||||||
|
self.boundedShiftShapes(self.selectedShapesCopy)
|
||||||
|
self.endMove(copy=True)
|
||||||
|
return self.selectedShapes
|
||||||
|
|
||||||
def boundedShiftShape(self, shape):
|
def boundedShiftShape(self, shape):
|
||||||
# Try to move in one direction, and if it fails in another.
|
# Try to move in one direction, and if it fails in another.
|
||||||
|
@ -560,8 +671,9 @@ class Canvas(QWidget):
|
||||||
if self.current:
|
if self.current:
|
||||||
self.current.paint(p)
|
self.current.paint(p)
|
||||||
self.line.paint(p)
|
self.line.paint(p)
|
||||||
if self.selectedShapeCopy:
|
if self.selectedShapesCopy:
|
||||||
self.selectedShapeCopy.paint(p)
|
for s in self.selectedShapesCopy:
|
||||||
|
s.paint(p)
|
||||||
|
|
||||||
# Paint rect
|
# Paint rect
|
||||||
if self.current is not None and len(self.line) == 2 and not self.fourpoint:
|
if self.current is not None and len(self.line) == 2 and not self.fourpoint:
|
||||||
|
@ -689,14 +801,14 @@ class Canvas(QWidget):
|
||||||
self.update()
|
self.update()
|
||||||
elif key == Qt.Key_Return and self.canCloseShape():
|
elif key == Qt.Key_Return and self.canCloseShape():
|
||||||
self.finalise()
|
self.finalise()
|
||||||
elif key == Qt.Key_Left and self.selectedShape:
|
# elif key == Qt.Key_Left and self.selectedShape:
|
||||||
self.moveOnePixel('Left')
|
# self.moveOnePixel('Left')
|
||||||
elif key == Qt.Key_Right and self.selectedShape:
|
# elif key == Qt.Key_Right and self.selectedShape:
|
||||||
self.moveOnePixel('Right')
|
# self.moveOnePixel('Right')
|
||||||
elif key == Qt.Key_Up and self.selectedShape:
|
# elif key == Qt.Key_Up and self.selectedShape:
|
||||||
self.moveOnePixel('Up')
|
# self.moveOnePixel('Up')
|
||||||
elif key == Qt.Key_Down and self.selectedShape:
|
# elif key == Qt.Key_Down and self.selectedShape:
|
||||||
self.moveOnePixel('Down')
|
# self.moveOnePixel('Down')
|
||||||
|
|
||||||
def moveOnePixel(self, direction):
|
def moveOnePixel(self, direction):
|
||||||
# print(self.selectedShape.points)
|
# print(self.selectedShape.points)
|
||||||
|
@ -739,6 +851,8 @@ class Canvas(QWidget):
|
||||||
|
|
||||||
if fill_color:
|
if fill_color:
|
||||||
self.shapes[-1].fill_color = fill_color
|
self.shapes[-1].fill_color = fill_color
|
||||||
|
#self.shapesBackups.pop() # 新建shape后要pop?
|
||||||
|
self.storeShapes()
|
||||||
|
|
||||||
return self.shapes[-1]
|
return self.shapes[-1]
|
||||||
|
|
||||||
|
@ -749,6 +863,17 @@ class Canvas(QWidget):
|
||||||
self.line.points = [self.current[-1], self.current[0]]
|
self.line.points = [self.current[-1], self.current[0]]
|
||||||
self.drawingPolygon.emit(True)
|
self.drawingPolygon.emit(True)
|
||||||
|
|
||||||
|
def undoLastPoint(self):
|
||||||
|
if not self.current or self.current.isClosed():
|
||||||
|
return
|
||||||
|
self.current.popPoint()
|
||||||
|
if len(self.current) > 0:
|
||||||
|
self.line[0] = self.current[-1]
|
||||||
|
else:
|
||||||
|
self.current = None
|
||||||
|
self.drawingPolygon.emit(False)
|
||||||
|
self.repaint()
|
||||||
|
|
||||||
def resetAllLines(self):
|
def resetAllLines(self):
|
||||||
assert self.shapes
|
assert self.shapes
|
||||||
self.current = self.shapes.pop()
|
self.current = self.shapes.pop()
|
||||||
|
@ -762,11 +887,18 @@ class Canvas(QWidget):
|
||||||
def loadPixmap(self, pixmap):
|
def loadPixmap(self, pixmap):
|
||||||
self.pixmap = pixmap
|
self.pixmap = pixmap
|
||||||
self.shapes = []
|
self.shapes = []
|
||||||
self.repaint() # 这函数在哪
|
self.repaint()
|
||||||
|
|
||||||
def loadShapes(self, shapes):
|
def loadShapes(self, shapes, replace=True):
|
||||||
self.shapes = list(shapes)
|
if replace:
|
||||||
|
self.shapes = list(shapes)
|
||||||
|
else:
|
||||||
|
self.shapes.extend(shapes)
|
||||||
self.current = None
|
self.current = None
|
||||||
|
self.hShape = None
|
||||||
|
self.hVertex = None
|
||||||
|
# self.hEdge = None
|
||||||
|
self.storeShapes()
|
||||||
self.repaint()
|
self.repaint()
|
||||||
|
|
||||||
def setShapeVisible(self, shape, value):
|
def setShapeVisible(self, shape, value):
|
||||||
|
@ -793,6 +925,25 @@ class Canvas(QWidget):
|
||||||
self.restoreCursor()
|
self.restoreCursor()
|
||||||
self.pixmap = None
|
self.pixmap = None
|
||||||
self.update()
|
self.update()
|
||||||
|
self.shapesBackups = []
|
||||||
|
|
||||||
def setDrawingShapeToSquare(self, status):
|
def setDrawingShapeToSquare(self, status):
|
||||||
self.drawSquare = status
|
self.drawSquare = status
|
||||||
|
|
||||||
|
def restoreShape(self): # 用于撤销
|
||||||
|
if not self.isShapeRestorable:
|
||||||
|
return
|
||||||
|
self.shapesBackups.pop() # latest
|
||||||
|
shapesBackup = self.shapesBackups.pop()
|
||||||
|
self.shapes = shapesBackup
|
||||||
|
#self.shapes.append(self.shapesBackups.pop()) # 为何这里之前是只将back赋值呢
|
||||||
|
self.selectedShapes = []
|
||||||
|
for shape in self.shapes:
|
||||||
|
shape.selected = False
|
||||||
|
self.repaint()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def isShapeRestorable(self):
|
||||||
|
if len(self.shapesBackups) < 2:
|
||||||
|
return False
|
||||||
|
return True
|
File diff suppressed because it is too large
Load Diff
|
@ -82,8 +82,11 @@ class Shape(object):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def addPoint(self, point):
|
def addPoint(self, point):
|
||||||
if not self.reachMaxPoints():
|
if not self.reachMaxPoints(): # 4个点时发出close信号
|
||||||
self.points.append(point)
|
if self.points and point == self.points[0]:
|
||||||
|
self.close()
|
||||||
|
else:
|
||||||
|
self.points.append(point)
|
||||||
|
|
||||||
def popPoint(self):
|
def popPoint(self):
|
||||||
if self.points:
|
if self.points:
|
||||||
|
|
|
@ -96,4 +96,7 @@ hideBox=隐藏所有标注
|
||||||
showBox=显示所有标注
|
showBox=显示所有标注
|
||||||
saveLabel=保存标记结果
|
saveLabel=保存标记结果
|
||||||
singleRe=重识别此区块
|
singleRe=重识别此区块
|
||||||
labelDialogOption=弹出标记输入框
|
labelDialogOption=弹出标记输入框
|
||||||
|
undo=撤销
|
||||||
|
undoLastPoint=撤销上个点
|
||||||
|
autoSaveMode=自动保存标记结果
|
|
@ -96,4 +96,7 @@ hideBox=Hide All Box
|
||||||
showBox=Show All Box
|
showBox=Show All Box
|
||||||
saveLabel=Save Label
|
saveLabel=Save Label
|
||||||
singleRe=Re-recognition RectBox
|
singleRe=Re-recognition RectBox
|
||||||
labelDialogOption=Pop-up Label Input Dialog
|
labelDialogOption=Pop-up Label Input Dialog
|
||||||
|
undo=Undo
|
||||||
|
undoLastPoint=Undo Last Point
|
||||||
|
autoSaveMode=Auto Save Label Mode
|
Loading…
Reference in New Issue