Russian Qt Forum

Qt => 2D и 3D графика => Тема начата: Admin от Апрель 28, 2005, 14:49



Название: Быстрый вывод картинки
Отправлено: Admin от Апрель 28, 2005, 14:49
Есть изображение, скажем массив RGB. Надо его быстро отобразить на экран. У кого какие соображения.

В данное время происходит так:

создаю QImage
в цикле ставлю setPixel у картинки
и вывожу ее на экран с помощью QPainter

но тормозно ужастно


Название: Быстрый вывод картинки
Отправлено: Sergeich от Апрель 28, 2005, 15:01
Самое быстрое что можно сделать - использовать OpenGL


Название: Быстрый вывод картинки
Отправлено: Admin от Апрель 28, 2005, 15:13
а можно пример в студию!


Название: Быстрый вывод картинки
Отправлено: Ruslan Popov от Апрель 28, 2005, 15:29
Вот альтернативный вариант с использованием SDL.

Внедрение SDL окна в Qt виджет:
http://forum.sources.ru/index.php?act=Attach&type=post&id=695090


Название: Быстрый вывод картинки
Отправлено: Admin от Апрель 28, 2005, 15:39
это SDL внедрять в проект
а это его утяжелит


Название: Быстрый вывод картинки
Отправлено: Ruslan Popov от Апрель 28, 2005, 15:45
Компакт-диски весят немного.

Кстати, если на CD записать на 200 мегабайт больше, он сильно потяжелеет в смысле веса? :)

И с каких пор OpenGL стал стандартной фичей Windows???


Название: Быстрый вывод картинки
Отправлено: Sergeich от Апрель 28, 2005, 16:12
Цитата: "Admin"
а можно пример в студию!

Дык сам напиши... там все просто: создаешь QGLWidget, и в paintGL() юзаешь ф-ции glRasterPos() и glDrawPixels()


Название: Быстрый вывод картинки
Отправлено: Admin от Апрель 28, 2005, 17:15
1. Часто программы скачивают из инета. А там размер важен, скачать 1 мег и 10 мег - большая разница

2. А OpenGL насколько быстрее будет?


Название: Быстрый вывод картинки
Отправлено: Sergeich от Апрель 28, 2005, 17:29
Цитата: "Admin"
1. Часто программы скачивают из инета. А там размер важен, скачать 1 мег и 10 мег - большая разница

А причем тут сеть? Можно поподробнее...
Цитата: "Admin"
2. А OpenGL насколько быстрее будет?

Все зависит от конфигурации: от скорости системной шины, скорости памяти и особенно от видеокарты


Название: Быстрый вывод картинки
Отправлено: Racheengel от Апрель 28, 2005, 17:50
Погоди... я так понимаю, уважаемому надо, что это работало ПРОСТО БЫСТРЕЕ. А ведь не факт, что у пользователей его проги будет работоспособен Gl. Да и применение такой библиотеки для подобной задачи - дело весьма сомнительное ИМХО...


Название: Быстрый вывод картинки
Отправлено: Sergeich от Апрель 28, 2005, 18:10
На самом деле все зависит от задачи, если надо быстро перекидывать байты из памяти на экран, то лучше юзать OpenGL, т.к. он работает напрямую с буфером кадра. А по поводу работоспособности OpenGL: под виндой это вообще не проблема, под линухом конечно нужно ставить дрова, но по крайней мере для NVidia чипов с этим проблем нет и вроде в последнее время исчезли проблемы с ATI.


Название: Быстрый вывод картинки
Отправлено: Admin от Апрель 28, 2005, 21:55
я вообще хотел способов типа

1. Использовать BitBlt. Я просто не очень понял, как его использовать

2. Использование HDC хендла возращаемого QPainter


У вас есть решения, основанные на этом подходе?


Название: Быстрый вывод картинки
Отправлено: Keiko от Апрель 28, 2005, 23:28
я эту проблему решил. Всё зависит от того, КАК ты получаешь картинку, которую надо вывести на экран. Если это простой несжатый RGB поток, и решение нужно только под X11, то нужно использовать MIT-SHM - в этом случае отрисовка летает. Если очень надо, могу прислать нужный класс [давай мейл].

P.S. Отрисовка QImage будет торомозить _всегда_, т.к. QImage сначала перегоняется в QPixmap, а потом только рисуется. Даже в доке написано, что такое преобразование очень медленное, да и ты сам можем убедиться, посетив qpixmap_x11.cpp из дистриба qt :)


Название: Быстрый вывод картинки
Отправлено: Admin от Апрель 28, 2005, 23:33
а сюда можешь приатачить?

я думаю будет интересно всем!!


Название: Быстрый вывод картинки
Отправлено: Keiko от Апрель 28, 2005, 23:36
ктсати, setPixel делать не надо. у QImage есть конструктор, который позволяет создавать объект из несжатых данных (RGB/RGBA/Indexed):

Код:

QImage::QImage ( uchar * yourdata, int w, int h, int depth, QRgb * colortable, int numColors, Endian bitOrder )

Constructs an image w pixels wide, h pixels high with a color depth of depth, that uses an existing memory buffer, yourdata.

The buffer must remain valid throughout the life of the QImage. The image does not delete the buffer at destruction.

If colortable is 0, a color table sufficient for numColors will be allocated (and destructed later).

Note that yourdata must be 32-bit aligned.


Название: Быстрый вывод картинки
Отправлено: Keiko от Апрель 28, 2005, 23:38
и ещё - OpenGL крайне не рекомедую - это сильно device-dependend решение, ну ты понял :) Томозить это будет без драйверов на видео ОЧЕНЬ сильно.


Название: Быстрый вывод картинки
Отправлено: Keiko от Апрель 28, 2005, 23:40
Код:

/***************************************************************************
                          sq_pixmap.h  -  description
                             -------------------
    begin                : Apr 10 2005
    copyright            : (C) 2005 by Baryshev Dmitry
    email                : ksquirrel@tut.by
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

/*
 *
 * Originally written by
 * Dmitry Smirnov,
 * Saint-Petersburg, Russia
 *
 */

#ifndef SQ_PIXMAP_H
#define SQ_PIXMAP_H

#include <X11/Xlib.h>
#include <X11/extensions/XShm.h>

#include <sys/timeb.h>

class QPaintDevice;

class SQ_Pixmap
{
    public:
        SQ_Pixmap(int, int);
SQ_Pixmap();
        ~SQ_Pixmap();

    private:
        XImage*          m_pXImage;
        XShmSegmentInfo* m_pXShmSegmentInfo;

    public:
        void draw(QPaintDevice *, int, int);
void fillPixmap(unsigned char *data, const int w, const int h);

int width() const;
int height() const;
int region_width() const;
int region_height() const;

    public:
        int* data;
        int  m_width;
        int  m_height;
        int  m_w, m_h;
};

inline int SQ_Pixmap::width() const
{
    return m_width;
}

inline int SQ_Pixmap::height() const
{
    return m_height;
}

inline int SQ_Pixmap::region_width() const
{
    return m_w;
}

inline int SQ_Pixmap::region_height() const
{
    return m_h;
}

#endif


Название: Быстрый вывод картинки
Отправлено: Keiko от Апрель 28, 2005, 23:41
Код:

/***************************************************************************
                          sq_pixmap.cpp  -  description
                             -------------------
    begin                : Apr 10 2005
    copyright            : (C) 2005 by Baryshev Dmitry
    email                : ksquirrel@tut.by
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

#include <qpaintdevice.h>
#include <qapplication.h>

#include <X11/Xutil.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#include "sq_pixmap.h"

SQ_Pixmap::SQ_Pixmap()
{
QDesktopWidget *d = QApplication::desktop();

SQ_Pixmap::SQ_Pixmap(d->width()+2, d->height()+2);
}

SQ_Pixmap::SQ_Pixmap(int iWidth, int iHeight) : m_w(0), m_h(0)
{
        m_width  = iWidth;
        m_height = iHeight;

        // create the shared segment
        m_pXShmSegmentInfo = new XShmSegmentInfo;

        // create the shared memory image
        m_pXImage = XShmCreateImage(QPaintDevice::x11AppDisplay(),
(Visual *)QPaintDevice::x11AppVisual(),
QPaintDevice::x11AppDepth(),
ZPixmap, 0,
m_pXShmSegmentInfo, m_width, m_height);

        // create the shared memory segment
m_pXShmSegmentInfo->shmid = shmget(IPC_PRIVATE, m_pXImage->bytes_per_line * m_pXImage->height, IPC_CREAT | 0777);

        // attach the shared memory segment to process
data = (int *)shmat(m_pXShmSegmentInfo->shmid, 0, 0);
m_pXShmSegmentInfo->shmaddr = m_pXImage->data = (char *)data;

        // make the shared memory segment writable
m_pXShmSegmentInfo->readOnly = false;

        // attach the shared memory segment to server
        XShmAttach(QPaintDevice::x11AppDisplay(), m_pXShmSegmentInfo);

memset(data, 0x80, m_width * m_height * 4);
}

SQ_Pixmap::~SQ_Pixmap()
{
        // detach the shared memory segment from server
        XShmDetach(QPaintDevice::x11AppDisplay(), m_pXShmSegmentInfo);

        // destroy the shared memory image
        XDestroyImage(m_pXImage);

        // destroy the shared memory segment
        shmdt(m_pXShmSegmentInfo->shmaddr);
        shmctl(m_pXShmSegmentInfo->shmid, IPC_RMID, 0);
}

void SQ_Pixmap::draw(QPaintDevice* pPaintDevice, int x, int y)
{
    // synchronize X server
    QApplication::syncX();

    // create device context
    GC gc = XCreateGC(pPaintDevice->x11Display(), pPaintDevice->handle(), 0, 0);

    // draw the shared memory image
    XShmPutImage(pPaintDevice->x11Display(), pPaintDevice->handle(), gc,
m_pXImage, 0, 0, x, y, m_w, m_h, true);

    // free device context
    XFreeGC(pPaintDevice->x11Display(), gc);
}

void SQ_Pixmap::fillPixmap(unsigned char *buf, const int w, const int h)
{
    m_w = w;
    m_h = h;

    const int row_stride = w << 2;

    if(w < m_width)
    {
for(int i = 0;i < h;i++)
   memcpy(data+m_width*i, buf + i*row_stride, row_stride);
    }
    else
memcpy(data, buf, (m_width * m_height) << 2);

}


Название: Быстрый вывод картинки
Отправлено: Keiko от Апрель 28, 2005, 23:44
Работает с несжатыми данными RGBA. Использование:

Код:

unsigned char *data = // ... каким-то образом получаешь данные
int w = 300, h = 200;

SQ_Pixmap *p  = new SQ_Pixmap(w, h);

p->fillPixmap(data, w, h);

// отрисовка по координатам x,y
p->draw(this, 10, 10);


Название: Быстрый вывод картинки
Отправлено: Admin от Апрель 29, 2005, 00:07
надо попробовать
только вот colortable пугает


Название: Быстрый вывод картинки
Отправлено: Keiko от Апрель 29, 2005, 00:15
чем ? :) Если данные 32-битные (RGBA), colortable = NULL.


Название: Быстрый вывод картинки
Отправлено: Admin от Апрель 29, 2005, 00:16
у меня данные RGB и без палитры


Название: Быстрый вывод картинки
Отправлено: Keiko от Апрель 29, 2005, 00:29
надо RGBA - RGB QImage'ем не поддерживается. без палитры, как я уже говорил, colortable = NULL, numColors = 0.


Название: Быстрый вывод картинки
Отправлено: Admin от Апрель 29, 2005, 07:18
понятно спасибо

буду значит преобразовывать в промежуточныйй формат


Название: Быстрый вывод картинки
Отправлено: Admin от Апрель 29, 2005, 08:52
в продолжение:

есть QScroollView, в нем картинка сидит QImage
при движение scrollbar картинка смещается и позволяет пользователю просматривать ее, когда она больше чем экран

так вот такой код в paintEvent

Код:
QPixmap pm(*m_pQImg);
bitBlt(viewport(), 0, 0, &pm,contentsX () ,contentsY () ,m_pQImg->width(),m_pQImg->height(),CopyROP, TRUE );


отрабатывает, но возникает проблема, что картинка ездит прекрасно
но края не переририсоваваются. Это понятно когда прогу свернешь и развернешь. Тогда рисует все ок.


что бы послать такое, QScrollBar что бы он перерисовался


Название: Быстрый вывод картинки
Отправлено: Ruslan Popov от Апрель 29, 2005, 08:59
А я вчера SDLWidget внедрил в свой проект и оно даже работает :)
Добавил в него функциональность для работы с оверлеем.
Постараюсь на выходных начать бросать на него кадры из потока...

Насчёт перерисовки, у тебя QPaintEvent не появляется, зови ручками...


Название: В продолжение темы...
Отправлено: west от Апрель 29, 2005, 11:06
У меня приложение MDI, размер загружемых изображений до гига. Проверял 1300 Мбт, грузило нормально (но долго). Машинки по т.з. слабенькие , ULTRA SPARC 1000, видео стоит совсем дохленькое. GL вертится, но слабо. А с загруженными изображениями еще надо работать - менять яркость - контраст, масштаб,  рисовать объекты и ессетственно скроллировать. Поэтому пришлось делать так - документе (MDI) хранил unsigned char* массив данных изображения. В docView  (он наследован от QScrollView) размещал QImage* m_pImage, размером с видимую userу часть viewport'а. Все события по изменению размера viewport - скроллы, ресайз, масштаб и все такое завязаны на свой метод типа createImage, куда передаю новый размер окна и положение ползунков. В соответствии с этими данными формирую новое изображение. Т.е.  сначала сохраняю существующую палитру из QImage::colorTable , потом m_pImage-reset() m_pImage->create(.........),  потом копирование ( memcpy) соответствующей позиции скроллов и размеру View части изображения из unsigned char* прямо в m_pImage->bits(), копирование назад в новое изображение палитры. Для рисования переописал drawContext(....), в нем вызываю painter->drawImage(....).
где, естесственно рисую свой новый Image. paintEvent не трогал вообще. Получается следующее: дергаешь скролл, попадаешь в обработчик скролла, в котором создается новое изображение. DrawContext система вызовет сама. Для отдельных случаев написал repaintImage, в котором вызывается тот же drawContext , только с параметрами по перерисовке всей видимой области. (Если он вызывается системой, то перерисовывает только добавившуюся , например при рисайзе, часть изображения). Впринципе, своего добился, если изображение загружется (оперативки всего 512 метров,  > 700Мбт свопит жутко), то работает быстро.


Название: Быстрый вывод картинки
Отправлено: Ruslan Popov от Апрель 29, 2005, 12:16
Я не разбирался с таким вопросом, но думаю в SDL на эту тему есть ответ.

Но если подойти в общем к решению проблемы, то надо посмотреть в сторону mmap (на MSWin тоже есть подобное). Смысл - отображение куска файла в память и никаких свопов!


Название: Быстрый вывод картинки
Отправлено: west от Апрель 29, 2005, 13:25
Если изображение больше размера оперативки, свопить будет полюбому. Не к файлу же мне каждый раз обращаться.


Название: Быстрый вывод картинки
Отправлено: Zmey от Апрель 29, 2005, 13:34
Почему бы не использовать QCanvas, QCanvasImage?
Я вывожу через него картинку 2000х1000 12 бит, работает мгновенно.


Название: Быстрый вывод картинки
Отправлено: Ruslan Popov от Апрель 29, 2005, 13:48
Цитата: "west"
Если изображение больше размера оперативки, свопить будет полюбому. Не к файлу же мне каждый раз обращаться.

Умные люди не зря mmap реализовали! Вы почитайте документацию.
Вы будете работать с изображением любого размера, как-будто оно находится в оперативной памяти. На экран выводится всё равно только небольшая его часть. В данное время вы тратите время на подкачку всего изображения в память, но потом работаете быстро. В предлагаемом варианте, пользователь быстро получит доступ к куску изображения, а вы закэшируете куски картинки по краям отображенного пользователю "окна" и при скролле, отобразите данные из кэша и так далее.


Название: Быстрый вывод картинки
Отправлено: west от Апрель 29, 2005, 16:19
Оно свопит у меня при загрузке. А при работе все ок. А насчет mmap - посмотрю обязательно.


Название: Быстрый вывод картинки
Отправлено: Keiko от Апрель 29, 2005, 16:22
Zmey

Пока дело не доходит до масштабирования ;)