diff --git a/PPOCRLabel/PPOCRLabel.py b/PPOCRLabel/PPOCRLabel.py index d93c4814cd..e3d47f4bd3 100644 --- a/PPOCRLabel/PPOCRLabel.py +++ b/PPOCRLabel/PPOCRLabel.py @@ -849,7 +849,7 @@ class MainWindow(QMainWindow): box = ast.literal_eval(item.text()) # print('shape in labelItemChanged is',shape.points) - if box != [(p.x(), p.y()) for p in shape.points]: + if box != [(int(p.x()), int(p.y())) for p in shape.points]: # shape.points = box shape.points = [QPointF(p[0], p[1]) for p in box] diff --git a/PPOCRLabel/libs/canvas.py b/PPOCRLabel/libs/canvas.py index 6116f357d6..8d257e6bd7 100644 --- a/PPOCRLabel/libs/canvas.py +++ b/PPOCRLabel/libs/canvas.py @@ -11,19 +11,13 @@ # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -try: - from PyQt5.QtGui import * - from PyQt5.QtCore import * - from PyQt5.QtWidgets import * -except ImportError: - from PyQt4.QtGui import * - from PyQt4.QtCore import * - -#from PyQt4.QtOpenGL import * +import copy +from PyQt5.QtCore import Qt, pyqtSignal, QPointF, QPoint +from PyQt5.QtGui import QPainter, QBrush, QColor, QPixmap +from PyQt5.QtWidgets import QWidget, QMenu, QApplication from libs.shape import Shape from libs.utils import distance -import copy CURSOR_DEFAULT = Qt.ArrowCursor CURSOR_POINT = Qt.PointingHandCursor @@ -31,8 +25,6 @@ CURSOR_DRAW = Qt.CrossCursor CURSOR_MOVE = Qt.ClosedHandCursor CURSOR_GRAB = Qt.OpenHandCursor -# class Canvas(QGLWidget): - class Canvas(QWidget): zoomRequest = pyqtSignal(int) @@ -129,7 +121,6 @@ class Canvas(QWidget): def selectedVertex(self): return self.hVertex is not None - def mouseMoveEvent(self, ev): """Update line with last point and current coordinates.""" pos = self.transformPos(ev.pos()) @@ -333,7 +324,6 @@ class Canvas(QWidget): self.movingShape = False - def endMove(self, copy=False): assert self.selectedShapes and self.selectedShapesCopy assert len(self.selectedShapesCopy) == len(self.selectedShapes) @@ -410,7 +400,6 @@ class Canvas(QWidget): self.selectionChanged.emit(shapes) self.update() - def selectShapePoint(self, point, multiple_selection_mode): """Select the first shape created which contains this point.""" if self.selectedVertex(): # A vertex is marked for selection. @@ -494,7 +483,6 @@ class Canvas(QWidget): else: shape.moveVertexBy(index, shiftPos) - def boundedMoveShape(self, shapes, pos): if type(shapes).__name__ != 'list': shapes = [shapes] if self.outOfPixmap(pos): @@ -515,6 +503,7 @@ class Canvas(QWidget): if dp: for shape in shapes: shape.moveBy(dp) + shape.close() self.prevPoint = pos return True return False @@ -728,6 +717,31 @@ class Canvas(QWidget): self.moveOnePixel('Up') elif key == Qt.Key_Down and self.selectedShapes: self.moveOnePixel('Down') + elif key == Qt.Key_X and self.selectedShapes: + for i in range(len(self.selectedShapes)): + self.selectedShape = self.selectedShapes[i] + if self.rotateOutOfBound(0.01): + continue + self.selectedShape.rotate(0.01) + self.shapeMoved.emit() + self.update() + + elif key == Qt.Key_C and self.selectedShapes: + for i in range(len(self.selectedShapes)): + self.selectedShape = self.selectedShapes[i] + if self.rotateOutOfBound(-0.01): + continue + self.selectedShape.rotate(-0.01) + self.shapeMoved.emit() + self.update() + + def rotateOutOfBound(self, angle): + for shape in range(len(self.selectedShapes)): + self.selectedShape = self.selectedShapes[shape] + for i, p in enumerate(self.selectedShape.points): + if self.outOfPixmap(self.selectedShape.rotatePoint(p, angle)): + return True + return False def moveOnePixel(self, direction): # print(self.selectedShape.points) diff --git a/PPOCRLabel/libs/shape.py b/PPOCRLabel/libs/shape.py index e2cdcb3227..528b1102b0 100644 --- a/PPOCRLabel/libs/shape.py +++ b/PPOCRLabel/libs/shape.py @@ -10,20 +10,15 @@ # SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF # CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN # THE SOFTWARE. -#!/usr/bin/python +# !/usr/bin/python # -*- coding: utf-8 -*- - - -try: - from PyQt5.QtGui import * - from PyQt5.QtCore import * -except ImportError: - from PyQt4.QtGui import * - from PyQt4.QtCore import * - -from libs.utils import distance +import math import sys +from PyQt5.QtCore import QPointF +from PyQt5.QtGui import QColor, QPen, QPainterPath, QFont +from libs.utils import distance + DEFAULT_LINE_COLOR = QColor(0, 255, 0, 128) DEFAULT_FILL_COLOR = QColor(255, 0, 0, 128) DEFAULT_SELECT_LINE_COLOR = QColor(255, 255, 255) @@ -59,6 +54,8 @@ class Shape(object): self.difficult = difficult self.paintLabel = paintLabel self.locked = False + self.direction = 0 + self.center = None self._highlightIndex = None self._highlightMode = self.NEAR_VERTEX self._highlightSettings = { @@ -74,7 +71,24 @@ class Shape(object): # is used for drawing the pending line a different color. self.line_color = line_color + def rotate(self, theta): + for i, p in enumerate(self.points): + self.points[i] = self.rotatePoint(p, theta) + self.direction -= theta + self.direction = self.direction % (2 * math.pi) + + def rotatePoint(self, p, theta): + order = p - self.center + cosTheta = math.cos(theta) + sinTheta = math.sin(theta) + pResx = cosTheta * order.x() + sinTheta * order.y() + pResy = - sinTheta * order.x() + cosTheta * order.y() + pRes = QPointF(self.center.x() + pResx, self.center.y() + pResy) + return pRes + def close(self): + self.center = QPointF((self.points[0].x() + self.points[2].x()) / 2, + (self.points[0].y() + self.points[2].y()) / 2) self._closed = True def reachMaxPoints(self): @@ -83,7 +97,9 @@ class Shape(object): return False def addPoint(self, point): - if not self.reachMaxPoints(): # 4个点时发出close信号 + if self.reachMaxPoints(): + self.close() + else: self.points.append(point) def popPoint(self): @@ -112,7 +128,7 @@ class Shape(object): # Uncommenting the following line will draw 2 paths # for the 1st vertex, and make it non-filled, which # may be desirable. - #self.drawVertex(vrtx_path, 0) + # self.drawVertex(vrtx_path, 0) for i, p in enumerate(self.points): line_path.lineTo(p) @@ -136,9 +152,9 @@ class Shape(object): font.setPointSize(8) font.setBold(True) painter.setFont(font) - if(self.label == None): + if self.label is None: self.label = "" - if(min_y < MIN_Y_LABEL): + if min_y < MIN_Y_LABEL: min_y += MIN_Y_LABEL painter.drawText(min_x, min_y, self.label) @@ -198,6 +214,8 @@ class Shape(object): def copy(self): shape = Shape("%s" % self.label) shape.points = [p for p in self.points] + shape.center = self.center + shape.direction = self.direction shape.fill = self.fill shape.selected = self.selected shape._closed = self._closed