# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from qtpy import QtWidgets, QtGui, QtCore from . import GripItem, LineItem, BBoxAnnotation class PolygonAnnotation(QtWidgets.QGraphicsPolygonItem): def __init__( self, labelIndex, shape, delPolygon, setDirty, insideColor=[255, 0, 0], borderColor=[0, 255, 0], opacity=0.5, cocoIndex=None, parent=None, ): super(PolygonAnnotation, self).__init__(parent) self.points = [] self.m_items = [] self.m_lines = [] self.coco_id = cocoIndex self.height, self.width = shape[:2] self.delPolygon = delPolygon self.setDirty = setDirty self.labelIndex = labelIndex self.item_hovering = False self.polygon_hovering = False self.anning = False # 是否标注模式 self.line_hovering = False self.noMove = False self.last_focse = False # 之前是不是焦点在 self.setZValue(10) self.opacity = opacity i = insideColor self.insideColor = QtGui.QColor(i[0], i[1], i[2]) self.insideColor.setAlphaF(opacity) self.halfInsideColor = QtGui.QColor(i[0], i[1], i[2]) self.halfInsideColor.setAlphaF(opacity / 2) self.setBrush(self.halfInsideColor) b = borderColor self.borderColor = QtGui.QColor(b[0], b[1], b[2]) self.borderColor.setAlphaF(0.8) self.setPen(QtGui.QPen(self.borderColor)) self.setAcceptHoverEvents(True) self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable, True) self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, False) self.setFlag(QtWidgets.QGraphicsItem.ItemSendsGeometryChanges, True) self.setFlag(QtWidgets.QGraphicsItem.ItemIsFocusable, True) self.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) # persistent this bbox instance and update when needed self.bbox = BBoxAnnotation(labelIndex, self, cocoIndex, self) self.bbox.setParentItem(self) # self.bbox.setVisible(False) @property def scnenePoints(self): points = [] for p in self.points: p = self.mapToScene(p) points.append([p.x(), p.y()]) return points def setAnning(self, isAnning=True): if isAnning: self.setAcceptHoverEvents(False) self.last_focse = self.polygon_hovering self.polygon_hovering = False self.anning = True self.setBrush(QtGui.QBrush(QtCore.Qt.NoBrush)) self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable, False) # self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, False) self.setFlag(QtWidgets.QGraphicsItem.ItemSendsGeometryChanges, False) self.setFlag(QtWidgets.QGraphicsItem.ItemIsFocusable, False) self.setCursor(QtGui.QCursor(QtCore.Qt.ArrowCursor)) for line in self.m_lines: line.setAnning(False) for grip in self.m_items: grip.setAnning(False) else: self.setAcceptHoverEvents(True) self.anning = False if self.last_focse: self.polygon_hovering = True self.setBrush(self.insideColor) else: self.setBrush(self.halfInsideColor) self.setFlag(QtWidgets.QGraphicsItem.ItemIsSelectable, True) # self.setFlag(QtWidgets.QGraphicsItem.ItemIsMovable, True) self.setFlag(QtWidgets.QGraphicsItem.ItemSendsGeometryChanges, True) self.setFlag(QtWidgets.QGraphicsItem.ItemIsFocusable, True) self.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor)) for line in self.m_lines: line.setAnning(True) for grip in self.m_items: grip.setAnning(True) def addPointMiddle(self, lineIdx, point): gripItem = GripItem(self, lineIdx + 1, self.borderColor, (self.height, self.width)) gripItem.setEnabled(False) gripItem.setPos(point) self.scene().addItem(gripItem) gripItem.updateSize() gripItem.setEnabled(True) for grip in self.m_items[lineIdx + 1:]: grip.m_index += 1 self.m_items.insert(lineIdx + 1, gripItem) self.points.insert(lineIdx + 1, self.mapFromScene(point)) self.setPolygon(QtGui.QPolygonF(self.points)) self.bbox.update() for line in self.m_lines[lineIdx + 1:]: line.idx += 1 line = QtCore.QLineF(self.mapToScene(self.points[lineIdx]), point) self.m_lines[lineIdx].setLine(line) lineItem = LineItem(self, lineIdx + 1, self.borderColor) line = QtCore.QLineF( point, self.mapToScene(self.points[(lineIdx + 2) % len(self)]), ) lineItem.setLine(line) self.m_lines.insert(lineIdx + 1, lineItem) self.scene().addItem(lineItem) lineItem.updateWidth() def addPointLast(self, p): grip = GripItem(self, len(self), self.borderColor, (self.height, self.width)) self.scene().addItem(grip) self.m_items.append(grip) grip.updateSize() grip.setPos(p) if len(self) == 0: line = LineItem(self, len(self), self.borderColor) self.scene().addItem(line) self.m_lines.append(line) line.setLine(QtCore.QLineF(p, p)) else: self.m_lines[-1].setLine(QtCore.QLineF(self.points[-1], p)) line = LineItem(self, len(self), self.borderColor) self.scene().addItem(line) self.m_lines.append(line) line.setLine(QtCore.QLineF(p, self.points[0])) self.points.append(p) self.setPolygon(QtGui.QPolygonF(self.points)) self.bbox.update() def remove(self): for grip in self.m_items: self.scene().removeItem(grip) for line in self.m_lines: self.scene().removeItem(line) while len(self.m_items) != 0: self.m_items.pop() while len(self.m_lines) != 0: self.m_lines.pop() self.scene().polygon_items.remove(self) self.scene().removeItem(self) self.bbox.remove_from_scene() del self.bbox del self def removeFocusPoint(self): focusIdx = None for idx, item in enumerate(self.m_items): if item.hasFocus(): focusIdx = idx break if focusIdx is not None: if len(self) <= 3: self.delPolygon(self) # 调用app的删除多边形,为了同时删除coco标签 return del self.points[focusIdx] self.setPolygon(QtGui.QPolygonF(self.points)) self.bbox.update() self.scene().removeItem(self.m_items[focusIdx]) del self.m_items[focusIdx] for grip in self.m_items[focusIdx:]: grip.m_index -= 1 self.scene().removeItem(self.m_lines[focusIdx]) del self.m_lines[focusIdx] line = QtCore.QLineF( self.mapToScene(self.points[(focusIdx - 1) % len(self)]), self.mapToScene(self.points[focusIdx % len(self)]), ) # print((focusIdx - 1) % len(self), len(self.m_lines), len(self)) self.m_lines[(focusIdx - 1) % len(self)].setLine(line) for line in self.m_lines[focusIdx:]: line.idx -= 1 def removeLastPoint(self): # TODO: 创建的时候用到,需要删line if len(self.points) == 0: self.points.pop() self.setPolygon(QtGui.QPolygonF(self.points)) self.bbox.update() it = self.m_items.pop() self.scene().removeItem(it) del it def movePoint(self, i, p): # print("Move point", i, p) if 0 <= i < len(self.points): p = self.mapFromScene(p) self.points[i] = p self.setPolygon(QtGui.QPolygonF(self.points)) self.bbox.update() self.moveLine(i) def moveLine(self, i): # print("Moving line: ", i, self.noMove) if self.noMove: return points = self.points # line[i] line = QtCore.QLineF( self.mapToScene(points[i]), self.mapToScene(points[(i + 1) % len(self)])) self.m_lines[i].setLine(line) # line[i-1] line = QtCore.QLineF( self.mapToScene(points[(i - 1) % len(self)]), self.mapToScene(points[i])) # print((i - 1) % len(self), len(self.m_lines), len(self)) self.m_lines[(i - 1) % len(self)].setLine(line) def move_item(self, i, pos): if 0 <= i < len(self.m_items): item = self.m_items[i] item.setEnabled(False) item.setPos(pos) item.setEnabled(True) self.moveLine(i) def itemChange(self, change, value): if change == QtWidgets.QGraphicsItem.ItemPositionHasChanged: for i, point in enumerate(self.points): self.move_item(i, self.mapToScene(point)) return super(PolygonAnnotation, self).itemChange(change, value) def hoverEnterEvent(self, ev): self.polygon_hovering = True self.setBrush(self.insideColor) super(PolygonAnnotation, self).hoverEnterEvent(ev) def hoverLeaveEvent(self, ev): self.polygon_hovering = False if not self.hasFocus(): self.setBrush(self.halfInsideColor) super(PolygonAnnotation, self).hoverLeaveEvent(ev) def focusInEvent(self, ev): if not self.anning: self.setBrush(self.insideColor) def focusOutEvent(self, ev): if not self.polygon_hovering and not self.anning: self.setBrush(self.halfInsideColor) def setColor(self, insideColor, borderColor): i = insideColor self.insideColor = QtGui.QColor(i[0], i[1], i[2]) self.insideColor.setAlphaF(self.opacity) self.halfInsideColor = QtGui.QColor(i[0], i[1], i[2]) self.halfInsideColor.setAlphaF(self.opacity / 2) self.setBrush(self.halfInsideColor) b = borderColor self.borderColor = QtGui.QColor(b[0], b[1], b[2]) self.borderColor.setAlphaF(0.8) self.setPen(QtGui.QPen(self.borderColor)) for grip in self.m_items: grip.setColor(self.borderColor) for line in self.m_lines: line.setColor(self.borderColor) def __len__(self): return len(self.points)