Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Торможения таймера при рисовании
Форум на CrossPlatform.RU > Разработка > Интерпретируемые языки
Страницы: 1, 2
zuze
Я пытаюсь закрасить область красным цветом за определённое время. Область будет закрашиватся каждый раз пока я не остановлю таймер.
Код:
# Глобальные
phi = 0.0
FlagStopRunPhi = 0
RunStopTimer = 1
timer = QtCore.QTimer()
im1 = QtGui.QImage(720, 492, QtGui.QImage.Format_ARGB32)

# В конструкторе

# Запустить таймер
self.connect(self.ui.pushButton_3, QtCore.SIGNAL("clicked()"), self.BlockTimer)

# Что происходит по таймеру
self.connect(timer, QtCore.SIGNAL("timeout()"), self.MyTimer)

def paintEvent(self, QPaintEvent):
      self.MyDraw()

# Запустить таймер
def BlockTimer(self):
            timer.start(0.05*1000)/60)

# Что происходит по таймеру
def MyTimer(self):
        global phi
        global im1

        if self.ui.checkBox_4.isChecked():
            for j in range(0, 720, 1):
                for i in range(491, -1, -1):
                    im1.setPixel(j, i, QtGui.QColor(255, 0, 0, 255).rgba())

        self.update()

        if self.ui.radioButton_2.isChecked():
            if int(self.MyRadianToGradus(phi)+0.5)*720/360 < 720:
                phi += self.MyGradusToRadian(6.0)
            else:
                phi = self.MyGradusToRadian(6.0)

# Рисуем
def MyDraw(self):
        global im1
        global phi

        Tochka = QtGui.QPainter()
        Tochka.begin(self)

        Tochka.translate(50, 50)

        Tochka.drawImage(0, 0, im1, 0, 0, int((2*self.MyRadianToGradus(phi))+0.5), 492)

        Tochka.end()


Должно быстро закрашиватся цветом, а закрашивается, только через каждые 0.5 секунды. Почему так происходит? В Qt всё быстро закрашивается.
Iron Bug
питон - интерпретатор. его скорость от 10 до 500 раз ниже, чем у кода С++, в зависимости от того, что делаешь.
zuze
Цитата(Iron Bug @ 29.3.2013, 11:02) *
питон - интерпретатор. его скорость от 10 до 500 раз ниже, чем у кода С++, в зависимости от того, что делаешь.


А можно ли в коде на Python вставить код, который однозначно показывал, что виноват сам Python, а не я?

Притом, такая простейшая операция, как закрашивание области цветом во времени. Мне не веритя, что такая простая операция затормаживает таймер в Python.
Iron Bug
если ты утверждаешь, что Qt не тормозит, то больше не на что списать тормоза, кроме как на интерфейс между Qt и питоном.

ну и реализация алгоритма весьма странная: у тебя каждый раз вызывается процедура закрашивания точки. это вызывает целую цепочку операций, в итоге идёт обращение к графической библиотеке и это происходит для каждой точки. естественно, что это тормозит. наверняка есть более быстрые методы работы с заполнением прямоугольника цветом, чтобы не делать столько длинных вызовов. кроме того, у тебя каждый раз в каждой итерации создаётся объект QColor, да ещё и с вызовом его метода, а на любое создание объекта нужно довольно много времени. питон - интерпретатор, он не умеет оптимизировать такие сложные вещи, это надо делать самому.
в общем, там много где можно опимизировать.

а для измерения времени можно попробовать навставлять таймеры и писать замеренное время в какой-то лог (только не на экран, а в память, а то ещё ужаснее будут тормоза из-за самих записей).
zuze
Прямоугольная область с торможениями закрашивается красным цветом. Но вот один раз я абсолютно также сделал и прямоугольная область быстро начала зарисовыватся красным цветом.
Как будто это сбой самого Pathon-а. Решил привести полный код. Может кто увидит, где может быть ошибка и отпишется.
Мой код:
# -*- coding: utf-8 -*-

from PyQt4 import QtCore, QtGui, uic
import math
import os
import struct

phi = 0.0
timer = QtCore.QTimer()
im = QtGui.QImage(720, 492, QtGui.QImage.Format_ARGB32)


class ld(QtGui.QDialog):
    def __init__(self, parent=None):
        super(ld, self).__init__(parent)
        self.ui = uic.loadUi("ld.ui", self)

        self.connect(timer, QtCore.SIGNAL("timeout()"), self.MyTimer)
        timer.start((0.005 * 1000) / 60)

    def paintEvent(self, QPaintEvent):
        if self.ui.radioButton.isChecked():
            painterRect = QtGui.QPainter(self)
            painterRect.setBrush(QtGui.QColor('black'))
            painterRect.drawRect(50, 50, 720, 492)

            self.MyDraw()

        self.update()

    def MyRadianToGradus(self, phiedit):
        gradus = phiedit * 360 / (2 * math.pi)
        return gradus

    def MyGradusToRadian(self, phiedit):
        radian = phiedit * 2 * math.pi / (360)
        return radian

    def MyTimer(self):
        global phi
        global im

        if self.ui.checkBox.isChecked():
            for j in range(0, 720, 1):
                for i in range(491, -1, -1):
                    im.setPixel(j, i, QtGui.QColor(255, 0, 0, 255).rgba())

        self.update()

        if int(self.MyRadianToGradus(phi) + 0.5) * 720 / 360 < 720:
            phi += self.MyGradusToRadian(6.0)
        else:
            phi = self.MyGradusToRadian(6.0)

    def MyDraw(self):
        global im
        global phi

        Tochka = QtGui.QPainter()
        Tochka.begin(self)

        Tochka.translate(50, 50)

        Tochka.drawImage(0, 0, im, 0, 0, int((2 * self.MyRadianToGradus(phi)) + 0.5), 492)

        Tochka.end()

if __name__ == '__main__':
    import sys

    app = QtGui.QApplication(sys.argv)

    window = ld()
    window.show()

    sys.exit(app.exec_())
lanz
timer.start((0.005 * 1000) / 60)

(0.005 * 1000) / 60 ~ 0
Поэтому таймер будет выстреливать так быстро как может, то есть постоянно.

А в обработчике таймера его ждет такой цикл:
if self.ui.checkBox.isChecked():
    for j in range(0, 720, 1):
        for i in range(491, -1, -1):
            im.setPixel(j, i, QtGui.QColor(255, 0, 0, 255).rgba())

Т.е. картинка перегенерируется постоянно, это небыстро, отсюда и тормоза.
zuze
Цитата(lanz @ 4.4.2013, 9:20) *
Т.е. картинка перегенерируется постоянно, это небыстро, отсюда и тормоза.


А как это поправить?

У меня даже таймер

timer.start((0.05 * 1000) / 60)


тормозит, а такой таймер необходим и в Qt работал. А почему он в Python иногда проскакивает с быстрой скоростью?
lanz
Цитата
А как это поправить?


Нужно картинку сгенерировать один раз, например при запуске программы.

Цитата
такой таймер необходим и в Qt работал

Может он и в Qt тормозил, 0.8 мс это очень быстро, так быстро даже курсор мыши не обновляется, 15-30 мс более разумные рамки.

Цитата
А почему он в Python иногда проскакивает с быстрой скоростью?

Может быть тысяча причин и ни на одну нельзя полагаться. Например удачно выпадает переключение процессов или байт код питоновский закешировался.
Написание приложений реального времени в Windows сродни квантовой механике :lol:
zuze
Цитата(lanz @ 4.4.2013, 9:50) *
Может он и в Qt тормозил, 0.8 мс это очень быстро, так быстро даже курсор мыши не обновляется, 15-30 мс более разумные рамки.


Я сделал так

timer.start(5000)


А в место 5 секунд обновляется, через каждые 3 секунды.

Я делал так

timer.start(15)


Картинка через каждые 0,5 секунды обновляется.

Что же с этим таймером?
lanz
Если картинка не успевает обновится за 15 мс (а она наверняка не успевает) то поток блокируется до тех пор, пока она не обновится. Все это время сообщения от таймера скапливаются и будут обработаны только когда поток освободится. Поэтому и задержка, т.е. реальное время где то 0,5 секунды и быстрее не получится.
zuze
Цитата(lanz @ 4.4.2013, 10:37) *
Поэтому и задержка, т.е. реальное время где то 0,5 секунды и быстрее не получится.


1. Можно ли это как-то документально прочитать, про скорости таймера в Python?
2. А почему тогда в место 5 секунд обновляется, через каждые 3 секунды?
lanz
1. Таймер в Qt. Python только вызывает функции.
2. А как были посчитаны эти 3 секунды?
zuze
Цитата(lanz @ 4.4.2013, 10:57) *
2. А как были посчитаны эти 3 секунды?


Я делал так

timer.start(5000)


А считал в уме. Решил проверинть на секундомере на смартфоне. В итоге первые несколько раз по 3 секунды, а потом идёт интервал по 5 секунд, даже немного поменше (4,7 или 4,8 секунды).
zuze
Как я понял, мой коде есть ряд ошибок:
1. Код не удовлетворяет модели "модель-представление-контроллер (Model-View-Controller, MVC)". Не совсем понимаю, как это сделать.
2. Я вызываю перерисовку всего окна по таймеру и жду следующей перерисовку от таймера. Наверно надо пересовывать, только следующий кусочек.
3. Возможно я не в той функции запускаю таймер.
4. В методе MyTimer ты в не зависимости от того активен self.checkBox или нет, проверяю phi на условие и в зависимости от результата меняю его.
Это я поправил, вот так:
def MyTimer(self):
        global phi
        global im1

        if self.ui.checkBox_4.isChecked():
            for j in range(0, 720, 1):
                for i in range(491, -1, -1):
                    im1.setPixel(j, i, QtGui.QColor(255, 0, 0, 255).rgba())

            self.update()

            if int(self.MyRadianToGradus(phi)+0.5)*720/360 < 720:
                phi += self.MyGradusToRadian(6.0)
            else:
                phi = self.MyGradusToRadian(6.0)


Помогите пожалуйста разобратся с ошибочками 1-3.
lanz
Цитата
Код не удовлетворяет модели "модель-представление-контроллер (Model-View-Controller, MVC)". Не совсем понимаю, как это сделать.

Это не ошибка сама по себе. Не любой код должен удовлетворять такой модели.
http://ru.wikipedia.org/wiki/Model-View-Controller

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

Основные тормоза не от этого, а скорее всего, что картинка готовится каждый раз, когда надо ее вывести:
if self.ui.checkBox_4.isChecked():
            for j in range(0, 720, 1):
                for i in range(491, -1, -1):
                    im1.setPixel(j, i, QtGui.QColor(255, 0, 0, 255).rgba())

Этот код не зависит от phi, зачем он вызывается каждый раз при перерисовке?

Цитата
Возможно я не в той функции запускаю таймер.

Не вижу проблемы.
zuze
Цитата(lanz @ 8.4.2013, 8:45) *
Основные тормоза не от этого, а скорее всего, что картинка готовится каждый раз, когда надо ее вывести:

if self.ui.checkBox_4.isChecked():
            for j in range(0, 720, 1):
                for i in range(491, -1, -1):
                    im1.setPixel(j, i, QtGui.QColor(255, 0, 0, 255).rgba())


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

Не ужели для такой простой задачи в Python без потоков не обойтись?

На всякий случай прикрепляю два фала ld.py и ld.ui лежащих в архиве ld.zip. Возможно они помогут решить проблему с торможением.
zuze
Решил проверить время выполнения кода.

if self.ui.radioButton.isChecked():
            self.start = time.time()
            for j in range(0, 720, 1):
                for i in range(491, -1, -1):
                    im.setPixel(j, i, QtGui.QColor(255, 0, 0, 255).rgba())

            self.end = time.time()
            self.secs = self.end - self.start
            print self.secs  # миллисекунды


Какие-то странные результаты, хотя я поставил таймер 5000 миллисекунд.
А сами результаты такие:
0.836999893188
0.838999986649
0.837999820709
0.832000017166
0.836999893188
lanz
Все правильно, подготовка картинки занимает почти секунду.

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

Картинку необязательно готовить каждый кадр, можно ее готовить только когда возникнет необходимость в новой.
zuze
Цитата(lanz @ 8.4.2013, 10:35) *
Картинку необязательно готовить каждый кадр, можно ее готовить только когда возникнет необходимость в новой.


У меня необходимость постоянная в выводе картинок. Сначала берутся значения из двоичного файла и рисуеться картинка, через определённый промежуток времени. Затем рисуется картинка из второго файла, а первая картинка, как бы затираеться. Затем рисуеться картинка из третьего файла, а вторая картинка, как бы затираеться.

Схема вывода картинок:

_______________________________
|-----------------------|------------------------|
|Первая картинка | Фон -----------------|
|-----------------------|------------------------|
_______________________________|

________________________________
|-----------------------|------------------------|
|Вторая картинка | Первая картинка |
|-----------------------|------------------------|
_______________________________|

_______________________________
|----------------------|-------------------------|
|Третья картинка | Вторая картинка |
|----------------------|------------------------|
______________________________|

и так далее.
lanz
Это все понятно, но картинка обновляется только когда начинает рисоваться новая, а не каждый шаг (по phi) отрисовки картинки.
zuze
Цитата(lanz @ 8.4.2013, 10:51) *
Это все понятно, но картинка обновляется только когда начинает рисоваться новая, а не каждый шаг (по phi) отрисовки картинки.


Вы говорите о том, что я из таймера должен убрать

self.update()


но это не помогло.
lanz
Нет, я о том чтобы убрать вот это
 if self.ui.checkBox_4.isChecked():
            for j in range(0, 720, 1):
                for i in range(491, -1, -1):
                    im1.setPixel(j, i, QtGui.QColor(255, 0, 0, 255).rgba())
zuze
Цитата(lanz @ 8.4.2013, 11:41) *
Нет, я о том чтобы убрать вот это

if self.ui.checkBox_4.isChecked():
            for j in range(0, 720, 1):
                for i in range(491, -1, -1):
                    im1.setPixel(j, i, QtGui.QColor(255, 0, 0, 255).rgba())


А куда, можно убрать?
lanz
Туда, где загружается картинка.
zuze
Цитата(lanz @ 8.4.2013, 12:22) *
Туда, где загружается картинка.


Так у меня картинка загружается тутже. Я загрузку картинки заменил на загрузку цвета. В таком случае, что делать?

Может такая задача в Python решаеться только с помощью потока и чтобы не использовался GIL (Global Interpreter Lock)?
zuze
Цитата(zuze @ 8.4.2013, 10:21) *
Все правильно, подготовка картинки занимает почти секунду.


Почему всё правильно. У меня же таймер обновляется 5 секунд значит значения должно показаться 5 или близкое.
А выводится:
0.836999893188
0.838999986649
0.837999820709
0.832000017166
0.836999893188
lanz
Потому что время замеряется ВНУТРИ одного вызова и показывает сколько времени проходит ВНУТРИ отрисовки, а не МЕЖДУ вызовами таймера.

Все зависит от того, как генерируются картинки. Они берутся не из файла, так откуда же?
zuze
Цитата(lanz @ 8.4.2013, 16:03) *
Все зависит от того, как генерируются картинки. Они берутся не из файла, так откуда же?


Значения беруться из двоичного файла и заносяться в список.
То есть в будущем будет такой код:

for j in range(0, 720, 1):
     for i in range(491, -1, -1):
            bf = struct.unpack("B", fp.read(1))
            im.setPixel(j, i, QtGui.QColor(bf[0], bf[0], bf[0], 255).rgba())


Это аналог кода в Qt который выгляжит так:

for (int j = 0; j < 720; j++)
{
     for (int i = 491; i >= 0; i--)
     {
          buffer[i][j] = getc(fp);
          im.setPixel(j, i, QColor(buffer[i][j], buffer[i][j], buffer[i][j], 255).rgba());
      }
}
lanz
Это я помню :lol:
В Qt этот код был не в paintEvent.
zuze
Цитата(lanz @ 8.4.2013, 16:52) *
В Qt этот код был не в paintEvent.


Он был в MyTimer, а тут

for j in range(0, 720, 1):
     for i in range(491, -1, -1):
            bf = struct.unpack("B", fp.read(1))
            im.setPixel(j, i, QtGui.QColor(bf[0], bf[0], bf[0], 255).rgba())


лежит в MyTimer. Всё аналогично.
lanz
И в том треде я писал, что надо вынести этот код из таймера.

И вообще, насколько я помню файлы запрещено использовать, значит данные будут приходить не из файлов, а каким то другим путем. Из сокетов или из порта/карты захвата. Значит надо формировать картинки по событию поступления их в программу. И добавлять в очередь например, но каждый кадр перерисовывать их нельзя.
zuze
Цитата(lanz @ 9.4.2013, 8:25) *
И вообще, насколько я помню файлы запрещено использовать, значит данные будут приходить не из файлов


Так как это эмуляция, то в настоящий момент использую файлы.

Как я понял всё работает прекрасно, если избавится от циклов.

Вот код:

# -*- coding: utf-8 -*-
from PyQt4 import QtCore, QtGui, uic
import math
phi = 0.0
class ld(QtGui.QDialog):
    def __init__(self, parent=None):
        super(ld, self).__init__(parent)
        self.ui = uic.loadUi("ld.ui", self)
        self.timer = QtCore.QTimer()
        self.connect(self.timer, QtCore.SIGNAL("timeout()"), self.MyTimer)
        self.timer.setInterval(3)
        self.timer.start()
    def paintEvent(self, QPaintEvent):
        if self.ui.radioButton.isChecked():
            painterRect = QtGui.QPainter(self)
            painterRect.setBrush(QtGui.QColor('black'))
            painterRect.drawRect(50, 50, 720, 492)
            self.MyDraw()
        self.update()
    def MyRadianToGradus(self, phiedit):
        gradus = phiedit * 360 / (2 * math.pi)
        return gradus
    def MyGradusToRadian(self, phiedit):
        radian = phiedit * 2 * math.pi / (360)
        return radian
    def MyTimer(self):
        global phi
        self.update()
        if int(self.MyRadianToGradus(phi) + 0.5) * 720 / 360 < 720:
            phi += self.MyGradusToRadian(6.0)
        else:
            phi = self.MyGradusToRadian(6.0)
    def MyDraw(self):
        global phi
        p = QtGui.QPainter(self)
        p.translate(50, 50)
        p.fillRect(0, 0, int(self.MyRadianToGradus(phi)+0.5)*720/360, 492, QtGui.QColor('red'))
if __name__ == '__main__':
    import sys
    app = QtGui.QApplication(sys.argv)
    window = ld()
    window.show()
    sys.exit(app.exec_())


То есть мне надо избавится от циклов в двух моментах:
1. Вывод изображений на экран.
2. Заполнения объекта QImage значениями из файла.

Если я в пункте номер 1 избавляюсь от циклов с помощью drawImage, то от циклов во втором пункте я не смог изавится.

Может кто знает, как избавится от циклов в обоих пунктах?
lanz
Во втором пункте никак не избавиться.

С какой скоростью появляются новые картинки?
zuze
Цитата(lanz @ 9.4.2013, 13:35) *
С какой скоростью появляются новые картинки?


Самая маленькая скорость появление следующей картинки будет, через 10 секунд, а самая большая скорось появление следующей картинки будет, через 0,05 секунды.
lanz
А сколько времени должна рисоваться одна картинка?
zuze
Цитата(lanz @ 10.4.2013, 14:20) *
А сколько времени должна рисоваться одна картинка?


Самая маленькая скорость появление следующей картинки будет, через 10 секунд, а самая большая скорось появление следующей картинки будет, через 0,05 секунды.
При скорости рисовании картинки 0,05 * 1000 мс, рисования одного кусочка картинки (0,05 * 1000) / 60 мс
При скорости рисовании картинки 10 * 1000 мс, рисования одного кусочка картинки (10 * 1000) / 60 мс

То есть за время "0,05 * 1000 мс" или "10 * 1000 мс" рисунок нарисуется полностью за 60 раз срабатывания таймера.
lanz
Очень странные цифры, за 50 мс - это два - три кадра, зачем перерисовывать картинку 60 раз?

И если надо так быстро получать картинки, используйте numpy например, а потом загружайте картинку напрямую через QImage::scanline ()
zuze
Цитата(lanz @ 10.4.2013, 16:21) *
зачем перерисовывать картинку 60 раз?


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

Цитата(lanz @ 10.4.2013, 16:21) *
И если надо так быстро получать картинки, используйте numpy например, а потом загружайте картинку напрямую через QImage::scanline()


a = numpy.fromfile(fp, dtype=numpy.uint8)
a = numpy.flipud(a.reshape((height, width), order='F'))


Но вот как правильно загрузить я не понял. Помогите пожалуйста это понять.

Я пробовал так сделать:

a = numpy.fromfile(fp, dtype=numpy.uint8)
a = numpy.flipud(a.reshape((492, 720), order='F'))
a.tostring()
im = QtGui.QImage.__init__(self, self, 492, 720, self.Format_Indexed8)


Для вывода так делаю:

def MyDraw(self):
        global im

        Tochka = QtGui.QPainter()
        Tochka.begin(self)

        Tochka.translate(50, 50)
        Tochka.drawImage(0, 0, im, 0, 0, int((2*self.MyRadianToGradus(phi))+0.5), 492)

        Tochka.end()

        self.update()


Выдаётся вот такая ошибка:

im = QtGui.QImage.__init__(self, self, 492, 720, self.Format_Indexed8)
TypeError: 'sip.methoddescriptor' object is not callable

Я пробовал в место

a.tostring()
im = QtGui.QImage.__init__(self, self, 492, 720, self.Format_Indexed8)


Написать

self.__data = a.tostring()
im = QtGui.QImage.__init__(self, self.__data, 492, 720, self.Format_Indexed8)


Пробоывал ещё так:

self.__data = a.tostring()
im = QtGui.QImage.__init__(self.__data, 492, 720, self.Format_Indexed8)


Таже самая ошибка. Не знаю важно или нет, но у меня Python 2.6

Как я понял я не правильно конструктор определил, а вот как правильно не понимаю. Помогите пожалуйста понять.
zuze
Сделал так:

data = a.tostring()
im = QtGui.QImage(data, 492, 720, QtGui.QImage.Format_ARGB32)


Это ошибка пропадает.
Но в момент первого срабатывания таймера возникает ошибка:
Появляется окно с выбором из трёх кнопок:
1 кнопка (Искать решение проблемы в Интернете и закрыть программу)
2 кнопка (Закрыть программу)
3 кнопка (отладить программу)

А текстом пишется:
Process finished with exit code -1073741819

В чём может быть дело?
lanz
Ошибка при работе с памятью скорее всего, видимо с размером что то напутано.

Выложите проект, попробую потыркать.
zuze
Цитата(lanz @ 15.4.2013, 13:55) *
Выложите проект, попробую потыркать.


# -*- coding: utf-8 -*-

from PyQt4 import QtCore, QtGui, uic
import numpy
import math  # Для pi, sin, cos
import os    # Для работы с файлами
import struct
import time

dir = os.path.join(os.getcwd(), "file") # Выбор текущей директории с файлами
phi = 0.0

im = QtGui.QImage(720, 492, QtGui.QImage.Format_ARGB32)

class ld(QtGui.QDialog):
    def __init__(self, parent=None):
        super(ld, self).__init__(parent)
        self.ui = uic.loadUi("ld.ui", self)

        self.connect(self.ui.radioButton_2, QtCore.SIGNAL("clicked()"), self.MyClickRect)

        self.timer = QtCore.QTimer()
        self.connect(self.timer, QtCore.SIGNAL("timeout()"), self.MyTimer)
        self.timer.setInterval(5000)
        self.timer.start()

    def paintEvent(self, QPaintEvent):
        if self.ui.radioButton_2.isChecked():
            painterRect = QtGui.QPainter(self)
            painterRect.setBrush(QtGui.QColor('black'))
            painterRect.drawRect(50, 50, 720, 492)
            self.MyDraw()

    def MyClickRect(self):
        self.update()

    def MyRadianToGradus(self, phiedit):
        gradus = phiedit * 360/(2*math.pi)
        return gradus

    def MyGradusToRadian(self, phiedit):
        radian = phiedit * 2*math.pi / (360)
        return radian

    def MyTimer(self):
        global dir
        global phi
        global im
        global fp

        if self.ui.checkBox_4.isChecked():
            os.chdir(dir)
            try:
                fp = open("1.dat", "rb")
            except IOError:
                print "Cannot open file read!"

            fp.seek(0, 2)
            size = fp.tell()
            fp.seek(size - (492*720), 0)

            a = numpy.fromfile(fp, dtype=numpy.uint8)
            a = numpy.flipud(a.reshape((492, 720), order='F'))
            data = a.tostring()
            im = QtGui.QImage(data, 492, 720, QtGui.QImage.Format_ARGB32)

            self.update()

        if self.ui.radioButton_2.isChecked():
            if int((self.MyRadianToGradus(phi)+0.5)*720)/360 < 720:
                phi += self.MyGradusToRadian(6.0) # Поворот и смещение линии в полярных и пямоугольных координатах
            else:
                phi = self.MyGradusToRadian(6.0)

    def MyDraw(self):
        global im

        Tochka = QtGui.QPainter()
        Tochka.begin(self)

        Tochka.translate(50, 50)
        Tochka.drawImage(0, 0, im, 0, 0, int((2*self.MyRadianToGradus(phi))+0.5), 492)

        Tochka.end()

        self.update()

if __name__ == '__main__':
    import sys

    app = QtGui.QApplication(sys.argv)

    window = ld()
    window.show()

    sys.exit(app.exec_())


К сожалению я немогу дать Вам файл. Можно использовать любую строку длинной 492 * 720, только тогда не нужен код:
fp.seek(0, 2)
size = fp.tell()
fp.seek(size - (492*720), 0)


Прикреплённый архив содержит ld.ui

Может дело в a.tostring(), которая вроде не всегда стабильно работает. Может какой другому можно подготовить данные из файла, что бы из загрузить затем в объект QImage?
lanz
1. Не нужно вызывать update в методе paintEvent это плодит ненужные циклы отрисовки.
2. Если используете Indexed8, то нужно определить таблицу цветов,
Цитата
If format is an indexed color format, the image color table is initially empty and must be sufficiently expanded with setColorCount() or setColorTable() before the image is used.

3. Если используете ARGB32, то байт должно быть в 4 раза больше (красная, зеленая, синияя и альфа - компоненты) т.е. размер файла должен быть 492*720*4.
4. data должен быть валиден в течении всего времени жизни картинки. (т.е. не должен быть локальной переменной)
Цитата
The buffer must remain valid throughout the life of the QImage. The image does not delete the buffer at destruction.

Это происходит потому что вызывается конструктор с неконстантным первым uchar*.
5. Эти преобразования бесполезны.
a = numpy.fromfile(fp, dtype=numpy.uint8)
a = numpy.flipud(a.reshape((492, 720), order='F'))
data = a.tostring()

То же самое будет если сделать
data = fp.read()

zuze
Я сделал так:
# -*- coding: utf-8 -*-

from PyQt4 import QtCore, QtGui, uic
import math
import os
import struct

dir = os.path.join(os.getcwd(), "file")
phi = 0.0

im = QtGui.QImage(720, 492, QtGui.QImage.Format_ARGB32)

class ld(QtGui.QDialog):
    def __init__(self, parent=None):
        super(ld, self).__init__(parent)
        self.ui = uic.loadUi("ld.ui", self)

        self.connect(self.ui.radioButton_2, QtCore.SIGNAL("clicked()"), self.MyClickRect)

        self.timer = QtCore.QTimer()
        self.connect(self.timer, QtCore.SIGNAL("timeout()"), self.MyTimer)
        self.timer.setInterval(5000)
        self.timer.start()

    def paintEvent(self, QPaintEvent):
        if self.ui.radioButton_2.isChecked():
            painterRect = QtGui.QPainter(self)
            painterRect.setBrush(QtGui.QColor('black'))
            painterRect.drawRect(50, 50, 720, 492)
            self.MyDraw()

    def MyClickRect(self):
        self.update()

    def MyTimer(self):
        global im
        global dir
        global phi
        global fp

        if self.ui.checkBox_4.isChecked():
            os.chdir(dir)
            try:
                fp = open("07_30_29.28C", "rb")
            except IOError:
                print "Cannot open file read!"

            fp.seek(0, 2)
            size = fp.tell()
            fp.seek(size - (492*720), 0)

            data = fp.read()

            im = QtGui.QImage(data, 720, 492, QtGui.QImage.Format_ARGB32)

            self.update()

        if self.ui.radioButton_2.isChecked():
            if int((math.degrees(phi)+0.5)*720)/360 < 720:
                phi += math.radians(6.0)
            else:
                phi = math.radians(6.0)

    def MyDraw(self):
        global im

        Tochka = QtGui.QPainter()
        Tochka.begin(self)

        Tochka.translate(50, 50)
        Tochka.drawImage(0, 0, im, 0, 0, int((2*math.degrees(phi))+0.5), 492)

        Tochka.end()

if __name__ == '__main__':
    import sys

    app = QtGui.QApplication(sys.argv)

    window = locatordialog()
    window.show()

    sys.exit(app.exec_())


В этом коде случилось следующие:
1. update в методе paintEvent.
2. В место собственных функций преобразование из радиан в градусы и обратно использовал стандартные.
3. Преобразование строки заменил на такое data = fp.read()

Я незнаю как сделать im локально, так как я im использую в MyTimer(), но также я im использую в MyDraw(). Подскажите пожалуйста, как это сделать?

Цитата(lanz @ 15.4.2013, 16:43) *
Эти преобразования бесполезны.

a = numpy.fromfile(fp, dtype=numpy.uint8)
a = numpy.flipud(a.reshape((492, 720), order='F'))
data = a.tostring()


Не знаю на сколько они безполезны, но если в циклах заполняем im сзначениями из a, то всё прекрасно, картинка рисуется, но медленно. Вот я немного удивлён, что эти преобразования бесполезны.
lanz
Цитата
Я незнаю как сделать im локально, так как я im использую в MyTimer(), но также я im использую в MyDraw(). Подскажите пожалуйста, как это сделать?

Не надо делать im локальным, надо сделать data глобальным/членом класса. data должна существовать после того как управление выйде из MyTimer поскольку коструктор QImage сохраняет только указатель на дату.

Цитата
Вот я немного удивлён, что эти преобразования бесполезны.

Это я проглядел что массив флипается.
zuze
Цитата(lanz @ 16.4.2013, 9:46) *
Не надо делать im локальным, надо сделать data глобальным/членом класса. data должна существовать после того как управление выйде из MyTimer поскольку коструктор QImage сохраняет только указатель на дату.


Сделал в конструкторе класса, так:

self.data = []


Сделал в MyTimer

a = numpy.fromfile(fp, dtype=numpy.uint8)
a = numpy.flipud(a.reshape((720, 492), order='F'))
self.data = a.tostring()

im = QtGui.QImage(self.data, 720, 492, QtGui.QImage.Format_ARGB32)


И всё равно, таже ошибка?
lanz
Конечно. Загружаете 720*492 байт, а картинке говорите что их 720*492*4 (Format_ARGB32)
zuze
Цитата(lanz @ 16.4.2013, 10:23) *
Конечно. Загружаете 720*492 байт, а картинке говорите что их 720*492*4 (Format_ARGB32)


А как картинке задать, что бы брала только 720*492? Я думал достаточно указать QtGui.QImage.Format_ARGB, но такого формата нету.
lanz
Можно использовать Format_Indexed8, только нужно обязательно задать таблицу цветов.
http://qt-project.org/doc/qt-4.8/qimage.html#setColorTable
zuze
Цитата(lanz @ 16.4.2013, 11:29) *
Можно использовать Format_Indexed8, только нужно обязательно задать таблицу цветов.


Сделал так:

a = numpy.fromfile(fp, dtype=numpy.uint8)
a = numpy.flipud(a.reshape((720, 492), order='F'))
self.data = a.tostring()

im = QtGui.QImage(self.data, 720, 492, QtGui.QImage.Format_Indexed8)
QtGui.QImage.setColorTable(QtGui.qRgba(255, 0, 0, 255))


Всё равно, тажа ошибка.
lanz
setColorTable нужно вызывать у конкретного экземпляра QImage, кроме того туда нужно передать вектор цветов, а не один цвет.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Форум IP.Board © 2001-2024 IPS, Inc.