Подключение слайдера к графическому представлению в PyQt

Я пытаюсь отобразить данные изображения, считанные из двоичного файла (у меня есть код, написанный для извлечения этих данных из файла и их сохранения в виде изображения для использования с QImage() ). Что я хотел бы сделать, так это подключить ползунок к виджету «Графическое представление», чтобы при перемещении ползунка он перемещался по кадрам и отображал изображение из этого кадра (это эхограммы длиной от 1 до 500 кадров). Я очень новичок в PyQt, и мне было любопытно, как можно вообще начать это делать?

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

person Victoria Price    schedule 28.06.2012    source источник


Ответы (2)


Я мог бы дать вам более конкретный ответ, если бы вы показали, что вы пытались до сих пор, но пока я просто сделаю предположения и приведу вам пример.

Сначала вам нужно создать QSlider. Вы устанавливаете минимум/максимум QSlider для диапазона доступных изображений. Когда вы сдвинете его, появится sliderMoved сигнал. огонь и сказать вам, каково новое значение.

Затем вы можете создать список, содержащий все ваши QPixmap изображения заранее. Если эти образы огромны и вас беспокоит память, возможно, вам придется создавать их по запросу, используя уже закодированный подход. Но мы предполагаем, что вы можете пока поместить их в список, чтобы упростить пример.

Затем вы создаете свою настройку QGraphics, используя один QGraphicsPixmapItem. Этому элементу можно заменить растровое изображение по запросу.

Собрав все вместе, вы получите что-то вроде этого:

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_()

Вы можете видеть, что мы установили диапазон ползунка в соответствии с вашим списком изображений. В любое время вы можете изменить этот диапазон, если содержимое вашего списка изображений изменится. Когда срабатывает sliderMoved, он будет использовать значение в качестве индекса списка изображений и установит растровое изображение.

Я также добавил проверку в наш sliderMoved() SLOT на случай, если ваш диапазон ползунка не синхронизируется со списком изображений. Если вы перейдете к индексу, которого нет в вашем списке изображений, он корректно завершится ошибкой и оставит существующее изображение.

person jdi    schedule 30.06.2012
comment
Большое спасибо, это феноменальная помощь! Я даже не знал, с чего начать, если честно. Я добавил код, который придумал для генерации данных и изображения из бинарного файла; на чем я застрял, так это на том, как генерировать данные (и, следовательно, изображение) для нового кадра каждый раз при перемещении ползунка... - person Victoria Price; 02.07.2012
comment
@VictoriaPrice: я не слишком понимаю ваш код. Как вы выбираете разные изображения с помощью кода? Если вы покажете мне пример того, как вы это делаете, я обновлю свой ответ примером того, как их соединить. - person jdi; 02.07.2012
comment
Извини! Я супер-новичок со всем этим (без опыта программирования до месяца назад). Я начинаю с бинарных файлов с гидроакустической камеры. Я читаю файлы и разделяю информацию заголовка файла, информацию заголовка кадра и каждую строку данных на массивы numpy. Затем я использую данные из массива numpy класса Frame для создания растрового изображения 0-255 с помощью класса Echogram. Прямо сейчас я сохраняю изображение (в основном только для того, чтобы убедиться, что оно работает), но в конечном итоге мне нужно перебрать каждый кадр в файле и создать изображение. Это помогает? - person Victoria Price; 02.07.2012
comment
К сожалению, не так много. Все, что я действительно хотел знать, это пара простых строк о том, как вы получаете кадры QPixmap по запросу. Это много кода, на который нужно смотреть и пытаться понять. Можете ли вы обновить свой вопрос простым примером в нескольких строках о том, как его использовать, и вытащить несколько QPixmaps? - person jdi; 02.07.2012
comment
Кроме того, мне трудно следовать коду из-за его структуры. Я полностью понимаю, что вы только учитесь. Если вы хотите поговорить об этом более подробно, мы можем начать чат. - person jdi; 03.07.2012
comment
давайте продолжим это обсуждение в чате - person jdi; 03.07.2012

Большая часть выполняемой вами работы — преобразование данных изображения в QImage, отображение кадров с помощью ползунка — может быть лучше решена с использованием библиотеки, написанной для этой цели. Я могу придумать пару библиотек, которые работают с PyQt и предоставляют все, что вам нужно:

(отказ от ответственности: бессовестная вилка)

Если вы можете собрать все данные изображения в один массив 3D numpy, код для отображения этого в pyqtgraph будет выглядеть так:

import pyqtgraph as pg
pg.image(imageData)

Это даст вам масштабируемое отображение изображения с ползунком кадра и элементами управления таблицей поиска цветов.

person Luke    schedule 02.07.2012
comment
Благодарю вас! Я потрачу некоторое время на изучение этого сегодня - похоже, это может быть именно то, что мне нужно. - person Victoria Price; 03.07.2012
comment
Привет, Люк, мне трудно заставить pyqtgraph работать... Я получаю ошибку типа NameError: имя asUnicode не определено, когда пытаюсь импортировать его. Любые идеи? - person Victoria Price; 11.07.2012
comment
Хм. Я не видел этого раньше. Можете ли вы сказать мне, какую версию вы скачали, а также версию вашей ОС и Python? (Возможно, лучше обсудить это в списке рассылки: groups.google.com. /forum/?fromgroups#!forum/pyqtgraph ) - person Luke; 12.07.2012