QGraphicsView мерцает

Я хотел написать программу слепоты к изменениям для своей бакалаврской диссертации. Он показывает изображение в течение X миллисекунд, показывает короткое «мерцающее изображение» (в данном случае просто серое), а затем показывает немного другое изображение, чем первое. Потом снова мерцание изображения.

Тогда все начинается сначала. Работает нормально, есть только графические артефакты. Я думаю, что холст / QGraphicsView обновляет его недостаточно быстро, поэтому во время обновления они представляют собой «линии».

Время отображения изображения: 70 мс, время мерцания: 30 мс. Таким образом, 100 мс = 10 кадров в секунду. Я думал, что это было бы возможно без использования графического процессора. Но похоже, что это не так.

Могу ли я использовать двойную буферизацию или что-то еще, чтобы избежать проблем с GPU? Или мне нужно использовать QGL для этого? Это около 1 мегабайта изображений.

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

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

С уважением :)

#ifndef PICTURES_H
#define PICTURES_H

#include <QMainWindow>
#include <QImage>
#include <QPixmap>
#include <QGraphicsPixmapItem>
#include <iostream>
#include <QDir>
#include <QGraphicsScene>
#include <QDebug>
#include <QTimer>


namespace Ui {
class pictures;
}

class pictures : public QMainWindow
{
    Q_OBJECT

public:
    explicit pictures(QWidget *parent = 0);
    ~pictures();

    void loadPics();
    void showPics();

public slots:
    void stopClicked();
    void clearPictures();
    void timePassed();
    void changeImage();
    void changeImageGrey();

private:
    int counter;
    int image_counter;
    int stop_time;
    Ui::pictures *ui;
    QVector<int> times;
    QTimer* timer;
    QTimer* timerImageChange;
    QTimer* timerGrey;

    int imageChangeTime;
    int greyTime;

    QVector<QGraphicsPixmapItem*> images;
    QGraphicsScene* scene;
    QGraphicsScene* scene_grey;
    QGraphicsPixmapItem* item1;
};

#endif // PICTURES_H


#include "pictures.h"
#include "ui_pictures.h"

pictures::pictures(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::pictures), times()
{
    counter = 1;
    stop_time = 0;
    image_counter = 0;
    timer = new QTimer(this);
    timerGrey = new QTimer(this);
    timerImageChange = new QTimer(this);
    connect(timer, SIGNAL(timeout()), this, SLOT(timePassed()));
    connect(timerImageChange, SIGNAL(timeout()), this, SLOT(changeImageGrey()));
    connect(timerGrey, SIGNAL(timeout()), this, SLOT(changeImage()));

    greyTime = 200;
    imageChangeTime = 500;


    qDebug() << "Hello im here in pictures";

    ui->setupUi(this);
    this->loadPics();
    connect(ui->pushButtonStop, SIGNAL(clicked()), this, SLOT(stopClicked()));
    connect(ui->pushButtonNext, SIGNAL(clicked()), this, SLOT(clearPictures()));

    timer->start(10);
    timerImageChange->start(imageChangeTime);
}

pictures::~pictures()
{
    delete ui;
}

void pictures::loadPics()
{
    qDebug() << QDir::toNativeSeparators((QDir::current().absolutePath() + QDir::separator () + "debug" + QDir::separator () + "pics" + QDir::separator () + QString::number(counter) + QDir::separator()+"1.jpg"));
    //QImage imageOne(QDir::toNativeSeparators(QDir::current().absolutePath() + QDir::separator () + "debug" + QDir::separator () + "pics" + QDir::separator () + QString::number(counter) + QDir::separator()+"1.jpg"));
    //QImage imageTwo(QString("./pics/")+counter+"/2.png");
    //QImage imageThree(QString("./pics/")+counter+"/3.jpg");
    //QImage imageFour(QString("./pics/")+counter+"/2.png");

    images.append(new QGraphicsPixmapItem(QDir::toNativeSeparators(QDir::current().absolutePath() + QDir::separator () + "debug" +  QDir::separator () + "pics" + QDir::separator () + QString::number(counter) + QDir::separator()+"1.jpg")));
    images.append(new QGraphicsPixmapItem(QDir::toNativeSeparators(QDir::current().absolutePath() + QDir::separator () + "debug" +  QDir::separator () + "pics" + QDir::separator () + QString::number(counter) + QDir::separator()+"2.jpg")));
    images.append(new QGraphicsPixmapItem(QDir::toNativeSeparators(QDir::current().absolutePath() + QDir::separator () + "debug" +  QDir::separator () + "pics" + QDir::separator () + QString::number(counter) + QDir::separator()+"3.jpg")));
    images.append(new QGraphicsPixmapItem(QDir::toNativeSeparators(QDir::current().absolutePath() + QDir::separator () + "debug" +  QDir::separator () + "pics" + QDir::separator () + QString::number(counter) + QDir::separator()+"4.jpg")));


    //QGraphicsPixmapItem* item1( QPixmap::fromImage(imageOne));
    item1 = images[image_counter];
    //QGraphicsPixmapItem item2( QPixmap::fromImage(imageTwo));
    //QGraphicsPixmapItem item3( QPixmap::fromImage(imageThree));
    //QGraphicsPixmapItem item4( QPixmap::fromImage(imageFour));
    scene = new QGraphicsScene;
    scene_grey = new QGraphicsScene;

    int maximum = item1->boundingRect().width() > item1->boundingRect().height() ? item1->boundingRect().width() : item1->boundingRect().height();
    int dimension_width  = ui->graphicsView->rect().width();
    int dimension_height = ui->graphicsView->rect().height();

    //int biggest_canvas_dimension = (((float)item1->boundingRect().width())/dimension_width) > (((float)item1->boundingRect().height())/dimension_height) ? dimension_width : dimension_height;
    int biggest_canvas_dimension = dimension_width > dimension_height ? dimension_width : dimension_height;

    if(maximum > ui->graphicsView->rect().width() || maximum > ui->graphicsView->rect().height())
    {
        dimension_width = (int) (item1->boundingRect().width() * ((float)(biggest_canvas_dimension )/maximum));
        dimension_height = (int) (item1->boundingRect().height() * ((float)(biggest_canvas_dimension)/maximum));
        item1->setPixmap(item1->pixmap().scaled(dimension_width,dimension_height));

        qDebug() << "Width: " << dimension_width << " Height " << dimension_height << " Pic High" << item1->boundingRect().height();
    }

    //item1->setPixmap(item1->pixmap().scaled(QSize(ui->graphicsView->rect().width(), ui->graphicsView->rect().height())));
    scene->setSceneRect(ui->graphicsView->rect());
    scene->addItem(item1);

    scene_grey->setSceneRect(ui->graphicsView->rect());
    scene_grey->addItem(images[1]);


    ui->graphicsView->setScene(scene);
    ui->graphicsView->adjustSize();

    //ui->graphicsView->show();


}

void pictures::timePassed()
{
    stop_time += 10;
}

void pictures::stopClicked()
{
    timerImageChange->stop();
    timerGrey->stop();
    times.append(stop_time);
    ui->pushButtonStop->setEnabled(false);
    ui->pushButtonNext->setEnabled(true);
    counter++;
    qDebug() << "Time: " << stop_time;

    stop_time = 0;
    timer->stop();
}

void pictures::clearPictures()
{
    scene->deleteLater();
    images.clear();
    loadPics();
    ui->pushButtonStop->setEnabled(true);
    ui->pushButtonNext->setEnabled(false);
    timer->start(10);
    timerImageChange->start(imageChangeTime);
}

void pictures::changeImageGrey()
{
    timerGrey->start(greyTime);
    timerImageChange->stop();
    image_counter = (image_counter+1)%4;

    //scene_grey->removeItem(scene_grey->items().at(0));
    //scene_grey->addItem(images[image_counter]);

    scene->removeItem(scene->items().at(0));
    scene->addItem(images[image_counter]);



    /*int maximum = item1->boundingRect().width() > item1->boundingRect().height() ? item1->boundingRect().width() : item1->boundingRect().height();
    int dimension_width  = ui->graphicsView->rect().width();
    int dimension_height = ui->graphicsView->rect().height();

    int biggest_canvas_dimension = dimension_width > dimension_height ? dimension_width : dimension_height;

    if(maximum > ui->graphicsView->rect().width() || maximum > ui->graphicsView->rect().height())
    {
        dimension_width = (int) (item1->boundingRect().width() * ((float)(biggest_canvas_dimension )/maximum));
        dimension_height = (int) (item1->boundingRect().height() * ((float)(biggest_canvas_dimension)/maximum));
        item1->setPixmap(item1->pixmap().scaled(dimension_width,dimension_height));
    }*/
    //scene->setSceneRect(ui->graphicsView->rect());

    //ui->graphicsView->setScene(scene_grey);

}

void pictures::changeImage()
{
    timerImageChange->start(imageChangeTime);
    timerGrey->stop();
    image_counter = (image_counter+1)%4;

    qDebug() << "    item1 = images[" + QString::number(image_counter) + "]";

    scene->removeItem(scene->items().at(0));

    item1 = images[image_counter];

    //qDebug() << QDir::toNativeSeparators((QDir::current().absolutePath() + QDir::separator () + "debug" + QDir::separator () + "pics" + QDir::separator () + QString::number(counter) + QDir::separator()+ QString::number(image_counter+1) +".jpg"));


    int maximum = item1->boundingRect().width() > item1->boundingRect().height() ? item1->boundingRect().width() : item1->boundingRect().height();
    int dimension_width  = ui->graphicsView->rect().width();
    int dimension_height = ui->graphicsView->rect().height();

    int biggest_canvas_dimension = dimension_width > dimension_height ? dimension_width : dimension_height;

    if(maximum > ui->graphicsView->rect().width() || maximum > ui->graphicsView->rect().height())
    {
        dimension_width = (int) (item1->boundingRect().width() * ((float)(biggest_canvas_dimension )/maximum));
        dimension_height = (int) (item1->boundingRect().height() * ((float)(biggest_canvas_dimension)/maximum));
        item1->setPixmap(item1->pixmap().scaled(dimension_width,dimension_height));
    }

    //item1->setPixmap(item1->pixmap().scaled(QSize(ui->graphicsView->rect().width(), ui->graphicsView->rect().height())));
    //scene->setSceneRect(ui->graphicsView->rect());
    scene->addItem(item1);
    //ui->graphicsView->setScene(scene);

    //ui->graphicsView->setScene(scene);
    //ui->graphicsView->adjustSize();

    //ui->graphicsView->show();

}

person user1439712    schedule 17.06.2012    source источник


Ответы (1)


Помните, что если частота обновления вашего монитора 60 Гц, то каждое изображение перерисовывается раз в 16 мс. Вы не можете рисовать с точным временем, например, 30 мс, возможно только время с интервалом 16,666 мс. И, по крайней мере, в Windows вы не можете легко узнать, когда изображение, отображаемое на мониторе, изменится. Если ваш код показывает изображение, например, в течение 10 мс, то вы либо видите изображение, либо нет. Если вы показываете изображение в течение 25 мс, вы видите изображение либо один раз (16,666 мс), либо два раза (33,333 мс).

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

Линии, которые вы видите во время рисования, вероятно, являются разрывами. Вы также можете избежать этого, используя информацию о вертикальной синхронизации монитора.

Вы также используете таймер Qt для подсчета интервалов в 10 мс. Это не работает. Тайм-аут составляет не менее 10 мс, но не гарантируется, что он будет точно равен 10 мс. На практике это больше, поэтому общее время 100 тайм-аутов, вероятно, составляет около 1100 мс. И даже больше, в зависимости от вашей операционной системы. В Windows разрешение таймера по умолчанию составляет 16 мс. Тогда 100 тайм-аутов в сумме составляют около 1700 мс. Вы можете изменить разрешение таймера, используя время начала периода.

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

person Community    schedule 17.06.2012
comment
Я поддерживаю идеи Року. В общем, вы можете использовать QElapsedTimer, чтобы проверить, сколько времени действительно прошло с момента какой-либо ссылки, и действовать в реальном времени, не делая никаких предположений о том, когда могло сработать событие таймера. Установите таймер на срабатывание, когда вы этого хотите, но внутри timerEvent или вашего слота выберите, что показывать, в зависимости от того, как далеко продвинулось реальное время. - person Kuba hasn't forgotten Monica; 17.06.2012
comment
Теперь я использовал 16-секундные интервалы, так как это кажется более точным. Теперь красиво, но меньше работы :P. Я пробую QGLWidget как Viewport (добавлен opengl в файл pro), чтобы избежать разрыва, который кажется проблемой. Спасибо вам за помощь :) - person user1439712; 17.06.2012