Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

zooming in on an image



  • Hello,

    I have been working with Pyqt5 to develop an application. I have created the design of the gui using the designer. One can execute the following code to start the application:
    from PyQt5 import QtCore, QtGui, QtWidgets

    class Ui_MainWindow(object):
        def setupUi(self, MainWindow):
            MainWindow.setObjectName("MainWindow")
            MainWindow.resize(930, 834)
            sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
            sizePolicy.setHorizontalStretch(0)
            sizePolicy.setVerticalStretch(0)
            sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
            MainWindow.setSizePolicy(sizePolicy)
            self.centralwidget = QtWidgets.QWidget(MainWindow)
            self.centralwidget.setObjectName("centralwidget")
            self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
            self.horizontalLayout.setObjectName("horizontalLayout")
            self.verticalLayout = QtWidgets.QVBoxLayout()
            self.verticalLayout.setSizeConstraint(QtWidgets.QLayout.SetDefaultConstraint)
            self.verticalLayout.setObjectName("verticalLayout")
            self.open_dir = QtWidgets.QPushButton(self.centralwidget)
            self.open_dir.setMinimumSize(QtCore.QSize(150, 75))
            self.open_dir.setMaximumSize(QtCore.QSize(16777215, 16777215))
            self.open_dir.setObjectName("open_dir")
            self.verticalLayout.addWidget(self.open_dir)
            self.next = QtWidgets.QPushButton(self.centralwidget)
            self.next.setMinimumSize(QtCore.QSize(150, 75))
            self.next.setObjectName("next")
            self.verticalLayout.addWidget(self.next)
            self.previous = QtWidgets.QPushButton(self.centralwidget)
            self.previous.setMinimumSize(QtCore.QSize(150, 75))
            self.previous.setObjectName("previous")
            self.verticalLayout.addWidget(self.previous)
            self.load_model = QtWidgets.QPushButton(self.centralwidget)
            self.load_model.setMinimumSize(QtCore.QSize(150, 75))
            self.load_model.setObjectName("load_model")
            self.verticalLayout.addWidget(self.load_model)
            self.predict = QtWidgets.QPushButton(self.centralwidget)
            self.predict.setMinimumSize(QtCore.QSize(150, 75))
            self.predict.setObjectName("predict")
            self.verticalLayout.addWidget(self.predict)
            self.clear = QtWidgets.QPushButton(self.centralwidget)
            self.clear.setMinimumSize(QtCore.QSize(150, 75))
            self.clear.setObjectName("clear")
            self.verticalLayout.addWidget(self.clear)
            self.save = QtWidgets.QPushButton(self.centralwidget)
            self.save.setMinimumSize(QtCore.QSize(150, 75))
            self.save.setMaximumSize(QtCore.QSize(16777215, 16777215))
            self.save.setObjectName("save")
            self.verticalLayout.addWidget(self.save)
            self.horizontalLayout.addLayout(self.verticalLayout)
            spacerItem = QtWidgets.QSpacerItem(37, 17, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum)
            self.horizontalLayout.addItem(spacerItem)
            self.gridLayout = QtWidgets.QGridLayout()
            self.gridLayout.setObjectName("gridLayout")
            self.image_label = QtWidgets.QLabel(self.centralwidget)
            self.image_label.setMinimumSize(QtCore.QSize(700, 500))
            self.image_label.setMaximumSize(QtCore.QSize(16777215, 16777215))
            self.image_label.setFrameShape(QtWidgets.QFrame.WinPanel)
            self.image_label.setFrameShadow(QtWidgets.QFrame.Sunken)
            self.image_label.setLineWidth(1)
            self.image_label.setScaledContents(True)
            self.image_label.setObjectName("image_label")
            self.gridLayout.addWidget(self.image_label, 0, 0, 1, 1)
            spacerItem1 = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Fixed)
            self.gridLayout.addItem(spacerItem1, 1, 0, 1, 1)
            self.classes = QtWidgets.QLabel(self.centralwidget)
            self.classes.setMinimumSize(QtCore.QSize(700, 201))
            self.classes.setFrameShape(QtWidgets.QFrame.WinPanel)
            self.classes.setFrameShadow(QtWidgets.QFrame.Plain)
            self.classes.setScaledContents(True)
            self.classes.setObjectName("classes")
            self.gridLayout.addWidget(self.classes, 2, 0, 1, 1)
            self.horizontalLayout.addLayout(self.gridLayout)
            MainWindow.setCentralWidget(self.centralwidget)
            self.menubar = QtWidgets.QMenuBar(MainWindow)
            self.menubar.setGeometry(QtCore.QRect(0, 0, 930, 26))
            self.menubar.setObjectName("menubar")
            MainWindow.setMenuBar(self.menubar)
            self.statusbar = QtWidgets.QStatusBar(MainWindow)
            self.statusbar.setObjectName("statusbar")
            MainWindow.setStatusBar(self.statusbar)
            self.actionRecent = QtWidgets.QAction(MainWindow)
            self.actionRecent.setObjectName("actionRecent")
    
            self.retranslateUi(MainWindow)
            QtCore.QMetaObject.connectSlotsByName(MainWindow)
    
        def retranslateUi(self, MainWindow):
            _translate = QtCore.QCoreApplication.translate
            MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
            self.open_dir.setText(_translate("MainWindow", "Open Directory"))
            self.next.setText(_translate("MainWindow", "Next Image -->"))
            self.previous.setText(_translate("MainWindow", "<-- Previous Image"))
            self.load_model.setText(_translate("MainWindow", "Load Model"))
            self.predict.setText(_translate("MainWindow", "Predict"))
            self.clear.setText(_translate("MainWindow", "Clear"))
            self.save.setText(_translate("MainWindow", "Save"))
            self.image_label.setText(_translate("MainWindow", "ImageLabel"))
            self.classes.setText(_translate("MainWindow", "TextLabel"))
            self.actionRecent.setText(_translate("MainWindow", "Recent"))
    
    
    if __name__ == "__main__":
        import sys
        app = QtWidgets.QApplication(sys.argv)
        MainWindow = QtWidgets.QMainWindow()
        ui = Ui_MainWindow()
        ui.setupUi(MainWindow)
        MainWindow.show()
        sys.exit(app.exec_())
    

    Now I am adding some functionalities to the image_label section of the gui i.e. zooming, panning and so on. In order to do this, I have written the following script:

    # Import pyqt stuff
    from PyQt5 import QtCore, QtGui, QtWidgets, Qt
    from PyQt5.QtWidgets import QFileDialog
    from PyQt5.QtWidgets import QApplication
    
    # Import the python script generated by the Qt-Designer
    from version4 import Ui_MainWindow
    
    # Import miscellaneous
    import sys
    import os
    
    
    class ImageViewer(QtWidgets.QGraphicsView):
        factor = 2.0
    
        def __init__(self, parent=None):
            super().__init__(parent)
            self.setRenderHints(
                QtGui.QPainter.Antialiasing | QtGui.QPainter.SmoothPixmapTransform
            )
            self.setAlignment(QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
            self.setBackgroundRole(QtGui.QPalette.Dark)
    
            scene = QtWidgets.QGraphicsScene()
            self.setScene(scene)
    
            self._pixmap_item = QtWidgets.QGraphicsPixmapItem()
            scene.addItem(self._pixmap_item)
    
        def load_image(self, fileName):
            pixmap = QtGui.QPixmap(fileName)
            if pixmap.isNull():
                return False
            self._pixmap_item.setPixmap(pixmap)
            return True
    
        def zoomIn(self):
            self.zoom(self.factor)
    
        def zoomOut(self):
            self.zoom(1 / self.factor)
    
        def zoom(self, f):
            self.scale(f, f)
    
        def resetZoom(self):
            self.resetTransform()
    
        def fitToWindow(self):
            self.fitInView(self.sceneRect(), QtCore.Qt.KeepAspectRatio)
    
    
    class mainProgram(QtWidgets.QMainWindow, Ui_MainWindow):
    
        def __init__(self, parent=None):
    
            # Inherit from the aforementioned class and set up the gui
            super(mainProgram, self).__init__(parent)
            self.setupUi(self)
    
            self.fileList = []
            self.dirIterator = None
    
            self.scaleFactor = 1.0
    
            self.view = ImageViewer()
    
            # Set an index to iterate through directory
            self.i = 0
    
            self.create_shortcuts()
            self.create_actions()
            self.create_menus()
    
            # Statusbar
            self.statusBar = QtWidgets.QStatusBar(self)
            self.setStatusBar(self.statusBar)
            self.statusBar.showMessage('Welcome')
    
        def create_shortcuts(self):
            self.open_dir.setShortcut(QtGui.QKeySequence("O"))
            self.next.setShortcut(QtGui.QKeySequence("D"))
            self.previous.setShortcut(QtGui.QKeySequence("A"))
    
        def all_callbacks(self):
            self.open_dir.clicked.connect(self.open_directory_callback)
            self.next.clicked.connect(self.next_button_callback)
            self.previous.clicked.connect(self.previous_button_callback)
    
        def open_directory_callback(self):
            # Paths
            self._base_dir = os.getcwd()
            self._images_dir = os.path.join(self._base_dir, 'test_images')
    
            # Open a File Dialog and select the folder path
            dialog = QFileDialog()
            self._folder_path = dialog.getExistingDirectory(None, "Select Folder")
    
            # Get the list of images in the folder and read using matplotlib and print its shape
            self.list_of_images = os.listdir(self._folder_path)
            self.list_of_images = sorted(self.list_of_images)
            if self.list_of_images:
                self.statusBar.showMessage('Total Number of Images in the directory \
                                           : {}'.format(len(self.list_of_images)))
    
            # Length of Images
            print('Number of Images in the selected folder: {}'.format(len(self.list_of_images)))
            filename = '{}\\{}'.format(self._images_dir, self.list_of_images[0])
            print(filename)
    
            # Show the first Image in the same window. (self.label comes from the Ui_main_window class)
            pixmap = QtGui.QPixmap(filename)
            if filename:
                is_loaded = self.view.load_image(filename)
                self.fitToWindowAct.setEnabled(is_loaded)
                self.updateActions()
            # self.image_label.setPixmap(pixmap)
            # self.image_label.show()
    
        def next_button_callback(self):
            total_images = len(self.list_of_images)
            if self.list_of_images:
                try:
                    self.i = (self.i + 1) % total_images
                    self.img = self.list_of_images[self.i]
                    pixmap = QtGui.QPixmap('{}\\{}'.format(self._images_dir, self.img))
                    self.image_label.setPixmap(pixmap)
                    self.image_label.show()
                    self.statusBar.showMessage('Current Image: {}'.format(self.list_of_images[self.i]))
                except ValueError as e:
                    print('The selected folder does not contain any images')
            self.fitToWindowAct.setEnabled(True)
            self.updateActions()
    
        def previous_button_callback(self):
            total_images = len(self.list_of_images)
            if self.list_of_images:
                try:
                    self.i = (self.i - 1) % total_images
                    self.img = self.list_of_images[self.i]
                    pixmap = QtGui.QPixmap('{}\\{}'.format(self._images_dir, self.img))
                    self.image_label.setPixmap(pixmap)
                    self.image_label.show()
                    self.statusBar.showMessage('Current Image: {}'.format(self.list_of_images[self.i]))
                except ValueError as e:
                    print('The selected folder does not contain any images')
            self.fitToWindowAct.setEnabled(True)
            self.updateActions()
    
        def fitToWindow(self):
            if self.fitToWindowAct.isChecked():
                self.view.fitToWindow()
            else:
                self.view.resetZoom()
            self.updateActions()
    
        def create_menus(self):
            # File Menu
            self.fileMenu = QtWidgets.QMenu("&File", self)
            self.fileMenu.addAction(self.exitAct)
    
            # Controls Menu
            self.controlsMenu = QtWidgets.QMenu("&Controls", self)
            self.controlsMenu.addAction(self.zoomInAct)
            self.controlsMenu.addAction(self.zoomOutAct)
            self.controlsMenu.addAction(self.normalSizeAct)
            self.fileMenu.addSeparator()
            self.controlsMenu.addAction(self.fitToWindowAct)
    
            # Add Menus
            self.menuBar().addMenu(self.fileMenu)
            self.menuBar().addMenu(self.controlsMenu)
    
        def create_actions(self):
            self.exitAct = QtWidgets.QAction("E&xit", self, shortcut="Ctrl+Q", triggered=self.close)
            self.zoomInAct = QtWidgets.QAction("Zoom &In (25%)", self, shortcut="Ctrl++", enabled=False,
                                               triggered=self.view.zoomIn)
            self.zoomOutAct = QtWidgets.QAction("Zoom &Out (25%)", self, shortcut="Ctrl+-", enabled=False,
                                                triggered=self.view.zoomOut)
            self.fitToWindowAct = QtWidgets.QAction("&Fit To Window", self, shortcut="Ctrl+F", enabled=False,
                                                    checkable=True, triggered=self.fitToWindow)
            self.normalSizeAct = QtWidgets.QAction("&Normal Size", self, shortcut="Ctrl+0", enabled=False,
                                                   triggered=self.view.resetZoom)
    
        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 execute_pipeline():
        # Make an object of the class and execute it
        app = QApplication(sys.argv)
    
        # Make an object and call the functions
        annotationGui = mainProgram()
        annotationGui.all_callbacks()
        annotationGui.show()
    
        # Exit the window
        sys.exit(app.exec_())
    
    
    if __name__ == "__main__":
        execute_pipeline()
    

    Here, the 'version4' is the code on the top.
    Now, I am trying to zoom in on the image using the ImageViewer class. But when the open_directory button is pressed, the image doesn't appear in the window. But when I remove the object 'self.view' of the ImageViewer class, the image does appear but then I can't using zoomIn andf zoomOut.

    Therefore, I am unsure as to what is wrong. Please let me know if something else should be specified in the question.

    Regards.


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Your view object is never shown nor added to a layout nor set as the central widget of your QMainWindow based class. Hence it stays invisible.



  • @SGaist But if I add view object to the base class like the following:

    self.setCentralWidget(self.view)
    

    then then the entire window blanks out. I just want to know how do I add the self.view to the image_label section of the gui.

    Thanks for the reply!!


Log in to reply