コード例 #1
0
    def handleDrawing(self, pos):
        if self.current and self.current.reachMaxPoints() is False:
            initPos = self.current[0]
            minX = initPos.x()
            minY = initPos.y()
            targetPos = self.line[1]
            maxX = targetPos.x()
            maxY = targetPos.y()

            if minX == maxX:
                maxX = maxX + 1
            if minY == maxY:
                maxY = maxY + 1

            self.current.addPoint(QPointF(
                maxX, minY))  # Adding canvas points is done here
            self.current.addPoint(targetPos)
            self.current.addPoint(QPointF(minX, maxY))
            self.finalise()
        elif not self.outOfPixmap(pos):
            self.current = Shape()
            self.current.addPoint(pos)
            self.line.points = [pos, pos]
            self.setHiding()
            self.drawingPolygon.emit(True)
            self.update()
コード例 #2
0
    def handleDrawing(self, pos):
        if self.current and self.current.reachMaxPoints() is False:
            if self.fourpoint:
                targetPos = self.line[self.pointnum]
                self.current.addPoint(targetPos)
                print('current points in handleDrawing is ',
                      self.line[self.pointnum])
                self.update()
                if self.pointnum == 3:
                    self.finalise()

            else:
                initPos = self.current[0]
                print('initPos', self.current[0])
                minX = initPos.x()
                minY = initPos.y()
                targetPos = self.line[1]
                maxX = targetPos.x()
                maxY = targetPos.y()
                self.current.addPoint(QPointF(maxX, minY))
                self.current.addPoint(targetPos)
                self.current.addPoint(QPointF(minX, maxY))
                self.finalise()

        elif not self.outOfPixmap(pos):
            print('release')
            self.current = Shape()
            self.current.addPoint(pos)
            self.line.points = [pos, pos]
            self.setHiding()
            self.drawingPolygon.emit(True)
            self.update()
コード例 #3
0
 def mousePressEvent(self, ev):
     if PYQT5:
         pos = self.transformPos(ev.pos())
     else:
         pos = self.transformPos(ev.posF())
     if ev.button() == QtCore.Qt.LeftButton:
         if self.drawing():
             if self.current:
                 try:
                     self.current.addPoint(self.line[1])
                 except Exception as e:
                     print(e, file=sys.stderr)
                     return
                 self.line[0] = self.current[-1]
                 if self.current.isClosed():
                     self.finalise()
             elif not self.outOfPixmap(pos):
                 self.current = Shape()
                 self.current.addPoint(pos)
                 self.line.points = [pos, pos]
                 self.setHiding()
                 self.drawingPolygon.emit(True)
                 self.update()
         else:
             self.selectShapePoint(pos)
             self.prevPoint = pos
             self.repaint()
     elif ev.button() == QtCore.Qt.RightButton and self.editing():
         self.selectShapePoint(pos)
         self.prevPoint = pos
         self.repaint()
コード例 #4
0
 def handleDrawing(self, pos):
     """
     Handles the drawing of a box.
     :param pos: The position of the box.
     """
     if self.current and self.current.reachMaxPoints() is False:
         initPos = self.current[0]
         minX = initPos.x()
         minY = initPos.y()
         targetPos = self.line[1]
         maxX = targetPos.x()
         maxY = targetPos.y()
         self.current.addPoint(QPointF(maxX, minY))
         self.current.addPoint(targetPos)
         self.current.addPoint(QPointF(minX, maxY))
         self.current.addPoint(initPos)
         self.line[0] = self.current[-1]
         if self.current.isClosed():
             self.finalize()
     elif not self.outOfPixmap(pos):
         self.current = Shape()
         self.current.addPoint(pos)
         self.line.points = [pos, pos]
         self.setHiding()
         self.drawingPolygon.emit(True)
         self.update()
コード例 #5
0
ファイル: canvas.py プロジェクト: bickey1996/labelImg-master
 def handleDrawing(self, pos):
     # if self.current and self.current.reachMaxPoints() is False:
     #     initPos = self.current[0]
     #     # minX = initPos.x()
     #     # minY = initPos.y()
     #     # targetPos = self.line[1]
     #     # maxX = targetPos.x()
     #     # maxY = targetPos.y()
     #     # maxX = pos.x()
     #     # maxY = pos.y()
     #     # self.current.addPoint(QPointF(maxX, minY))
     #     # self.current.addPoint(QPointF(minX, maxY))
     #     # print(minX,maxX,minY,maxY)
     #     if(self.closeEnough(pos, initPos)):
     #         self.finalise()
     #     else:
     #         print(self.current)
     #         self.current.addPoint(pos)
     if self.current and self.current.reachMaxPoints() is False:
         self.current.addPoint(pos)
         if self.current.isLastPoint():
             self.minimumBoundingRectangle()
             self.finalise()
     elif not self.outOfPixmap(pos):
         self.current = Shape()
         self.current.addPoint(pos)
         self.line.points = [pos, pos]
         self.setHiding()
         self.drawingPolygon.emit(True)
         self.update()
コード例 #6
0
    def __init__(self, *args, **kwargs):
        super(Canvas, self).__init__(*args, **kwargs)
        # Initialise local state.
        self.mode = self.EDIT           # 默认为EDIT模式
        self.shapes = []            # 用于存储当前图像上的bbox,内容为current(libs.shape.py中Shape()类型的数据结构)
        self.current = None         # 用于存储当前绘制的bbox的四个角的坐标的数据
        self.selectedShape = None  # save the selected shape here
        self.selectedShapeCopy = None
        self.drawingLineColor = QColor(0, 0, 255)
        self.drawingRectColor = QColor(0, 0, 255)
        self.line = Shape(line_color=self.drawingLineColor)
        self.prevPoint = QPointF()  # 这个是存储上一次的按键位置吗
        self.offsets = QPointF(), QPointF()
        self.scale = 1.0            # 图像缩放的比例
        self.pixmap = QPixmap()     # 显示图像的控件
        self.visible = {}           # TODO 这是啥
        self._hideBackround = False # TODO 这两个是啥?
        self.hideBackround = False
        self.hShape = None
        self.hVertex = None
        self._painter = QPainter()
        self._cursor = CURSOR_DEFAULT   # 鼠标指针形状,默认就是正常的指针
        # Menus:
        self.menus = (QMenu(), QMenu()) # 不知道这是啥
        # Set widget options.
        self.setMouseTracking(True)     # 鼠标追踪,要想实现mouseMoveEvent,则需要开启鼠标追踪
        self.setFocusPolicy(Qt.WheelFocus)  # 与焦点设置有关,tab+鼠标滚轮选择焦点
        self.verified = False           # TODO 这个是啥
        self.drawSquare = False         # TODO 盲猜点Create RectBox设为True,画完BBox后变为False

        #initialisation for panning
        self.pan_initial_pos = QPoint() # QPoint代表一个坐标点
コード例 #7
0
ファイル: canvas.py プロジェクト: AprilJW/2020_2020_backup
 def __init__(self, *args, **kwargs):
     super(Canvas, self).__init__(*args, **kwargs)
     # Initialise local state.
     self.mode = self.EDIT
     self.shapes = []
     self.current = None
     self.selectedShape = None
     self.selectedShapes = []  # save the selected shape here
     self.lineColor = QColor(255, 0, 0)
     self.line = Shape()
     self.lineWidth = 1
     self.prevPoint = QPointF()
     self.offsets = QPointF(), QPointF()
     self.scale = 1.0
     self.pixmap = QPixmap()
     self.visible = {}
     self._hideBackround = False
     self.hideBackround = False
     self.hShape = None
     self.hVertex = None
     self._painter = QPainter()
     self._cursor = CURSOR_DEFAULT
     # Menus:
     self.menu = QMenu()
     # Set widget options.
     self.setMouseTracking(True)
     self.setFocusPolicy(Qt.WheelFocus)
     self.verified = False
     self.currentLabel = ""
     self.currentDType = self.POLYGON
     self.undoStack = QUndoStack(self)
     self.image_editing_status = self.LABEL
     self.eraser_strength = 5
     self.image_np = None
     self.erasing_points = []
コード例 #8
0
 def handleDrawing(self, pos):
     if self.current:
         #and self.current.reachMaxPoints() is False:
         if self.ploygon():
             self.current.addPoint(self.line[1])
         else:
             initPos = self.current[0]
             minX = initPos.x()
             minY = initPos.y()
             targetPos = self.line[1]
             maxX = targetPos.x()
             maxY = targetPos.y()
             self.current.addPoint(QPointF(maxX, minY))
             self.current.addPoint(targetPos)
             self.current.addPoint(QPointF(minX, maxY))
             self.current.addPoint(initPos)
         self.line[0] = self.current[-1]
         if self.current.isClosed():
             self.finalise()
     elif not self.outOfPixmap(pos):
         self.current = Shape()
         self.current.addPoint(pos)
         self.line.points = [pos, pos]
         self.setHiding()
         self.drawingPolygon.emit(True)
         self.update()
コード例 #9
0
ファイル: canvas.py プロジェクト: NoName115/labelImg
    def __init__(self, *args, **kwargs):
        super(Canvas, self).__init__(*args, **kwargs)
        # Initialise local state.
        self.mode = self.EDIT
        self.shapes = []
        self.current = None
        self.selected_shape = None  # save the selected shape here
        self.selected_shape_copy = None
        self.drawing_line_color = QColor(0, 0, 255)
        self.drawing_rect_color = QColor(0, 0, 255)
        self.line = Shape(line_color=self.drawing_line_color)
        self.prev_point = QPointF()
        self.offsets = QPointF(), QPointF()
        self.scale = 1.0
        self.label_font_size = 8
        self.pixmap = QPixmap()
        self.visible = {}
        self._hide_background = False
        self.hide_background = False
        self.h_shape = None
        self.h_vertex = None
        self._painter = QPainter()
        self._cursor = CURSOR_DEFAULT
        # Menus:
        self.menus = (QMenu(), QMenu())
        # Set widget options.
        self.setMouseTracking(True)
        self.setFocusPolicy(Qt.WheelFocus)
        self.verified = False
        self.draw_square = False

        # initialisation for panning
        self.pan_initial_pos = QPoint()
コード例 #10
0
 def __init__(self, *args, **kwargs):
     super(Canvas, self).__init__(*args, **kwargs)
     # Initialise local state.
     self.mode = self.EDIT
     self.shapes = []
     self.current = None
     self.selectedShape = None  # save the selected shape here
     self.selectedShapeCopy = None
     self.drawingLineColor = QColor(0, 0, 255)
     self.drawingRectColor = QColor(0, 0, 255)
     self.line = Shape(line_color=self.drawingLineColor)
     self.prevPoint = QPointF()
     self.offsets = QPointF(), QPointF()
     self.scale = 1.0
     self.pixmap = QPixmap()
     self.visible = {}
     self._hideBackround = False
     self.hideBackround = False
     self.hShape = None
     self.hVertex = None
     self._painter = QPainter()
     self._cursor = CURSOR_DEFAULT
     # Menus:
     self.menus = (QMenu(), QMenu())
     # Set widget options.
     self.setMouseTracking(True)
     self.setFocusPolicy(Qt.WheelFocus)
     self.verified = False
     self.drawSquare = False
コード例 #11
0
ファイル: canvas.py プロジェクト: cris-j-dev/labelImage
    def cutImageRect(self):
        self.reImage = Shape()
        minX = 0
        minY = 0
        maxX = 1280
        maxY = 720

        if self.W > self.H:
            if maxX > self.W:
                maxX = self.W

            if maxY > self.H:
                maxY = self.H
                maxX = maxY * 16 / 9
        else:
            if maxY > self.H:
                maxY = self.H
            if maxX > self.W:
                maxX = self.W
                maxY = maxX * 9 / 16

        self.line.points = [QPointF(minX, minY), QPointF(maxX, maxY)]
        targetPos = self.line[1]
        self.reImage.addPoint(QPointF(minX, minY))
        self.reImage.addPoint(QPointF(maxX, minY))
        self.reImage.addPoint(targetPos)
        self.reImage.addPoint(QPointF(minX, maxY))
        self.refinalise()
コード例 #12
0
    def mouseMoveEvent(self, ev):
        pos = self.transformPos(ev.pos())
        self.hilightVertex(None)
        index = self.findShapeNearest(pos)
        self.hilightVertex(index, visible=True)
        for i in range(len(self.shapes)):
            corner = self.findCorner(pos, self.shapes[i])
            self.idRecreate = None
            if corner is not None:
                self.hilightVertex(i, corner=corner)
                self.idRecreate = i
                break
        if self.recreate and not self.drawing:
            self.br = pos
            self.shapes[self.idRecreate] = Shape(self.tl, self.br,
                                                 self.idRecreate)

        if self.pixmap is None:
            return super(Canvas, self).mouseMoveEvent(ev)

        if self.edit:
            p1 = QPointF(0, pos.y())
            p2 = QPointF(self.pixmap.width(), pos.y())
            self.line_x = [p1, p2]

            p1 = QPointF(pos.x(), 0)
            p2 = QPointF(pos.x(), self.pixmap.height())
            self.line_y = [p1, p2]

        elif self.drawing:
            self.br = pos
            self.current = Shape(self.tl, self.br, len(self.shapes))
コード例 #13
0
    def rotateBackPoints(self, xmin, ymin, xmax, ymax, angle):
        center=QPointF((xmin+xmax)/2,(ymin+ymax)/2)

        k0=Shape.rotatePoint(self,center,QPointF(xmin,ymin),-angle)
        k2=Shape.rotatePoint(self,center,QPointF(xmax,ymax),-angle)
        rotatedPoints=[k0,k2]
        points= [(int(point.x()),int(point.y())) for point in rotatedPoints]
        return points
コード例 #14
0
 def startCreatingBBox(self, pos):
     if not self.outOfPixmap(pos):
         self.current = Shape()
         self.current.addPoint(pos)
         self.line = Shape()
         self.line.points = [pos, pos]
         self.setHiding()
         self.drawingPolygon.emit(True)
         self.update()
コード例 #15
0
ファイル: canvas.py プロジェクト: GeYouheng/labelImg
    def handleDrawing(self, pos):
        if not self.outOfPixmap(pos):
            if (self.current == None):
                self.current = Shape()
            self.current.addPoint(pos)
            if (len(self.current.points) == 22):
                self.finalise()
            self.line.points = [pos, pos]

            self.update()
コード例 #16
0
ファイル: canvas.py プロジェクト: meryusha/labelImg
    def detectShapes(self, image_QT):
        image_QT = image_QT.convertToFormat(4)
        width = image_QT.width()
        height = image_QT.height()
        ptr = image_QT.bits()
        ptr = image_QT.bits()
        ptr.setsize(image_QT.byteCount())
        arr = np.array(ptr).reshape(height, width, 4)
        # cv2.imwrite("test.png",arr)
        arr = cv2.cvtColor(arr, cv2.COLOR_RGBA2RGB)
        arr = cv2.cvtColor(arr, cv2.COLOR_BGR2RGB)

        cnt_germ, cnt_nongerm = classifySeeds(arr)
        # print(cnt_germ)
        # print(cnt_nongerm)

        for germ in cnt_germ:
            minX = germ[0]
            minY = germ[1]
            maxX = germ[0] + germ[2]
            maxY = germ[1] + germ[3]

            self.current = Shape()
            self.current.addPoint(QPointF(minX, minY))
            self.current.addPoint(QPointF(maxX, minY))
            self.current.addPoint(QPointF(maxX, maxY))
            self.current.addPoint(QPointF(minX, maxY))
            self.current.label = "germinated"
            self.current.close()

            self.shapes.append(self.current)
            self.current = None
            self.newShape.emit()
            self.update()
            self.repaint()

        for germ in cnt_nongerm:
            minX = germ[0]
            minY = germ[1]
            maxX = germ[0] + germ[2]
            maxY = germ[1] + germ[3]

            self.current = Shape()
            self.current.addPoint(QPointF(minX, minY))
            self.current.addPoint(QPointF(maxX, minY))
            self.current.addPoint(QPointF(maxX, maxY))
            self.current.addPoint(QPointF(minX, maxY))
            self.current.label = "non-germinated"
            self.current.close()

            self.shapes.append(self.current)
            self.current = None
            self.newShape.emit()
            self.update()
            self.repaint()
コード例 #17
0
 def autoDrawing(self, pos):
     self.current = Shape()
     minX = pos[0]
     minY = pos[1]
     maxX = pos[2]
     maxY = pos[3]
     self.current.addPoint(QPointF(maxX, maxY))
     self.current.addPoint(QPointF(maxX, minY))
     self.current.addPoint(QPointF(minX, minY))
     self.current.addPoint(QPointF(minX, maxY))
     self.autoFinalise()
コード例 #18
0
 def __init__(self, *args, **kwargs):
     super(Canvas, self).__init__(*args, **kwargs)#*args将输入的参数存放为元组,**kwargs将输入的参数存放为字典
     # Initialise local state.
     self.shape_type = self.POLYGON_SHAPE
     self.brush_point = None
     self.task_mode = 3
     self.erase_mode = False
     self.current_brush_path = None
     self.mask_Image = None
     self.brush_color =QColor(255,0,0,255)
     self.brush_size = 10
     self.brush = QPainter();
     self.mode = self.EDIT
     self.shapes = []
     self.current = None
     self.selectedShape = None  # save the selected shape here
     self.selectedShapeCopy = None
     self.lineColor = QColor(0, 0, 255)
     self.line = Shape(line_color=self.lineColor)
     self.prevPoint = QPointF()
     self.offsets = QPointF(), QPointF()
     self.scale = 1.0
     self.bg_image = QImage()
     self.visible = {}
     self._hideBackround = False
     self.hideBackround = False
     self.hShape = None
     self.hVertex = None
     self._painter = QPainter(self)
     self.font_size = 50
     self._cursor = CURSOR_DEFAULT
     # Menus:
     self.menus = (QMenu(), QMenu())
     # Set widget options.
     self.setMouseTracking(True)
     self.setFocusPolicy(Qt.WheelFocus)
     ##point
     self.point_point=None
     self.point_point_list=[]
     self.point_dex=None
     self.point_color=[QColor(r ,g ,b ) for r in [0,255,120,30] for g in [0,255,120,30] for b in [0,255,120,30]]
     self.point_move=None
     self.point_path= None
     self.point_selecteditem=None
     self.point_delete=False
     self.point_modified=False
     self.point_shape={}
     self.point_link=[[1, 2], [1, 3], [2, 3], [2, 4], [3, 5], [4, 6], [5, 7], [6, 7], [6, 8], [6, 12], [7, 9], [7, 13], [8, 10], [9, 11], [12, 13], [12, 14], [13, 15], [14, 16], [15, 17]]
     self.point_num =max(np.array(self.point_link)[:,1])
     self.point_visible = {i:True for i in range(len(self.point_link))}
     self.point_deletedid=[]
     self.point_ids=[]
     self.point_all_deleted=False
コード例 #19
0
ファイル: canvas.py プロジェクト: cris-j-dev/labelImage
 def createImageRect(self):
     self.current = Shape()
     minX = 0
     minY = 0
     maxX = 160
     maxY = 160
     self.line.points = [QPointF(minX, minY), QPointF(maxX, maxY)]
     targetPos = self.line[1]
     self.current.addPoint(QPointF(minX, minY))
     self.current.addPoint(QPointF(maxX, minY))
     self.current.addPoint(targetPos)
     self.current.addPoint(QPointF(minX, maxY))
     self.finalise()
コード例 #20
0
ファイル: canvas.py プロジェクト: AprilJW/2020_2020_backup
 def handleDrawing(self, pos):
     if self.current:
         self.undoStack.push(AddPointCommand(self, pos))
         self.line.points = [pos, pos]
     elif not self.outOfPixmap(pos):
         self.current = Shape()
         self.current.label = self.currentLabel
         self.current.d_type = self.currentDType
         self.undoStack.push(AddPointCommand(self, pos))
         self.line.points = [pos, pos]
         self.setHiding()
         self.drawingPolygon.emit(True)
         self.update()
コード例 #21
0
    def makeBackRotatedShape(self, points, angle):
        canvas=Canvas()
        shape=Shape()
        xmax=points[2][0]
        xmin=points[0][0]
        ymax=points[2][1]
        ymin=points[0][1]

        shape.centerPoint=QPointF(( xmin+xmax)/2,(ymin+ymax)/2)
        shape.points= [QPointF(point[0],point[1]) for point in points]
        rotatedShapePoints=canvas.getRotatedShape(shape,angle)
        points= [(round(point.x(),0),round(point.y(),0)) for point in rotatedShapePoints]

        return points
コード例 #22
0
ファイル: canvas.py プロジェクト: angelxuhan/Priv-LabelImg
 def __init__(self, *args, **kwargs):
     super(Canvas,
           self).__init__(*args,
                          **kwargs)  #*args将输入的参数存放为元组,**kwargs将输入的参数存放为字典
     # Initialise local state.
     self.shape_type = self.POLYGON_SHAPE
     self.brush_point = None
     self.task_mode = 3
     self.erase_mode = False
     self.current_brush_path = None
     self.mask_Image = None
     self.brush_color = QColor(255, 0, 0, 255)
     self.brush_size = 10
     self.brush = QPainter()
     self.mode = self.EDIT
     self.shapes = []
     self.current = None
     self.selectedShape = None  # save the selected shape here
     self.selectedShapeCopy = None
     self.lineColor = QColor(0, 0, 255)
     self.line = Shape(line_color=self.lineColor)
     self.prevPoint = QPointF()
     self.offsets = QPointF(), QPointF()
     self.scale = 1.0
     self.bg_image = QImage()
     self.visible = {}
     self._hideBackround = False
     self.hideBackround = False
     self.hShape = None
     self.hVertex = None
     self._painter = QPainter(self)
     self.font_size = 50
     self._cursor = CURSOR_DEFAULT
     # Menus:
     self.menus = (QMenu(), QMenu())
     # Set widget options.
     self.setMouseTracking(True)
     self.setFocusPolicy(Qt.WheelFocus)
     ##point
     self.point_point = None
     self.point_point_list = []
     self.point_dex = None
     self.point_color = [
         QColor(r, g, b) for r in [0, 255, 120, 30]
         for g in [0, 255, 120, 30] for b in [0, 255, 120, 30]
     ]
     self.point_move = None
     self.point_path = None
     self.point_selecteditem = None
     self.point_delete = False
コード例 #23
0
    def Segment_Roi(self):
        # self.seg_count = self.seg_count +1
        if self.flag_enter_polygon:
            bgdmodel = np.zeros((1, 65), np.float64)
            fgdmodel = np.zeros((1, 65), np.float64)
            cv2.grabCut(self.img2_for_grab, self.mask_for_grab,
                        self.rect_for_grab, bgdmodel, fgdmodel, 1,
                        cv2.GC_INIT_WITH_RECT)
            cv2.grabCut(self.img2_for_grab, self.mask_for_grab,
                        self.rect_for_grab, bgdmodel, fgdmodel, 1,
                        cv2.GC_INIT_WITH_MASK)

            mask2 = np.where(
                (self.mask_for_grab == 1) + (self.mask_for_grab == 3), 255,
                0).astype('uint8')
            self.output = cv2.bitwise_and(self.img2_for_grab,
                                          self.img2_for_grab,
                                          mask=mask2)
            gray = cv2.cvtColor(self.output, cv2.COLOR_BGR2GRAY)
            ret, binary = cv2.threshold(gray, 1, 255, cv2.THRESH_BINARY)
            contours = cv2.findContours(binary, cv2.RETR_TREE,
                                        cv2.CHAIN_APPROX_SIMPLE)  #,hierarchy
            contours_big_area = []
            max_contours = 0
            max_contours_i = 0
            for i in range(len(contours[1])):
                if len(contours[1][i]) > max_contours:
                    max_contours = len(contours[1][i])
                    max_contours_i = i
            # for i in range(len(contours[1][max_contours_i])):
            contours_tmp = np.array(contours[1][max_contours_i])
            contours_big_area.append(contours_tmp)
            # if self.seg_count == 1:
            self.shapes.remove(self.shapes[len(self.shapes) - 1])  #
            self.update()

            self.contours_t = Shape()
            for i in range(len(contours_big_area[0])):
                self.contours_t.addPoint(
                    QPointF(contours_big_area[0][i][0][0],
                            contours_big_area[0][i][0][1]))
            self.contours_t.addPoint(
                QPointF(contours_big_area[0][0][0][0],
                        contours_big_area[0][0][0][1]))
            self.shapes.append(self.contours_t)
            self.setHiding(False)
            self.newShape.emit()
            self.update()
        else:
            print('Please paint polygon first')
コード例 #24
0
    def handleDrawing(self, pos):
        if self.current:
            self.current.addPoint(pos, self.transformToLatLon(pos, True))
            if len(self.current) == 3:
                self.current.close()
                self.finalise()
        elif not self.outOfPixmap(pos):
            self.current = Shape(parent_canvas=self)

            self.current.addPoint(pos, self.transformToLatLon(pos, True))

            self.recalculateMovedLatlonPointsSelectedShape()

            self.update()
コード例 #25
0
ファイル: canvas.py プロジェクト: fisis/PTF
 def add_shape(self, bbox, label, bbox_source, id_number):
     is_gate = label == "gate"
     shape = Shape(label, bbox_source=bbox_source, id_number=id_number, is_gate=is_gate)
     xmin, ymin, xmax, ymax = bbox
     if is_gate:
         shape.addPoint(QPointF(xmin, ymin))
         shape.addPoint(QPointF(xmax, ymax))
     else:
         shape.addPoint(QPointF(xmin, ymin))
         shape.addPoint(QPointF(xmax, ymin))
         shape.addPoint(QPointF(xmax, ymax))
         shape.addPoint(QPointF(xmin, ymax))
     shape.close()
     self.main_window.addLabel(shape)
     self.shapes.append(shape)
コード例 #26
0
    def handleDrawing(self, pos):
        # left button up to end drawing
        if self.current:
            # Add point to existing shape
            if self.shapeFactory.isType(shapeTypes.polygon):
                self.current.addPoint(self.line[1])
                self.line[0] = self.current[-1]
                if self.current.isClosed():
                    self.finalise()
            elif self.shapeFactory.isType(shapeTypes.line):
                assert len(self.current.points) == 1
                self.current.points = self.line.points
                self.finalise()
            elif self.shapeFactory.isType(shapeTypes.box):
                initPos = self.current[0]
                minX = initPos.x()
                minY = initPos.y()
                targetPos = self.line[1]
                maxX = targetPos.x()
                maxY = targetPos.y()
                self.current.addPoint(QPointF(maxX, minY))
                self.current.addPoint(targetPos)
                self.current.addPoint(QPointF(minX, maxY))
                self.finalise()
            elif self.shapeFactory.isType(shapeTypes.ellipse):
                if self.current.tooClose(pos):
                    self.escapeCurrent()
                    return
                elif len(self.current.points) == 1:
                    self.current.addPoint(self.line[1])
                    self.line = Shape(line_color=self.drawingLineColor)
                elif len(self.current.points) == 2:
                    self.line.points = [pos, pos]
                    self.current.addPoint(self.line[0])
                elif len(self.current.points) == 3:
                    self.current.addPoint(self.line[1])               
                if self.current.isClosed():
                    self.finalise()

        # left button down to create new shape.
        elif not self.outOfPixmap(pos):  
            self.current = self.shapeFactory.getShape()
            self.current.addPoint(pos)
            self.line.points = [pos, pos]
            self.setHiding()
            self.drawingPolygon.emit(True)

            self.update()
コード例 #27
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.__pixmap = QPixmap()
        self.__mode = PMode.IDLE
        self.__prevmode = PMode.IDLE
        self.__current = None
        self.__hShape = None
        self.__hVertex = None
        self.__shapes = []
        self.__drawingLineColor = QColor(45, 168, 179)
        self.__drawingRectColor = QColor(45, 168, 179)
        self.__line = Shape(line_color=self.drawingLineColor)
        self.__prevPoint = QPointF()
        self.__selectedShape = None
        self.__verified = False
        self.__hideBackground = False
        self.__toggleBackground = False
        self.__visible = {}
        self.scale = 1.0
        self._painter = QPainter()
        self._cursor = CURSOR_DEFAULT

        # Load string bundle for i18n
        self.__stringBundle = StringBundle.getBundle()

        self.setMouseTracking(True)
        self.setFocusPolicy(Qt.WheelFocus)
コード例 #28
0
ファイル: canvas.py プロジェクト: cdicle/labelImg
 def __init__(self, *args, **kwargs):
     super(Canvas, self).__init__(*args, **kwargs)
     # Initialise local state.
     self.mode = self.EDIT
     self.shapes = []
     self.current = None
     self.selectedShape = None  # save the selected shape here
     self.selectedShapeCopy = None
     self.lineColor = QColor(0, 0, 255)
     self.line = Shape(line_color=self.lineColor)
     self.prevPoint = QPointF()
     self.offsets = QPointF(), QPointF()
     self.scale = 1.0
     self.pixmap = QPixmap()
     self.visible = {}
     self._hideBackround = False
     self.hideBackround = False
     self.hShape = None
     self.hVertex = None
     self._painter = QPainter()
     self._cursor = CURSOR_DEFAULT
     # Menus:
     self.menus = (QMenu(), QMenu())
     # Set widget options.
     self.setMouseTracking(True)
     self.setFocusPolicy(Qt.WheelFocus)
     self.verified = False
コード例 #29
0
ファイル: canvas.py プロジェクト: neeraj-j/maskImg
    def handleMasking(self, pos):
        if not self.outOfPixmap(pos):
            if self.pVertex is None:
                self.pVertex = Shape(line_color=self.drawingLineColor)
                if self.maskType == self.BOX_MASK:
                    self.drawingPolygon.emit(True)
                    self.pVertex.penWidth = 2
                    self.pVertex.close()
                else:
                    self.pVertex.penWidth = self.penWidth

            self.pVertex.addPoint(pos)
            self.pVertex.maskType = self.maskType
            self.pVertex.highlightVertex(
                len(self.pVertex) - 1, self.pVertex.MOVE_VERTEX)
            self.update()
コード例 #30
0
    def load_record(self):
        if not self.may_continue():
            return
        self.set_clean()
        self.clear_labels()
        item = self.recordList.selectedItems()[0]
        if not item:
            return
        self.current_record = item.text()
        if self.stream_enabled:
            self._stop_video()

        component = self.componentList.selectedItems()[0].text()
        filename = item.text().replace('№', '')
        f = filename.split(' ')
        filename = '{}{:04d}'.format(f[0], int(f[1]))
        path = os.path.join(self.path, component, 'records', filename)

        img_path = path + '.jpg'
        txt_path = path + '.txt'
        self.frame = cv2.imread(img_path)
        if self.frame is None:
            return
        self.frame = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)
        self.canvas.loadPixmap(
            QPixmap.fromImage(qimage2ndarray.array2qimage(self.frame)))
        self.canvas.adjustSize()

        with open(txt_path, 'r') as bndboxes_file:
            for box in bndboxes_file:
                index, xcen, ycen, w, h = box.strip().split(' ')
                label = self.database_handler.classes[int(index)]
                xmin, ymin, xmax, ymax = yolo2points(xcen, ycen, w, h,
                                                     self.frame.shape[1],
                                                     self.frame.shape[0])
                points = [(xmin, ymin), (xmax, ymin), (xmax, ymax),
                          (xmin, ymax)]

                shape = Shape(label=label)
                for x, y in points:
                    x, y, snapped = self.canvas.snapPointToCanvas(x, y)
                    if snapped:
                        self.set_dirty()
                    shape.addPoint(QPointF(x, y))
                shape.difficult = False
                shape.fill_color = generate_color_by_text(label)
                shape.line_color = generate_color_by_text(label)
                shape.close()
                self.shapes.append(shape)
                self.add_label(shape)
        self.canvas.loadShapes(self.shapes)
コード例 #31
0
ファイル: canvas.py プロジェクト: walldas/labelImg_last_one
 def boundedMoveVertex(self, pos):
     index, shape = self.hVertex, self.hShape
     if self.shapeOutOfPixmap(shape.points):
         #this is pre fix. For bug when shape reach Picmap edge.
         return
     if shape.shape3D:
         # 3D editing OFF
         return
     rotatedAxis = False
     if shape.deg > 0 and not shape.tetragon:
         rotatedAxis = True
         shape.points = self.getRotatedShape(shape, -shape.deg)
         pos = Shape.rotatePoint(self, shape.centerPoint, pos, -shape.deg)
     point = shape[index]
     if self.outOfPixmap(pos):
         if self.shapeOutOfPixmap(shape.points) == False:
             pos = self.intersectionPoint(point, pos)
     shiftPos = pos - point
     shape.moveVertexBy(index, shiftPos)
     lindex = (index + 1) % 4
     rindex = (index + 3) % 4
     lshift = None
     rshift = None
     if index % 2 == 0:
         #lyginiai index
         if shape.tetragon == True:
             rshift = QPointF(0, 0)
             lshift = QPointF(0, 0)
         elif shape.tetragon == False:
             rshift = QPointF(shiftPos.x(), 0)
             lshift = QPointF(0, shiftPos.y())
     else:
         #nelyginiai index
         if shape.tetragon == True:
             lshift = QPointF(0, 0)
             rshift = QPointF(0, 0)
         elif shape.tetragon == False:
             lshift = QPointF(shiftPos.x(), 0)
             rshift = QPointF(0, shiftPos.y())
     shape.moveVertexBy(rindex, rshift)
     shape.moveVertexBy(lindex, lshift)
     if rotatedAxis:
         shape.points = self.getRotatedShape(shape, shape.deg)
         pos = Shape.rotatePoint(self, shape.centerPoint, pos, shape.deg)
コード例 #32
0
ファイル: canvas.py プロジェクト: cdicle/labelImg
 def handleDrawing(self, pos):
     if self.current and self.current.reachMaxPoints() is False:
         initPos = self.current[0]
         minX = initPos.x()
         minY = initPos.y()
         targetPos = self.line[1]
         maxX = targetPos.x()
         maxY = targetPos.y()
         self.current.addPoint(QPointF(maxX, minY))
         self.current.addPoint(targetPos)
         self.current.addPoint(QPointF(minX, maxY))
         self.finalise()
     elif not self.outOfPixmap(pos):
         self.current = Shape()
         self.current.addPoint(pos)
         self.line.points = [pos, pos]
         self.setHiding()
         self.drawingPolygon.emit(True)
         self.update()
コード例 #33
0
ファイル: canvas.py プロジェクト: cdicle/labelImg
class Canvas(QWidget):
    zoomRequest = pyqtSignal(int)
    scrollRequest = pyqtSignal(int, int)
    newShape = pyqtSignal()
    selectionChanged = pyqtSignal(bool)
    shapeMoved = pyqtSignal()
    drawingPolygon = pyqtSignal(bool)

    CREATE, EDIT = list(range(2))

    epsilon = 11.0

    def __init__(self, *args, **kwargs):
        super(Canvas, self).__init__(*args, **kwargs)
        # Initialise local state.
        self.mode = self.EDIT
        self.shapes = []
        self.current = None
        self.selectedShape = None  # save the selected shape here
        self.selectedShapeCopy = None
        self.lineColor = QColor(0, 0, 255)
        self.line = Shape(line_color=self.lineColor)
        self.prevPoint = QPointF()
        self.offsets = QPointF(), QPointF()
        self.scale = 1.0
        self.pixmap = QPixmap()
        self.visible = {}
        self._hideBackround = False
        self.hideBackround = False
        self.hShape = None
        self.hVertex = None
        self._painter = QPainter()
        self._cursor = CURSOR_DEFAULT
        # Menus:
        self.menus = (QMenu(), QMenu())
        # Set widget options.
        self.setMouseTracking(True)
        self.setFocusPolicy(Qt.WheelFocus)
        self.verified = False

    def enterEvent(self, ev):
        self.overrideCursor(self._cursor)

    def leaveEvent(self, ev):
        self.restoreCursor()

    def focusOutEvent(self, ev):
        self.restoreCursor()

    def isVisible(self, shape):
        return self.visible.get(shape, True)

    def drawing(self):
        return self.mode == self.CREATE

    def editing(self):
        return self.mode == self.EDIT

    def setEditing(self, value=True):
        self.mode = self.EDIT if value else self.CREATE
        if not value:  # Create
            self.unHighlight()
            self.deSelectShape()
        self.prevPoint = QPointF()
        self.repaint()

    def unHighlight(self):
        if self.hShape:
            self.hShape.highlightClear()
        self.hVertex = self.hShape = None

    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())

        # Polygon drawing.
        if self.drawing():
            self.overrideCursor(CURSOR_DRAW)
            if self.current:
                color = self.lineColor
                if self.outOfPixmap(pos):
                    # Don't allow the user to draw outside the pixmap.
                    # Project the point to the pixmap's edges.
                    pos = self.intersectionPoint(self.current[-1], pos)
                elif len(self.current) > 1 and self.closeEnough(pos, self.current[0]):
                    # Attract line to starting point and colorise to alert the
                    # user:
                    pos = self.current[0]
                    color = self.current.line_color
                    self.overrideCursor(CURSOR_POINT)
                    self.current.highlightVertex(0, Shape.NEAR_VERTEX)
                self.line[1] = pos
                self.line.line_color = color
                self.prevPoint = QPointF()
                self.current.highlightClear()
            else:
                self.prevPoint = pos
            self.repaint()
            return

        # Polygon copy moving.
        if Qt.RightButton & ev.buttons():
            if self.selectedShapeCopy and self.prevPoint:
                self.overrideCursor(CURSOR_MOVE)
                self.boundedMoveShape(self.selectedShapeCopy, pos)
                self.repaint()
            elif self.selectedShape:
                self.selectedShapeCopy = self.selectedShape.copy()
                self.repaint()
            return

        # Polygon/Vertex moving.
        if Qt.LeftButton & ev.buttons():
            if self.selectedVertex():
                self.boundedMoveVertex(pos)
                self.shapeMoved.emit()
                self.repaint()
            elif self.selectedShape and self.prevPoint:
                self.overrideCursor(CURSOR_MOVE)
                self.boundedMoveShape(self.selectedShape, pos)
                self.shapeMoved.emit()
                self.repaint()
            return

        # Just hovering over the canvas, 2 posibilities:
        # - Highlight shapes
        # - Highlight vertex
        # Update shape/vertex fill and tooltip value accordingly.
        self.setToolTip("Image")
        for shape in reversed([s for s in self.shapes if self.isVisible(s)]):
            # Look for a nearby vertex to highlight. If that fails,
            # check if we happen to be inside a shape.
            index = shape.nearestVertex(pos, self.epsilon)
            if index is not None:
                if self.selectedVertex():
                    self.hShape.highlightClear()
                self.hVertex, self.hShape = index, shape
                shape.highlightVertex(index, shape.MOVE_VERTEX)
                self.overrideCursor(CURSOR_POINT)
                self.setToolTip("Click & drag to move point")
                self.setStatusTip(self.toolTip())
                self.update()
                break
            elif shape.containsPoint(pos):
                if self.selectedVertex():
                    self.hShape.highlightClear()
                self.hVertex, self.hShape = None, shape
                self.setToolTip(
                    "Click & drag to move shape '%s'" % shape.label)
                self.setStatusTip(self.toolTip())
                self.overrideCursor(CURSOR_GRAB)
                self.update()
                break
        else:  # Nothing found, clear highlights, reset state.
            if self.hShape:
                self.hShape.highlightClear()
                self.update()
            self.hVertex, self.hShape = None, None
            self.overrideCursor(CURSOR_DEFAULT)

    def mousePressEvent(self, ev):
        pos = self.transformPos(ev.pos())

        if ev.button() == Qt.LeftButton:
            if self.drawing():
                self.handleDrawing(pos)
            else:
                self.selectShapePoint(pos)
                self.prevPoint = pos
                self.repaint()
        elif ev.button() == Qt.RightButton and self.editing():
            self.selectShapePoint(pos)
            self.prevPoint = pos
            self.repaint()

    def mouseReleaseEvent(self, ev):
        if ev.button() == Qt.RightButton:
            menu = self.menus[bool(self.selectedShapeCopy)]
            self.restoreCursor()
            if not menu.exec_(self.mapToGlobal(ev.pos()))\
               and self.selectedShapeCopy:
                # Cancel the move by deleting the shadow copy.
                self.selectedShapeCopy = None
                self.repaint()
        elif ev.button() == Qt.LeftButton and self.selectedShape:
            if self.selectedVertex():
                self.overrideCursor(CURSOR_POINT)
            else:
                self.overrideCursor(CURSOR_GRAB)
        elif ev.button() == Qt.LeftButton:
            pos = self.transformPos(ev.pos())
            if self.drawing():
                self.handleDrawing(pos)

    def endMove(self, copy=False):
        assert self.selectedShape and self.selectedShapeCopy
        shape = self.selectedShapeCopy
        #del shape.fill_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

    def hideBackroundShapes(self, value):
        self.hideBackround = value
        if self.selectedShape:
            # Only hide other shapes if there is a current selection.
            # Otherwise the user will not be able to select a shape.
            self.setHiding(True)
            self.repaint()

    def handleDrawing(self, pos):
        if self.current and self.current.reachMaxPoints() is False:
            initPos = self.current[0]
            minX = initPos.x()
            minY = initPos.y()
            targetPos = self.line[1]
            maxX = targetPos.x()
            maxY = targetPos.y()
            self.current.addPoint(QPointF(maxX, minY))
            self.current.addPoint(targetPos)
            self.current.addPoint(QPointF(minX, maxY))
            self.finalise()
        elif not self.outOfPixmap(pos):
            self.current = Shape()
            self.current.addPoint(pos)
            self.line.points = [pos, pos]
            self.setHiding()
            self.drawingPolygon.emit(True)
            self.update()

    def setHiding(self, enable=True):
        self._hideBackround = self.hideBackround if enable else False

    def canCloseShape(self):
        return self.drawing() and self.current and len(self.current) > 2

    def mouseDoubleClickEvent(self, ev):
        # We need at least 4 points here, since the mousePress handler
        # adds an extra one before this handler is called.
        if self.canCloseShape() and len(self.current) > 3:
            self.current.popPoint()
            self.finalise()

    def selectShape(self, shape):
        self.deSelectShape()
        shape.selected = True
        self.selectedShape = shape
        self.setHiding()
        self.selectionChanged.emit(True)
        self.update()

    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
        for shape in reversed(self.shapes):
            if self.isVisible(shape) and shape.containsPoint(point):
                self.selectShape(shape)
                self.calculateOffsets(shape, point)
                return

    def calculateOffsets(self, shape, point):
        rect = shape.boundingRect()
        x1 = rect.x() - point.x()
        y1 = rect.y() - point.y()
        x2 = (rect.x() + rect.width()) - point.x()
        y2 = (rect.y() + rect.height()) - point.y()
        self.offsets = QPointF(x1, y1), QPointF(x2, y2)

    def boundedMoveVertex(self, pos):
        index, shape = self.hVertex, self.hShape
        point = shape[index]
        if self.outOfPixmap(pos):
            pos = self.intersectionPoint(point, pos)

        shiftPos = pos - point
        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)

    def boundedMoveShape(self, shape, pos):
        if self.outOfPixmap(pos):
            return False  # No need to move
        o1 = pos + self.offsets[0]
        if self.outOfPixmap(o1):
            pos -= QPointF(min(0, o1.x()), min(0, o1.y()))
        o2 = pos + self.offsets[1]
        if self.outOfPixmap(o2):
            pos += QPointF(min(0, self.pixmap.width() - o2.x()),
                           min(0, self.pixmap.height() - o2.y()))
        # The next line tracks the new position of the cursor
        # relative to the shape, but also results in making it
        # a bit "shaky" when nearing the border and allows it to
        # go outside of the shape's area for some reason. XXX
        #self.calculateOffsets(self.selectedShape, pos)
        dp = pos - self.prevPoint
        if dp:
            shape.moveBy(dp)
            self.prevPoint = pos
            return True
        return False

    def deSelectShape(self):
        if self.selectedShape:
            self.selectedShape.selected = False
            self.selectedShape = None
            self.setHiding(False)
            self.selectionChanged.emit(False)
            self.update()

    def deleteSelected(self):
        if self.selectedShape:
            shape = self.selectedShape
            self.shapes.remove(self.selectedShape)
            self.selectedShape = None
            self.update()
            return shape

    def copySelectedShape(self):
        if self.selectedShape:
            shape = self.selectedShape.copy()
            self.deSelectShape()
            self.shapes.append(shape)
            shape.selected = True
            self.selectedShape = shape
            self.boundedShiftShape(shape)
            return shape

    def boundedShiftShape(self, shape):
        # Try to move in one direction, and if it fails in another.
        # Give up if both fail.
        point = shape[0]
        offset = QPointF(2.0, 2.0)
        self.calculateOffsets(shape, point)
        self.prevPoint = point
        if not self.boundedMoveShape(shape, point - offset):
            self.boundedMoveShape(shape, point + offset)

    def paintEvent(self, event):
        if not self.pixmap:
            return super(Canvas, self).paintEvent(event)

        p = self._painter
        p.begin(self)
        p.setRenderHint(QPainter.Antialiasing)
        p.setRenderHint(QPainter.HighQualityAntialiasing)
        p.setRenderHint(QPainter.SmoothPixmapTransform)

        p.scale(self.scale, self.scale)
        p.translate(self.offsetToCenter())

        p.drawPixmap(0, 0, self.pixmap)
        Shape.scale = self.scale
        for shape in self.shapes:
            if (shape.selected or not self._hideBackround) and self.isVisible(shape):
                shape.fill = shape.selected or shape == self.hShape
                shape.paint(p)
        if self.current:
            self.current.paint(p)
            self.line.paint(p)
        if self.selectedShapeCopy:
            self.selectedShapeCopy.paint(p)

        # Paint rect
        if self.current is not None and len(self.line) == 2:
            leftTop = self.line[0]
            rightBottom = self.line[1]
            rectWidth = rightBottom.x() - leftTop.x()
            rectHeight = rightBottom.y() - leftTop.y()
            color = QColor(0, 220, 0)
            p.setPen(color)
            brush = QBrush(Qt.BDiagPattern)
            p.setBrush(brush)
            p.drawRect(leftTop.x(), leftTop.y(), rectWidth, rectHeight)

        if self.drawing() and not self.prevPoint.isNull() and not self.outOfPixmap(self.prevPoint):
            p.setPen(QColor(0, 0, 0))
            p.drawLine(self.prevPoint.x(), 0, self.prevPoint.x(), self.pixmap.height())
            p.drawLine(0, self.prevPoint.y(), self.pixmap.width(), self.prevPoint.y())

        self.setAutoFillBackground(True)
        if self.verified:
            pal = self.palette()
            pal.setColor(self.backgroundRole(), QColor(184, 239, 38, 128))
            self.setPalette(pal)
        else:
            pal = self.palette()
            pal.setColor(self.backgroundRole(), QColor(232, 232, 232, 255))
            self.setPalette(pal)

        p.end()

    def transformPos(self, point):
        """Convert from widget-logical coordinates to painter-logical coordinates."""
        return point / self.scale - self.offsetToCenter()

    def offsetToCenter(self):
        s = self.scale
        area = super(Canvas, self).size()
        w, h = self.pixmap.width() * s, self.pixmap.height() * s
        aw, ah = area.width(), area.height()
        x = (aw - w) / (2 * s) if aw > w else 0
        y = (ah - h) / (2 * s) if ah > h else 0
        return QPointF(x, y)

    def outOfPixmap(self, p):
        w, h = self.pixmap.width(), self.pixmap.height()
        return not (0 <= p.x() <= w and 0 <= p.y() <= h)

    def finalise(self):
        assert self.current
        if self.current.points[0] == self.current.points[-1]:
            self.current = None
            self.drawingPolygon.emit(False)
            self.update()
            return

        self.current.close()
        self.shapes.append(self.current)
        self.current = None
        self.setHiding(False)
        self.newShape.emit()
        self.update()

    def closeEnough(self, p1, p2):
        #d = distance(p1 - p2)
        #m = (p1-p2).manhattanLength()
        # print "d %.2f, m %d, %.2f" % (d, m, d - m)
        return distance(p1 - p2) < self.epsilon

    def intersectionPoint(self, p1, p2):
        # Cycle through each image edge in clockwise fashion,
        # and find the one intersecting the current line segment.
        # http://paulbourke.net/geometry/lineline2d/
        size = self.pixmap.size()
        points = [(0, 0),
                  (size.width(), 0),
                  (size.width(), size.height()),
                  (0, size.height())]
        x1, y1 = p1.x(), p1.y()
        x2, y2 = p2.x(), p2.y()
        d, i, (x, y) = min(self.intersectingEdges((x1, y1), (x2, y2), points))
        x3, y3 = points[i]
        x4, y4 = points[(i + 1) % 4]
        if (x, y) == (x1, y1):
            # Handle cases where previous point is on one of the edges.
            if x3 == x4:
                return QPointF(x3, min(max(0, y2), max(y3, y4)))
            else:  # y3 == y4
                return QPointF(min(max(0, x2), max(x3, x4)), y3)
        return QPointF(x, y)

    def intersectingEdges(self, x1y1, x2y2, points):
        """For each edge formed by `points', yield the intersection
        with the line segment `(x1,y1) - (x2,y2)`, if it exists.
        Also return the distance of `(x2,y2)' to the middle of the
        edge along with its index, so that the one closest can be chosen."""
        x1, y1 = x1y1
        x2, y2 = x2y2
        for i in range(4):
            x3, y3 = points[i]
            x4, y4 = points[(i + 1) % 4]
            denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1)
            nua = (x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)
            nub = (x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)
            if denom == 0:
                # This covers two cases:
                #   nua == nub == 0: Coincident
                #   otherwise: Parallel
                continue
            ua, ub = nua / denom, nub / denom
            if 0 <= ua <= 1 and 0 <= ub <= 1:
                x = x1 + ua * (x2 - x1)
                y = y1 + ua * (y2 - y1)
                m = QPointF((x3 + x4) / 2, (y3 + y4) / 2)
                d = distance(m - QPointF(x2, y2))
                yield d, i, (x, y)

    # These two, along with a call to adjustSize are required for the
    # scroll area.
    def sizeHint(self):
        return self.minimumSizeHint()

    def minimumSizeHint(self):
        if self.pixmap:
            return self.scale * self.pixmap.size()
        return super(Canvas, self).minimumSizeHint()

    def wheelEvent(self, ev):
        qt_version = 4 if hasattr(ev, "delta") else 5
        if qt_version == 4:
            if ev.orientation() == Qt.Vertical:
                v_delta = ev.delta()
                h_delta = 0
            else:
                h_delta = ev.delta()
                v_delta = 0
        else:
            delta = ev.angleDelta()
            h_delta = delta.x()
            v_delta = delta.y()

        mods = ev.modifiers()
        if Qt.ControlModifier == int(mods) and v_delta:
            self.zoomRequest.emit(v_delta)
        else:
            v_delta and self.scrollRequest.emit(v_delta, Qt.Vertical)
            h_delta and self.scrollRequest.emit(h_delta, Qt.Horizontal)
        ev.accept()

    def keyPressEvent(self, ev):
        key = ev.key()
        if key == Qt.Key_Escape and self.current:
            print('ESC press')
            self.current = None
            self.drawingPolygon.emit(False)
            self.update()
        elif key == Qt.Key_Return and self.canCloseShape():
            self.finalise()
        elif key == Qt.Key_Left and self.selectedShape:
            self.moveOnePixel('Left')
        elif key == Qt.Key_Right and self.selectedShape:
            self.moveOnePixel('Right')
        elif key == Qt.Key_Up and self.selectedShape:
            self.moveOnePixel('Up')
        elif key == Qt.Key_Down and self.selectedShape:
            self.moveOnePixel('Down')

    def moveOnePixel(self, direction):
        # print(self.selectedShape.points)
        if direction == 'Left' and not self.moveOutOfBound(QPointF(-1.0, 0)):
            # print("move Left one pixel")
            self.selectedShape.points[0] += QPointF(-1.0, 0)
            self.selectedShape.points[1] += QPointF(-1.0, 0)
            self.selectedShape.points[2] += QPointF(-1.0, 0)
            self.selectedShape.points[3] += QPointF(-1.0, 0)
        elif direction == 'Right' and not self.moveOutOfBound(QPointF(1.0, 0)):
            # print("move Right one pixel")
            self.selectedShape.points[0] += QPointF(1.0, 0)
            self.selectedShape.points[1] += QPointF(1.0, 0)
            self.selectedShape.points[2] += QPointF(1.0, 0)
            self.selectedShape.points[3] += QPointF(1.0, 0)
        elif direction == 'Up' and not self.moveOutOfBound(QPointF(0, -1.0)):
            # print("move Up one pixel")
            self.selectedShape.points[0] += QPointF(0, -1.0)
            self.selectedShape.points[1] += QPointF(0, -1.0)
            self.selectedShape.points[2] += QPointF(0, -1.0)
            self.selectedShape.points[3] += QPointF(0, -1.0)
        elif direction == 'Down' and not self.moveOutOfBound(QPointF(0, 1.0)):
            # print("move Down one pixel")
            self.selectedShape.points[0] += QPointF(0, 1.0)
            self.selectedShape.points[1] += QPointF(0, 1.0)
            self.selectedShape.points[2] += QPointF(0, 1.0)
            self.selectedShape.points[3] += QPointF(0, 1.0)
        self.shapeMoved.emit()
        self.repaint()

    def moveOutOfBound(self, step):
        points = [p1+p2 for p1, p2 in zip(self.selectedShape.points, [step]*4)]
        return True in map(self.outOfPixmap, points)

    def setLastLabel(self, text):
        assert text
        self.shapes[-1].label = text
        return self.shapes[-1]

    def undoLastLine(self):
        assert self.shapes
        self.current = self.shapes.pop()
        self.current.setOpen()
        self.line.points = [self.current[-1], self.current[0]]
        self.drawingPolygon.emit(True)

    def resetAllLines(self):
        assert self.shapes
        self.current = self.shapes.pop()
        self.current.setOpen()
        self.line.points = [self.current[-1], self.current[0]]
        self.drawingPolygon.emit(True)
        self.current = None
        self.drawingPolygon.emit(False)
        self.update()

    def loadPixmap(self, pixmap):
        self.pixmap = pixmap
        self.shapes = []
        self.repaint()

    def loadShapes(self, shapes):
        self.shapes = list(shapes)
        self.current = None
        self.repaint()

    def setShapeVisible(self, shape, value):
        self.visible[shape] = value
        self.repaint()

    def currentCursor(self):
        cursor = QApplication.overrideCursor()
        if cursor is not None:
            cursor = cursor.shape()
        return cursor

    def overrideCursor(self, cursor):
        self._cursor = cursor
        if self.currentCursor() is None:
            QApplication.setOverrideCursor(cursor)
        else:
            QApplication.changeOverrideCursor(cursor)

    def restoreCursor(self):
        QApplication.restoreOverrideCursor()

    def resetState(self):
        self.restoreCursor()
        self.pixmap = None
        self.update()