#!/usr/bin/env python # plotimage.py # Read and plot several different image types, including FITS # Sky Coyote for SWRI 2007 # Import modules used import sys import pyfits import numpy from PyQt4 import QtCore, QtGui # Scrolling, zooming, image viewer window class ImageViewer(QtGui.QMainWindow): def __init__(self, session, fileName, min, max, parent = None): QtGui.QMainWindow.__init__(self, parent) self.scaleFactor = 1.0 # Draw the image as a label's pixmap self.imageLabel = QtGui.QLabel() self.imageLabel.setBackgroundRole(QtGui.QPalette.Base) self.imageLabel.setSizePolicy(QtGui.QSizePolicy.Ignored, QtGui.QSizePolicy.Ignored) self.imageLabel.setScaledContents(True) # Put the label in a scrolling area self.scrollArea = QtGui.QScrollArea() self.scrollArea.setBackgroundRole(QtGui.QPalette.Dark) self.scrollArea.setWidget(self.imageLabel) self.setCentralWidget(self.scrollArea) # Create menus and associated actions self.createActions() self.createMenus() # Load the image self.loadImage(fileName, min, max) self.setWindowTitle(self.tr(str(session) + ': ' + fileName)) self.resize(self.imageLabel.size().width(), self.imageLabel.size().height()) # Convert ndarray to Qt Pixmap def ndarray2pixmap(self, ndArray, min=-1, max=-1): # Flip array print 'Flipping array' ndArray = ndArray[::-1, :] # Clip array print 'Clipping array' if min == -1: min = ndArray.min() if max == -1: max = ndArray.max() ndArray = ndArray.clip(min=min, max=max) min = ndArray.min() max = ndArray.max() # Faster Python-like way to copy and scale image into RGB buffer print 'Filling RGB buffer' byteArray = (255 * (ndArray - min) / (max - min)).astype('b').repeat(4) # Pixmap data must have a Python reference, or it will be deleted! byteString = byteArray.tostring() # Create QPixmap from byte buffer print 'Creating pixmap from buffer' return QtGui.QPixmap.fromImage(QtGui.QImage(byteString, ndArray.shape[1], \ ndArray.shape[0], QtGui.QImage.Format_RGB32)) def loadImage(self, fileName, min, max): # Read FITS file if fileName.upper().endswith(".FITS"): print 'Reading ', fileName ndArray = pyfits.getdata(fileName) print 'Converting ndarray to pixmap' self.imageLabel.setPixmap(self.ndarray2pixmap(ndArray, min, max)) # Read other image file else: image = QtGui.QImage(fileName) if image.isNull(): QtGui.QMessageBox.information(self, self.tr("Image Viewer"), self.tr("Cannot load %1.").arg(fileName)) return self.imageLabel.setPixmap(QtGui.QPixmap.fromImage(image)) self.scaleFactor = 1.0 self.fitToWindowAct.setEnabled(True) self.updateActions() if not self.fitToWindowAct.isChecked(): self.imageLabel.adjustSize() def zoomIn(self): self.scaleImage(1.25) def zoomOut(self): self.scaleImage(0.8) def normalSize(self): self.imageLabel.adjustSize() self.scaleFactor = 1.0 def fitToWindow(self): fitToWindow = self.fitToWindowAct.isChecked() self.scrollArea.setWidgetResizable(fitToWindow) if not fitToWindow: self.imageLabel.adjustSize() self.updateActions() def about(self): QtGui.QMessageBox.about(self, self.tr("About plotimage"), self.tr( "

The plotimage example shows how to combine QLabel " "and QScrollArea to display an image. QLabel is typically used " "for displaying text, but it can also display an image. " "QScrollArea provides a scrolling view around another widget. " "If the child widget exceeds the size of the frame, QScrollArea " "automatically provides scroll bars.

The example " "demonstrates how QLabel's ability to scale its contents " "(QLabel.scaledContents), and QScrollArea's ability to " "automatically resize its contents " "(QScrollArea.widgetResizable), can be used to implement " "zooming and scaling features.

In addition the example " "shows how to use pyfits and numpy to display a FITS image.

")) def createActions(self): self.zoomInAct = QtGui.QAction(self.tr("Zoom &In (25%)"), self) self.zoomInAct.setShortcut(self.tr("Ctrl++")) self.zoomInAct.setEnabled(False) self.connect(self.zoomInAct, QtCore.SIGNAL("triggered()"), self.zoomIn) self.zoomOutAct = QtGui.QAction(self.tr("Zoom &Out (25%)"), self) self.zoomOutAct.setShortcut(self.tr("Ctrl+-")) self.zoomOutAct.setEnabled(False) self.connect(self.zoomOutAct, QtCore.SIGNAL("triggered()"), self.zoomOut) self.normalSizeAct = QtGui.QAction(self.tr("&Normal Size"), self) self.normalSizeAct.setShortcut(self.tr("Ctrl+S")) self.normalSizeAct.setEnabled(False) self.connect(self.normalSizeAct, QtCore.SIGNAL("triggered()"), self.normalSize) self.fitToWindowAct = QtGui.QAction(self.tr("&Fit to Window"), self) self.fitToWindowAct.setEnabled(False) self.fitToWindowAct.setCheckable(True) self.fitToWindowAct.setShortcut(self.tr("Ctrl+F")) self.connect(self.fitToWindowAct, QtCore.SIGNAL("triggered()"), self.fitToWindow) self.aboutAct = QtGui.QAction(self.tr("&About"), self) self.connect(self.aboutAct, QtCore.SIGNAL("triggered()"), self.about) self.aboutQtAct = QtGui.QAction(self.tr("About &Qt"), self) self.connect(self.aboutQtAct, QtCore.SIGNAL("triggered()"), \ QtGui.qApp, QtCore.SLOT("aboutQt()")) def createMenus(self): self.viewMenu = QtGui.QMenu(self.tr("&View"), self) self.viewMenu.addAction(self.zoomInAct) self.viewMenu.addAction(self.zoomOutAct) self.viewMenu.addAction(self.normalSizeAct) self.viewMenu.addSeparator() self.viewMenu.addAction(self.fitToWindowAct) self.helpMenu = QtGui.QMenu(self.tr("&Help"), self) self.helpMenu.addAction(self.aboutAct) self.helpMenu.addAction(self.aboutQtAct) #self.menuBar().addMenu(self.fileMenu) self.menuBar().addMenu(self.viewMenu) self.menuBar().addMenu(self.helpMenu) 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.imageLabel.resize(self.scaleFactor * self.imageLabel.pixmap().size()) self.adjustScrollBar(self.scrollArea.horizontalScrollBar(), factor) self.adjustScrollBar(self.scrollArea.verticalScrollBar(), factor) self.zoomInAct.setEnabled(self.scaleFactor < 3.0) self.zoomOutAct.setEnabled(self.scaleFactor > 0.333) def adjustScrollBar(self, scrollBar, factor): scrollBar.setValue(int(factor * scrollBar.value() \ + ((factor - 1) * scrollBar.pageStep()/2))) # Run as main program if __name__ == "__main__": if len(sys.argv) < 2: print 'Usage: python plotimage.py image-file' sys.exit(1) min = max = -1 if len(sys.argv) > 2: min = float(sys.argv[2]) if len(sys.argv) > 3: max = float(sys.argv[3]) app = QtGui.QApplication([]) imageViewer = ImageViewer(0, sys.argv[1], min, max) imageViewer.show() sys.exit(app.exec_())