python python-3.x pyqt4 zoom qgraphicsview

python - Cómo habilitar Pan y Zoom en un QGraphicsView



python-3.x pyqt4 (2)

Es posible abrir archivos TIFF de hasta varios gigabytes con la biblioteca PIL (almohada) ordinaria. No es del todo fácil, pero funciona.

Puede ver el ejemplo aquí , segundo ejemplo después de que la cadena EDIT negrita podría abrir, mover y hacer zoom en los archivos TIFF.

Estoy usando Python y Qt Designer para implementar la carga de imágenes tiff y para activar Pan y Zoom en algún evento del mouse (rueda - zoom, presione rueda - pan).

Estaba buscando algunas opciones y clases que pueden funcionar con imágenes, etc., y hasta ahora he encontrado:

QGraphicsScene, QImage, QGraphicsView

Tengo tres clases (solo pruebas)

  1. ViewerDemo que tiene el elemento QGraphicsView :

    """description of class""" # Form implementation generated from reading ui file ''GraphicsViewdemo.ui'' try: _fromUtf8 = QtCore.QString.fromUtf8 except AttributeError: def _fromUtf8(s): return s class Ui_Dialog(object): def setupUi(self, Dialog): Dialog.setObjectName(("Dialog")) Dialog.resize(500, 500) self.graphicsView = QtGui.QGraphicsView(Dialog) self.graphicsView.setGeometry(QtCore.QRect(0, 0, 500, 500)) self.graphicsView.setObjectName(("graphicsView")) self.retranslateUi(Dialog) QtCore.QMetaObject.connectSlotsByName(Dialog) def retranslateUi(self, Dialog): Dialog.setWindowTitle(QtGui.QApplication.translate("Dialog", "Dialog", None, QtGui.QApplication.UnicodeUTF8))

  2. Clase MyForm , que es QDialog , donde llamo a la clase ViewerDemo , cargando Imagen y pongo la imagen en QGraphicsView

    import sys from ViewerDemo import * from PyQt4 import QtGui class MyForm(QtGui.QDialog): def __init__(self, url, parent=None): QtGui.QWidget.__init__(self, parent) self.ui = Ui_Dialog() self.ui.setupUi(self) self.scene = QtGui.QGraphicsScene(self) self.image = QtGui.QImage(url) pixmap= QtGui.QPixmap.fromImage(self.image) item=QtGui.QGraphicsPixmapItem(pixmap) self.scene.addItem(item) self.ui.graphicsView.setScene(self.scene) self.scale = 1 QtCore.QObject.connect(self.scene, QtCore.SIGNAL(''mousePressEvent()''),self.mousePressEvent) def mousePressEvent(self, event): print (''PRESSED : '',event.pos())

(3) es justo donde se ejecuta la aplicación:

from PyQt4 import QtGui, QtCore import sys from MyForm import MyForm if __name__ == "__main__": app = QtGui.QApplication(sys.argv) url = "D:/probaTiff" myapp = MyForm(url) myapp.show() sys.exit(app.exec_())

Encontré cómo hacer algo al hacer clic con el mouse (clic izquierdo y rueda), para imprimir coordenadas de píxeles (lo necesitaré para obtener las coordenadas en el Sistema de coordenadas de la imagen WGS84, por ejemplo).

Lo que necesito más es cómo hacer zoom en la imagen (rueda o doble clic, lo que sea) y encuadrar la imagen (presionando el botón izquierdo del mouse o presionando la rueda).

O, ¿hay algunas mejores clases de Qt para hacer esto, y alguna forma mejor? ¿Me pueden ayudar por favor?

Esto es lo que tengo hasta ahora con este código


Esto no es demasiado difícil de hacer usando las capacidades QGraphicsView de QGraphicsView .

La secuencia de comandos de demostración a continuación tiene desplazamiento panorámico con el botón izquierdo y zoom de la rueda (incluido el anclaje a la posición actual del cursor). El método fitInView se ha vuelto a implementar porque la versión incorporada agrega un margen fijo extraño que no se puede eliminar.

Versión PyQt4:

from PyQt4 import QtCore, QtGui class PhotoViewer(QtGui.QGraphicsView): photoClicked = QtCore.pyqtSignal(QtCore.QPoint) def __init__(self, parent): super(PhotoViewer, self).__init__(parent) self._zoom = 0 self._empty = True self._scene = QtGui.QGraphicsScene(self) self._photo = QtGui.QGraphicsPixmapItem() self._scene.addItem(self._photo) self.setScene(self._scene) self.setTransformationAnchor(QtGui.QGraphicsView.AnchorUnderMouse) self.setResizeAnchor(QtGui.QGraphicsView.AnchorUnderMouse) self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(30, 30, 30))) self.setFrameShape(QtGui.QFrame.NoFrame) def hasPhoto(self): return not self._empty def fitInView(self, scale=True): rect = QtCore.QRectF(self._photo.pixmap().rect()) if not rect.isNull(): self.setSceneRect(rect) if self.hasPhoto(): unity = self.transform().mapRect(QtCore.QRectF(0, 0, 1, 1)) self.scale(1 / unity.width(), 1 / unity.height()) viewrect = self.viewport().rect() scenerect = self.transform().mapRect(rect) factor = min(viewrect.width() / scenerect.width(), viewrect.height() / scenerect.height()) self.scale(factor, factor) self._zoom = 0 def setPhoto(self, pixmap=None): self._zoom = 0 if pixmap and not pixmap.isNull(): self._empty = False self.setDragMode(QtGui.QGraphicsView.ScrollHandDrag) self._photo.setPixmap(pixmap) else: self._empty = True self.setDragMode(QtGui.QGraphicsView.NoDrag) self._photo.setPixmap(QtGui.QPixmap()) self.fitInView() def wheelEvent(self, event): if self.hasPhoto(): if event.delta() > 0: factor = 1.25 self._zoom += 1 else: factor = 0.8 self._zoom -= 1 if self._zoom > 0: self.scale(factor, factor) elif self._zoom == 0: self.fitInView() else: self._zoom = 0 def toggleDragMode(self): if self.dragMode() == QtGui.QGraphicsView.ScrollHandDrag: self.setDragMode(QtGui.QGraphicsView.NoDrag) elif not self._photo.pixmap().isNull(): self.setDragMode(QtGui.QGraphicsView.ScrollHandDrag) def mousePressEvent(self, event): if self._photo.isUnderMouse(): self.photoClicked.emit(QtCore.QPoint(event.pos())) super(PhotoViewer, self).mousePressEvent(event) class Window(QtGui.QWidget): def __init__(self): super(Window, self).__init__() self.viewer = PhotoViewer(self) # ''Load image'' button self.btnLoad = QtGui.QToolButton(self) self.btnLoad.setText(''Load image'') self.btnLoad.clicked.connect(self.loadImage) # Button to change from drag/pan to getting pixel info self.btnPixInfo = QtGui.QToolButton(self) self.btnPixInfo.setText(''Enter pixel info mode'') self.btnPixInfo.clicked.connect(self.pixInfo) self.editPixInfo = QtGui.QLineEdit(self) self.editPixInfo.setReadOnly(True) self.viewer.photoClicked.connect(self.photoClicked) # Arrange layout VBlayout = QtGui.QVBoxLayout(self) VBlayout.addWidget(self.viewer) HBlayout = QtGui.QHBoxLayout() HBlayout.setAlignment(QtCore.Qt.AlignLeft) HBlayout.addWidget(self.btnLoad) HBlayout.addWidget(self.btnPixInfo) HBlayout.addWidget(self.editPixInfo) VBlayout.addLayout(HBlayout) def loadImage(self): self.viewer.setPhoto(QtGui.QPixmap(''image.jpg'')) def pixInfo(self): self.viewer.toggleDragMode() def photoClicked(self, pos): if self.viewer.dragMode() == QtGui.QGraphicsView.NoDrag: self.editPixInfo.setText(''%d, %d'' % (pos.x(), pos.y())) if __name__ == ''__main__'': import sys app = QtGui.QApplication(sys.argv) window = Window() window.setGeometry(500, 300, 800, 600) window.show() sys.exit(app.exec_())

Versión PyQt5:

from PyQt5 import QtCore, QtGui, QtWidgets class PhotoViewer(QtWidgets.QGraphicsView): photoClicked = QtCore.pyqtSignal(QtCore.QPoint) def __init__(self, parent): super(PhotoViewer, self).__init__(parent) self._zoom = 0 self._empty = True self._scene = QtWidgets.QGraphicsScene(self) self._photo = QtWidgets.QGraphicsPixmapItem() self._scene.addItem(self._photo) self.setScene(self._scene) self.setTransformationAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse) self.setResizeAnchor(QtWidgets.QGraphicsView.AnchorUnderMouse) self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) self.setBackgroundBrush(QtGui.QBrush(QtGui.QColor(30, 30, 30))) self.setFrameShape(QtWidgets.QFrame.NoFrame) def hasPhoto(self): return not self._empty def fitInView(self, scale=True): rect = QtCore.QRectF(self._photo.pixmap().rect()) if not rect.isNull(): self.setSceneRect(rect) if self.hasPhoto(): unity = self.transform().mapRect(QtCore.QRectF(0, 0, 1, 1)) self.scale(1 / unity.width(), 1 / unity.height()) viewrect = self.viewport().rect() scenerect = self.transform().mapRect(rect) factor = min(viewrect.width() / scenerect.width(), viewrect.height() / scenerect.height()) self.scale(factor, factor) self._zoom = 0 def setPhoto(self, pixmap=None): self._zoom = 0 if pixmap and not pixmap.isNull(): self._empty = False self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag) self._photo.setPixmap(pixmap) else: self._empty = True self.setDragMode(QtWidgets.QGraphicsView.NoDrag) self._photo.setPixmap(QtGui.QPixmap()) self.fitInView() def wheelEvent(self, event): if self.hasPhoto(): if event.angleDelta().y() > 0: factor = 1.25 self._zoom += 1 else: factor = 0.8 self._zoom -= 1 if self._zoom > 0: self.scale(factor, factor) elif self._zoom == 0: self.fitInView() else: self._zoom = 0 def toggleDragMode(self): if self.dragMode() == QtWidgets.QGraphicsView.ScrollHandDrag: self.setDragMode(QtWidgets.QGraphicsView.NoDrag) elif not self._photo.pixmap().isNull(): self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag) def mousePressEvent(self, event): if self._photo.isUnderMouse(): self.photoClicked.emit(QtCore.QPoint(event.pos())) super(PhotoViewer, self).mousePressEvent(event) class Window(QtWidgets.QWidget): def __init__(self): super(Window, self).__init__() self.viewer = PhotoViewer(self) # ''Load image'' button self.btnLoad = QtWidgets.QToolButton(self) self.btnLoad.setText(''Load image'') self.btnLoad.clicked.connect(self.loadImage) # Button to change from drag/pan to getting pixel info self.btnPixInfo = QtWidgets.QToolButton(self) self.btnPixInfo.setText(''Enter pixel info mode'') self.btnPixInfo.clicked.connect(self.pixInfo) self.editPixInfo = QtWidgets.QLineEdit(self) self.editPixInfo.setReadOnly(True) self.viewer.photoClicked.connect(self.photoClicked) # Arrange layout VBlayout = QtWidgets.QVBoxLayout(self) VBlayout.addWidget(self.viewer) HBlayout = QtWidgets.QHBoxLayout() HBlayout.setAlignment(QtCore.Qt.AlignLeft) HBlayout.addWidget(self.btnLoad) HBlayout.addWidget(self.btnPixInfo) HBlayout.addWidget(self.editPixInfo) VBlayout.addLayout(HBlayout) def loadImage(self): self.viewer.setPhoto(QtGui.QPixmap(''image.jpg'')) def pixInfo(self): self.viewer.toggleDragMode() def photoClicked(self, pos): if self.viewer.dragMode() == QtWidgets.QGraphicsView.NoDrag: self.editPixInfo.setText(''%d, %d'' % (pos.x(), pos.y())) if __name__ == ''__main__'': import sys app = QtWidgets.QApplication(sys.argv) window = Window() window.setGeometry(500, 300, 800, 600) window.show() sys.exit(app.exec_())