Frage

I'm trying to display image data read in from a binary file (I have the code written for retrieving this data from a file and storing it as an image for use with QImage() ). What I would like to do is connect a slider to a Graphics View widget so that when you move the slider, it moves through the frames and displays the image from that frame (these are echograms ranging from 1-500 frames in length). I'm very new to PyQt and was curious how one might even begin doing this?

from PyQt4.QtCore import *
from PyQt4.QtGui import *
import numpy as np



class FileHeader(object):

    fileheader_fields=      ("filetype","fileversion","numframes","framerate","resolution","numbeams","samplerate","samplesperchannel","receivergain","windowstart","winlengthsindex","reverse","serialnumber","date","idstring","ID1","ID2","ID3","ID4","framestart","frameend","timelapse","recordInterval","radioseconds","frameinterval","userassigned")
   fileheader_formats=('S3','B','i4','i4','i4','i4','f','i4','i4','i4','i4','i4','i4','S32','S256','i4','i4','i4','i4','i4','i4','i4','i4','i4','i4','S136')

    def __init__(self,filename,parent=None):
        a=QApplication([])
        filename=str(QFileDialog.getOpenFileName(None,"open file","C:/vprice/DIDSON/DIDSON Data","*.ddf"))
        self.infile=open(filename, 'rb')
        dtype=dict(names=self.fileheader_fields, formats=self.fileheader_formats)
        self.fileheader=np.fromfile(self.infile, dtype=dtype, count=1)
        self.fileheader_length=self.infile.tell()


    for field in self.fileheader_fields:
        setattr(self,field,self.fileheader[field])



    def get_frame_first(self):
        frame=Frame(self.infile)
        print self.fileheader
        self.infile.seek(self.fileheader_length)
        print frame.frameheader
        print frame.data



    def __iter__(self):
        self.infile.seek(self.fileheader_length)

    for _ in range(self.numframes):
        yield Frame(self.infile)

    #def close(self):
        #self.infile.close()
    def display(self):
        print self.fileheader


class Frame(object):
    frameheader_fields=("framenumber","frametime","version","status","year","month","day","hour","minute","second","hsecond","transmit","windowstart","index","threshold","intensity","receivergain","degc1","degc2","humidity","focus","battery","status1","status2","velocity","depth","altitude","pitch","pitchrate","roll","rollrate","heading","headingrate","sonarpan","sonartilt","sonarroll","latitude","longitude","sonarposition","configflags","userassigned")
    frameheader_formats=("i4","2i4","S4","i4","i4","i4","i4","i4","i4","i4","i4","i4","i4","i4","i4","i4","i4","i4","i4","i4","i4","i4","S16","S16","f","f","f","f","f","f","f","f","f","f","f","f","f8","f8","f","i4","S60")
    data_format="uint8"

    def __init__(self,infile):

        dtype=dict(names=self.frameheader_fields,formats=self.frameheader_formats)
        self.frameheader=np.fromfile(infile,dtype=dtype,count=1)


        for field in self.frameheader_fields:
            setattr(self,field,self.frameheader[field])

        ncols,nrows=96,512


        self.data=np.fromfile(infile,self.data_format,count=ncols*nrows)

        self.data=self.data.reshape((nrows,ncols))

class QEchogram():
    def __init__(self):
        self.__colorTable=[]
        self.colorTable=None
        self.threshold=[50,255]
        self.painter=None
        self.image=None

    def echogram(self):
        fileheader=FileHeader(self)
        frame=Frame(fileheader.infile)
        echoData=frame.data

        #fileName = fileName

        self.size=[echoData.shape[0],echoData.shape[1]]

        #  define the size of the data (and resulting image)
        #size = [96, 512]

        #  create a color table for our image
        #  first define the colors as RGB triplets
        colorTable =  [(255,255,255),
                       (159,159,159),
                       (95,95,95),
                       (0,0,255),
                       (0,0,127),
                       (0,191,0),
                       (0,127,0),
                       (255,255,0),
                       (255,127,0),
                       (255,0,191),
                       (255,0,0),
                       (166,83,60),
                       (120,60,40),
                       (200,200,200)]

    #  then create a color table for Qt - this encodes the color table
    #  into a list of 32bit integers (4 bytes) where each byte is the
    #  red, green, blue and alpha 8 bit values. In this case we don't
    #  set alpha so it defaults to 255 (opaque)
        ctLength = len(colorTable)
        self.__ctLength=ctLength
        __colorTable = []
        for c in colorTable:
            __colorTable.append(QColor(c[0],c[1],c[2]).rgb())




        echoData = np.round((echoData - self.threshold[0])*(float(self.__ctLength)/(self.threshold[1]-self.threshold[0])))
        echoData[echoData < 0] = 0
        echoData[echoData > self.__ctLength-1] = self.__ctLength-1
        echoData = echoData.astype(np.uint8)
        self.data=echoData

    #  create an image from our numpy data
        image = QImage(echoData.data, echoData.shape[1], echoData.shape[0], echoData.shape[1],
                   QImage.Format_Indexed8)
        image.setColorTable(__colorTable)

    #  convert to ARGB
        image = image.convertToFormat(QImage.Format_ARGB32)


    #  save the image to file
        image.save(fileName)
        self.image=QImage(self.size[0],self.size[1],QImage.Format_ARGB32)
        self.painter=QPainter(self.image)
        self.painter.drawImage(QRect(0.0,0.0,self.size[0],self.size[1]),image)

    def getImage(self):
        self.painter.end()
        return self.image
    def getPixmap(self):
        self.painter.end()
        return QPixmap.fromImage(self.image)




if __name__=="__main__":

    data=QEchogram()
    fileName="horizontal.png"
    data.echogram()
    dataH=data.data
    print "Horizontal data", dataH
War es hilfreich?

Lösung

I could give you a more specific answer if you showed what you were trying so far, but for now I will just make assumptions and give you an example.

First what you would do is create a QSlider. You set the QSlider minimum/maximum to the range of images that you have available. When you slide it, the sliderMoved signal will fire and tell you what the new value is.

Next, you can create a list containing all of your QPixmap images ahead of time. If these images are huge and you are concerned about memory, you might have to create them on demand using your already coded approach. But we will assume you can put them in a list for now, to make the example easier.

Then you create your QGraphics set up, using a single QGraphicsPixmapItem. This item can have its pixmap replaced on demand.

Putting it all together, you get something like this:

from PyQt4 import QtCore, QtGui

class Widget(QtGui.QWidget):

    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)
        self.resize(640,480)
        self.layout = QtGui.QVBoxLayout(self)

        self.scene = QtGui.QGraphicsScene(self)
        self.view = QtGui.QGraphicsView(self.scene)
        self.layout.addWidget(self.view)

        self.image = QtGui.QGraphicsPixmapItem()
        self.scene.addItem(self.image)
        self.view.centerOn(self.image)

        self._images = [
            QtGui.QPixmap('Smiley.png'),
            QtGui.QPixmap('Smiley2.png')
        ]

        self.slider = QtGui.QSlider(self)
        self.slider.setOrientation(QtCore.Qt.Horizontal)
        self.slider.setMinimum(0)
        # max is the last index of the image list
        self.slider.setMaximum(len(self._images)-1)
        self.layout.addWidget(self.slider)

        # set it to the first image, if you want.
        self.sliderMoved(0)

        self.slider.sliderMoved.connect(self.sliderMoved)

    def sliderMoved(self, val):
        print "Slider moved to:", val
        try:
            self.image.setPixmap(self._images[val])
        except IndexError:
            print "Error: No image at index", val

if __name__ == "__main__":
    app = QtGui.QApplication([])
    w = Widget()
    w.show()
    w.raise_()
    app.exec_()

You can see that we set the range of the slider to match your image list. At any time, you can change this range if the contents of your image list change. When the sliderMoved fires, it will use the value as the index of the image list and set the pixmap.

I also added a check to our sliderMoved() SLOT just in case your slider range gets out of sync with your image list. If you slide to an index that doesn't exist in your image list, it will fail gracefully and leave the existing image.

Andere Tipps

A lot of the work you are doing--converting image data to QImage, displaying frames with a slider--might be solved better using a library written for this purpose. There are a couple libraries I can think of that work with PyQt and provide everything you need:

(disclaimer: shameless plug)

If you can collect all of the image data into a single 3D numpy array, the code for displaying this in pyqtgraph looks like:

import pyqtgraph as pg
pg.image(imageData)

This would give you a zoomable image display with frame slider and color lookup table controls.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top