コード例 #1
0
ファイル: unidice.py プロジェクト: m-sakano/unidice
class SelectWidget(QWidget, Ui_Form2):

    select = [0,0,0,0]

    def __init__(self, parent=None):
        super(SelectWidget, self).__init__(parent)
        self.setWindowOpacity(0.5)
        self.setupUi(self)
        desktop = QtWidgets.QDesktopWidget()
        self.resize(desktop.availableGeometry().width(), desktop.availableGeometry().height())
        self.rubberband = QRubberBand(
            QRubberBand.Rectangle, self)
        self.setMouseTracking(True)

    def mousePressEvent(self, event):
        self.select[0] = event.screenPos().x()
        self.select[1] = event.screenPos().y()
        self.origin = event.pos()
        self.rubberband.setGeometry(
            QtCore.QRect(self.origin, QtCore.QSize()))
        self.rubberband.show()
        QWidget.mousePressEvent(self, event)

    def mouseMoveEvent(self, event):
        if self.rubberband.isVisible():
            self.rubberband.setGeometry(
                QtCore.QRect(self.origin, event.pos()).normalized())
        QWidget.mouseMoveEvent(self, event)

    def mouseReleaseEvent(self, event):
        self.select[2] = event.screenPos().x()
        self.select[3] = event.screenPos().y()
        if self.rubberband.isVisible():
            self.rubberband.hide()
            rect = self.rubberband.geometry()

        # ポインタ座標を左上→右下に揃える
        if self.select[0] > self.select[2]:
            tmp = self.select[0]
            self.select[0] = self.select[2]
            self.select[2] = tmp
        if self.select[1] > self.select[3]:
            tmp = self.select[1]
            self.select[1] = self.select[3]
            self.select[3] = tmp
        # 選択した面積がゼロの場合は何もしないで関数を終わる
        if self.select[0]==self.select[2] or self.select[1]==self.select[3]:
            QWidget.mouseReleaseEvent(self, event)
            self.close()
            return
        # ポインタ座標をメインウインドウに設定する
        area = ''
        for point in self.select:
            area = area + str(int(point)) + ','
        main_window.lineEdit.setText(area[0:-1])
        self.close()
        QWidget.mouseReleaseEvent(self, event)
コード例 #2
0
ファイル: gui.py プロジェクト: riverrun/cheesemaker
class ImageView(QGraphicsView):
    def __init__(self, parent=None):
        QGraphicsView.__init__(self, parent)

        self.go_prev_img = parent.go_prev_img
        self.go_next_img = parent.go_next_img

        pal = self.palette()
        pal.setColor(self.backgroundRole(), Qt.black)
        self.setPalette(pal)
        self.setFrameShape(QFrame.NoFrame)

    def mousePressEvent(self, event):
        """Go to the next / previous image, or be able to drag the image with a hand."""
        if event.button() == Qt.LeftButton:
            x = event.x()
            if x < 100:
                self.go_prev_img()
            elif x > self.width() - 100:
                self.go_next_img()
            else:
                self.setDragMode(QGraphicsView.ScrollHandDrag)
        QGraphicsView.mousePressEvent(self, event)

    def mouseReleaseEvent(self, event):
        self.setDragMode(QGraphicsView.NoDrag)
        QGraphicsView.mouseReleaseEvent(self, event)

    def zoom(self, zoomratio):
        self.scale(zoomratio, zoomratio)

    def wheelEvent(self, event):
        zoomratio = 1.1
        if event.angleDelta().y() < 0:
            zoomratio = 1.0 / zoomratio
        self.scale(zoomratio, zoomratio)

    def setup_crop(self, width, height):
        self.rband = QRubberBand(QRubberBand.Rectangle, self)
        coords = self.mapFromScene(0, 0, width, height)
        self.rband.setGeometry(QRect(coords.boundingRect()))
        self.rband.show()

    def crop_draw(self, x, y, width, height):
        coords = self.mapFromScene(x, y, width, height)
        self.rband.setGeometry(QRect(coords.boundingRect()))

    def get_coords(self):
        rect = self.rband.geometry()
        size = self.mapToScene(rect).boundingRect()
        x = int(size.x())
        y = int(size.y())
        width = int(size.width())
        height = int(size.height())
        return (x, y, width, height)
コード例 #3
0
ファイル: dragwidget.py プロジェクト: freeaks/filer
class DragWidget(QWidget):
    spacerX = 16
    spacerY = 16
    clipicon = None
    new_window_signal = pyqtSignal(str)
    query = pyqtSignal()
    src_dragwidget = None
    src_selected = []

    def __init__(self, path, parent=None):
        super(DragWidget, self).__init__(parent)
        self.setMinimumSize(400, 200)
        self.setAcceptDrops(True)
        self.parent = parent
        # self.parent.menu.connect(self.delete_icon)
        self.modifier = False
        self.rubberband = QRubberBand(QRubberBand.Rectangle, self)
        self.path = path
        self.icons = []
        self.icon_offsetx = 0
        self.icon_offsety = 0
        # self.clipicon = None
        # self.moving_icons = []
        self.read_drawer()
        self.clean_up()
        # print(type(IconWidget.icon))
        # print(self.findChildren(ClickableIcon))

    def read_drawer(self):
        # self.icons.clear()
        for item in os.scandir(self.path):
            if item.is_dir():
                icon_widget = IconWidget(parent=self, name=item.name, path=self.path, dir=True)
            else:
                icon_widget = IconWidget(parent=self, name=item.name, path=self.path, dir=False)
            icon_widget.new_window.connect(self.new_window_signal.emit)
            icon_widget.clipboard.connect(self.on_clipboard)
            self.icons.append(icon_widget)
            self.icons[-1].setAttribute(Qt.WA_DeleteOnClose)
        # self.update()

    def updateScrollArea(self):
        """ set the dimension of the widget """
        iconx = []
        icony = []
        if len(self.icons) > 0:
            for item in self.icons:
                iconx.append(item.x())
                icony.append(item.y())
            self.setMinimumWidth(max(iconx)+75)
            self.setMinimumHeight(max(icony)+75)
        
    def dragEnterEvent(self, event):
        event.accept()

    def dragMoveEvent(self, event):
        event.accept()

    def get_dnd_list(self, event):
        icon_list = []
        icon_offsetx = None
        icon_offsety = None
        if len(DragWidget.src_selected) > 0:
            for item in DragWidget.src_selected:
                icon_list.append(item)
        else:
            icon_list.append(event.source())
        return icon_list

    def create_icon(self, name, drawer):
        if drawer:
            icon_widget = IconWidget(self, name=name, path=self.path, dir=True)
        else: 
            icon_widget = IconWidget(self, name=name, path=self.path, dir=False)
        icon_widget.new_window.connect(self.new_window_signal.emit)
        self.icons.append(icon_widget)

    def place_icon(self, x, y):
        self.icons[-1].move(x, y)
        self.icons[-1].show()

    def dropEvent(self, event):
        event.accept()
        icon_list = self.get_dnd_list(event)
        icon_offsetx = event.pos().x()
        icon_offsety = event.pos().y()
        for item in icon_list:
            name = item.name
            drawer = item.drawer
            src_path = item.path + "/" + name
            dst_path = self.path + "/"
            if event.mimeData().hasFormat("application/x-icon"):
                self.create_icon(name, drawer)
                self.move_data(src_path, dst_path)
                self.place_icon(icon_offsetx, icon_offsety)
                icon_offsetx += 100 
                if icon_offsetx > self.window().width():
                    icon_offsetx = event.pos().x()
                    icon_offsety += 75

        icon_offsetx = None
        icon_offsety = None
        self.updateScrollArea()

    def clear_dnd(self):
        DragWidget.src_dragwidget = None
        DragWidget.src_selected.clear()

    def get_modifier(self):
        return self.parent.modifier

    def mousePressEvent(self, event):
        if event.buttons() == Qt.LeftButton:
            for item in self.icons:
                item.icon.deselect_icon()
            self.clear_dnd() 

            self.origin = event.pos()
            self.rubberband.setGeometry(QRect(self.origin, QSize()))
            self.rubberband.show()

    def mouseMoveEvent(self, event):
        if self.rubberband.isVisible():
            self.rubberband.setGeometry(
                QRect(self.origin, event.pos()).normalized())
        # QWidget.mouseMoveEvent(self, event)

    def mouseReleaseEvent(self, event):
        self.clear_dnd()
        if self.rubberband.isVisible():
            self.rubberband.hide()
            rect = self.rubberband.geometry()
            for child in self.findChildren(IconWidget):
                if rect.intersects(child.geometry()):
                    child.icon.select_icon()
                    DragWidget.src_selected.append(child)
                    if DragWidget.src_dragwidget is not self:
                        DragWidget.src_dragwidget = self

    def mouseDoubleClickEvent(self, event):
        print(BLU, "Double Click", END) 
        self.query.emit()

    def create_file(self):
        new_file = self.path + "/" + "newfile.txt"
        open(new_file, 'w').close()
        icon_widget = IconWidget(self, name="newfile.txt", path=self.path, dir=False)
        icon_widget.new_window.connect(self.new_window_signal.emit)
        icon_widget.show()
        self.icons.append(icon_widget)

    def create_drawer(self):
        print("creating new drawer")
        new_drawer = self.path + "/" + "NewDrawer"
        os.makedirs(new_drawer)
        icon_widget = IconWidget(self, name="NewDrawer", path=self.path, dir=True)
        icon_widget.new_window.connect(self.new_window_signal.emit)
        icon_widget.show()
        self.icons.append(icon_widget)

    def rename_file(self):
        print("renaming file")

    def clean_up(self):
        for item in self.icons:
            item.move(DragWidget.spacerX, DragWidget.spacerY)
            # initial icon placement
            DragWidget.spacerX += 100
            if DragWidget.spacerX + 100 > self.window().width():
                DragWidget.spacerY += 75
                DragWidget.spacerX = 16
        # reset placement values
        DragWidget.spacerX = 16
        DragWidget.spacerY = 16
        self.updateScrollArea()

    def move_data(self, source, dest):
        srce_path = source.rsplit('/', 1)[0]
        dest_path = dest.rsplit('/', 1)[0]
        if srce_path != dest_path:
            try:
                shutil.move(source, dest)
            except Exception as err:
                print(err)

    def copy_icon(self, source, dest):
        pass

    def delete_icon(self):
        dest = os.path.expanduser("~") + "/.Trash/"
        error_string = ""
        for item in self.icons:
            if item.icon.selected:
                source = item.path + "/" + item.name
                if source is not "":
                    try:
                        shutil.move(source, dest)
                    except Exception as err:
                        error_string += str(err) + "\n" + "\n"
                    else:
                        self.icons.remove(item)
                        item.deleteLater()
        if error_string is not "":
            QMessageBox.information(self, 'Info', error_string, QMessageBox.Ok)

    def paste_icon(self):
        print("---")
        print("srce=", self.clipicon.path + "/" + self.clipicon.name)
        # print("res=", self.clipicon.path + "/" + self.clipicon.name)
        print("dest=", self.path + "/")

        # if os.path.isdir(os.path.join(self.clipicon.path, self.clipicon.name)):
        SRCE = self.clipicon.path + "/" + self.clipicon.name
        DEST = self.path+"/" + self.clipicon.name
        shutil.copytree(SRCE, DEST)

    def on_clipboard(self, icon):
        print("realpath", self.path)
        print("clip_icon_name=", icon.name)
        DragWidget.clipicon = icon
コード例 #4
0
class FsApp(QMainWindow):

    def __init__(self, app):
        super(FsApp, self).__init__()
        self.app       = app
        self.selRect   = None
        self.screenPix = None

        # Set up the user interface from Designer.
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        #self.setWindowOpacity(0.5)
        #self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
        self.captureScreen()
        self.showMaximized()
        self.showFullScreen()


        #capture screen and display
        rec = QApplication.desktop().screenGeometry()
        height = rec.height()
        width = rec.width()
        self.ui.labPix.resize(width, height)
        self.ui.labPix.setScaledContents(True)
        self.ui.labPix.setPixmap(self.screenPix)

        #start rubberband
        self.rubberband = QRubberBand(QRubberBand.Rectangle, self)
        bla = QtGui.QPalette()
        bla.setBrush(QtGui.QPalette.Highlight, QtGui.QBrush(QtCore.Qt.red))
        self.rubberband.setPalette(bla)
        self.rubberband.setWindowOpacity(1.0)

    def captureScreen(self):
        screens = self.app.screens()
        self.screenPix = screens[0].grabWindow(0)

    def mousePressEvent(self, event):
        self.origin = event.pos()
        self.rubberband.setGeometry(QtCore.QRect(self.origin, QtCore.QSize()))
        self.rubberband.show()
        QWidget.mousePressEvent(self, event)

    def mouseMoveEvent(self, event):
        if self.rubberband.isVisible():
            self.rubberband.setGeometry(QtCore.QRect(self.origin, event.pos()).normalized())
        QWidget.mouseMoveEvent(self, event)

    def mouseReleaseEvent(self, event):
        if self.rubberband.isVisible():
            self.selRect = self.rubberband.geometry()
            self.rubberband.hide()
            codePix = self.screenPix.copy(    self.selRect.x(),
                            self.selRect.y(), 
                            self.selRect.width(),
                            self.selRect.height())
            QApplication.clipboard().setPixmap(codePix)
            self.exit()
        QWidget.mouseReleaseEvent(self, event)

    def exit(self):
        sys.exit(0)
コード例 #5
0
ファイル: widget.py プロジェクト: wanghai1988/pyqimageview
class ImageView(QGraphicsView):
    imageChanged = pyqtSignal()

    def __init__(self, *args, **kwargs):
        QGraphicsView.__init__(self, *args, **kwargs)
        scene = QGraphicsScene(self)
        self.graphics_pixmap = QGraphicsPixmapItem()
        scene.addItem(self.graphics_pixmap)
        self.zoom_factor = 1.5
        self.setScene(scene)
        self.start_drag = QPoint()
        self.rubberBand = None
        self.panning = False
        self.first_show_occured = False
        self.last_scene_roi = None

    @property
    def pixmap(self):
        return self.graphics_pixmap.pixmap()

    @pixmap.setter
    def pixmap(self, image, image_format=None):
        pixmap = None
        if have_numpy and isinstance(image, np.ndarray):
            if image.ndim == 3:
                if image.shape[2] == 3:
                    if image_format is None:
                        image_format = QImage.Format_RGB888
                    q_image = QImage(image.data, image.shape[1],
                                     image.shape[0], image_format)
                    pixmap = QPixmap.fromImage(
                        q_image
                    )  #note this copies the data from the QImage referencing image original data
                elif image.shape[2] == 4:
                    if image_format is None:
                        image_format = QImage.Format_RGB32
                    q_image = QImage(image.data, image.shape[1],
                                     image.shape[0], image_format)
                    pixmap = QPixmap.fromImage(
                        q_image
                    )  #note this copies the data from the QImage referencing image original data
                else:
                    raise TypeError(image)
            elif image.ndim == 2:
                image_rgb = np.dstack((image, image, image))
                if image_format is None:
                    image_format = QImage.Format_RGB888
                q_image = QImage(image.data, image.shape[1], image.shape[0],
                                 image_format)
                pixmap = QPixmap.fromImage(
                    q_image
                )  #note this copies the data from the QImage referencing original image
            else:
                raise ValueError(image)

        elif isinstance(image, QImage):
            pixmap = QPixmap.fromImage(image)
        elif isinstance(image, QPixmap):
            pixmap = image
        else:
            raise TypeError(image)

        self.graphics_pixmap.setPixmap(pixmap)
        self.setSceneDims()
        #self.fitInView()
        self.graphics_pixmap.update()
        self.imageChanged.emit()

    #image property alias
    @property
    def image(self):
        return self.pixmap

    @image.setter
    def image(self, image):
        self.pixmap = image

    def setSceneDims(self):
        pixmap = self.pixmap
        self.setSceneRect(
            QRectF(
                #-QPointF(pixmap.width(), pixmap.height())/2, 1.5*QPointF(pixmap.width(), pixmap.height())
                QPointF(0, 0),
                QPointF(pixmap.width(), pixmap.height())))

    @property
    def image_scene_rect(self):
        return QRectF(self.graphics_pixmap.pos(), QSizeF(self.pixmap.size()))

    def resizeEvent(self, event):
        QGraphicsView.resizeEvent(self, event)
        self.setSceneDims()
        event.accept()
        #self.reset()
        #self.fitInView(roi, Qt.KeepAspectRatio)
        self.fitInView(self.last_scene_roi, Qt.KeepAspectRatio)
        self.update()

    def zoomROICentered(self, p, zoom_level_delta):
        pixmap = self.graphics_pixmap.pixmap()
        roi = self.current_scene_ROI
        roi_dims = QPointF(roi.width(), roi.height())
        roi_scalef = 1
        if zoom_level_delta > 0:
            roi_scalef = 1 / self.zoom_factor
        elif zoom_level_delta < 0:
            roi_scalef = self.zoom_factor
        nroi_dims = roi_dims * roi_scalef
        nroi_dims.setX(max(nroi_dims.x(), 1))
        nroi_dims.setY(max(nroi_dims.y(), 1))
        if nroi_dims.x() > self.pixmap.size().width() or nroi_dims.y(
        ) > self.pixmap.size().height():
            self.reset()
        else:
            nroi_center = p
            nroi_dimsh = nroi_dims / 2
            nroi_topleft = nroi_center - nroi_dimsh
            nroi = QRectF(nroi_topleft.x(), nroi_topleft.y(), nroi_dims.x(),
                          nroi_dims.y())
            self.fitInView(nroi, Qt.KeepAspectRatio)
            self.update()

    def zoomROITo(self, p, zoom_level_delta):
        pixmap = self.graphics_pixmap.pixmap()
        roi = self.current_scene_ROI
        roi_dims = QPointF(roi.width(), roi.height())
        roi_topleft = roi.topLeft()
        roi_scalef = 1
        if zoom_level_delta > 0:
            roi_scalef = 1 / self.zoom_factor
        elif zoom_level_delta < 0:
            roi_scalef = self.zoom_factor
        nroi_dims = roi_dims * roi_scalef
        nroi_dims.setX(max(nroi_dims.x(), 1))
        nroi_dims.setY(max(nroi_dims.y(), 1))
        if nroi_dims.x() > self.pixmap.size().width() or nroi_dims.y(
        ) > self.pixmap.size().height():
            self.reset()
        else:
            prel_scaled_x = (p.x() - roi_topleft.x()) / roi_dims.x()
            prel_scaled_y = (p.y() - roi_topleft.y()) / roi_dims.y()
            nroi_topleft_x = p.x() - prel_scaled_x * nroi_dims.x()
            nroi_topleft_y = p.y() - prel_scaled_y * nroi_dims.y()

            nroi = QRectF(nroi_topleft_x, nroi_topleft_y, nroi_dims.x(),
                          nroi_dims.y())
            self.fitInView(nroi, Qt.KeepAspectRatio)
            self.update()

    def _scene_ROI(self, geometry):
        return QRectF(self.mapToScene(geometry.topLeft()),
                      self.mapToScene(geometry.bottomRight()))

    @property
    def current_scene_ROI(self):
        return self.last_scene_roi
        #return self._scene_ROI(self.viewport().geometry())

    def mousePressEvent(self, event):
        QGraphicsView.mousePressEvent(self, event)
        button = event.button()
        modifier = event.modifiers()

        #pan
        if modifier == Qt.ControlModifier and button == Qt.LeftButton:
            self.start_drag = event.pos()
            self.panning = True

        #initiate/show ROI selection
        if modifier == Qt.ShiftModifier and button == Qt.LeftButton:
            self.start_drag = event.pos()
            if self.rubberBand is None:
                self.rubberBand = QRubberBand(QRubberBand.Rectangle,
                                              self.viewport())
            self.rubberBand.setGeometry(QRect(self.start_drag, QSize()))
            self.rubberBand.show()

    def mouseMoveEvent(self, event):
        QGraphicsView.mouseMoveEvent(self, event)
        #update selection display
        if self.rubberBand is not None:
            self.rubberBand.setGeometry(
                QRect(self.start_drag, event.pos()).normalized())

        if self.panning:
            scene_end_drag = self.mapToScene(event.pos())
            end_drag = event.pos()
            pan_vector = end_drag - self.start_drag
            scene2view = self.transform()
            #skip shear
            sx = scene2view.m11()
            sy = scene2view.m22()
            dx = scene2view.dx()
            dy = scene2view.dy()
            scene_pan_vector = QPointF(pan_vector.x() / sx,
                                       pan_vector.y() / sy)
            roi = self.current_scene_ROI
            top_left = roi.topLeft()
            new_top_left = top_left - scene_pan_vector
            scene_rect = self.sceneRect()
            new_top_left.setX(
                clamp(new_top_left.x(), scene_rect.left(), scene_rect.right()))
            new_top_left.setY(
                clamp(new_top_left.y(), scene_rect.top(), scene_rect.bottom()))
            nroi = QRectF(new_top_left, roi.size())
            self.fitInView(nroi, Qt.KeepAspectRatio)
            self.start_drag = end_drag
        self.update()

    def mouseReleaseEvent(self, event):
        QGraphicsView.mouseReleaseEvent(self, event)
        #consume rubber band selection
        if self.rubberBand is not None:
            self.rubberBand.hide()

            #set view to ROI
            rect = self.rubberBand.geometry().normalized()

            if rect.width() > 5 and rect.height() > 5:
                roi = QRectF(self.mapToScene(rect.topLeft()),
                             self.mapToScene(rect.bottomRight()))
                self.fitInView(roi, Qt.KeepAspectRatio)

            self.rubberBand = None

        if self.panning:
            self.panning = False
        self.update()

    def wheelEvent(self, event):
        dy = event.angleDelta().y()
        update = False
        #adjust zoom
        if abs(dy) > 0:
            scene_pos = self.mapToScene(event.pos())
            sign = 1 if dy >= 0 else -1
            self.zoomROITo(scene_pos, sign)

    def keyPressEvent(self, event):
        pass

    def showEvent(self, event):
        QGraphicsView.showEvent(self, event)
        if event.spontaneous():
            return
        if not self.first_show_occured:
            self.first_show_occured = True
            self.reset()

    def reset(self):
        self.setSceneDims()
        self.fitInView(self.image_scene_rect, Qt.KeepAspectRatio)
        self.update()

    #override arbitrary and unwanted margins: https://bugreports.qt.io/browse/QTBUG-42331 - based on QT sources
    def fitInView(self, rect, flags=Qt.IgnoreAspectRatio):
        if self.scene() is None or rect.isNull():
            return
        self.last_scene_roi = rect
        unity = self.transform().mapRect(QRectF(0, 0, 1, 1))
        self.scale(1 / unity.width(), 1 / unity.height())
        viewRect = self.viewport().rect()
        sceneRect = self.transform().mapRect(rect)
        xratio = viewRect.width() / sceneRect.width()
        yratio = viewRect.height() / sceneRect.height()
        if flags == Qt.KeepAspectRatio:
            xratio = yratio = min(xratio, yratio)
        elif flags == Qt.KeepAspectRatioByExpanding:
            xratio = yratio = max(xratio, yratio)
        self.scale(xratio, yratio)
        self.centerOn(rect.center())
コード例 #6
0
class ViewerWidget(QAbstractScrollArea):
    """
    The main ViewerWidget class. Should be embeddable in
    other applications. See the open() function for loading
    images.
    """
    # signals
    geolinkMove = pyqtSignal(GeolinkInfo, name='geolinkMove')
    geolinkQueryPoint = pyqtSignal(GeolinkInfo, name='geolinkQueryPoint')
    # can't use ViewerWidget - use base class instead
    layerAdded = pyqtSignal(QAbstractScrollArea, name='layerAdded')
    showStatusMessage = pyqtSignal('QString', name='showStatusMessage')
    activeToolChanged = pyqtSignal(ActiveToolChangedInfo,
                                   name='activeToolChanged')
    polygonCollected = pyqtSignal(PolygonToolInfo, name='polygonCollected')
    polylineCollected = pyqtSignal(PolylineToolInfo, name='polylineCollected')
    vectorLocationSelected = pyqtSignal(list,
                                        viewerlayers.ViewerVectorLayer,
                                        name='vectorLocationSelected')
    locationSelected = pyqtSignal(QueryInfo, name='locationSelected')

    def __init__(self, parent):
        QAbstractScrollArea.__init__(self, parent)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)

        # tracking works awfully badly under X
        # turn off until we work out a workaround
        self.verticalScrollBar().setTracking(False)
        self.horizontalScrollBar().setTracking(False)

        self.layers = viewerlayers.LayerManager()

        self.paintPoint = QPoint()  # normally 0,0 unless we are panning

        # when moving the scroll bars
        # events get fired that we wish to ignore
        self.suppressscrollevent = False

        # set the background color to black so window
        # is black when nothing loaded and when panning
        # new areas are initially black.
        self.setBackgroundColor(Qt.black)

        # to do with tools
        self.rubberBand = None
        self.panCursor = None
        self.panGrabCursor = None
        self.zoomInCursor = None
        self.zoomOutCursor = None
        self.queryCursor = None
        self.vectorQueryCursor = None
        self.polygonCursor = None
        self.activeTool = VIEWER_TOOL_NONE
        self.panOrigin = None
        self.toolPoints = None  # for line and polygon tools - list of points
        self.toolPointsFinished = True  # True if we finished collecting
        # with line and poly tools
        self.toolPen = QPen()  # for drawing the toolPoints
        self.toolPen.setWidth(1)
        self.toolPen.setColor(Qt.yellow)
        self.toolPen.setDashPattern([5, 5, 5, 5])

        # Define the scroll wheel behaviour
        self.mouseWheelZoom = True
        # do we follow extent when geolinking?
        self.geolinkFollowExtent = True
        # to we query all layers or only displayed?
        self.queryOnlyDisplayed = False

    def updateScrollBars(self):
        """
        Update the scroll bars to accurately show where
        we are relative to the full extent
        """
        fullextent = self.layers.getFullExtent()
        setbars = False
        self.suppressscrollevent = True
        if fullextent is not None:
            (fullleft, fulltop, fullright, fullbottom) = fullextent
            layer = self.layers.getTopLayer()
            if layer is not None:
                (left, top, right, bottom) = layer.coordmgr.getWorldExtent()
                (wldX, wldY) = layer.coordmgr.getWorldCenter()
                verticalBar = self.verticalScrollBar()
                horizontalBar = self.horizontalScrollBar()
                # always set range to 0 - 1000 and calculate
                # everything as fraction of that
                verticalBar.setRange(0, 1000)
                horizontalBar.setRange(0, 1000)

                # to pagestep which is also the slider size
                fullxsize = float(fullright - fullleft)
                if fullxsize == 0:
                    fullxsize = 100
                hpagestep = (float(right - left) / fullxsize) * 1000
                horizontalBar.setPageStep(int(hpagestep))
                fullysize = float(fulltop - fullbottom)
                if fullysize == 0:
                    fullysize = 100
                vpagestep = (float(top - bottom) / fullysize) * 1000
                verticalBar.setPageStep(int(vpagestep))

                # position of the slider relative to the center of the image
                hpos = (float(wldX - fullleft) / fullxsize) * 1000
                horizontalBar.setSliderPosition(int(hpos))
                vpos = (float(fulltop - wldY) / fullysize) * 1000
                verticalBar.setSliderPosition(int(vpos))
                setbars = True
        if not setbars:
            # something went wrong - disable
            self.horizontalScrollBar().setRange(0, 0)
            self.verticalScrollBar().setRange(0, 0)
        self.suppressscrollevent = False

    def addRasterLayer(self,
                       gdalDataset,
                       stretch,
                       lut=None,
                       ignoreProjectionMismatch=False,
                       quiet=False):
        """
        Add the given dataset to the stack of images being displayed
        as a raster layer
        """
        size = self.viewport().size()
        self.layers.addRasterLayer(gdalDataset, size.width(), size.height(),
                                   stretch, lut, ignoreProjectionMismatch,
                                   quiet)
        # get rid off tool points
        self.toolPoints = None
        self.toolPointsFinished = True

        self.viewport().update()
        self.updateScrollBars()

        self.layerAdded.emit(self)

    def addVectorLayer(self,
                       ogrDataSource,
                       ogrLayer,
                       color=None,
                       resultSet=False,
                       origSQL=None,
                       quiet=False):
        """
        Add the vector given by the ogrDataSource and its dependent 
        ogrLayer to the stack of images.
        """
        size = self.viewport().size()
        if color is None:
            color = viewerlayers.DEFAULT_VECTOR_COLOR

        self.layers.addVectorLayer(ogrDataSource, ogrLayer, size.width(),
                                   size.height(), color, resultSet, origSQL,
                                   quiet)
        self.viewport().update()
        self.updateScrollBars()

        self.layerAdded.emit(self)

    def addVectorFeatureLayer(self,
                              ogrDataSource,
                              ogrLayer,
                              ogrFeature,
                              color=None,
                              quiet=None):
        """
        Just a single feature vector
        """
        size = self.viewport().size()
        if color is None:
            color = viewerlayers.DEFAULT_VECTOR_COLOR

        self.layers.addVectorFeatureLayer(ogrDataSource, ogrLayer, ogrFeature,
                                          size.width(), size.height(), color,
                                          quiet)
        self.viewport().update()
        self.updateScrollBars()

        self.layerAdded.emit(self)

    def addLayersFromJSONFile(self, fileobj, nlayers):
        """
        Get the layer manager to read all the layer descriptions from fileobj
        and load these layers into this widget.
        """
        size = self.viewport().size()
        self.layers.fromFile(fileobj, nlayers, size.width(), size.height())

        self.viewport().update()
        self.updateScrollBars()

        self.layerAdded.emit(self)

    def removeLayer(self):
        """
        Removes the top later
        """
        self.layers.removeTopLayer()
        # get rid off tool points
        self.toolPoints = None
        self.toolPointsFinished = True
        self.viewport().update()
        self.updateScrollBars()

    # query point functions
    def setQueryPoint(self,
                      senderid,
                      easting,
                      northing,
                      color,
                      size=None,
                      cursor=None):
        """
        Sets/Updates query point keyed on the id() of the sender
        """
        self.layers.queryPointLayer.setQueryPoint(senderid, easting, northing,
                                                  color, size, cursor)
        self.layers.queryPointLayer.getImage()
        self.viewport().update()

    def removeQueryPoint(self, senderid):
        """
        Removes a query point. keyed on the id() of the sender
        """
        self.layers.queryPointLayer.removeQueryPoint(senderid)
        self.layers.queryPointLayer.getImage()
        self.viewport().update()

    def highlightValues(self, color, selectionArray=None):
        """
        Applies a QColor to the LUT where selectionArray == True
        to the top layer and redraws. Pass None to reset
        """
        layer = self.layers.getTopRasterLayer()
        if layer is not None:
            if len(layer.stretch.bands) != 1:
                msg = 'can only highlight values on single band images'
                raise viewererrors.InvalidDataset(msg)
            layer.highlightRows(color, selectionArray)

            # force repaint
            self.viewport().update()

    def setColorTableLookup(self,
                            lookupArray=None,
                            colName=None,
                            surrogateLUT=None,
                            surrogateName=None):
        """
        Uses the supplied lookupArray to look up image
        data before indexing into color table in the top
        layer and redraws. Pass None to reset.
        """
        layer = self.layers.getTopRasterLayer()
        if layer is not None:
            if len(layer.stretch.bands) != 1:
                msg = 'can only highlight values on single band images'
                raise viewererrors.InvalidDataset(msg)
            layer.setColorTableLookup(lookupArray, colName, surrogateLUT,
                                      surrogateName)

            # force repaint
            self.viewport().update()

    def zoomNativeResolution(self):
        """
        Sets the zoom to native resolution wherever
        the current viewport is centered
        """
        self.layers.zoomNativeResolution()
        # force repaint
        self.viewport().update()
        self.updateScrollBars()
        # geolink
        self.emitGeolinkMoved()

    def zoomFullExtent(self):
        """
        Resets the zoom to full extent - should be
        the same as when file was opened.
        """
        self.layers.zoomFullExtent()
        # force repaint
        self.viewport().update()
        self.updateScrollBars()
        # geolink
        self.emitGeolinkMoved()

    def setActiveTool(self, tool, senderid):
        """
        Set active tool (one of VIEWER_TOOL_*).
        pass VIEWER_TOOL_NONE to disable
        pass the id() of the calling object. This is passed around
        in the activeToolChanged signal so GUI elements can recognise
        who asked for the change
        """
        # if the tool was line or polygon
        # now is the time to remove the outline from the widget
        if (self.activeTool == VIEWER_TOOL_POLYGON
                or self.activeTool == VIEWER_TOOL_POLYLINE):
            self.toolPoints = None
            self.toolPointsFinished = True
            # force repaint
            self.viewport().update()

        self.activeTool = tool
        if tool == VIEWER_TOOL_ZOOMIN:
            if self.zoomInCursor is None:
                # create if needed.
                self.zoomInCursor = QCursor(
                    QPixmap([
                        "16 16 3 1", ". c None", "a c #000000", "# c #ffffff",
                        ".....#####......", "...##aaaaa##....",
                        "..#.a.....a.#...", ".#.a...a...a.#..",
                        ".#a....a....a#..", "#a.....a.....a#.",
                        "#a.....a.....a#.", "#a.aaaa#aaaa.a#.",
                        "#a.....a.....a#.", "#a.....a.....a#.",
                        ".#a....a....a#..", ".#.a...a...aaa#.",
                        "..#.a.....a#aaa#", "...##aaaaa###aa#",
                        ".....#####...###", "..............#."
                    ]))
            self.viewport().setCursor(self.zoomInCursor)

        elif tool == VIEWER_TOOL_ZOOMOUT:
            if self.zoomOutCursor is None:
                # create if needed
                self.zoomOutCursor = QCursor(
                    QPixmap([
                        "16 16 4 1", "b c None", ". c None", "a c #000000",
                        "# c #ffffff", ".....#####......", "...##aaaaa##....",
                        "..#.a.....a.#...", ".#.a.......a.#..",
                        ".#a.........a#..", "#a...........a#.",
                        "#a...........a#.", "#a.aaaa#aaaa.a#.",
                        "#a...........a#.", "#a...........a#.",
                        ".#a.........a#..", ".#.a.......aaa#.",
                        "..#.a.....a#aaa#", "...##aaaaa###aa#",
                        ".....#####...###", "..............#."
                    ]))
            self.viewport().setCursor(self.zoomOutCursor)

        elif tool == VIEWER_TOOL_PAN:
            if self.panCursor is None:
                # both these used for pan operations
                self.panCursor = QCursor(Qt.OpenHandCursor)
                self.panGrabCursor = QCursor(Qt.ClosedHandCursor)
            self.viewport().setCursor(self.panCursor)

        elif tool == VIEWER_TOOL_QUERY:
            if self.queryCursor is None:
                self.queryCursor = QCursor(Qt.CrossCursor)
            self.viewport().setCursor(self.queryCursor)

        elif tool == VIEWER_TOOL_VECTORQUERY:
            if self.vectorQueryCursor is None:
                self.vectorQueryCursor = QCursor(
                    QPixmap([
                        "16 16 3 1", "# c None", "a c #000000", ". c #ffffff",
                        "######aaaa######", "######a..a######",
                        "######a..a######", "######a..a######",
                        "######a..a######", "######aaaa######",
                        "aaaaa######aaaaa", "a...a######a...a",
                        "a...a######a...a", "aaaaa######aaaaa",
                        "######aaaa######", "######a..a###a.a",
                        "######a..a###aaa", "######a..a###a.a",
                        "######a..a###a.a", "######aaaa###aaa"
                    ]))
            self.viewport().setCursor(self.vectorQueryCursor)

        elif tool == VIEWER_TOOL_POLYGON or tool == VIEWER_TOOL_POLYLINE:
            if self.polygonCursor is None:
                self.polygonCursor = QCursor(
                    QPixmap([
                        "16 16 3 1", "      c None", ".     c #000000",
                        "+     c #FFFFFF", "                ",
                        "       +.+      ", "      ++.++     ",
                        "     +.....+    ", "    +.     .+   ",
                        "   +.   .   .+  ", "  +.    .    .+ ",
                        " ++.    .    .++", " ... ...+... ...",
                        " ++.    .    .++", "  +.    .    .+ ",
                        "   +.   .   .+  ", "   ++.     .+   ",
                        "    ++.....+    ", "      ++.++     ",
                        "       +.+      "
                    ]))
            self.viewport().setCursor(self.polygonCursor)
            msg = ('Left click adds a point, middle to remove last,' +
                   ' right click to end')
            self.showStatusMessage.emit(msg)

        elif tool == VIEWER_TOOL_NONE:
            # change back
            self.viewport().setCursor(Qt.ArrowCursor)

        obj = ActiveToolChangedInfo(self.activeTool, senderid)
        self.activeToolChanged.emit(obj)

    def setNewStretch(self, newstretch, layer, local=False):
        """
        Change the stretch being applied to the current data
        """
        layer.setNewStretch(newstretch, local)
        self.viewport().update()

    def timeseriesBackward(self):
        """
        Assume images are a stacked timeseries oldest
        to newest. Turn on the previous one to the current
        topmost displayed
        """
        self.layers.timeseriesBackward()
        self.viewport().update()

    def timeseriesForward(self):
        """
        Assume images are a stacked timeseries oldest
        to newest. Turn off the current topmost displayed
        """
        self.layers.timeseriesForward()
        self.viewport().update()

    def setMouseScrollWheelAction(self, scrollZoom):
        "Set the action for a mouse wheen event (scroll/zoom)"
        self.mouseWheelZoom = scrollZoom

    def setBackgroundColor(self, color):
        "Sets the background color for the widget"
        widget = self.viewport()
        palette = widget.palette()
        palette.setColor(widget.backgroundRole(), color)
        widget.setPalette(palette)

    def setGeolinkFollowExtentAction(self, followExtent):
        "Set whether we are following geolink extent of just center"
        self.geolinkFollowExtent = followExtent

    def setQueryOnlyDisplayed(self, queryOnlyDisplayed):
        """
        set whether we are only querying displayed layers (True)
        or all (False)
        """
        self.queryOnlyDisplayed = queryOnlyDisplayed

    def flicker(self):
        """
        Call to change the flicker state (ie draw the top raster image
        or not). 
        """
        state = False
        layer = self.layers.getTopLayer()
        if layer is not None:
            state = not layer.displayed
            self.layers.setDisplayedState(layer, state)
            self.viewport().update()
        return state

    def scrollContentsBy(self, dx, dy):
        """
        Handle the user moving the scroll bars
        """
        if not self.suppressscrollevent:
            layer = self.layers.getTopLayer()
            if layer is not None:
                (left, top, right, bottom) = layer.coordmgr.getWorldExtent()
                hpagestep = float(self.horizontalScrollBar().pageStep())
                xamount = -(float(dx) / hpagestep) * (right - left)
                vpagestep = float(self.verticalScrollBar().pageStep())
                yamount = (float(dy) / vpagestep) * (top - bottom)
                wldX, wldY = layer.coordmgr.getWorldCenter()
                layer.coordmgr.setWorldCenter(wldX + xamount, wldY + yamount)
                # not sure why we need this but get black strips
                # around otherwise
                layer.coordmgr.recalcBottomRight()
                self.layers.makeLayersConsistent(layer)
                self.layers.updateImages()
                self.viewport().update()
                self.updateScrollBars()

                # geolink
                self.emitGeolinkMoved()

    def wheelEvent(self, event):
        """
        User has used mouse wheel to zoom in/out or pan depending on defined preference
        """
        layer = self.layers.getTopRasterLayer()
        if layer is not None:
            delta = event.angleDelta().y()

            # Shift scrolling will move you forward and backwards through the time series
            if QApplication.keyboardModifiers() == Qt.ShiftModifier:
                if delta > 0:
                    self.timeseriesBackward()
                elif delta < 0:
                    self.timeseriesForward()

            elif self.mouseWheelZoom:
                (wldX, wldY) = layer.coordmgr.getWorldCenter()

                impixperwinpix = layer.coordmgr.imgPixPerWinPix
                if delta > 0:
                    impixperwinpix *= 1.0 - VIEWER_ZOOM_WHEEL_FRACTION
                elif delta < 0:
                    impixperwinpix *= 1.0 + VIEWER_ZOOM_WHEEL_FRACTION
                layer.coordmgr.setZoomFactor(impixperwinpix)
                layer.coordmgr.setWorldCenter(wldX, wldY)
                # not sure why we need this but get black strips
                # around otherwise
                layer.coordmgr.recalcBottomRight()
                self.layers.makeLayersConsistent(layer)
                self.layers.updateImages()
                self.updateScrollBars()
                self.viewport().update()
            else:
                dx = event.angleDelta().x()
                dy = delta
                self.scrollContentsBy(dx, dy)

            # geolink
            self.emitGeolinkMoved()

    def resizeEvent(self, event):
        """
        Window has been resized - get new data
        """
        size = event.size()
        self.layers.setDisplaySize(size.width(), size.height())
        self.updateScrollBars()

    def paintEvent(self, event):
        """
        Viewport needs to be redrawn. Assume that
        each layer's image is current (as created by getImage())
        we can just draw it with QPainter
        """
        paint = QPainter(self.viewport())

        for layer in self.layers.layers:
            if layer.displayed:
                paint.drawImage(self.paintPoint, layer.image)

        # draw any query points on top of image
        paint.drawImage(self.paintPoint, self.layers.queryPointLayer.image)

        # now any tool points
        if self.toolPoints is not None:
            path = QPainterPath()
            firstpt = self.toolPoints[0]
            path.moveTo(firstpt.x(), firstpt.y())
            for pt in self.toolPoints[1:]:
                path.lineTo(pt.x(), pt.y())
            paint.setPen(self.toolPen)
            paint.drawPath(path)

        paint.end()

    def mousePressEvent(self, event):
        """
        Mouse has been clicked down if we are in zoom/pan
        mode we need to start doing stuff here
        """
        QAbstractScrollArea.mousePressEvent(self, event)
        pos = event.pos()

        if (self.activeTool == VIEWER_TOOL_ZOOMIN
                or self.activeTool == VIEWER_TOOL_ZOOMOUT):
            if self.rubberBand is None:
                self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
            self.rubberBand.setGeometry(QRect(pos, QSize()))
            self.rubberBand.show()
            self.rubberBand.origin = pos

        elif self.activeTool == VIEWER_TOOL_PAN:
            # remember pos
            self.panOrigin = pos
            # change cursor
            self.viewport().setCursor(self.panGrabCursor)

        elif self.activeTool == VIEWER_TOOL_QUERY:

            modifiers = event.modifiers()
            (dspX, dspY) = (pos.x(), pos.y())
            self.newQueryPoint(dspX=dspX, dspY=dspY, modifiers=modifiers)

        elif self.activeTool == VIEWER_TOOL_VECTORQUERY:

            modifiers = event.modifiers()
            (dspX, dspY) = (pos.x(), pos.y())
            self.newVectorQueryPoint(dspX, dspY, modifiers=modifiers)

        elif self.activeTool == VIEWER_TOOL_POLYGON:
            button = event.button()
            if button == Qt.LeftButton:
                # adding points
                if self.toolPoints is None or self.toolPointsFinished:
                    # first point - starts and ends at same pos
                    self.toolPoints = [pos, pos]
                    self.toolPointsFinished = False
                else:
                    # last point same as first - insert before last
                    self.toolPoints.insert(-1, pos)

            elif button == Qt.MiddleButton and self.toolPoints is not None:
                # delete last point
                if len(self.toolPoints) > 2:
                    del self.toolPoints[-2]

            elif button == Qt.RightButton and self.toolPoints is not None:
                # finished
                # create object for signal
                layer = self.layers.getTopRasterLayer()
                modifiers = event.modifiers()
                obj = PolygonToolInfo(self.toolPoints, layer, modifiers)
                self.polygonCollected.emit(obj)

                self.toolPointsFinished = True  # done, but still display

            # redraw so paint() gets called
            self.viewport().update()

        elif self.activeTool == VIEWER_TOOL_POLYLINE:
            button = event.button()
            if button == Qt.LeftButton:
                # adding points
                if self.toolPoints is None or self.toolPointsFinished:
                    # first point
                    self.toolPoints = [pos]
                    self.toolPointsFinished = False
                else:
                    # add to list
                    self.toolPoints.append(pos)

            elif button == Qt.MiddleButton and self.toolPoints is not None:
                # delete last point
                if len(self.toolPoints) > 1:
                    self.toolPoints.pop()

            elif button == Qt.RightButton and self.toolPoints is not None:
                # finished
                # create object for signal
                if self.queryOnlyDisplayed:
                    layer = self.layers.getTopDisplayedRasterLayer()
                else:
                    layer = self.layers.getTopRasterLayer()
                modifiers = event.modifiers()
                obj = PolylineToolInfo(self.toolPoints, layer, modifiers)
                self.polylineCollected.emit(obj)

                self.toolPointsFinished = True  # done, but still display

            # redraw so paint() gets called
            self.viewport().update()

    def mouseReleaseEvent(self, event):
        """
        Mouse has been released, if we are in zoom/pan
        mode we do stuff here.
        """
        QAbstractScrollArea.mouseReleaseEvent(self, event)
        if self.rubberBand is not None and self.rubberBand.isVisible():
            # get the information about the rect they have drawn
            # note this is on self, rather than viewport()
            selection = self.rubberBand.geometry()
            geom = self.viewport().geometry()

            selectionsize = float(selection.width() * selection.height())

            geomsize = float(geom.width() * geom.height())

            self.rubberBand.hide()

            layer = self.layers.getTopRasterLayer()
            if layer is not None:
                if selectionsize < MIN_SELECTION_SIZE_PX:
                    # this is practically a '0' size selection on a 4K screen and
                    # an improbably small selection on an HD screen so assume user
                    # has just clicked the image and set fraction to 0.5
                    fraction = 0.5
                else:
                    fraction = numpy.sqrt(selectionsize / geomsize)

                if self.activeTool == VIEWER_TOOL_ZOOMIN:
                    if selectionsize < MIN_SELECTION_SIZE_PX:
                        # user 'just clicked' (see if statement above).
                        # NOTE: this fixes issues with 0 or negative dimensions
                        #  inside else: below that used ot hard-crash tuiview

                        wldX, wldY = layer.coordmgr.display2world(
                            selection.left(), selection.top())
                        layer.coordmgr.setZoomFactor(
                            layer.coordmgr.imgPixPerWinPix * fraction)
                        layer.coordmgr.setWorldCenter(wldX, wldY)
                        # not sure why we need this but get black strips
                        # around otherwise
                        layer.coordmgr.recalcBottomRight()
                    else:
                        # I don't think anything needs to be added here
                        dspTop = selection.top()
                        dspLeft = selection.left()
                        dspBottom = selection.bottom()
                        dspRight = selection.right()
                        (rastLeft, rastTop) = layer.coordmgr.display2pixel(
                            dspLeft, dspTop)
                        (rastRight, rastBottom) = layer.coordmgr.display2pixel(
                            dspRight, dspBottom)
                        #print layer.coordmgr
                        layer.coordmgr.setTopLeftPixel(rastLeft, rastTop)
                        layer.coordmgr.calcZoomFactor(rastRight, rastBottom)
                        # not sure why we need this but get black strips
                        # around otherwise
                        layer.coordmgr.recalcBottomRight()
                        #print layer.coordmgr

                elif self.activeTool == VIEWER_TOOL_ZOOMOUT:
                    # the smaller the area the larger the zoom
                    center = selection.center()
                    wldX, wldY = layer.coordmgr.display2world(
                        center.x(), center.y())
                    layer.coordmgr.setZoomFactor(
                        layer.coordmgr.imgPixPerWinPix / fraction)
                    layer.coordmgr.setWorldCenter(wldX, wldY)
                    # not sure why we need this but get black strips
                    # around otherwise
                    layer.coordmgr.recalcBottomRight()

                # redraw
                self.layers.makeLayersConsistent(layer)
                self.layers.updateImages()
                self.viewport().update()
                self.updateScrollBars()

                # geolink
                self.emitGeolinkMoved()

        elif self.activeTool == VIEWER_TOOL_PAN:
            # change cursor back
            self.viewport().setCursor(self.panCursor)
            layer = self.layers.getTopRasterLayer()
            if layer is not None:
                # stop panning and move viewport
                dspXmove = -self.paintPoint.x()
                dspYmove = -self.paintPoint.y()
                (pixNewX,
                 pixNewY) = layer.coordmgr.display2pixel(dspXmove, dspYmove)
                #print 'panning'
                #print layer.coordmgr
                layer.coordmgr.setTopLeftPixel(pixNewX, pixNewY)
                layer.coordmgr.recalcBottomRight()
                #print layer.coordmgr
                # reset
                self.paintPoint.setX(0)
                self.paintPoint.setY(0)
                # redraw
                self.layers.makeLayersConsistent(layer)
                self.layers.updateImages()
                self.viewport().update()
                self.updateScrollBars()
                # geolink
                self.emitGeolinkMoved()

    def mouseMoveEvent(self, event):
        """
        Mouse has been moved while dragging. If in zoom/pan
        mode we need to do something here.
        """
        QAbstractScrollArea.mouseMoveEvent(self, event)
        if self.rubberBand is not None and self.rubberBand.isVisible():
            # must be doing zoom in/out. extend rect
            rect = QRect(self.rubberBand.origin, event.pos()).normalized()
            self.rubberBand.setGeometry(rect)

        elif self.activeTool == VIEWER_TOOL_PAN:
            # panning. Work out the offset from where we
            # starting panning and draw the current image
            # at an offset
            pos = event.pos()
            xamount = pos.x() - self.panOrigin.x()
            yamount = pos.y() - self.panOrigin.y()
            self.paintPoint.setX(xamount)
            self.paintPoint.setY(yamount)
            # force repaint - self.paintPoint used by paintEvent()
            self.viewport().update()
            self.updateScrollBars()

    # query point routines
    def newQueryPoint(self,
                      easting=None,
                      northing=None,
                      dspY=None,
                      dspX=None,
                      column=None,
                      row=None,
                      modifiers=None):
        """
        This viewer has recorded a new query point. Or
        user has entered new coords in querywindow.

        Calls updateQueryPoint and emits the geolinkQueryPoint signal

        pass either [easting and northing] or [dspX,dspY] or [column, row]
        """
        if self.queryOnlyDisplayed:
            layer = self.layers.getTopDisplayedRasterLayer()
        else:
            layer = self.layers.getTopRasterLayer()
        if layer is None:
            return

        if ((easting is None or northing is None)
                and (dspX is None or dspY is None)
                and (column is None or row is None)):
            msg = ("must provide one of [easting,northing] or [dspX,dspY] " +
                   "or [column, row]")
            raise ValueError(msg)

        if dspX is not None and dspY is not None:
            (column, row) = layer.coordmgr.display2pixel(dspX, dspY)
            (easting, northing) = layer.coordmgr.pixel2world(column, row)
        elif easting is not None and northing is not None:
            (column, row) = layer.coordmgr.world2pixel(easting, northing)
        elif column is not None and row is not None:
            (easting, northing) = layer.coordmgr.pixel2world(column, row)

        # update the point
        self.updateQueryPoint(easting, northing, column, row, modifiers)

        # emit the geolinked query point signal
        obj = GeolinkInfo(id(self), easting, northing)
        self.geolinkQueryPoint.emit(obj)

    def newVectorQueryPoint(self, dspX, dspY, modifiers=None):
        """
        New vector query point. Does the spatial query
        and emits the vectorLocationSelected signal with
        the results
        """
        if self.queryOnlyDisplayed:
            layer = self.layers.getTopDisplayedVectorLayer()
        else:
            layer = self.layers.getTopVectorLayer()
        if layer is None:
            return

        (easting, northing) = layer.coordmgr.display2world(dspX, dspY)
        tolerance = layer.coordmgr.metersperpix * 3  # maybe should be a pref?

        # show hourglass while query running
        oldCursor = self.cursor()
        self.setCursor(Qt.WaitCursor)

        results = layer.getAttributesAtPoint(easting, northing, tolerance)

        self.setCursor(oldCursor)

        self.vectorLocationSelected.emit(results, layer)

    def updateQueryPoint(self, easting, northing, column, row, modifiers):
        """
        Map has been clicked, get the value and emit
        a locationSelected signal.
        Called by newQueryPoint or when a geolinkQueryPoint signal
        has been received.
        """
        # read the data out of the dataset
        if self.queryOnlyDisplayed:
            layer = self.layers.getTopDisplayedRasterLayer()
        else:
            layer = self.layers.getTopRasterLayer()
        if (layer is not None and column >= 0
                and column < layer.gdalDataset.RasterXSize and row >= 0
                and row < layer.gdalDataset.RasterYSize):
            data = layer.gdalDataset.ReadAsArray(int(column), int(row), 1, 1)
            if data is not None:
                # we just want the single 'drill down' of data as a 1d array
                data = data[..., 0, 0]
                # if single band GDAL gives us a single value -
                # convert back to array
                # to make life easier
                if data.size == 1:
                    data = numpy.array([data])

                qi = QueryInfo(easting, northing, column, row, data, layer,
                               modifiers)
                # emit the signal - handled by the QueryDockWidget
                self.locationSelected.emit(qi)

    def doGeolinkQueryPoint(self, easting, northing):
        """
        Call this when the widget query point has been moved
        in another viewer and should be updated in this
        one if the query tool is active.
        """
        if self.activeTool == VIEWER_TOOL_QUERY:
            if self.queryOnlyDisplayed:
                layer = self.layers.getTopDisplayedRasterLayer()
            else:
                layer = self.layers.getTopRasterLayer()
            if layer is not None:
                (col, row) = layer.coordmgr.world2pixel(easting, northing)
                self.updateQueryPoint(easting, northing, col, row, None)

    # geolinking routines
    def doGeolinkMove(self, easting, northing, metresperwinpix):
        """
        Call this when widget needs to be moved because
        of geolinking event.
        """
        layer = self.layers.getTopRasterLayer()
        if layer is not None:
            if self.geolinkFollowExtent and metresperwinpix != 0:
                imgpixperwinpix = metresperwinpix / layer.coordmgr.geotransform[
                    1]
                layer.coordmgr.setZoomFactor(imgpixperwinpix)

            layer.coordmgr.setWorldCenter(easting, northing)
            self.layers.makeLayersConsistent(layer)
            self.layers.updateImages()
            self.updateScrollBars()
            self.viewport().update()

    def getGeolinkInfo(self):
        """
        Called by emitGeolinkMoved and anything else that needs the
        current GeolinkInfo
        """
        info = None
        # get the coords of the current centre
        layer = self.layers.getTopRasterLayer()
        if layer is not None:
            easting, northing = layer.coordmgr.getWorldCenter()
            metresperwinpix = (layer.coordmgr.imgPixPerWinPix *
                               layer.coordmgr.geotransform[1])
            info = GeolinkInfo(id(self), easting, northing, metresperwinpix)
        return info

    def emitGeolinkMoved(self):
        """
        Call this on each zoom/pan to emit the appropriate signal.
        """
        info = self.getGeolinkInfo()
        if info is not None:
            # emit the signal
            self.geolinkMove.emit(info)
コード例 #7
0
ファイル: QgsVideo.py プロジェクト: Mariosmsk/QGISFMV
class VideoWidget(QVideoWidget):
    def __init__(self, parent=None):
        ''' Constructor '''
        super(VideoWidget, self).__init__(parent)
        self.surface = VideoWidgetSurface(self)
        self.Tracking_RubberBand = QRubberBand(QRubberBand.Rectangle, self)

        self.Censure_RubberBand = QRubberBand(QRubberBand.Rectangle, self)

        pal = QPalette()
        pal.setBrush(QPalette.Highlight, QBrush(QColor(Qt.blue)))
        self.Tracking_RubberBand.setPalette(pal)

        pal = QPalette()
        pal.setBrush(QPalette.Highlight, QBrush(QColor(Qt.black)))
        self.Censure_RubberBand.setPalette(pal)

        self.var_currentMouseMoveEvent = None

        self._interaction = InteractionState()
        self._filterSatate = FilterState()

        self.setUpdatesEnabled(True)
        self.snapped = False
        self.zoomed = False
        self._isinit = False
        self.gt = None

        self.drawCesure = []
        self.poly_coordinates, self.drawPtPos, self.drawLines, self.drawRuler, self.drawPolygon = [], [], [], [], []
        self.poly_RubberBand = QgsRubberBand(iface.mapCanvas(),
                                             True)  # Polygon type
        # set rubber band style
        color = QColor(176, 255, 128)
        self.poly_RubberBand.setColor(color)
        color.setAlpha(190)
        self.poly_RubberBand.setStrokeColor(color)
        self.poly_RubberBand.setWidth(3)

        self.parent = parent.parent()

        self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)

        self.setAttribute(Qt.WA_NoSystemBackground)
        self.setAttribute(Qt.WA_PaintOnScreen)
        self.setAttribute(Qt.WA_OpaquePaintEvent)
        self.setAttribute(Qt.WA_DeleteOnClose)
        palette = self.palette()
        palette.setColor(QPalette.Background, Qt.black)
        self.setPalette(palette)
        self.setSizePolicy(QSizePolicy.MinimumExpanding,
                           QSizePolicy.MinimumExpanding)

        self.offset, self.origin, self.pressPos, self.dragPos = QPoint(
        ), QPoint(), QPoint(), QPoint()
        self.tapTimer = QBasicTimer()
        self.zoomPixmap, self.maskPixmap = QPixmap(), QPixmap()

    def removeLastLine(self):
        ''' Remove Last Line Objects '''
        if len(self.drawLines) > 0:
            for pt in range(len(self.drawLines) - 1, -1, -1):
                del self.drawLines[pt]
                try:
                    if self.drawLines[pt - 1][0] is None:
                        break
                except Exception:
                    None
            self.UpdateSurface()
            AddDrawLineOnMap(self.drawLines)
        return

    def removeLastSegmentLine(self):
        ''' Remove Last Segment Line Objects '''
        if len(self.drawLines) > 0:
            del self.drawLines[-1]
            self.UpdateSurface()
            AddDrawLineOnMap(self.drawLines)
        return

    def removeAllLines(self):
        ''' Resets Line List '''
        self.drawLines = []
        self.UpdateSurface()
        # Clear all Layer
        RemoveAllDrawLineOnMap()

    def ResetDrawRuler(self):
        ''' Resets Ruler List '''
        self.drawRuler = []

    def removeAllCensure(self):
        ''' Remove All Censure Objects '''
        self.drawCesure = []

    def removeLastCensured(self):
        ''' Remove Last Censure Objects '''
        if len(self.drawCesure) > 0:
            del self.drawCesure[-1]

    def removeLastPoint(self):
        ''' Remove All Point Drawer Objects '''
        if len(self.drawPtPos) > 0:
            del self.drawPtPos[-1]
            self.UpdateSurface()
            RemoveLastDrawPointOnMap()
        return

    def removeAllPoint(self):
        ''' Remove All Point Drawer Objects '''
        self.drawPtPos = []
        self.UpdateSurface()
        # Clear all Layer
        RemoveAllDrawPointOnMap()
        return

    def removeAllPolygon(self):
        ''' Remove All Polygon Drawer Objects '''
        self.drawPolygon = []
        self.UpdateSurface()
        # Clear all Layer
        RemoveAllDrawPolygonOnMap()

    def removeLastPolygon(self):
        ''' Remove Last Polygon Drawer Objects '''
        if len(self.drawPolygon) > 0:
            for pt in range(len(self.drawPolygon) - 1, -1, -1):
                del self.drawPolygon[pt]
                try:
                    if self.drawPolygon[pt - 1][0] is None:
                        break
                except Exception:
                    None
            self.UpdateSurface()
            # remove last index layer
            RemoveLastDrawPolygonOnMap()

    def currentMouseMoveEvent(self, event):
        self.var_currentMouseMoveEvent = event

    def keyPressEvent(self, event):
        ''' Exit fullscreen '''
        if event.key() == Qt.Key_Escape and self.isFullScreen():
            self.setFullScreen(False)
            event.accept()
        elif event.key() == Qt.Key_Enter and event.modifiers() & Qt.Key_Alt:
            self.setFullScreen(not self.isFullScreen())
            event.accept()
        else:
            super(VideoWidget, self).keyPressEvent(event)

    def mouseDoubleClickEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if GetImageHeight() == 0:
            return

        if (not vut.IsPointOnScreen(event.x(), event.y(), self.surface)):
            return

        if self.gt is not None and self._interaction.lineDrawer:
            self.drawLines.append([None, None, None])
            self.UpdateSurface()
            return
        if self.gt is not None and self._interaction.ruler:
            self.drawRuler.append([None, None, None])
            self.UpdateSurface()
            return
        if self.gt is not None and self._interaction.polygonDrawer:
            self.drawPolygon.append([None, None, None])

            AddDrawPolygonOnMap(self.poly_coordinates)

            # Empty RubberBand
            for _ in range(self.poly_RubberBand.numberOfVertices()):
                self.poly_RubberBand.removeLastPoint()
            # Empty List
            self.poly_coordinates = []
            self.UpdateSurface()
            return

        self.setFullScreen(not self.isFullScreen())
        event.accept()

    def videoSurface(self):
        ''' Return video Surface '''
        return self.surface

    def UpdateSurface(self):
        ''' Update Video Surface '''
        self.surface.widget.update()

    def sizeHint(self):
        ''' This property holds the recommended size for the widget '''
        return self.surface.surfaceFormat().sizeHint()

    def GetCurrentFrame(self):
        ''' Return current frame QImage '''
        return self.surface.image

    def SetInvertColor(self, value):
        ''' Set Invert color filter '''
        self._filterSatate.invertColorFilter = value

    def SetObjectTracking(self, value):
        ''' Set Object Tracking '''
        self._interaction.objectTracking = value

    def SetRuler(self, value):
        ''' Set Ruler '''
        self._interaction.ruler = value

    def SetHandDraw(self, value):
        ''' Set Hand Draw '''
        self._interaction.HandDraw = value

    def SetCensure(self, value):
        ''' Set Censure Video Parts '''
        self._interaction.censure = value

    def SetGray(self, value):
        ''' Set gray scale '''
        self._filterSatate.grayColorFilter = value

    def SetMirrorH(self, value):
        ''' Set Horizontal Mirror '''
        self._filterSatate.MirroredHFilter = value

    def SetEdgeDetection(self, value):
        ''' Set Canny Edge filter '''
        self._filterSatate.edgeDetectionFilter = value

    def SetAutoContrastFilter(self, value):
        ''' Set Automatic Contrast filter '''
        self._filterSatate.contrastFilter = value

    def SetMonoFilter(self, value):
        ''' Set mono filter '''
        self._filterSatate.monoFilter = value

    def RestoreFilters(self):
        ''' Remove and restore all video filters '''
        self._filterSatate.clear()

    def RestoreDrawer(self):
        ''' Remove and restore all Drawer Options '''
        self._interaction.clear()

    def paintEvent(self, event):
        ''' Paint Event '''
        self.gt = GetGCPGeoTransform()

        self.painter = QPainter(self)
        self.painter.setRenderHint(QPainter.HighQualityAntialiasing)

        if (self.surface.isActive()):
            videoRect = self.surface.videoRect()
            if not videoRect.contains(event.rect()):
                region = event.region()
                region.subtracted(QRegion(videoRect))
                brush = self.palette().window()
                for rect in region.rects():
                    self.painter.fillRect(rect, brush)

            try:
                self.painter = self.surface.paint(self.painter)
            except Exception:
                None
        else:
            self.painter.fillRect(event.rect(), self.palette().window())
        try:
            SetImageSize(self.surface.currentFrame.width(),
                         self.surface.currentFrame.height())
        except Exception:
            None

        # Draw On Video
        draw.drawOnVideo(self.drawPtPos, self.drawLines, self.drawPolygon,
                         self.drawRuler, self.drawCesure, self.painter,
                         self.surface, self.gt)

        # Magnifier Glass
        if self.zoomed and self._interaction.magnifier:
            draw.drawMagnifierOnVideo(self.width(), self.height(),
                                      self.maskPixmap, self.dragPos,
                                      self.zoomPixmap, self.surface,
                                      self.painter, self.offset)

        self.painter.end()
        return

    def resizeEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        QWidget.resizeEvent(self, event)
        self.zoomed = False
        self.surface.updateVideoRect()

    def mouseMoveEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if GetImageHeight() == 0:
            return

        # check if the point  is on picture (not in black borders)
        if (not vut.IsPointOnScreen(event.x(), event.y(), self.surface)):
            return

        if self._interaction.pointDrawer or self._interaction.polygonDrawer or self._interaction.lineDrawer or self._interaction.ruler:
            self.setCursor(QCursor(Qt.CrossCursor))

        # Cursor Coordinates
        if self.gt is not None:

            Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                event, self.surface)

            txt = "<span style='font-size:10pt; font-weight:bold;'>Lon :</span>"
            txt += "<span style='font-size:9pt; font-weight:normal;'>" + \
                ("%.3f" % Longitude) + "</span>"
            txt += "<span style='font-size:10pt; font-weight:bold;'> Lat :</span>"
            txt += "<span style='font-size:9pt; font-weight:normal;'>" + \
                ("%.3f" % Latitude) + "</span>"

            if hasElevationModel():
                txt += "<span style='font-size:10pt; font-weight:bold;'> Alt :</span>"
                txt += "<span style='font-size:9pt; font-weight:normal;'>" + \
                    ("%.0f" % Altitude) + "</span>"
            else:
                txt += "<span style='font-size:10pt; font-weight:bold;'> Alt :</span>"
                txt += "<span style='font-size:9pt; font-weight:normal;'>-</span>"

            self.parent.lb_cursor_coord.setText(txt)

        else:
            self.parent.lb_cursor_coord.setText(
                "<span style='font-size:10pt; font-weight:bold;'>Lon :</span>"
                + "<span style='font-size:9pt; font-weight:normal;'>-</span>" +
                "<span style='font-size:10pt; font-weight:bold;'> Lat :</span>"
                + "<span style='font-size:9pt; font-weight:normal;'>-</span>" +
                "<span style='font-size:10pt; font-weight:bold;'> Alt :</span>"
                + "<span style='font-size:9pt; font-weight:normal;'>-</span>")

        if not event.buttons():
            return

        if not self.Tracking_RubberBand.isHidden():
            self.Tracking_RubberBand.setGeometry(
                QRect(self.origin, event.pos()).normalized())

        if not self.Censure_RubberBand.isHidden():
            self.Censure_RubberBand.setGeometry(
                QRect(self.origin, event.pos()).normalized())

        if not self.zoomed:
            delta = event.pos() - self.pressPos
            if not self.snapped:
                self.pressPos = event.pos()
                self.pan(delta)
                self.tapTimer.stop()
                return
            else:
                threshold = 10
                self.snapped &= delta.x() < threshold
                self.snapped &= delta.y() < threshold
                self.snapped &= delta.x() > -threshold
                self.snapped &= delta.y() > -threshold

        else:
            self.dragPos = event.pos()
            self.surface.updateVideoRect()

    def pan(self, delta):
        """ Pan Action (Magnifier method)"""
        self.offset += delta
        self.surface.updateVideoRect()

    def timerEvent(self, _):
        """ Time Event (Magnifier method)"""
        if not self.zoomed:
            self.activateMagnifier()
        self.surface.updateVideoRect()

    def mousePressEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if GetImageHeight() == 0:
            return

        if event.button() == Qt.LeftButton:
            self.snapped = True
            self.pressPos = self.dragPos = event.pos()
            self.tapTimer.stop()
            self.tapTimer.start(100, self)

            if (not vut.IsPointOnScreen(event.x(), event.y(), self.surface)):
                self.UpdateSurface()
                return

            # point drawer
            if self.gt is not None and self._interaction.pointDrawer:
                Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                    event, self.surface)

                pointIndex = len(self.drawPtPos) + 1
                AddDrawPointOnMap(pointIndex, Longitude, Latitude, Altitude)

                self.drawPtPos.append([Longitude, Latitude, Altitude])

            # polygon drawer
            if self.gt is not None and self._interaction.polygonDrawer:
                Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                    event, self.surface)
                self.poly_RubberBand.addPoint(QgsPointXY(Longitude, Latitude))
                self.poly_coordinates.extend(QgsPointXY(Longitude, Latitude))
                self.drawPolygon.append([Longitude, Latitude, Altitude])

            # line drawer
            if self.gt is not None and self._interaction.lineDrawer:
                Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                    event, self.surface)

                self.drawLines.append([Longitude, Latitude, Altitude])

                AddDrawLineOnMap(self.drawLines)

            if self._interaction.objectTracking:
                self.origin = event.pos()
                self.Tracking_RubberBand.setGeometry(
                    QRect(self.origin, QSize()))
                self.Tracking_RubberBand.show()

            if self._interaction.censure:
                self.origin = event.pos()
                self.Censure_RubberBand.setGeometry(QRect(
                    self.origin, QSize()))
                self.Censure_RubberBand.show()

            # Ruler drawer
            if self.gt is not None and self._interaction.ruler:
                Longitude, Latitude, Altitude = vut.GetPointCommonCoords(
                    event, self.surface)
                self.drawRuler.append([Longitude, Latitude, Altitude])

        # if not called, the paint event is not triggered.
        self.UpdateSurface()

    def activateMagnifier(self):
        """ Activate Magnifier Glass """
        self.zoomed = True
        self.tapTimer.stop()
        self.surface.updateVideoRect()

    def SetMagnifier(self, value):
        """ Set Magnifier Glass """
        self._interaction.magnifier = value

    def SetPointDrawer(self, value):
        """ Set Point Drawer """
        self._interaction.pointDrawer = value

    def SetLineDrawer(self, value):
        """ Set Line Drawer """
        self._interaction.lineDrawer = value

    def SetPolygonDrawer(self, value):
        """ Set Polygon Drawer """
        self._interaction.polygonDrawer = value

    def mouseReleaseEvent(self, _):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if self._interaction.censure:
            geom = self.Tracking_RubberBand.geometry()
            self.Censure_RubberBand.hide()
            self.drawCesure.append([geom])

        if self._interaction.objectTracking:
            geom = self.Tracking_RubberBand.geometry()
            bbox = (geom.x(), geom.y(), geom.width(), geom.height())
            frame = convertQImageToMat(self.GetCurrentFrame())
            self.Tracking_RubberBand.hide()
            self.tracker = cv2.TrackerBoosting_create()
            self.tracker.clear()
            ok = self.tracker.init(frame, bbox)
            if ok:
                self._isinit = True
            else:
                self._isinit = False

    def leaveEvent(self, _):
        self.parent.lb_cursor_coord.setText("")
        self.setCursor(QCursor(Qt.ArrowCursor))
コード例 #8
0
ファイル: QMUtil.py プロジェクト: sw-Cheon/ROS-EYE
class ImageViewer(QLabel):
    def __init__(self):
        super(ImageViewer, self).__init__()
        self.crop = Signal()
        #pixmap = QPixmap(640, 640)
        pixmap = QPixmap()
        self.setPixmap(pixmap)


        self.first_x, self.first_y = None, None
        self.last_x, self.last_y = None, None
        self.pen_color = QColor('#000000')        
        self.scaleFactor = 0.0
        self.setBackgroundRole(QPalette.Base)
        #self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
        #self.setScaledContents(True)

        #self.setGeometry(QRect(110, 550, 640, 640))
        self.setText("Feature")
        #self.setAlignment(Qt.AlignTop | Qt.AlignLeft)
        self.setAlignment(Qt.AlignCenter)
        self.setWordWrap(False)
        #self.setFixedSize(640,640)
        self.createActions()
        self.show()


    def setImage(self, q_img):        
        self.setPixmap(q_img)
        self.scaleFactor = 1.0
        #self.fitToWindowAct.setEnabled(True)
        self.updateActions()

        if not self.fitToWindowAct.isChecked():
            self.adjustSize()

    def open(self):
        fileName, _ = QFileDialog.getOpenFileName(self, "Open File",
                QDir.currentPath())
        if fileName:
            image = QImage(fileName)
            if image.isNull():
                QMessageBox.information(self, "Image Viewer",
                        "Cannot load %s." % fileName)
                return

            self.setPixmap(QPixmap.fromImage(image))
            self.scaleFactor = 1.0

            self.fitToWindowAct.setEnabled(True)
            self.updateActions()

            if not self.fitToWindowAct.isChecked():
                self.adjustSize()


    def zoomIn(self):
        self.scaleImage(1.25)

    def zoomOut(self):
        self.scaleImage(0.8)

    def normalSize(self):
        self.adjustSize()
        self.scaleFactor = 1.0

    def fitToWindow(self):
        fitToWindow = self.fitToWindowAct.isChecked()
        self.scrollArea.setWidgetResizable(fitToWindow)
        if not fitToWindow:
            self.normalSize()

        self.updateActions()


    def createActions(self):
        self.openAct = QAction("&Open...", self, shortcut="Ctrl+O",
                triggered=self.open)

        self.zoomInAct = QAction("Zoom &In (25%)", self, shortcut="Ctrl++",
                enabled=False, triggered=self.zoomIn)

        self.zoomOutAct = QAction("Zoom &Out (25%)", self, shortcut="Ctrl+-",
                enabled=False, triggered=self.zoomOut)

        self.normalSizeAct = QAction("&Normal Size", self, shortcut="Ctrl+S",
                enabled=False, triggered=self.normalSize)

        self.fitToWindowAct = QAction("&Fit to Window", self, enabled=False,
                checkable=True, shortcut="Ctrl+F", triggered=self.fitToWindow)


    def updateActions(self):
        self.zoomInAct.setEnabled(not self.fitToWindowAct.isChecked())
        self.zoomOutAct.setEnabled(not self.fitToWindowAct.isChecked())
        self.normalSizeAct.setEnabled(not self.fitToWindowAct.isChecked())

    def scaleImage(self, factor):
        self.scaleFactor *= factor
        self.resize(self.scaleFactor * self.pixmap().size())
        self.zoomInAct.setEnabled(self.scaleFactor < 3.0)
        self.zoomOutAct.setEnabled(self.scaleFactor > 0.333)


    def mousePressEvent (self, eventQMouseEvent):
        self.originQPoint = self.mapFrom(self, eventQMouseEvent.pos())
        self.first_x = int(eventQMouseEvent.x())
        self.first_y = int(eventQMouseEvent.y())
        self.currentQRubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.currentQRubberBand.setGeometry(QRect(self.originQPoint, QSize()))
        self.currentQRubberBand.show()


    def mouseMoveEvent (self, eventQMouseEvent):
        self.x = int(eventQMouseEvent.x())
        self.y = int(eventQMouseEvent.y())
        text1 = str(self.x)
        text2 = str(self.y)
        p = self.mapToGlobal(eventQMouseEvent.pos())
        #QToolTip.showText(eventQMouseEvent.pos() , "X: "+text1+" "+"Y: "+text2,self)
        QToolTip.showText(p, "X: "+text1+" "+"Y: "+text2,self)
        # print ('mouse QToolTip 1') 전체장에서의 위젯 시작점의 좌표가 오리진 포인트가 되어야 함.
        '''
        if self.currentQRubberBand.isVisible():
            self.currentQRubberBand.setGeometry(QRect(self.originQPoint, eventQMouseEvent.pos()).normalized() & self.pixmap().rect())
        '''
        pos = self.mapFromGlobal(self.mapToGlobal(eventQMouseEvent.pos()))
        #QToolTip.showText(eventQMouseEvent.pos(), "X: {} Y: {}".format(p.x(), p.y()), self)
        if self.currentQRubberBand.isVisible() and self.pixmap() is not None:
            self.currentQRubberBand.setGeometry(QRect(self.originQPoint, pos).normalized() & self.rect())



    def mouseReleaseEvent (self, eventQMouseEvent):
        self.last_x = int(eventQMouseEvent.x())
        self.last_y = int(eventQMouseEvent.y())

        '''
        self.currentQRubberBand.hide()
        currentQRect = self.currentQRubberBand.geometry()
        self.currentQRubberBand.deleteLater()
        if self.pixmap() is not None:
            tr = QTransform()
            if self.fitToWindowAct.isChecked():
                tr.scale(self.pixmap().width() / self.scrollArea.width(),
                         self.pixmap().height() / self.scrollArea.height())
            else:
                tr.scale(1 / self.scaleFactor, 1 / self.scaleFactor)
            r = tr.mapRect(currentQRect)
            cropQPixmap = self.pixmap().copy(r)
            cropQPixmap.save('output.png')
        '''

        self.currentQRubberBand.hide()
        currentQRect = self.currentQRubberBand.geometry()
        self.currentQRubberBand.deleteLater()
        cropQPixmap = self.pixmap().copy(currentQRect)
        #size = cropQPixmap.size() 
        # 직접변환 해서 저장하는 코드... 나중에 
        #s = cropQPixmap.bits().asstring(size.width() * size.height() * image.depth() // 8)  # format 0xffRRGGBB
        #arr = np.fromstring(s, dtype=np.uint8).reshape((size.height(), size.width(), cropQPixmap.depth() // 8))
        #new_image = Image.fromarray(array)
        cropQPixmap.save('output.png')
        img = cv2.imread("output.png", cv2.IMREAD_COLOR)
        h, w = self.cut_imgSize()
        self.crop.cut_signal.emit(img, h, w)

    def cut_imgSize (self) :
        h = abs(self.last_y - self.first_y)
        w = abs(self.last_x - self.first_x)
        return h,w
コード例 #9
0
        class RubberbandEnhancedLabel(QLabel):

            def __init__(self, parent=None):
                self._parent_class = _parent_class
                QLabel.__init__(self, parent)
                self.selection = QRubberBand(QRubberBand.Rectangle, self)

            def mousePressEvent(self, event):
                '''
                    Mouse is pressed. If selection is visible either set dragging mode (if close to border) or hide selection.
                    If selection is not visible make it visible and start at this point.
                '''
                #
                if event.button() == Qt.LeftButton:

                    position = QPoint(event.pos())
                    if self.selection.isVisible():
                        # visible selection
                        if (self.upper_left - position).manhattanLength() < 20:
                            # close to upper left corner, drag it
                            self.mode = "drag_upper_left"
                        elif (self.lower_right - position).manhattanLength() < 20:
                            # close to lower right corner, drag it
                            self.mode = "drag_lower_right"
                        else:
                            # clicked somewhere else, hide selection
                            self.selection.hide()
                    else:
                        # no visible selection, start new selection
                        self.upper_left = position
                        self.lower_right = position
                        self.mode = "drag_lower_right"
                        self.selection.show()


            def mouseMoveEvent(self, event):
                '''
                    Mouse moved. If selection is visible, drag it according to drag mode.
                '''
                if self.selection.isVisible():
                    # visible selection
                    if self.mode == "drag_lower_right":
                        self.lower_right = QPoint(event.pos())
                    elif self.mode == "drag_upper_left":
                        self.upper_left = QPoint(event.pos())
                    # update geometry
                    self.selection.setGeometry(QRect(self.upper_left, self.lower_right).normalized())

            def mouseReleaseEvent(self, event):

                if self.selection.isVisible():
                    currentQRect = self.selection.geometry()
                    cropQPixmap = self.pixmap().copy(currentQRect)
                    cropQPixmap.save('output.png')

                    image = QImage("output.png")
                    if image.isNull():
                        QMessageBox.information(self.centralwidget, "Image Viewer", "Cannot load %s." % self.fileName)
                        return

                    pm = QPixmap.fromImage(image)
                    h = pm.height()
                    w = pm.width()

                    if (h > w):
                        self._parent_class.originalImageLabel.setPixmap(pm.scaledToHeight(400))

                    else:
                        self._parent_class.originalImageLabel.setPixmap(pm.scaledToWidth(400))



                    self.selection.hide()
コード例 #10
0
class VideoWidget(QVideoWidget):
    def __init__(self, parent=None):
        super(VideoWidget, self).__init__(parent)
        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        pal = QPalette()
        pal.setBrush(QPalette.Highlight, QBrush(QColor(Qt.green)))
        self.rubberBand.setPalette(pal)
        self.setUpdatesEnabled(True)
        self.setMouseTracking(True)
        self.origin = QPoint()
        self.changeRubberBand = False

        self.parent = parent.parent()
        self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)

        self.setAttribute(Qt.WA_NoSystemBackground, True)
        self.setAttribute(Qt.WA_PaintOnScreen, True)
        palette = self.palette()
        palette.setColor(QPalette.Background, Qt.black)
        self.setPalette(palette)
        self.setSizePolicy(QSizePolicy.MinimumExpanding,
                           QSizePolicy.MinimumExpanding)

        self.surface = VideoWidgetSurface(self)

        self.setAttribute(Qt.WA_OpaquePaintEvent)
        self.gt = None

        self.pressed = False
        self.snapped = False
        self.zoomed = False
        self.zoomedRect = False

        self.offset = QPoint()
        self.pressPos = QPoint()
        self.dragPos = QPoint()
        self.tapTimer = QBasicTimer()
        self.zoomPixmap = QPixmap()
        self.maskPixmap = QPixmap()

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape and self.isFullScreen():
            self.setFullScreen(False)
            event.accept()
        elif event.key() == Qt.Key_Enter and event.modifiers() & Qt.Key_Alt:
            self.setFullScreen(not self.isFullScreen())
            event.accept()
        else:
            super(VideoWidget, self).keyPressEvent(event)

    def mouseDoubleClickEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        self.setFullScreen(not self.isFullScreen())
        event.accept()

    def videoSurface(self):
        return self.surface

    def UpdateSurface(self):
        self.surface.widget.update()

    def sizeHint(self):
        return self.surface.surfaceFormat().sizeHint()

    def GetCurrentFrame(self):
        return self.surface.image

    def SetInvertColor(self, value):
        global invertColorFilter
        invertColorFilter = value

    def SetGray(self, value):
        global grayColorFilter
        grayColorFilter = value

    def SetEdgeDetection(self, value):
        global edgeDetectionFilter
        edgeDetectionFilter = value

    def SetAutoContrastFilter(self, value):
        global contrastFilter
        contrastFilter = value

    def SetMonoFilter(self, value):
        global monoFilter
        monoFilter = value

    def RestoreFilters(self):
        global invertColorFilter, grayColorFilter, edgeDetectionFilter, monoFilter, contrastFilter
        invertColorFilter = grayColorFilter = edgeDetectionFilter = monoFilter = contrastFilter = False

    def GetXBlackZone(self):
        x = 0.0
        normalizedWidth = self.surface.widget.height() * (GetImageWidth() /
                                                          GetImageHeight())
        if (self.surface.widget.width() / self.surface.widget.height()) > (
                GetImageWidth() / GetImageHeight()):
            x = (self.surface.widget.width() - (normalizedWidth)) / 2.0
        return x

    def GetYBlackZone(self):
        y = 0.0
        normalizedHeight = self.surface.widget.width() / (GetImageWidth() /
                                                          GetImageHeight())
        if (self.surface.widget.width() / self.surface.widget.height()) < (
                GetImageWidth() / GetImageHeight()):
            y = (self.surface.widget.height() - (normalizedHeight)) / 2.0
        return y

    # determines if a clicked point lands on the image (False if lands on the
    # black borders or outside)
    def IsPointOnScreen(self, x, y):
        res = True
        normalizedWidth = self.surface.widget.height() * (GetImageWidth() /
                                                          GetImageHeight())
        normalizedHeight = self.surface.widget.width() / (GetImageWidth() /
                                                          GetImageHeight())
        if x > (normalizedWidth +
                self.GetXBlackZone()) or x < self.GetXBlackZone():
            res = False
        if y > (normalizedHeight +
                self.GetYBlackZone()) or y < self.GetYBlackZone():
            res = False
        return res

    # ratio between event.x() and real image width on screen.
    def GetXRatio(self):
        return GetImageWidth() / (self.surface.widget.width() -
                                  (2 * self.GetXBlackZone()))

    # ratio between event.y() and real image height on screen.
    def GetYRatio(self):
        return GetImageHeight() / (self.surface.widget.height() -
                                   (2 * self.GetYBlackZone()))

    def paintEvent(self, event):
        self.gt = GetGCPGeoTransform()
        painter = QPainter(self)

        if (self.surface.isActive()):
            videoRect = self.surface.videoRect()
            if not videoRect.contains(event.rect()):
                region = event.region()
                region.subtracted(QRegion(videoRect))
                brush = self.palette().window()
                for rect in region.rects():
                    painter.fillRect(rect, brush)

            try:
                self.surface.paint(painter)
            except Exception:
                None
        else:
            painter.fillRect(event.rect(), self.palette().window())
        try:
            SetImageSize(self.surface.currentFrame.width(),
                         self.surface.currentFrame.height())
        except:
            None

        # Magnifier Glass
        if self.zoomed and magnifier:
            dim = min(self.width(), self.height())
            magnifierSize = min(MAX_MAGNIFIER, dim * 2 / 3)
            radius = magnifierSize / 2
            ring = radius - 15
            box = QSize(magnifierSize, magnifierSize)

            # reupdate our mask
            if self.maskPixmap.size() != box:
                self.maskPixmap = QPixmap(box)
                self.maskPixmap.fill(Qt.transparent)
                g = QRadialGradient()
                g.setCenter(radius, radius)
                g.setFocalPoint(radius, radius)
                g.setRadius(radius)
                g.setColorAt(1.0, QColor(64, 64, 64, 0))
                g.setColorAt(0.5, QColor(0, 0, 0, 255))
                mask = QPainter(self.maskPixmap)
                mask.setRenderHint(QPainter.Antialiasing)
                mask.setCompositionMode(QPainter.CompositionMode_Source)
                mask.setBrush(g)
                mask.setPen(Qt.NoPen)
                mask.drawRect(self.maskPixmap.rect())
                mask.setBrush(QColor(Qt.transparent))
                mask.drawEllipse(g.center(), ring, ring)
                mask.end()

            center = self.dragPos - QPoint(0, radius)
            center += QPoint(0, radius / 2)
            corner = center - QPoint(radius, radius)
            xy = center * 2 - QPoint(radius, radius)
            # only set the dimension to the magnified portion
            if self.zoomPixmap.size() != box:
                self.zoomPixmap = QPixmap(box)
                self.zoomPixmap.fill(Qt.lightGray)

            if True:
                painter = QPainter(self.zoomPixmap)
                painter.translate(-xy)
                self.largePixmap = QPixmap.fromImage(self.surface.image)
                painter.drawPixmap(self.offset, self.largePixmap)
                painter.end()

            clipPath = QPainterPath()
            clipPath.addEllipse(QPointF(center), ring, ring)
            painter = QPainter(self)
            painter.setRenderHint(QPainter.Antialiasing)
            painter.setClipPath(clipPath)
            painter.drawPixmap(corner, self.zoomPixmap)
            painter.drawPixmap(corner, self.maskPixmap)
            painter.setPen(Qt.gray)
            painter.drawPath(clipPath)
        return

    def resizeEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        QWidget.resizeEvent(self, event)
        self.zoomed = False
        if zoomRect and self.surface.zoomedrect is not None:
            self.surface.updatetest()
            return
        self.surface.updateVideoRect()

    def mouseMoveEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        # Cursor Coordinates
        if self.gt is not None:

            # check if the point  is on picture (not in black borders)
            if (not self.IsPointOnScreen(event.x(), event.y())):
                return

            transf = self.gt([
                (event.x() - self.GetXBlackZone()) * self.GetXRatio(),
                (event.y() - self.GetYBlackZone()) * self.GetYRatio()
            ])

            Longitude = transf[1]
            Latitude = transf[0]
            Altitude = 0.0

            self.parent.lb_cursor_coord.setText(
                "<span style='font-size:10pt; font-weight:bold;'>Lon :</span>"
                + "<span style='font-size:9pt; font-weight:normal;'>" +
                ("%.3f" % Longitude) + "</span>" +
                "<span style='font-size:10pt; font-weight:bold;'> Lat :</span>"
                + "<span style='font-size:9pt; font-weight:normal;'>" +
                ("%.3f" % Latitude) + "</span>")
        else:
            self.parent.lb_cursor_coord.setText(
                "<span style='font-size:10pt; font-weight:bold;'>Lon :</span>"
                +
                "<span style='font-size:9pt; font-weight:normal;'>Null</span>"
                +
                "<span style='font-size:10pt; font-weight:bold;'> Lat :</span>"
                +
                "<span style='font-size:9pt; font-weight:normal;'>Null</span>")

        if not event.buttons():
            return

        if self.changeRubberBand:
            self.rubberBand.setGeometry(
                QRect(self.origin, event.pos()).normalized())

        if self.zoomed is True:
            self.rubberBand.hide()
            self.zoomedRect = False

        if not self.zoomed:
            if not self.pressed or not self.snapped:
                delta = event.pos() - self.pressPos
                self.pressPos = event.pos()
                self.pan(delta)
                return
            else:
                threshold = 10
                delta = event.pos() - self.pressPos
                if self.snapped:
                    self.snapped &= delta.x() < threshold
                    self.snapped &= delta.y() < threshold
                    self.snapped &= delta.x() > -threshold
                    self.snapped &= delta.y() > -threshold

                if not self.snapped:
                    self.tapTimer.stop()

        else:
            self.dragPos = event.pos()
            self.surface.updateVideoRect()

#     TODO: MAKE PAINT GEOMETRY ACTION AND CREATE SHAPES

    def pan(self, delta):
        """ Pan Action """
        self.offset += delta
        self.surface.updateVideoRect()

    def timerEvent(self, _):
        """ Time Event """
        if not self.zoomed:
            self.activateMagnifier()
        self.surface.updateVideoRect()

    def mousePressEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if event.button() == Qt.LeftButton:
            self.pressed = self.snapped = True
            self.pressPos = self.dragPos = event.pos()
            self.tapTimer.stop()
            self.tapTimer.start(HOLD_TIME, self)

        if zoomRect and event.button() == Qt.LeftButton:
            self.origin = event.pos()
            self.rubberBand.setGeometry(QRect(self.origin, QSize()))
            self.rubberBand.show()
            self.changeRubberBand = True

    def activateMagnifier(self):
        """ Activate Magnifier Glass """
        self.zoomed = True
        self.tapTimer.stop()
        self.surface.updateVideoRect()

    def SetMagnifier(self, value):
        """ Set Magnifier Glass """
        global magnifier
        magnifier = value

    def SetZoomRect(self, value):
        """ Set Zoom Rectangle """
        global zoomRect
        zoomRect = value

    def mouseReleaseEvent(self, _):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        self.changeRubberBand = False
        if self.zoomed is True:
            return
        self.zoomed = False
        if not zoomRect:
            self.surface.updateVideoRect()
        else:
            self.rubberBand.hide()
            self.zoomedRect = True

            # TODO :  ACTUALIZAR LA IMAGEN
            selRect = self.rubberBand.geometry()

            orig2widgScale = self.surface.widget.contentsRect().width() / \
                self.surface.image.width()

            X1 = selRect.topLeft().x() / orig2widgScale
            Y1 = selRect.topLeft().y() / orig2widgScale
            X2 = selRect.bottomRight().x() / self.surface.widget.contentsRect().bottomRight().x() * \
                self.surface.image.width()
            Y2 = selRect.bottomRight().y() / self.surface.widget.contentsRect().bottomRight().y() * \
                self.surface.image.height()

            self.surface.image.width()
            self.surface.image.height()

            wid2origRect = QRect(X1, Y1, X2, Y2)
            zoom_img = self.surface.image.copy(wid2origRect)
            # zoom_img.save('D:\\test.png')
            #             n_img = self.surface.image.copy(selRect)
            #             n_img.save('D:\\test.png')
            zoom_img.scaled(1920, 1080)
            self.surface.currentFrame = QVideoFrame(zoom_img)
            #             self.surface.targetRect=selRect
            self.surface.currentFrame.unmap()
            self.UpdateSurface()

    def leaveEvent(self, _):
        self.parent.lb_cursor_coord.setText("")
コード例 #11
0
ファイル: canvas2d.py プロジェクト: opme/dxf2gcode
class MyGraphicsView(CanvasBase):
    """
    This is the used Canvas to print the graphical interface of dxf2gcode.
    All GUI things should be performed in the View and plotting functions in
    the scene
    """

    def __init__(self, parent=None):
        """
        Initialisation of the View Object. This is called by the gui created
        with the QTDesigner.
        @param parent: Main is passed as a pointer for reference.
        """
        super(MyGraphicsView, self).__init__(parent)
        self.currentItem = None

        self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
        self.setResizeAnchor(QGraphicsView.AnchorViewCenter)

        # self.setDragMode(QGraphicsView.RubberBandDrag )
        self.setDragMode(QGraphicsView.NoDrag)

        self.parent = parent
        self.mppos = None

        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        self.prvRectRubberBand = QtCore.QRect()

    def tr(self, string_to_translate):
        """
        Translate a string using the QCoreApplication translation framework
        @param string_to_translate: a unicode string
        @return: the translated unicode string if it was possible to translate
        """
        return text_type(QtCore.QCoreApplication.translate('MyGraphicsView',
                                                           string_to_translate))

    def contextMenuEvent(self, event):
        """
        Create the contextmenu.
        @purpose: Links the new Class of ContextMenu to Graphicsview.
        """
        position = self.mapToGlobal(event.pos())
        GVPos = self.mapToScene(event.pos())
        real_pos = Point(GVPos.x(), -GVPos.y())

        menu = MyDropDownMenu(self.scene(), position, real_pos)

    def wheelEvent(self, event):
        """
        With Mouse Wheel the object is scaled
        @purpose: Scale by mouse wheel
        @param event: Event Parameters passed to function
        """
        if c.PYQT5notPYQT4:
            delta = event.angleDelta().y()
        else:
            delta = event.delta()
        scale = (1000 + delta) / 1000.0
        self.scale(scale, scale)

    def mousePressEvent(self, event):
        """
        Right Mouse click shall have no function, Therefore pass only left
        click event
        @purpose: Change inherited mousePressEvent
        @param event: Event Parameters passed to function
        """

        if self.dragMode() == 1:
            super(MyGraphicsView, self).mousePressEvent(event)
        elif event.button() == QtCore.Qt.LeftButton:
            self.mppos = event.pos()
        else:
            pass

    def mouseReleaseEvent(self, event):
        """
        Right Mouse click shall have no function, Therefore pass only left
        click event
        @purpose: Change inherited mousePressEvent
        @param event: Event Parameters passed to function
        """
        delta = 2

        if self.dragMode() == 1:
            # if (event.key() == QtCore.Qt.Key_Shift):
            # self.setDragMode(QGraphicsView.NoDrag)
            super(MyGraphicsView, self).mouseReleaseEvent(event)

        # Selection only enabled for left Button
        elif event.button() == QtCore.Qt.LeftButton:
            self.currentItems = []
            scene = self.scene()
            if not self.isMultiSelect:
                for item in scene.selectedItems():
                    item.setSelected(False, False)
            # If the mouse button is pressed without movement of rubberband
            if self.rubberBand.isHidden():
                rect = QtCore.QRect(event.pos().x()-delta,
                                    event.pos().y() - delta,
                                    2 * delta, 2*delta)
                # logger.debug(rect)

                point = self.mapToScene(event.pos())
                min_distance = float(0x7fffffff)
                for item in self.items(rect):
                    itemDistance = item.contains_point(point)
                    if itemDistance < min_distance:
                        min_distance = itemDistance
                        self.currentItems = item
                if self.currentItems:
                    if self.currentItems.isSelected():
                        self.currentItems.setSelected(False, False)
                    else:
                        self.currentItems.setSelected(True, False)
            else:
                rect = self.rubberBand.geometry()
                self.currentItems = self.items(rect)
                self.rubberBand.hide()
                # logger.debug("Rubberband Selection")

                # All items in the selection
                # self.currentItems = self.items(rect)
                # print self.currentItems
                # logger.debug(rect)

                for item in self.currentItems:
                    if item.isSelected():
                        item.setSelected(False, False)
                    else:
                        # print (item.flags())
                        item.setSelected(True, False)

        else:
            pass

        self.mppos = None
        # super(MyGraphicsView, self).mouseReleaseEvent(event)

    def mouseMoveEvent(self, event):
        """
        MouseMoveEvent of the Graphiscview. May also be used for the Statusbar.
        @purpose: Get the MouseMoveEvent and use it for the Rubberband Selection
        @param event: Event Parameters passed to function
        """
        if self.mppos is not None:
            Point = event.pos() - self.mppos
            if Point.manhattanLength() > 3:
                # print 'the mouse has moved more than 3 pixels since the oldPosition'
                # print "Mouse Pointer is currently hovering at: ", event.pos()
                rect = QtCore.QRect(self.mppos, event.pos())
                '''
                The following is needed because of PyQt5 doesn't like to switch from sign
                 it will keep displaying last rectangle, i.e. you can end up will multiple rectangles
                '''
                if self.prvRectRubberBand.width() > 0 and not rect.width() > 0 or rect.width() == 0 or\
                   self.prvRectRubberBand.height() > 0 and not rect.height() > 0 or rect.height() == 0:
                    self.rubberBand.hide()
                self.rubberBand.setGeometry(rect.normalized())
                self.rubberBand.show()
                self.prvRectRubberBand = rect

        scpoint = self.mapToScene(event.pos())

        # self.setStatusTip('X: %3.1f; Y: %3.1f' % (scpoint.x(), -scpoint.y()))
        # works not as supposed to
        self.setToolTip('X: %3.1f; Y: %3.1f' %(scpoint.x(), -scpoint.y()))

        super(MyGraphicsView, self).mouseMoveEvent(event)

    def autoscale(self):
        """
        Automatically zooms to the full extend of the current GraphicsScene
        """
        scene = self.scene()
        width = scene.bottomRight.x - scene.topLeft.x
        height = scene.topLeft.y - scene.bottomRight.y
        scext = QtCore.QRectF(scene.topLeft.x, -scene.topLeft.y, width * 1.05, height * 1.05)
        self.fitInView(scext, QtCore.Qt.KeepAspectRatio)
        logger.debug(self.tr("Autoscaling to extend: %s") % scext)

    def setShowPathDirections(self, flag):
        """
        This function is called by the Main Window from the Menubar.
        @param flag: This flag is true if all Path Direction shall be shown
        """
        scene = self.scene()
        for shape in scene.shapes:
            shape.starrow.setallwaysshow(flag)
            shape.enarrow.setallwaysshow(flag)
            shape.stmove.setallwaysshow(flag)

    def resetAll(self):
        """
        Deletes the existing GraphicsScene.
        """
        scene = self.scene()
        del scene
コード例 #12
0
class VideoWidget(QVideoWidget):
    def __init__(self, parent=None):
        super(VideoWidget, self).__init__(parent)
        self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
        pal = QPalette()
        pal.setBrush(QPalette.Highlight, QBrush(QColor(Qt.green)))
        self.rubberBand.setPalette(pal)
        self.setUpdatesEnabled(True)
        self.setMouseTracking(True)
        self.origin = QPoint()
        self.changeRubberBand = False

        self.parent = parent.parent()
        self.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)

        self.setAttribute(Qt.WA_NoSystemBackground, True)
        self.setAttribute(Qt.WA_PaintOnScreen, True)
        palette = self.palette()
        palette.setColor(QPalette.Background, Qt.black)
        self.setPalette(palette)
        self.setSizePolicy(QSizePolicy.MinimumExpanding,
                           QSizePolicy.MinimumExpanding)

        self.surface = VideoWidgetSurface(self)

        self.setAttribute(Qt.WA_OpaquePaintEvent)
        self.gt = None

        self.pressed = False
        self.snapped = False
        self.zoomed = False
        self.zoomedRect = False

        self.offset = QPoint()
        self.pressPos = QPoint()
        self.drawPtPos = []
        self.drawLines = []
        self.dragPos = QPoint()
        self.tapTimer = QBasicTimer()
        self.zoomPixmap = QPixmap()
        self.maskPixmap = QPixmap()

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_Escape and self.isFullScreen():
            self.setFullScreen(False)
            event.accept()
        elif event.key() == Qt.Key_Enter and event.modifiers() & Qt.Key_Alt:
            self.setFullScreen(not self.isFullScreen())
            event.accept()
        else:
            super(VideoWidget, self).keyPressEvent(event)

    def mouseDoubleClickEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        self.setFullScreen(not self.isFullScreen())
        event.accept()

    def videoSurface(self):
        return self.surface

    def UpdateSurface(self):
        self.surface.widget.update()

    def sizeHint(self):
        return self.surface.surfaceFormat().sizeHint()

    def GetCurrentFrame(self):
        return self.surface.image

    def SetInvertColor(self, value):
        global invertColorFilter
        invertColorFilter = value

    def SetGray(self, value):
        global grayColorFilter
        grayColorFilter = value

    def SetEdgeDetection(self, value):
        global edgeDetectionFilter
        edgeDetectionFilter = value

    def SetAutoContrastFilter(self, value):
        global contrastFilter
        contrastFilter = value

    def SetMonoFilter(self, value):
        global monoFilter
        monoFilter = value

    def RestoreFilters(self):
        global invertColorFilter, grayColorFilter, edgeDetectionFilter, monoFilter, contrastFilter
        invertColorFilter = grayColorFilter = edgeDetectionFilter = monoFilter = contrastFilter = False

    def GetXBlackZone(self):
        x = 0.0
        normalizedWidth = self.surface.widget.height() * (GetImageWidth() /
                                                          GetImageHeight())
        if (self.surface.widget.width() / self.surface.widget.height()) > (
                GetImageWidth() / GetImageHeight()):
            x = (self.surface.widget.width() - (normalizedWidth)) / 2.0
        return x

    def GetYBlackZone(self):
        y = 0.0
        normalizedHeight = self.surface.widget.width() / (GetImageWidth() /
                                                          GetImageHeight())
        if (self.surface.widget.width() / self.surface.widget.height()) < (
                GetImageWidth() / GetImageHeight()):
            y = (self.surface.widget.height() - (normalizedHeight)) / 2.0
        return y

    # determines if a clicked point lands on the image (False if lands on the
    # black borders or outside)
    def IsPointOnScreen(self, x, y):
        res = True
        normalizedWidth = self.surface.widget.height() * (GetImageWidth() /
                                                          GetImageHeight())
        normalizedHeight = self.surface.widget.width() / (GetImageWidth() /
                                                          GetImageHeight())
        if x > (normalizedWidth +
                self.GetXBlackZone()) or x < self.GetXBlackZone():
            res = False
        if y > (normalizedHeight +
                self.GetYBlackZone()) or y < self.GetYBlackZone():
            res = False
        return res

    def GetXRatio(self):
        ''' ratio between event.x() and real image width on screen. '''
        return GetImageWidth() / (self.surface.widget.width() -
                                  (2 * self.GetXBlackZone()))

    def GetYRatio(self):
        ''' ratio between event.y() and real image height on screen. '''
        return GetImageHeight() / (self.surface.widget.height() -
                                   (2 * self.GetYBlackZone()))

    def paintEvent(self, event):
        self.gt = GetGCPGeoTransform()
        painter = QPainter(self)

        if (self.surface.isActive()):
            videoRect = self.surface.videoRect()
            if not videoRect.contains(event.rect()):
                region = event.region()
                region.subtracted(QRegion(videoRect))
                brush = self.palette().window()
                for rect in region.rects():
                    painter.fillRect(rect, brush)

            try:
                self.surface.paint(painter)
            except Exception:
                None
        else:
            painter.fillRect(event.rect(), self.palette().window())
        try:
            SetImageSize(self.surface.currentFrame.width(),
                         self.surface.currentFrame.height())
        except:
            None

        #Draw clicked points on video
        for pt in self.drawPtPos:
            #adds a mark on the video
            self.drawPointOnVideo(pt)

        #Draw clicked lines on video
        for pt in self.drawLines:
            #adds a mark on the video
            self.drawLinesOnVideo(pt)

        # Magnifier Glass
        if self.zoomed and magnifier:
            dim = min(self.width(), self.height())
            magnifierSize = min(MAX_MAGNIFIER, dim * 2 / 3)
            radius = magnifierSize / 2
            ring = radius - 15
            box = QSize(magnifierSize, magnifierSize)

            # reupdate our mask
            if self.maskPixmap.size() != box:
                self.maskPixmap = QPixmap(box)
                self.maskPixmap.fill(Qt.transparent)
                g = QRadialGradient()
                g.setCenter(radius, radius)
                g.setFocalPoint(radius, radius)
                g.setRadius(radius)
                g.setColorAt(1.0, QColor(64, 64, 64, 0))
                g.setColorAt(0.5, QColor(0, 0, 0, 255))
                mask = QPainter(self.maskPixmap)
                mask.setRenderHint(QPainter.Antialiasing)
                mask.setCompositionMode(QPainter.CompositionMode_Source)
                mask.setBrush(g)
                mask.setPen(Qt.NoPen)
                mask.drawRect(self.maskPixmap.rect())
                mask.setBrush(QColor(Qt.transparent))
                mask.drawEllipse(g.center(), ring, ring)
                mask.end()

            center = self.dragPos - QPoint(0, radius)
            center += QPoint(0, radius / 2)
            corner = center - QPoint(radius, radius)
            xy = center * 2 - QPoint(radius, radius)
            # only set the dimension to the magnified portion
            if self.zoomPixmap.size() != box:
                self.zoomPixmap = QPixmap(box)
                self.zoomPixmap.fill(Qt.lightGray)

            if True:
                painter = QPainter(self.zoomPixmap)
                painter.translate(-xy)
                self.largePixmap = QPixmap.fromImage(self.surface.image)
                painter.drawPixmap(self.offset, self.largePixmap)
                painter.end()

            clipPath = QPainterPath()
            clipPath.addEllipse(QPointF(center), ring, ring)
            painter = QPainter(self)
            painter.setRenderHint(QPainter.Antialiasing)
            painter.setClipPath(clipPath)
            painter.drawPixmap(corner, self.zoomPixmap)
            painter.drawPixmap(corner, self.maskPixmap)
            painter.setPen(Qt.gray)
            painter.drawPath(clipPath)
        return

    def GetInverseMatrix(self, x, y):
        ''' inverse matrix transformation (lon-lat to video units x,y) '''
        transf = (~self.gt)([x, y])
        scr_x = (transf[0] / self.GetXRatio()) + self.GetXBlackZone()
        scr_y = (transf[1] / self.GetYRatio()) + self.GetYBlackZone()
        return scr_x, scr_y

    def drawLinesOnVideo(self, pt):
        ''' Draw Lines on Video '''
        scr_x, scr_y = self.GetInverseMatrix(pt[1], pt[0])

        radius = 3
        center = QPoint(scr_x, scr_y)

        pen = QPen(Qt.yellow)
        pen.setWidth(radius)
        pen.setCapStyle(Qt.RoundCap)
        pen.setDashPattern([1, 4, 5, 4])
        painter_p = QPainter(self)
        painter_p.setPen(pen)
        painter_p.setRenderHint(QPainter.HighQualityAntialiasing, True)
        painter_p.drawPoint(center)

        if len(self.drawLines) > 1:
            try:
                idx = self.drawLines.index(pt)
                scr_x, scr_y = self.GetInverseMatrix(
                    self.drawLines[idx + 1][1], self.drawLines[idx + 1][0])
                end = QPoint(scr_x, scr_y)
                painter_p.drawLine(center, end)
            except:
                None

        return

    def drawPointOnVideo(self, pt):
        scr_x, scr_y = self.GetInverseMatrix(pt[1], pt[0])

        radius = 10
        center = QPoint(scr_x, scr_y)

        pen = QPen(Qt.red)
        pen.setWidth(radius)
        pen.setCapStyle(Qt.RoundCap)
        painter_p = QPainter(self)
        painter_p.setPen(pen)
        painter_p.setRenderHint(QPainter.HighQualityAntialiasing, True)
        painter_p.drawPoint(center)

        return

    def resizeEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        QWidget.resizeEvent(self, event)
        self.zoomed = False
        if zoomRect and self.surface.zoomedrect is not None:
            self.surface.updatetest()
            return
        self.surface.updateVideoRect()

    def mouseMoveEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        # check if the point  is on picture (not in black borders)
        if (not self.IsPointOnScreen(event.x(), event.y())):
            return

#         # Draw Line on the fly
#         if self.gt is not None and lineDrawer:
#                 if len(self.drawLines) > 0:
#                     scr_x, scr_y = self.GetInverseMatrix(self.drawLines[-1][1],self.drawLines[-1][1])
#
#                     radius = 3
#                     center = QPoint(scr_x, scr_y)
#
#                     pen = QPen(Qt.yellow)
#                     pen.setWidth(radius)
#                     pen.setCapStyle(Qt.RoundCap)
#                     pen.setDashPattern([1, 4, 5, 4])
#                     painter_p = QPainter(self)
#                     painter_p.setPen(pen)
#                     painter_p.setRenderHint(QPainter.HighQualityAntialiasing, True)
#                     painter_p.drawPoint(center)
#
#                     try:
#                         transf = self.gt([(event.x() - self.GetXBlackZone()) * self.GetXRatio(), (event.y() - self.GetYBlackZone()) * self.GetYRatio()])
#                         scr_x, scr_y = self.GetInverseMatrix(float(round(transf[1], 4)) , float(round(transf[0], 4)))
#                         end = QPoint(scr_x, scr_y)
#                         painter_p.drawLine(center, end)
#                         self.UpdateSurface()
#                     except:
#                         None

# Cursor Coordinates
        if self.gt is not None:

            transf = self.gt([
                (event.x() - self.GetXBlackZone()) * self.GetXRatio(),
                (event.y() - self.GetYBlackZone()) * self.GetYRatio()
            ])

            Longitude = transf[1]
            Latitude = transf[0]
            #Altitude = 0.0

            self.parent.lb_cursor_coord.setText(
                "<span style='font-size:10pt; font-weight:bold;'>Lon :</span>"
                + "<span style='font-size:9pt; font-weight:normal;'>" +
                ("%.3f" % Longitude) + "</span>" +
                "<span style='font-size:10pt; font-weight:bold;'> Lat :</span>"
                + "<span style='font-size:9pt; font-weight:normal;'>" +
                ("%.3f" % Latitude) + "</span>")
        else:
            self.parent.lb_cursor_coord.setText(
                "<span style='font-size:10pt; font-weight:bold;'>Lon :</span>"
                +
                "<span style='font-size:9pt; font-weight:normal;'>Null</span>"
                +
                "<span style='font-size:10pt; font-weight:bold;'> Lat :</span>"
                +
                "<span style='font-size:9pt; font-weight:normal;'>Null</span>")

        if not event.buttons():
            return

        if self.changeRubberBand:
            self.rubberBand.setGeometry(
                QRect(self.origin, event.pos()).normalized())

        if self.zoomed is True:
            self.rubberBand.hide()
            self.zoomedRect = False

        if not self.zoomed:
            if not self.pressed or not self.snapped:
                delta = event.pos() - self.pressPos
                self.pressPos = event.pos()
                self.pan(delta)
                return
            else:
                threshold = 10
                delta = event.pos() - self.pressPos
                if self.snapped:
                    self.snapped &= delta.x() < threshold
                    self.snapped &= delta.y() < threshold
                    self.snapped &= delta.x() > -threshold
                    self.snapped &= delta.y() > -threshold

                if not self.snapped:
                    self.tapTimer.stop()

        else:
            self.dragPos = event.pos()
            self.surface.updateVideoRect()

    def pan(self, delta):
        """ Pan Action """
        self.offset += delta
        self.surface.updateVideoRect()

    def timerEvent(self, _):
        """ Time Event """
        if not self.zoomed:
            self.activateMagnifier()
        self.surface.updateVideoRect()

    def mousePressEvent(self, event):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        if event.button() == Qt.LeftButton:
            self.pressed = self.snapped = True
            self.pressPos = self.dragPos = event.pos()
            self.tapTimer.stop()
            self.tapTimer.start(HOLD_TIME, self)

            #point drawer
            if self.gt is not None and pointDrawer:
                if (not self.IsPointOnScreen(event.x(), event.y())):
                    return

                transf = self.gt([
                    (event.x() - self.GetXBlackZone()) * self.GetXRatio(),
                    (event.y() - self.GetYBlackZone()) * self.GetYRatio()
                ])
                #targetAlt = GetFrameCenter()[2]
                Longitude = float(round(transf[1], 4))
                Latitude = float(round(transf[0], 4))
                #Altitude = targetAlt
                Altitude = 0.0
                #add pin point on the map
                pointLyr = qgsu.selectLayerByName(Point_lyr)
                pointLyr.startEditing()
                feature = QgsFeature()
                feature.setAttributes([Longitude, Latitude, Altitude])
                p = QgsPointXY()
                p.set(Longitude, Latitude)
                geom = QgsGeometry.fromPointXY(p)
                feature.setGeometry(geom)
                pointLyr.addFeatures([feature])

                CommonLayer(pointLyr)

                self.drawPtPos.append([Longitude, Latitude])
                #if not called, the paint event is not triggered.
                self.UpdateSurface()

            #line drawer
            if self.gt is not None and lineDrawer:
                if (not self.IsPointOnScreen(event.x(), event.y())):
                    return

                transf = self.gt([
                    (event.x() - self.GetXBlackZone()) * self.GetXRatio(),
                    (event.y() - self.GetYBlackZone()) * self.GetYRatio()
                ])
                #targetAlt = GetFrameCenter()[2]
                Longitude = float(round(transf[1], 4))
                Latitude = float(round(transf[0], 4))
                #Altitude = targetAlt
                Altitude = 0.0
                #add pin point on the map
                linelyr = qgsu.selectLayerByName(Line_lyr)
                linelyr.startEditing()
                feature = QgsFeature()
                f = QgsFeature()
                if linelyr.featureCount() == 0:
                    f.setAttributes([Longitude, Latitude, Altitude])
                    surface = QgsGeometry.fromPolylineXY([
                        QgsPointXY(Longitude, Latitude),
                        QgsPointXY(Longitude, Latitude)
                    ])
                    f.setGeometry(surface)
                    linelyr.addFeatures([f])

                else:
                    f_last = linelyr.getFeature(linelyr.featureCount())
                    f.setAttributes([Longitude, Latitude, Altitude])
                    surface = QgsGeometry.fromPolylineXY([
                        QgsPointXY(Longitude, Latitude),
                        QgsPointXY(f_last.attribute(0), f_last.attribute(1))
                    ])
                    f.setGeometry(surface)
                    linelyr.addFeatures([f])

                CommonLayer(linelyr)

                self.drawLines.append([Longitude, Latitude])
                #if not called, the paint event is not triggered.
                self.UpdateSurface()

        if zoomRect and event.button() == Qt.LeftButton:
            self.origin = event.pos()
            self.rubberBand.setGeometry(QRect(self.origin, QSize()))
            self.rubberBand.show()
            self.changeRubberBand = True

    def activateMagnifier(self):
        """ Activate Magnifier Glass """
        self.zoomed = True
        self.tapTimer.stop()
        self.surface.updateVideoRect()

    def SetMagnifier(self, value):
        """ Set Magnifier Glass """
        global magnifier
        magnifier = value

    def SetPointDrawer(self, value):
        """ Set Point Drawer """
        global pointDrawer
        pointDrawer = value

    def SetLineDrawer(self, value):
        """ Set Line Drawer """
        global lineDrawer
        lineDrawer = value

    def SetZoomRect(self, value):
        """ Set Zoom Rectangle """
        global zoomRect
        zoomRect = value

    def mouseReleaseEvent(self, _):
        """
        :type event: QMouseEvent
        :param event:
        :return:
        """
        self.changeRubberBand = False
        if self.zoomed is True:
            return
        self.zoomed = False
        if not zoomRect:
            self.surface.updateVideoRect()
        else:
            self.rubberBand.hide()
            self.zoomedRect = True

            # TODO :  make zoom rectangle functionality
            selRect = self.rubberBand.geometry()

            orig2widgScale = self.surface.widget.contentsRect().width() / \
                self.surface.image.width()

            X1 = selRect.topLeft().x() / orig2widgScale
            Y1 = selRect.topLeft().y() / orig2widgScale
            X2 = selRect.bottomRight().x() / self.surface.widget.contentsRect().bottomRight().x() * \
                self.surface.image.width()
            Y2 = selRect.bottomRight().y() / self.surface.widget.contentsRect().bottomRight().y() * \
                self.surface.image.height()

            self.surface.image.width()
            self.surface.image.height()

            wid2origRect = QRect(X1, Y1, X2, Y2)
            zoom_img = self.surface.image.copy(wid2origRect)
            #             zoom_img.save('D:\\test.png')
            #             n_img = self.surface.image.copy(selRect)
            #             n_img.save('D:\\test.png')
            zoom_img.scaled(1920, 1080)
            self.surface.currentFrame = QVideoFrame(zoom_img)
            #             self.surface.targetRect=selRect
            self.surface.currentFrame.unmap()
            self.UpdateSurface()

    def leaveEvent(self, _):
        self.parent.lb_cursor_coord.setText("")
コード例 #13
0
ファイル: main.py プロジェクト: fractal161/stackmaker
class View(QGraphicsView):
  def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    self.rubberBandActive = False
    self.rubberBand = QRubberBand(QRubberBand.Rectangle, self)
    self.baseRect = QRect()
    self.clearSelection()
    self.setStyleSheet("border: 1px solid black")

  # Returns a QRect that covers the scene tile the coords are over
  def _getBox(self, pos):
    scenePos = self.mapToScene(pos)
    newX = scenePos.x() // 8
    newY = scenePos.y() // 8
    topLeft = QPointF(8*newX, 8*newY)
    bottomRight = topLeft+QPointF(8.0,8.0)
    return QRect(self.mapFromScene(topLeft), self.mapFromScene(bottomRight))

  def setRect(self):
    self.setTransform(QTransform())
    self.scale(self.viewport().width() / max(1, self.sceneRect().width()), self.viewport().height() / max(1, self.sceneRect().height()))


  def toggleBand(self):
    self.rubberBandActive = not self.rubberBandActive
    if self.rubberBandActive:
      self.scene().cursor.setVisible(False)
    else:
      self.clearSelection()

  def clearSelection(self):
    self.rubberBand.setGeometry(QRect())

  def selection(self):
    return self.rubberBand.geometry()

  def sceneSelection(self):
    topLeft = self.rubberBand.geometry().topLeft()
    topLeft = self.mapToScene(topLeft)
    bottomRight = self.rubberBand.geometry().bottomRight()
    bottomRight = self.mapToScene(bottomRight)
    return QRectF(topLeft, bottomRight)

  def mousePressEvent(self, e):
    if self.rubberBandActive:
      if e.button() == Qt.LeftButton:
        if self.rubberBand.geometry() == QRect():
          self.baseRect = self._getBox(e.pos())
          self.rubberBand.setGeometry(self.baseRect)
          self.rubberBand.show()
        else:
          self.clearSelection()
    else:
      super().mousePressEvent(e)
      print(e.pos())
      print(self.mapToScene(e.pos()))
  def mouseMoveEvent(self, e):
    if self.rubberBandActive:
      if int(e.buttons()) & Qt.LeftButton and self.rubberBand.geometry() != QRect():
        newRect = self._getBox(e.pos())
        self.rubberBand.setGeometry(self.baseRect.united(newRect))
    else:
      super().mouseMoveEvent(e)


  def mouseReleaseEvent(self, e):
    super().mouseReleaseEvent(e)

  def mouseDoubleClickEvent(self, e):
    if not self.rubberBandActive:
      super().mouseDoubleClickEvent(e)
    # self.clearSelection()

  def paintEvent(self, e):
    super().paintEvent(e)
    painter = QPainter(self.viewport())
    painter.end()
コード例 #14
0
class ImageViewer(QGraphicsView, QObject):
    points_selection_sgn = pyqtSignal(list)
    key_press_sgn = pyqtSignal(QtGui.QKeyEvent)

    def __init__(self, parent=None):
        super(ImageViewer, self).__init__(parent)
        self.setDragMode(QGraphicsView.ScrollHandDrag)
        self.setRenderHints(QPainter.Antialiasing
                            | QPainter.SmoothPixmapTransform)
        self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
        self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)

        self._scene = ImageViewerScene(self)
        self.setScene(self._scene)
        self._image = None
        self._image_original = None
        self._pixmap = None
        self._img_contrast = 1.0
        self._img_brightness = 50.0
        self._img_gamma = 1.0
        self._create_grid()
        self._channels = []
        self._current_tool = SELECTION_TOOL.POINTER
        self._dataset = None

        # create grid lines
        pen_color = QColor(255, 255, 255, 255)
        pen = QPen(pen_color)
        pen.setWidth(2)
        pen.setStyle(QtCore.Qt.DotLine)
        self.vline = QGraphicsLineItem()
        self.vline.setVisible(False)
        self.vline.setPen(pen)
        self.hline = QGraphicsLineItem()
        self.hline.setVisible(False)
        self.hline.setPen(pen)
        self._scene.addItem(self.vline)
        self._scene.addItem(self.hline)
        self._current_label = None

        # rectangle selection tool
        self._rectangle_tool_origin = QPoint()
        self._rectangle_tool_picker = QRubberBand(QRubberBand.Rectangle, self)

        # polygon selection tool
        app = QApplication.instance()
        color = app.palette().color(QPalette.Highlight)
        self._polygon_guide_line_pen = QPen(color)
        self._polygon_guide_line_pen.setWidth(3)
        self._polygon_guide_line_pen.setStyle(QtCore.Qt.DotLine)
        self._polygon_guide_line = QGraphicsLineItem()
        self._polygon_guide_line.setVisible(False)
        self._polygon_guide_line.setPen(self._polygon_guide_line_pen)
        self._scene.addItem(self._polygon_guide_line)
        self._current_polygon = None

        # circle
        self._current_ellipse = None

        # free selection tool
        self._current_free_path = None
        self._is_drawing = False
        self._last_point_drawn = QPoint()
        self._last_click_point = None
        self._free_Path_pen = QPen(color)
        self._free_Path_pen.setWidth(10)

        self._extreme_points = Queue(maxsize=4)

    @property
    def current_label(self):
        return self._current_label

    @current_label.setter
    def current_label(self, value):
        self._current_label = value
        if self._current_label:
            color = QColor(self._current_label.color)
            self._free_Path_pen.setColor(color)
            self._polygon_guide_line_pen.setColor(color)
            self._polygon_guide_line.setPen(self._polygon_guide_line_pen)

    @property
    def dataset(self):
        return self._dataset

    @dataset.setter
    def dataset(self, value):
        self._dataset = value

    @property
    def img_contrast(self):
        return self._img_contrast

    @img_contrast.setter
    def img_contrast(self, value):
        self._img_contrast = value

    @property
    def img_gamma(self):
        return self._img_gamma

    @img_gamma.setter
    def img_gamma(self, value):
        self._img_gamma = value

    @property
    def img_brightness(self):
        return self._img_brightness

    @img_brightness.setter
    def img_brightness(self, value):
        self._img_brightness = value

    @property
    def image(self):
        return self._image

    @image.setter
    def image(self, value):
        self._image = value
        self._image_original = value.copy()
        self.update_viewer()

    @property
    def pixmap(self) -> ImagePixmap:
        return self._pixmap

    @gui_exception
    def update_viewer(self, fit_image=True):
        rgb = cv2.cvtColor(self._image, cv2.COLOR_BGR2RGB)
        rgb = ImageUtilities.adjust_image(rgb, self._img_contrast,
                                          self._img_brightness)
        rgb = ImageUtilities.adjust_gamma(rgb, self._img_gamma)
        pil_image = Image.fromarray(rgb)
        qppixmap_image = pil_image.toqpixmap()
        x, y = -qppixmap_image.width() / 2, -qppixmap_image.height() / 2
        if self._pixmap:
            self._pixmap.resetTransform()
            self._pixmap.setPixmap(qppixmap_image)
            self._pixmap.setOffset(x, y)
        else:
            self._pixmap = ImagePixmap()
            self._pixmap.setPixmap(qppixmap_image)
            self._pixmap.setOffset(x, y)
            self._scene.addItem(self._pixmap)
            self._pixmap.signals.hoverEnterEventSgn.connect(
                self.pixmap_hoverEnterEvent_slot)
            self._pixmap.signals.hoverLeaveEventSgn.connect(
                self.pixmap_hoverLeaveEvent_slot)
            self._pixmap.signals.hoverMoveEventSgn.connect(
                self.pixmap_hoverMoveEvent_slot)
        self._hide_guide_lines()
        if fit_image:
            self.fit_to_window()

    @gui_exception
    def reset_viewer(self):
        self._img_contrast = 1.0
        self._img_brightness = 50.0
        self._img_gamma = 1.0
        self._image = self._image_original.copy()

    @gui_exception
    def equalize_histogram(self):
        self._image = ImageUtilities.histogram_equalization(self._image)

    @gui_exception
    def correct_lightness(self):
        self._image = ImageUtilities.correct_lightness(self._image)

    def clusterize(self, k):
        self._image = ImageUtilities.kmeans(self._image.copy(), k)

    @property
    def current_tool(self):
        return self._current_tool

    @current_tool.setter
    def current_tool(self, value):
        self._polygon_guide_line.hide()
        self._current_polygon = None
        self._current_free_path = None
        self._current_ellipse = None
        self._is_drawing = value == SELECTION_TOOL.FREE
        self._current_tool = value
        self.clear_extreme_points()
        if value == SELECTION_TOOL.POINTER:
            self.enable_items(True)
        else:
            self.enable_items(False)

    def fit_to_window(self):
        if not self._pixmap or not self._pixmap.pixmap():
            return
        self.resetTransform()
        self.setTransform(QtGui.QTransform())
        self.fitInView(self._pixmap, QtCore.Qt.KeepAspectRatio)

    def _create_grid(self, gridSize=15):
        app: QApplication = QApplication.instance()
        curr_theme = "dark"
        if app:
            curr_theme = app.property("theme")
        if curr_theme == "light":
            color1 = QtGui.QColor("white")
            color2 = QtGui.QColor(237, 237, 237)
        else:
            color1 = QtGui.QColor(20, 20, 20)
            color2 = QtGui.QColor(0, 0, 0)
        backgroundPixmap = QtGui.QPixmap(gridSize * 2, gridSize * 2)
        backgroundPixmap.fill(color1)
        painter = QtGui.QPainter(backgroundPixmap)
        painter.fillRect(0, 0, gridSize, gridSize, color2)
        painter.fillRect(gridSize, gridSize, gridSize, gridSize, color2)
        painter.end()
        self._scene.setBackgroundBrush(QtGui.QBrush(backgroundPixmap))

    def wheelEvent(self, event: QWheelEvent):
        adj = (event.angleDelta().y() / 120) * 0.1
        self.scale(1 + adj, 1 + adj)

    @gui_exception
    def keyPressEvent(self, event: QKeyEvent):
        if event.key() == QtCore.Qt.Key_Space:
            image_rect: QRectF = self._pixmap.sceneBoundingRect()
            if self.current_tool == SELECTION_TOOL.POLYGON and self._current_polygon:
                points = self._current_polygon.points
                self._polygon_guide_line.hide()
                self.setDragMode(QGraphicsView.ScrollHandDrag)
                if len(points) <= 2:
                    self._current_polygon.delete_item()
                self.current_tool = SELECTION_TOOL.POINTER
            elif self.current_tool == SELECTION_TOOL.EXTREME_POINTS and \
                    self._extreme_points.full():
                points = []
                image_offset = QPointF(image_rect.width() / 2,
                                       image_rect.height() / 2)
                for pt in self._extreme_points.queue:
                    pt: EditablePolygonPoint
                    center = pt.sceneBoundingRect().center()
                    x = math.floor(center.x() + image_offset.x())
                    y = math.floor(center.y() + image_offset.y())
                    points.append([x, y])
                self.points_selection_sgn.emit(points)
                self.current_tool = SELECTION_TOOL.POINTER
        else:
            event.ignore()

    # guide lines events
    def _show_guide_lines(self):
        if self.hline and self.vline:
            self.hline.show()
            self.vline.show()

    def _hide_guide_lines(self):
        if self.hline and self.vline:
            self.hline.hide()
            self.vline.hide()

    def _update_guide_lines(self, x, y):
        bbox: QRect = self._pixmap.boundingRect()
        offset = QPointF(bbox.width() / 2, bbox.height() / 2)
        self.vline.setLine(x, -offset.y(), x, bbox.height() - offset.y())
        self.vline.setZValue(1)
        self.hline.setLine(-offset.x(), y, bbox.width() - offset.x(), y)
        self.hline.setZValue(1)

    def pixmap_hoverMoveEvent_slot(self, evt: QGraphicsSceneHoverEvent, x, y):
        self._update_guide_lines(x, y)

    def pixmap_hoverEnterEvent_slot(self):
        self._show_guide_lines()

    def pixmap_hoverLeaveEvent_slot(self):
        self._hide_guide_lines()

    def delete_polygon_slot(self, polygon: EditablePolygon):
        self._current_polygon = None
        self.current_tool = SELECTION_TOOL.POINTER
        self._polygon_guide_line.hide()

    @gui_exception
    def mousePressEvent(self, evt: QtGui.QMouseEvent) -> None:
        image_rect: QRectF = self._pixmap.boundingRect()
        mouse_pos = self.mapToScene(evt.pos())
        if evt.buttons() == QtCore.Qt.LeftButton:
            if self.current_tool == SELECTION_TOOL.BOX:
                # create rectangle
                self.setDragMode(QGraphicsView.NoDrag)
                self._rectangle_tool_origin = evt.pos()
                geometry = QRect(self._rectangle_tool_origin, QSize())
                self._rectangle_tool_picker.setGeometry(geometry)
                self._rectangle_tool_picker.show()
            elif self.current_tool == SELECTION_TOOL.POLYGON:
                if image_rect.contains(mouse_pos):
                    if self._current_polygon is None:
                        self._current_polygon = EditablePolygon()
                        self._current_polygon.label = self._current_label
                        self._current_polygon.tag = self._dataset
                        self._current_polygon.signals.deleted.connect(
                            self.delete_polygon_slot)
                        self._scene.addItem(self._current_polygon)
                        self._current_polygon.addPoint(mouse_pos)
                    else:
                        self._current_polygon.addPoint(mouse_pos)
            elif self.current_tool == SELECTION_TOOL.ELLIPSE:
                if image_rect.contains(mouse_pos):
                    self.setDragMode(QGraphicsView.NoDrag)
                    ellipse_rec = QtCore.QRectF(mouse_pos.x(), mouse_pos.y(),
                                                0, 0)
                    self._current_ellipse = EditableEllipse()
                    self._current_ellipse.tag = self.dataset
                    self._current_ellipse.label = self._current_label
                    self._current_ellipse.setRect(ellipse_rec)
                    self._scene.addItem(self._current_ellipse)

            elif self.current_tool == SELECTION_TOOL.FREE:
                # consider only the points into the image
                if image_rect.contains(mouse_pos):
                    self.setDragMode(QGraphicsView.NoDrag)
                    self._last_point_drawn = mouse_pos
                    self._current_free_path = QGraphicsPathItem()
                    self._current_free_path.setOpacity(0.6)
                    self._current_free_path.setPen(self._free_Path_pen)
                    painter = QPainterPath()
                    painter.moveTo(self._last_point_drawn)
                    self._current_free_path.setPath(painter)
                    self._scene.addItem(self._current_free_path)

            elif self.current_tool == SELECTION_TOOL.EXTREME_POINTS:
                if image_rect.contains(mouse_pos):
                    if not self._extreme_points.full():

                        def delete_point(idx):
                            del self._extreme_points.queue[idx]

                        idx = self._extreme_points.qsize()
                        editable_pt = EditablePolygonPoint(idx)
                        editable_pt.signals.deleted.connect(delete_point)
                        editable_pt.setPos(mouse_pos)
                        self._scene.addItem(editable_pt)
                        self._extreme_points.put(editable_pt)

        else:
            self.setDragMode(QGraphicsView.ScrollHandDrag)
        super(ImageViewer, self).mousePressEvent(evt)

    @gui_exception
    def mouseMoveEvent(self, evt: QtGui.QMouseEvent) -> None:
        mouse_pos = self.mapToScene(evt.pos())
        image_rect: QRectF = self._pixmap.boundingRect()
        if self.current_tool == SELECTION_TOOL.BOX:
            if not self._rectangle_tool_origin.isNull():
                geometry = QRect(self._rectangle_tool_origin,
                                 evt.pos()).normalized()
                self._rectangle_tool_picker.setGeometry(geometry)
        elif self.current_tool == SELECTION_TOOL.POLYGON:
            if self._current_polygon and image_rect.contains(mouse_pos):
                if self._current_polygon.count > 0:
                    last_point: QPointF = self._current_polygon.last_point
                    self._polygon_guide_line.setZValue(1)
                    self._polygon_guide_line.show()
                    mouse_pos = self.mapToScene(evt.pos())
                    self._polygon_guide_line.setLine(last_point.x(),
                                                     last_point.y(),
                                                     mouse_pos.x(),
                                                     mouse_pos.y())
            else:
                self._polygon_guide_line.hide()
        elif self.current_tool == SELECTION_TOOL.ELLIPSE:
            if self._current_ellipse and image_rect.contains(mouse_pos):
                ellipse_rect = self._current_ellipse.rect()
                ellipse_pos = QPointF(ellipse_rect.x(), ellipse_rect.y())
                distance = math.hypot(mouse_pos.x() - ellipse_pos.x(),
                                      mouse_pos.y() - ellipse_pos.y())
                ellipse_rect.setWidth(distance)
                ellipse_rect.setHeight(distance)
                self._current_ellipse.setRect(ellipse_rect)
        elif self.current_tool == SELECTION_TOOL.FREE and evt.buttons(
        ) and QtCore.Qt.LeftButton:
            if self._current_free_path and image_rect.contains(mouse_pos):
                painter: QPainterPath = self._current_free_path.path()
                self._last_point_drawn = self.mapToScene(evt.pos())
                painter.lineTo(self._last_point_drawn)
                self._current_free_path.setPath(painter)
        super(ImageViewer, self).mouseMoveEvent(evt)

    @gui_exception
    def mouseReleaseEvent(self, evt: QtGui.QMouseEvent) -> None:
        image_rect: QRectF = self._pixmap.boundingRect()
        if self.current_tool == SELECTION_TOOL.BOX:
            roi: QRect = self._rectangle_tool_picker.geometry()
            roi: QRectF = self.mapToScene(roi).boundingRect()
            self._rectangle_tool_picker.hide()
            if image_rect == roi.united(image_rect):
                rect = EditableBox(roi)
                rect.label = self.current_label
                rect.tag = self._dataset
                self._scene.addItem(rect)
                self.current_tool = SELECTION_TOOL.POINTER
                self.setDragMode(QGraphicsView.ScrollHandDrag)

        elif self.current_tool == SELECTION_TOOL.ELLIPSE and self._current_ellipse:
            roi: QRect = self._current_ellipse.boundingRect()
            if image_rect == roi.united(image_rect):
                self.current_tool = SELECTION_TOOL.POINTER
                self.setDragMode(QGraphicsView.ScrollHandDrag)
            else:
                self._current_ellipse.delete_item()
        elif self.current_tool == SELECTION_TOOL.FREE and self._current_free_path:
            # create polygon
            self._current_free_path: QGraphicsPathItem
            path_rect = self._current_free_path.boundingRect()
            if image_rect == path_rect.united(image_rect):
                path = self._current_free_path.path()
                path_polygon = EditablePolygon()
                path_polygon.tag = self.dataset
                path_polygon.label = self.current_label
                self._scene.addItem(path_polygon)
                for i in range(0, path.elementCount(), 10):
                    x, y = path.elementAt(i).x, path.elementAt(i).y
                    path_polygon.addPoint(QPointF(x, y))
            self._scene.removeItem(self._current_free_path)
            self.current_tool = SELECTION_TOOL.POINTER
            self.setDragMode(QGraphicsView.ScrollHandDrag)
        super(ImageViewer, self).mouseReleaseEvent(evt)

    def remove_annotations(self):
        for item in self._scene.items():
            if isinstance(item, EditableItem):
                item.delete_item()

    def remove_annotations_by_label(self, label_name):
        for item in self._scene.items():
            if isinstance(item, EditableItem):
                if item.label and item.label.name == label_name:
                    item.delete_item()

    def enable_items(self, value):
        for item in self._scene.items():
            if isinstance(item, EditableItem):
                item.setEnabled(value)

    def clear_extreme_points(self):
        if self._extreme_points.qsize() > 0:
            for pt in self._extreme_points.queue:
                self._scene.removeItem(pt)
            self._extreme_points.queue.clear()
コード例 #15
0
class ImageViewer(QGraphicsView, QObject):
    def __init__(self, parent=None):
        super(ImageViewer, self).__init__(parent)
        self.setRenderHints(QPainter.Antialiasing
                            | QPainter.SmoothPixmapTransform)
        #self.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
        self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
        self.setDragMode(QGraphicsView.ScrollHandDrag)
        #self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
        #self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
        self._scene = ImageViewerScene(self)
        self.setScene(self._scene)
        self._create_grid()
        self._create_grid_lines()
        self._pixmap = None
        self._selection_mode = SELECTION_MODE.NONE

        # polygon selection
        _polygon_guide_line_pen = QPen(QtGui.QColor(235, 72, 40))
        _polygon_guide_line_pen.setWidth(2)
        _polygon_guide_line_pen.setStyle(QtCore.Qt.DotLine)
        self._polygon_guide_line = QGraphicsLineItem()
        self._polygon_guide_line.setVisible(False)
        self._polygon_guide_line.setPen(_polygon_guide_line_pen)
        self._scene.addItem(self._polygon_guide_line)
        self._current_polygon = None
        # rectangle selection
        self._box_origin = QPoint()
        self._box_picker = QRubberBand(QRubberBand.Rectangle, self)

        # free selection
        self._current_free_path = None
        self._is_drawing = False
        self._last_point_drawn = QPoint()
        self._current_label = None

    @property
    def current_label(self):
        return self._current_label

    @current_label.setter
    def current_label(self, value):
        self._current_label = value

    @property
    def pixmap(self) -> ImagePixmap:
        return self._pixmap

    @pixmap.setter
    def pixmap(self, value: QPixmap):
        self.selection_mode = SELECTION_MODE.NONE
        self.resetTransform()
        if self.pixmap:
            self._scene.removeItem(self._pixmap)
        self.remove_annotations()
        self._pixmap = ImagePixmap()
        self._pixmap.setPixmap(value)
        self._pixmap.setOffset(-value.width() / 2, -value.height() / 2)
        self._pixmap.setTransformationMode(QtCore.Qt.SmoothTransformation)
        self._pixmap.signals.hoverEnterEventSgn.connect(
            self.pixmap_hoverEnterEvent_slot)
        self._pixmap.signals.hoverLeaveEventSgn.connect(
            self.pixmap_hoverLeaveEvent_slot)
        self._pixmap.signals.hoverMoveEventSgn.connect(
            self.pixmap_hoverMoveEvent_slot)
        self._scene.addItem(self._pixmap)
        # rect=self._scene.addRect(QtCore.QRectF(0,0,100,100), QtGui.QPen(QtGui.QColor("red")))
        # rect.setZValue(1.0)
        self.fit_to_window()

    @property
    def selection_mode(self):
        return self._selection_mode

    @selection_mode.setter
    def selection_mode(self, value):
        self._polygon_guide_line.hide()
        self._current_polygon = None
        self._current_free_path = None
        self._is_drawing = value == SELECTION_MODE.FREE
        if value == SELECTION_MODE.NONE:
            self.enable_items(True)
        else:
            self.enable_items(False)
        self._selection_mode = value

    def remove_annotations(self):
        for item in self._scene.items():
            if isinstance(item, EditableBox):
                self._scene.removeItem(item)
            elif isinstance(item, EditablePolygon):
                item.delete_polygon()

    def remove_annotations_by_label(self, label_name):
        for item in self._scene.items():
            if isinstance(item, EditableBox):
                if item.label and item.label.name == label_name:
                    self._scene.removeItem(item)
            elif isinstance(item, EditablePolygon):
                if item.label and item.label.name == label_name:
                    item.delete_polygon()

    def enable_items(self, value):
        for item in self._scene.items():
            if isinstance(item, EditablePolygon) or isinstance(
                    item, EditableBox):
                item.setEnabled(value)

    def _create_grid(self):
        gridSize = 15
        backgroundPixmap = QtGui.QPixmap(gridSize * 2, gridSize * 2)
        #backgroundPixmap.fill(QtGui.QColor("white"))
        backgroundPixmap.fill(QtGui.QColor(20, 20, 20))
        #backgroundPixmap.fill(QtGui.QColor("powderblue"))
        painter = QtGui.QPainter(backgroundPixmap)
        #backgroundColor=QtGui.QColor("palegoldenrod")
        #backgroundColor=QtGui.QColor(237,237,237)
        backgroundColor = QtGui.QColor(0, 0, 0)
        painter.fillRect(0, 0, gridSize, gridSize, backgroundColor)
        painter.fillRect(gridSize, gridSize, gridSize, gridSize,
                         backgroundColor)
        painter.end()
        self._scene.setBackgroundBrush(QtGui.QBrush(backgroundPixmap))

    def _create_grid_lines(self):
        pen_color = QColor(255, 255, 255, 255)
        pen = QPen(pen_color)
        pen.setWidth(2)
        pen.setStyle(QtCore.Qt.DotLine)
        self.vline = QGraphicsLineItem()
        self.vline.setVisible(False)
        self.vline.setPen(pen)
        self.hline = QGraphicsLineItem()
        self.hline.setVisible(False)
        self.hline.setPen(pen)
        self._scene.addItem(self.vline)
        self._scene.addItem(self.hline)

    def wheelEvent(self, event: QWheelEvent):
        adj = (event.angleDelta().y() / 120) * 0.1
        self.scale(1 + adj, 1 + adj)

    def fit_to_window(self):
        """Fit image within view."""
        if not self.pixmap or not self._pixmap.pixmap():
            return
        #self._pixmap.setTransformationMode(QtCore.Qt.SmoothTransformation)
        self.fitInView(self._pixmap, QtCore.Qt.KeepAspectRatio)

    def show_guide_lines(self):
        if self.hline and self.vline:
            self.hline.show()
            self.vline.show()

    def hide_guide_lines(self):
        if self.hline and self.vline:
            self.hline.hide()
            self.vline.hide()

    def pixmap_hoverEnterEvent_slot(self):
        self.show_guide_lines()

    def pixmap_hoverLeaveEvent_slot(self):
        self.hide_guide_lines()

    def pixmap_hoverMoveEvent_slot(self, evt: QGraphicsSceneHoverEvent, x, y):
        bbox: QRect = self._pixmap.boundingRect()
        offset = QPointF(bbox.width() / 2, bbox.height() / 2)
        self.vline.setLine(x, -offset.y(), x, bbox.height() - offset.y())
        self.vline.setZValue(1)
        self.hline.setLine(-offset.x(), y, bbox.width() - offset.x(), y)
        self.hline.setZValue(1)

    def mouseMoveEvent(self, evt: QtGui.QMouseEvent) -> None:
        if self.selection_mode == SELECTION_MODE.BOX:
            if not self._box_origin.isNull():
                self._box_picker.setGeometry(
                    QRect(self._box_origin, evt.pos()).normalized())
        elif self.selection_mode == SELECTION_MODE.POLYGON:
            if self._current_polygon:
                if self._current_polygon.count > 0:
                    last_point: QPointF = self._current_polygon.last_point
                    self._polygon_guide_line.setZValue(1)
                    self._polygon_guide_line.show()
                    mouse_pos = self.mapToScene(evt.pos())
                    self._polygon_guide_line.setLine(last_point.x(),
                                                     last_point.y(),
                                                     mouse_pos.x(),
                                                     mouse_pos.y())
            else:
                self._polygon_guide_line.hide()

        elif self.selection_mode == SELECTION_MODE.FREE and evt.buttons(
        ) and QtCore.Qt.LeftButton:
            if self._current_free_path:
                painter: QPainterPath = self._current_free_path.path()
                self._last_point_drawn = self.mapToScene(evt.pos())
                painter.lineTo(self._last_point_drawn)
                self._current_free_path.setPath(painter)

        super(ImageViewer, self).mouseMoveEvent(evt)

    def mousePressEvent(self, evt: QtGui.QMouseEvent) -> None:

        if evt.buttons() == QtCore.Qt.LeftButton:
            if self.selection_mode == SELECTION_MODE.BOX:
                self.setDragMode(QGraphicsView.NoDrag)
                self._box_origin = evt.pos()
                self._box_picker.setGeometry(QRect(self._box_origin, QSize()))
                self._box_picker.show()

            elif self._selection_mode == SELECTION_MODE.POLYGON:
                pixmap_rect: QRectF = self._pixmap.boundingRect()
                new_point = self.mapToScene(evt.pos())
                # consider only the points intothe image
                if pixmap_rect.contains(new_point):
                    if self._current_polygon is None:
                        self._current_polygon = EditablePolygon()
                        self._current_polygon.signals.deleted.connect(
                            self.delete_polygon_slot)
                        self._scene.addItem(self._current_polygon)
                        self._current_polygon.addPoint(new_point)
                    else:
                        self._current_polygon.addPoint(new_point)

            elif self._selection_mode == SELECTION_MODE.FREE:
                # start drawing
                new_point = self.mapToScene(evt.pos())
                pixmap_rect: QRectF = self._pixmap.boundingRect()
                # consider only the points intothe image
                if pixmap_rect.contains(new_point):
                    self.setDragMode(QGraphicsView.NoDrag)
                    pen = QPen(QtGui.QColor(235, 72, 40))
                    pen.setWidth(10)
                    self._last_point_drawn = new_point
                    self._current_free_path = QGraphicsPathItem()
                    self._current_free_path.setOpacity(0.6)
                    self._current_free_path.setPen(pen)
                    painter = QPainterPath()
                    painter.moveTo(self._last_point_drawn)
                    self._current_free_path.setPath(painter)
                    self._scene.addItem(self._current_free_path)
        else:
            self.setDragMode(QGraphicsView.ScrollHandDrag)

        super(ImageViewer, self).mousePressEvent(evt)

    def mouseReleaseEvent(self, evt: QtGui.QMouseEvent) -> None:
        if evt.button() == QtCore.Qt.LeftButton:
            if self.selection_mode == SELECTION_MODE.BOX:
                roi: QRect = self._box_picker.geometry()
                roi: QRectF = self.mapToScene(roi).boundingRect()
                pixmap_rect = self._pixmap.boundingRect()
                self._box_picker.hide()
                if pixmap_rect == roi.united(pixmap_rect):
                    rect = EditableBox(roi)
                    rect.label = self.current_label
                    self._scene.addItem(rect)
                    self.selection_mode = SELECTION_MODE.NONE
                    self.setDragMode(QGraphicsView.ScrollHandDrag)

            elif self.selection_mode == SELECTION_MODE.FREE and self._current_free_path:
                # create polygon
                self._current_free_path: QGraphicsPathItem
                path_rect = self._current_free_path.boundingRect()
                pixmap_rect = self._pixmap.boundingRect()
                if pixmap_rect == path_rect.united(pixmap_rect):
                    path = self._current_free_path.path()
                    path_polygon = EditablePolygon()
                    path_polygon.label = self.current_label
                    self._scene.addItem(path_polygon)
                    for i in range(0, path.elementCount(), 10):
                        x, y = path.elementAt(i).x, path.elementAt(i).y
                        path_polygon.addPoint(QPointF(x, y))
                self._scene.removeItem(self._current_free_path)
                self.selection_mode = SELECTION_MODE.NONE
                self.setDragMode(QGraphicsView.ScrollHandDrag)

        super(ImageViewer, self).mouseReleaseEvent(evt)

    def keyPressEvent(self, event: QtGui.QKeyEvent) -> None:
        if self._current_polygon and event.key() == QtCore.Qt.Key_Space:
            points = self._current_polygon.points
            self._current_polygon.label = self.current_label
            self._current_polygon = None
            self.selection_mode = SELECTION_MODE.NONE
            self._polygon_guide_line.hide()
            self.setDragMode(QGraphicsView.ScrollHandDrag)
        super(ImageViewer, self).keyPressEvent(event)

    def delete_polygon_slot(self, polygon: EditablePolygon):
        self._current_polygon = None
        self.selection_mode = SELECTION_MODE.NONE
        self._polygon_guide_line.hide()
コード例 #16
0
class MainScene(QGraphicsScene):
    COLORS = {
        'black': QColor(Qt.black),
        'white': QColor(Qt.white),
        'red': QColor(Qt.red),
        'green': QColor(Qt.green),
        'blue': QColor(Qt.blue),
        'bark_red': QColor(Qt.darkRed),
        'dark_green': QColor(Qt.darkGreen),
        'dark_blue': QColor(Qt.darkBlue),
        'cyan': QColor(Qt.cyan),
        'magenta': QColor(Qt.magenta),
        'yellow': QColor(Qt.yellow),
        'gray': QColor(Qt.gray),
        'dark_cyan': QColor(Qt.darkCyan),
        'dark_magenta': QColor(Qt.darkMagenta),
        'dark_yellow': QColor(Qt.darkYellow),
        'dark_gray': QColor(Qt.darkGray),
        'light_gray': QColor(Qt.lightGray)
    }

    def __init__(self, parent):
        super().__init__()
        self.parent = parent

        # Variables
        self.graph_to_display = None
        self.default_graph = None
        self.clustering_algorithm = None
        self.graph_center = None
        self.scale_factor = None
        self.scene_graph_rect = None

        self.points = []
        self.lines = []
        self.vertex_to_display = []
        self.edge_to_display = []

        self._move = False
        self.highlighted_item = None
        self.selected_item = None
        self.rb_selected_points = SelectionList()
        self.rb_origin = None
        self.rubber_band = None

        self.init_variables()

    def add_link(self, edge):
        point_a = self.points[edge.source]
        point_b = self.points[edge.target]
        line_pen = QPen(self.COLORS[edge['edge_color']])
        line_pen.setWidth(edge['edge_width'])
        line = MainEdge(edge, point_a, point_b, line_pen, self)
        self.addItem(line)
        self.lines.append(line)

    def add_node(self, vertex):
        point_pen = QPen(self.COLORS['black'])
        point_pen.setWidth(self.parent.SETTINGS['point_border_width'])
        d = self.parent.SETTINGS['point_diameter']
        point = MainVertex(vertex, d, point_pen, vertex['color'], self)
        self.addItem(point)
        self.points.append(point)

    def init_variables(self):
        self.graph_to_display = self.parent.main_window.graph
        self.default_graph = self.graph_to_display.copy()
        self.clustering_algorithm = self.parent.main_window.clustering_algorithm

        graph_rect = QRectF(
            QPointF(min(self.graph_to_display.vs['x']),
                    min(self.graph_to_display.vs['y'])),
            QPointF(max(self.graph_to_display.vs['x']),
                    max(self.graph_to_display.vs['y'])))
        self.graph_center = QPointF(graph_rect.center())
        self.scale_factor = scale_factor_hint(self.parent.geometry(),
                                              graph_rect, 1.05)

        self.init_edge_color_to_default()
        self.set_background_color()

    def init_edge_color_to_default(self, ):
        for edge in self.graph_to_display.es:
            edge['edge_width'] = self.parent.SETTINGS['edge_width']
            edge['edge_color'] = self.parent.SETTINGS['edge_color']

    def set_background_color(self):
        background_color = QBrush(
            QColor(self.COLORS[self.parent.SETTINGS['background_color']]))
        self.setBackgroundBrush(background_color)

    def display(self):
        def availability_color_to_vertex():
            for v in self.graph_to_display.vs:
                if v['availability']:
                    v['color'] = QBrush(self.COLORS['green'])
                else:
                    v['color'] = QBrush(self.COLORS['red'])

        def assign_color_to_vertex():
            colors = list(self.COLORS.keys())

            for v in self.graph_to_display.vs:
                color_index = v['cluster'] % len(colors)
                if colors[color_index] == self.parent.SETTINGS[
                        'highlight_color']:  # highlighted items will stand out
                    color_index = (color_index + 1) % len(colors)
                q_color = self.COLORS[colors[color_index]]
                cluster_color = QBrush(q_color)
                v['color'] = cluster_color

        def assign_vertex_to_cluster():
            for v in self.graph_to_display.vs:
                for cluster in clusters:
                    # If elements of clusters are not lists, then clusters had been a VertexDendrogram object, which
                    # gives a "list" of igraph.Graph objects when subgraphed. The VertexClustering object, on the other
                    # hand, gives a list of lists of vertex ids when subgraphed
                    if isinstance(cluster,
                                  Graph) and v['id'] in cluster.vs['id']:
                        v['cluster'] = clusters.index(cluster)
                        break
                    elif isinstance(cluster, list) and v.index in cluster:
                        v['cluster'] = clusters.index(cluster)
                        break

        clusters = getattr(self.graph_to_display, self.clustering_algorithm)()
        # Some clustering algorithms return VertexDendrogram, some return VertexClustering, and VertexDendrogram object
        # has to be transformed into VertexClustering (as_clustering()) before it can be subgraphed
        if isinstance(clusters, VertexDendrogram):
            clusters = clusters.as_clustering()
        clusters = clusters.subgraphs()
        assign_vertex_to_cluster()
        assign_color_to_vertex()  # based on the cluster it belongs to
        if self.parent.availability:
            availability_color_to_vertex()

        self.display_vertices()
        self.display_edges()

    def display_vertices(self):
        point_pen = QPen(self.COLORS['black'])
        point_pen.setWidth(self.parent.SETTINGS['point_border_width'])
        d = self.parent.SETTINGS['point_diameter']
        for vertex in self.graph_to_display.vs:
            x, y = dilate(vertex['x'], vertex['y'], self.graph_center,
                          self.scale_factor)
            vertex['pos'] = {'x': x, 'y': y}
            point = MainVertex(vertex, d, point_pen, vertex['color'], self)
            self.addItem(point)
            self.points.append(point)

    def display_edges(self):
        for edge in self.graph_to_display.es:
            point_a = self.points[edge.source]
            point_b = self.points[edge.target]
            line_pen = QPen(self.COLORS[edge['edge_color']])
            line_pen.setWidth(edge['edge_width'])
            line = MainEdge(edge, point_a, point_b, line_pen, self)
            self.addItem(line)
            self.lines.append(line)

    def scalling(self):
        bandwidth = []
        attribute = self.parent.main_window.DEFAULT_ATTRIBUTE

        for edge in self.graph_to_display.es:
            bandwidth.append(edge[attribute])

        max_value = max(bandwidth)
        min_value = min(bandwidth)
        max_min = max_value - min_value
        for i in range(len(bandwidth)):
            bandwidth[i] = (bandwidth[i] - min_value) / max_min

        return bandwidth

    # This is a more complete way of showing gradient in the edge
    def display_edges_by_gradient(self):
        if not self.parent.main_window.contains_attribute():
            return
        bandwidth = self.scalling()
        n = 0

        # set the thickness of QPen according to the attribute value
        for edge in self.graph_to_display.es:
            line = self.lines[edge.index]
            line.edge['edge_color'] = QColor(255 - bandwidth[n] * 255, 0,
                                             bandwidth[n] * 255)
            line_pen = QPen(line.edge['edge_color'])
            line_pen.setWidthF(line.edge['edge_width'])
            line.setPen(line_pen)
            line._pen = line_pen
            n += 1

    def display_edges_by_thickness(self):
        if not self.parent.main_window.contains_attribute():
            return
        bandwidth = self.scalling()
        n = 0

        # set the thickness of QPen according to the attribute value
        for edge in self.graph_to_display.es:
            line = self.lines[edge.index]
            line.edge['edge_width'] = self.parent.SETTINGS[
                'edge_width'] * bandwidth[n] * 2
            line_pen = QPen(QColor('black'))
            line_pen.setWidthF(line.edge['edge_width'])
            line.setPen(line_pen)
            line._pen = line_pen
            n += 1

    def change_color_all_links(self, the_color):
        for edge in self.graph_to_display.es:
            line = self.lines[edge.index]
            line.edge['edge_color'] = the_color
            line_pen = QPen(line.edge['edge_color'])
            line_pen.setWidthF(line.edge['edge_width'])
            line.setPen(line_pen)
            line._pen = line_pen

    def highlight_edges(self, edge_path):
        for edge_id in edge_path:
            line = self.lines[edge_id]
            line.highlight_self()
            line.setHighlighted(True)

    def unhighlight_edges(self, edge_path):
        for edge_id in edge_path:
            line = self.lines[edge_id]
            line.unhighlight_self()
            line.setHighlighted(False)

    def highlight_vertices(self, vertex_path):
        for vertex_id in vertex_path:
            point = self.points[vertex_id]
            point.highlight_self()
            point.setHighlighted(True)

    def unhighlight_vertices(self, vertex_path):
        for vertex_id in vertex_path:
            point = self.points[vertex_id]
            point.unhighlight_self()
            point.setHighlighted(False)

    def update_vertex(self, point):
        dilated_x, dilated_y = point.x(), point.y()
        original_x, original_y = undilate(dilated_x, dilated_y,
                                          self.graph_center, self.scale_factor)
        point.vertex.update_attributes(x=original_x,
                                       y=original_y,
                                       pos={
                                           'x': dilated_x,
                                           'y': dilated_y
                                       })

    def crop(self):
        if self.rb_selected_points.is_empty():
            return

        lines_to_keep = []
        for point in self.rb_selected_points:
            for line in point.lines:
                if line not in lines_to_keep and \
                        (self.rb_selected_points.contains(line.point_a) and self.rb_selected_points.contains(
                            line.point_b)):
                    lines_to_keep.append(line)

        for item in self.items():
            if item not in lines_to_keep and not self.rb_selected_points.contains(
                    item):
                self.removeItem(item)

        self.save_cropped()

    def reverse_crop(self):
        if self.rb_selected_points.is_empty():
            return

        for point in self.rb_selected_points:
            if point in self.items():
                for line in point.lines:
                    if line in self.items():
                        self.removeItem(line)
                self.removeItem(point)

        self.save_cropped()

    def save_cropped(self):
        graph = Graph()
        items = self.items()

        points = []
        point_index = 0
        for point in self.points:
            if point in items:
                create_vertices(graph, 1)

                created_vertex = graph.vs[point_index]
                created_vertex.update_attributes(point.vertex.attributes())

                points.append(point)
                point_index += 1
        self.points = points

        lines = []
        line_index = 0
        for line in self.lines:
            if line in items:
                st_tuple = [0, 0]
                for vertex in graph.vs:
                    if vertex['id'] == line.point_a.vertex['id']:
                        st_tuple[0] = vertex.index
                        break
                for vertex in graph.vs:
                    if vertex['id'] == line.point_b.vertex['id']:
                        st_tuple[1] = vertex.index
                        break
                st_tuple = [tuple(st_tuple)]
                create_edges(graph, st_tuple)

                created_edge = graph.es[line_index]
                created_edge.update_attributes(line.edge.attributes())

                lines.append(line)
                line_index += 1
        self.lines = lines

        self.rb_selected_points.clear()
        self.parent.main_window.graph = graph
        self.graph_to_display = self.parent.main_window.graph

    def revert_to_default(self):
        items = self.items()

        for point in self.points:
            if point not in items:
                self.addItem(point)

        for line in self.lines:
            if line not in items:
                self.addItem(line)

        self.rb_selected_points.clear()
        self.graph_to_display = self.default_graph.copy()
        self.parent.main_window.graph = self.graph_to_display

    def remove_point(self, point):
        self.removeItem(point)
        for line in point.lines:
            self.removeItem(line)

        self.save_cropped()

    def remove_line(self, line):
        self.removeItem(line)

        self.save_cropped()

    # For add vertex
    def mouseDoubleClickEvent(self, event):
        if self.parent.main_window.MODE_ADD_NODE:
            cursor_pos = event.scenePos().toPoint()
            item_under_cursor = self.itemAt(cursor_pos, QTransform())

            if item_under_cursor is None:
                self.parent.main_window.add_node(event, self.graph_center,
                                                 self.scale_factor)

    # For add edge
    def real_add_edge(self, vertex):
        if len(self.parent.main_window.SOURCE_TARGET) == 0:
            self.parent.main_window.SOURCE_TARGET.append(vertex)

        elif len(self.parent.main_window.SOURCE_TARGET) == 1:
            self.parent.main_window.SOURCE_TARGET.append(vertex)

            self.parent.main_window.graph = create_edges(
                self.parent.main_window.graph,
                [(int(self.parent.main_window.SOURCE_TARGET[0].index),
                  int(self.parent.main_window.SOURCE_TARGET[1].index))])

            # Set default value for new edge
            self.parent.main_window.graph.es[
                self.parent.main_window.graph.ecount() - 1]['edge_color'] = ""
            self.parent.main_window.graph.es[
                self.parent.main_window.graph.ecount() - 1]['weight'] = 1000.0
            self.parent.main_window.graph.es[
                self.parent.main_window.graph.ecount() - 1]['LinkType'] = ""
            self.parent.main_window.graph.es[
                self.parent.main_window.graph.ecount() - 1]['LinkNote'] = ""
            self.parent.main_window.graph.es[
                self.parent.main_window.graph.ecount() -
                1]['LinkSpeedUnits'] = "G"
            self.parent.main_window.graph.es[
                self.parent.main_window.graph.ecount() -
                1]['label'] = "1000.0 MBit/s"
            self.parent.main_window.graph.es[
                self.parent.main_window.graph.ecount() - 1]['LinkLabel'] = ""
            self.parent.main_window.graph.es[
                self.parent.main_window.graph.ecount() - 1]['edge_width'] = 1
            self.parent.main_window.graph.es[
                self.parent.main_window.graph.ecount() -
                1]['LinkSpeedRaw'] = 1000000000.0
            self.parent.main_window.graph.es[
                self.parent.main_window.graph.ecount() - 1]['key'] = 0.0
            self.parent.main_window.graph.es[
                self.parent.main_window.graph.ecount() - 1]['zorder'] = 1.0

            # Check for attribute delay, if it exists set default value for new edge
            dictionary = self.parent.main_window.graph.es[0].attributes()
            for key, value in dictionary.items():
                if str(key) == "delay":
                    self.parent.main_window.graph.es[
                        self.parent.main_window.graph.ecount() -
                        1]['delay'] = 50.0

            self.edge_to_display.append(self.parent.main_window.graph.es[
                self.parent.main_window.graph.ecount() - 1])

            point_a = self.points[self.edge_to_display[-1].source]
            point_b = self.points[self.edge_to_display[-1].target]
            line_pen = QPen(self.COLORS['black'])
            line_pen.setWidth(1)
            line = MainEdge(self.edge_to_display[-1], point_a, point_b,
                            line_pen, self)
            self.addItem(line)
            self.lines.append(line)

            self.parent.main_window.SOURCE_TARGET = []
            self.parent.main_window.ADD_EDGE_STATE = False
            # self.parent.main_window.button_add_edge.setToolTip("Add Edge")

    def mousePressEvent(self, event):
        self.rb_selected_points.clear()

        cursor_pos = event.scenePos().toPoint()
        item_under_cursor = self.itemAt(cursor_pos, QTransform())

        if item_under_cursor is not None:
            if self.highlighted_item is not None and \
                    not self.highlighted_item.isHighlighted() and \
                    not self.highlighted_item.isPersistent():
                self.highlighted_item.unhighlight_self()
            if self.selected_item is not None and \
                    not self.selected_item.isHighlighted() and \
                    not self.selected_item.isPersistent():
                self.selected_item.unhighlight_self()

            self.selected_item = item_under_cursor
            self.selected_item.mousePressEvent(event)
            if not self.parent.main_window.MODE_RECOLOR_NODE:
                self.highlighted_item = item_under_cursor
                self.highlighted_item.highlight_self()
            self._move = True
        else:
            # Clicking else where resets any selection previously made
            if self.highlighted_item is not None:
                if not self.highlighted_item.isHighlighted(
                ) and not self.highlighted_item.isPersistent():
                    self.highlighted_item.unhighlight_self()
            if self.selected_item is not None:
                if not self.selected_item.isHighlighted(
                ) and not self.selected_item.isPersistent():
                    self.selected_item.unhighlight_self()
            self.highlighted_item = None
            self.selected_item = None

            if self.parent.main_window.MODE_RUBBER_BAND:
                # Initializing rubber band
                self.rb_origin = self.parent.mapFromScene(cursor_pos)
                self.rubber_band = QRubberBand(QRubberBand.Rectangle,
                                               self.parent)
                self.rubber_band.setGeometry(QRect(self.rb_origin, QSize()))
                self.rubber_band.show()

    def mouseMoveEvent(self, event):
        cursor_pos = event.scenePos().toPoint()

        if self.selected_item is not None and self._move:
            self.selected_item.highlight_self()
            self.selected_item.mouseMoveEvent(event)
        elif self.parent.main_window.MODE_RUBBER_BAND and self.rb_origin is not None:
            if self.rb_origin is not None:
                adjusted_cursor_pos = self.parent.mapFromScene(cursor_pos)
                self.rubber_band.setGeometry(
                    QRect(self.rb_origin, adjusted_cursor_pos).normalized())
        elif not self.parent.main_window.MODE_RUBBER_BAND and not self.parent.main_window.MODE_RECOLOR_NODE:
            item_under_cursor = self.itemAt(cursor_pos, QTransform())

            if item_under_cursor is None and self.highlighted_item is not None:
                # When mouse moves out of an item into background
                self.parent.setDragMode(self.parent.drag_mode_hint())

                if self.highlighted_item != self.selected_item and not self.highlighted_item.isHighlighted(
                ):
                    self.highlighted_item.unhighlight_self()
                self.highlighted_item = item_under_cursor
            elif item_under_cursor is not None and self.highlighted_item is None:
                # When mouse moves from background into an item
                self.parent.setDragMode(QGraphicsView.NoDrag)

                self.highlighted_item = item_under_cursor
                self.highlighted_item.highlight_self()
            elif item_under_cursor is not None and self.highlighted_item is not None:
                # When mouse moves out of one item into another item
                if self.highlighted_item != self.selected_item and not self.highlighted_item.isHighlighted(
                ):
                    self.highlighted_item.unhighlight_self()

                self.highlighted_item = item_under_cursor
                self.highlighted_item.highlight_self()

    def mouseReleaseEvent(self, event):
        if self.selected_item is not None:
            self._move = False
        elif self.parent.main_window.MODE_RUBBER_BAND and self.rb_origin is not None:
            self.rubber_band.hide()
            rect = self.rubber_band.geometry()
            rect_scene = self.parent.mapToScene(rect).boundingRect()
            selected = self.items(rect_scene)
            for item in selected:
                if isinstance(item, MainVertex):
                    self.rb_selected_points.append(item)

            self.rb_origin = None
            self.rubber_band = None