提交 ecf8b569 编写于 作者: qq_25193841's avatar qq_25193841

New functions like batch move, delete, withdraw with redundant codes

上级 0ae2b779
...@@ -206,7 +206,7 @@ class MainWindow(QMainWindow, WindowMixin): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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
#changedShape.append(self.canvas.hShape) #changedShape: #
for shape in self.canvas.selectedShapes+[self.canvas.hShape]:
item = self.shapesToItemsbox[shape] # listitem item = self.shapesToItemsbox[shape] # listitem
text = [(int(p.x()), int(p.y())) for p in shape.points] text = [(int(p.x()), int(p.y())) for p in shape.points]
item.setText(str(text)) 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): ...@@ -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
# else:
# self.labelList.clearSelection()
# self.actions.delete.setEnabled(selected)
# self.actions.copy.setEnabled(selected)
# self.actions.edit.setEnabled(selected)
# self.actions.shapeLineColor.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.labelList.clearSelection()
self.actions.delete.setEnabled(selected) self.canvas.selectedShapes = selected_shapes # 这里没有把选择的两个都加入
self.actions.copy.setEnabled(selected) for shape in self.canvas.selectedShapes:
self.actions.edit.setEnabled(selected) shape.selected = True
self.actions.shapeLineColor.setEnabled(selected) # item = self.labelList.findItemByShape(shape)
self.actions.shapeFillColor.setEnabled(selected) # self.labelList.selectItem(item)
self.actions.singleRere.setEnabled(selected) # 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,10 +1001,11 @@ class MainWindow(QMainWindow, WindowMixin): ...@@ -941,10 +1001,11 @@ 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
for shape in shapes:
item = self.shapesToItems[shape] item = self.shapesToItems[shape]
self.labelList.takeItem(self.labelList.row(item)) self.labelList.takeItem(self.labelList.row(item))
del self.shapesToItems[shape] del self.shapesToItems[shape]
...@@ -1001,7 +1062,7 @@ class MainWindow(QMainWindow, WindowMixin): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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=[]): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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() self.finalise()
elif self.drawSquare: # 增加
assert len(self.current.points) == 1
self.current.points = self.line.points
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): ...@@ -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
if selection is None:
#pan
QApplication.setOverrideCursor(QCursor(Qt.OpenHandCursor))
self.pan_initial_pos = pos self.pan_initial_pos = pos
# self.repaint()
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:
for i, shape in enumerate(self.selectedShapesCopy):
self.shapes.append(shape) self.shapes.append(shape)
self.selectedShape.selected = False self.selectedShapes[i].selected = False
self.selectedShape = shape self.selectedShapes[i] = shape
self.repaint()
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): ...@@ -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
else:
for shape in reversed(self.shapes): for shape in reversed(self.shapes):
if self.isVisible(shape) and shape.containsPoint(point): if self.isVisible(shape) and shape.containsPoint(point):
self.selectShape(shape)
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,8 +539,8 @@ class Canvas(QWidget): ...@@ -465,8 +539,8 @@ class Canvas(QWidget):
else: else:
shiftPos = pos - point shiftPos = pos - point
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) shape.moveVertexBy(index, shiftPos)
lindex = (index + 1) % 4 lindex = (index + 1) % 4
rindex = (index + 3) % 4 rindex = (index + 3) % 4
lshift = None lshift = None
...@@ -480,7 +554,11 @@ class Canvas(QWidget): ...@@ -480,7 +554,11 @@ class Canvas(QWidget):
shape.moveVertexBy(rindex, rshift) shape.moveVertexBy(rindex, rshift)
shape.moveVertexBy(lindex, lshift) shape.moveVertexBy(lindex, lshift)
def boundedMoveShape(self, shape, pos): else:
shape.moveVertexBy(index, shiftPos)
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): ...@@ -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:
for shape in shapes:
shape.moveBy(dp) 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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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): ...@@ -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):
if replace:
self.shapes = list(shapes) 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): ...@@ -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
\ No newline at end of file
因为 它太大了无法显示 source diff 。你可以改为 查看blob
...@@ -82,7 +82,10 @@ class Shape(object): ...@@ -82,7 +82,10 @@ 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信号
if self.points and point == self.points[0]:
self.close()
else:
self.points.append(point) self.points.append(point)
def popPoint(self): def popPoint(self):
......
...@@ -97,3 +97,6 @@ showBox=显示所有标注 ...@@ -97,3 +97,6 @@ showBox=显示所有标注
saveLabel=保存标记结果 saveLabel=保存标记结果
singleRe=重识别此区块 singleRe=重识别此区块
labelDialogOption=弹出标记输入框 labelDialogOption=弹出标记输入框
undo=撤销
undoLastPoint=撤销上个点
autoSaveMode=自动保存标记结果
\ No newline at end of file
...@@ -97,3 +97,6 @@ showBox=Show All Box ...@@ -97,3 +97,6 @@ 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
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册