zuze
Опытный
Offline
Пол:
Россия, Москва
|
|
« : 14-05-2013 06:10 » |
|
Здравствуйте.
Я задавал много, где на форумах этот вопрос, но пока решения не получилось. Может быть здесь найдётся решение.
Задача: У меня есть двоичный (бинарный) файл. То есть каждый байт файл это значение RGB. R = 1-й байт G = 1-й байт B = 1-й байт На следующей стадии цикла будет R = 2-й байт G = 2-й байт B = 2-й байт и так далее
Я пробовал заполнить объект QImage с помощью метода "setPixel" и выводить через метод "drawImage", так как этот метод позволяет выводить по частям. Но увы для использования метода "setPixel" нужен двойной цикл, а значений очень много и из-за этого всё тормозит.
OpenGL использовать нельзя.
Может есть механизм без циклов заполнить объект QImage или какой-то другой механизм заполнения есть?
Мне нужно, что бы ни при заполнении, ни при выводе циклов не было, при том вывод должен уметь выводить по частям.
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #1 : 14-05-2013 06:14 » |
|
zuze, привет ) Я перенёс в общий, так как для Qt раздела у нас ещё нет, а тема не про Unix вовсе
Добавлено через 3 минуты и 12 секунд: а по задаче - вроде всё уже выяснили неоднократно . Ты заполняешь QImage один раз (циклами или методом), потом пользуешься на здоровье.
|
|
« Последнее редактирование: 14-05-2013 06:17 от Алексей1153 »
|
Записан
|
|
|
|
zuze
Опытный
Offline
Пол:
Россия, Москва
|
|
« Ответ #2 : 14-05-2013 06:21 » |
|
Добавлено через 3 минуты и 12 секунд: а по задаче - вроде всё уже выяснили неоднократно . Ты заполняешь QImage один раз (циклами или методом), потом пользуешься на здоровье.
Циклами заполнить QImage это легко, но тормозит всё, а что же за метод который может без циклов заполнить?
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #3 : 14-05-2013 06:22 » |
|
zuze, покажи цикл, который у тебя тормозит. Без всего лишнего
|
|
|
Записан
|
|
|
|
zuze
Опытный
Offline
Пол:
Россия, Москва
|
|
« Ответ #4 : 14-05-2013 06:26 » |
|
Алексей++, вот этот цикл жутко тормозит. // Глобальные int buffer[492][720]; QImage im(720, 492, QImage::Format_ARGB32);
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()); } }
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #5 : 14-05-2013 06:44 » |
|
zuze, есть метод
QImage::fromData ( const QByteArray & data, const char * format = 0 )
1) создаёшь экземпляр QByteArray 2) в цикле заполняешь его из источника 3) перетусовываешь байты под твой формат 4) вызываешь QImage::fromData
на мой взгляд это всё выполнится достаточно быстро
|
|
|
Записан
|
|
|
|
darkelf
Молодой специалист
Offline
|
|
« Ответ #6 : 14-05-2013 07:12 » |
|
Алексей++, вот этот цикл жутко тормозит. // Глобальные int buffer[492][720]; QImage im(720, 492, QImage::Format_ARGB32);
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()); } }
имхо, как вариант попробовать вычитать buffer, зараннее одним чтением fread(), правда тогда надо будет поменять int buffer[][] на unsigned char buffer[][] (или в файле хранить не байты, а int-ы), и поменять порядок обхода - тогда лучше будет работать кеши процессора: fread(buffer, 1, sizeof(buffer), fp); for (int i = 0; i < 492; i++) { for (int j = 0; j < 720; j++) { im.setPixel(j, i, QColor(buffer[i][j], buffer[i][j], buffer[i][j], 255).rgba()); } }
|
|
« Последнее редактирование: 14-05-2013 07:44 от darkelf »
|
Записан
|
|
|
|
zuze
Опытный
Offline
Пол:
Россия, Москва
|
|
« Ответ #7 : 14-05-2013 07:14 » |
|
zuze, есть метод
QImage::fromData ( const QByteArray & data, const char * format = 0 )
1) создаёшь экземпляр QByteArray 2) в цикле заполняешь его из источника 3) перетусовываешь байты под твой формат 4) вызываешь QImage::fromData
на мой взгляд это всё выполнится достаточно быстро
А почему это убыстрит скорость, ведь "2) в цикле заполняешь его из источника", тоже значит циклы есть?
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #8 : 14-05-2013 07:21 » |
|
darkelf, это кроссплатформа, не думай про кеши ) А вычитать можно и кусками побольше, это я согласен.
zuze, потому что QImage::setPixel - медленная операция . Ну и побайтное чтение из потока - тоже не айс, как выше правильно отметили )
|
|
|
Записан
|
|
|
|
darkelf
Молодой специалист
Offline
|
|
« Ответ #9 : 14-05-2013 07:27 » |
|
Алексей++, э.. ну если мы пишем на C/C++, а не на Java, то, по возможности, про кеши надо думать всегда, если интересно - есть статья Ульриха Дреппера "Что каждый программист должен знать о памяти" по этому поводу, если интересно - вот ссылка на её перевод на русский: http://rus-linux.net/MyLDP/hard/memory/memory.html, думаю, что она может оказаться полезной. Кстати, по поводу конструктора - у QImage, если я правильно понял, есть ещё вариант: QImage ( uchar * data, int width, int height, Format format );
т.е. можно, сделать что-то типа такого: fread(buffer, 1, sizeof(buffer), fp); QImage (buffer, 720, 492, QImage::Format_ARGB32);
Хотя наверное надо будет буфер, как сказал Алексей++, ещё обработать..
|
|
« Последнее редактирование: 14-05-2013 07:45 от darkelf »
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #10 : 14-05-2013 07:31 » |
|
darkelf, я гляну, но в данном случае это всё не имеет отношения к делу ИМХО )
|
|
|
Записан
|
|
|
|
zuze
Опытный
Offline
Пол:
Россия, Москва
|
|
« Ответ #11 : 15-05-2013 04:52 » |
|
zuze, потому что QImage::setPixel - медленная операция . Ну и побайтное чтение из потока - тоже не айс, как выше правильно отметили )
И что же в таких случаях используют? Скорее всего я не первый, кто с такой проблемой сталкивается. Может какие другие надо модули использовать.
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #12 : 15-05-2013 11:26 » |
|
zuze, так уже снова всё расписали )) Прочитай!
|
|
|
Записан
|
|
|
|
zuze
Опытный
Offline
Пол:
Россия, Москва
|
|
« Ответ #13 : 17-05-2013 04:48 » |
|
zuze, так уже снова всё расписали )) Прочитай!
Прошу прощения, у нас сейчас переест вообще замаялся и не увидел Вашу строчку в конце "на мой взгляд это всё выполнится достаточно быстро". Я понял, что надо сделать по Вашему алгоритму. QImage::fromData ( const QByteArray & data, const char * format = 0 )
1) создаёшь экземпляр QByteArray 2) в цикле заполняешь его из источника 3) перетусовываешь байты под твой формат 4) вызываешь QImage::fromData
Как будет готово всё покажу. Может кому тоже пригодится.
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #14 : 17-05-2013 05:07 » |
|
ещё момент - если заранее знаешь, какой будет конечный объём QByteArray после чтения из файла , имеет смысл перед чтением вызвать
QByteArray::reserve(конечный объём в байтах)
поскольку читать ты будешь кусками, а не разом, это тоже чуток повысит скорость работы. Хотя, может и незначительно в данном случае. Попробуешь, в общем
|
|
|
Записан
|
|
|
|
zuze
Опытный
Offline
Пол:
Россия, Москва
|
|
« Ответ #15 : 17-05-2013 09:58 » |
|
Алексей++, вот у меня неожиданно появился вопрос по поводу заполнения QByteArray значениями из файла. Пытался сделать так:QByteArray b;
for (int k = 0; k < 492*720; k++) b[k] = getc(fp);
qDebug() << b.toInt();
fp определён так:Выскакивает ошибка вообще, не из той области.Ошибка такая: QColor::setRgb: RGB parameters out of range. То есть данный код, повлиял на код который ниже расположен, а без этого кода ни какой ошибки нет. Как же это поправить?Я бы с удовольствием использовал в место FILE модуль QFile, но в нём возникает ошибка. я делаю так:chdir("file");
QFile fp("1.dat");
if (!fp.open(QIODevice::ReadOnly)) qDebug() << "File not open"; QByteArray file; file = fp.readAll();
qDebug() << file.toInt();
Выводиться 0 хотя в бинарном (двоичном) файле куча байт. Если последнюю строчку заменяю наТо выводятся, только первые десять байт.Почему такие странные результаты вывода? Мне нужно, что бы выводились все значения из файла в десятичном виде.
|
|
« Последнее редактирование: 17-05-2013 12:09 от zuze »
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #16 : 17-05-2013 16:22 » |
|
ты же место в массиве не выделил, а заполняешь - естественно всё падать будет. Но в Qt всё проще можно, и не нужно никаких FILE : QFile file("путь"); if(file.open(file.ReadOnly) { QByteArray data=file.readAll (); file.close();
//работаем ... }
|
|
|
Записан
|
|
|
|
zuze
Опытный
Offline
Пол:
Россия, Москва
|
|
« Ответ #17 : 20-05-2013 05:20 » |
|
Алексей++, сделал по Вашему примеру аналогичный код. Вот он:chdir("file"); QFile file("1.dat");
if (file.open(file.ReadOnly)) { QByteArray data = file.readAll(); file.close(); qDebug() << data; }
В результате всё равно выводятся только первый десять байт. А на самом деле байт намного больше. Я посмотрел в редакторе двоичных (бинарных) файлов и увидел, что обрыв происходит на байте со значением "00". Но я не могу поверить, что "readAll()" не может обработать значение байта "00", а может это, так "qDebug()" реагирует на байт со значением "00". Что же всё таки произошло, почему не всё выводится?
|
|
« Последнее редактирование: 20-05-2013 05:27 от zuze »
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #18 : 20-05-2013 05:44 » |
|
всё происходит правильно. Продолжай размер data.size()
|
|
|
Записан
|
|
|
|
zuze
Опытный
Offline
Пол:
Россия, Москва
|
|
« Ответ #19 : 20-05-2013 08:31 » |
|
всё происходит правильно. Продолжай chdir("file"); QFile file("1.dat");
if (file.open(file.ReadOnly)) { file.seek(file.size() - (492*720));
QByteArray mydata = file.readAll(); file.close();
im = QImage::fromData(mydata, QImage::Format_ARGB32);
QPainter Tochka; Tochka.begin(this);
Tochka.translate(50, 50); Tochka.drawImage(0, 0, im, 0, 0, 720, 492);
Tochka.end();
Конечно перед строчкой "im = QImage::fromData(mydata, QImage::Format_ARGB32);" надо было сделать "перетусовывание байтов под формат", но я не совсем понял, как это сделать, это что надо было QByteArray надо использовать как двухмерный массив и возможно ли это. Что касается строки:file.seek(file.size() - (492*720));
Так это смещение, так как первые 8 байт это управляющие байты. im объявлена глобально:QImage im(720, 492, QImage::Format_ARGB32);
Но в результате выскакивает ошибка явно не с тем, что я не "перетусовал байты под формат". Ошибка такая:conversion from 'qbytearray' to 'const uchar*' is ambiguous candidates are: QByteArray::operator QNotImplicitBoolCast() const <near match> QByteArray::operator const void*() const <near match> QByteArray::operator const char*() const <near match> Ошибка указывает на строку:im = QImage::fromData(mydata, QImage::Format_ARGB32);
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #20 : 20-05-2013 08:58 » |
|
if (file.open(file.ReadOnly)) { /* строка file.seek(file.size() - (492*720)); у тебя ничего не делает и вообще не нужна. Две цифры - вообще непонятно откуда ) откуда инфа про 8 служебных байтов ? Где структура, которая их описывает ? пропустить размер в 8 байтов проще удалением их из загруженного массива */ QByteArray mydata = file.readAll(); file.close(); mydata.remove(0,8/*sizeof(та самая структура с описанием)*/); /*сильно предполагаю, что в этой структуре и размеры сидят*/ int xsize=...; int ysize=...;
//здесь переформатирование //... /* If format is not specified (which is the default), the loader probes the file for a header to determine the file format. If format is specified, it must be one of the values returned by QImageReader::supportedImageFormats(). */ QImage::Format f=QImage::Format_ARGB32; im = QImage::fromData(mydata, &f); }
|
|
|
Записан
|
|
|
|
zuze
Опытный
Offline
Пол:
Россия, Москва
|
|
« Ответ #21 : 20-05-2013 09:37 » |
|
откуда инфа про 8 служебных байтов ?
Это из условия которое мне сказали, когда дали файл. Где структура, которая их описывает ?
По горизонтали 720, а по вертикали 492. Заполняется картинка с лева на право с низу вверх. То есть, пока xsize = 0, int ysize меняется от 0 до 491. Сначала берётся первые 492 байта, затем следующие 492 байта и так далее. Добавлено через 23 минуты и 14 секунд:Алексей++, сделал вроде как Вы написали: chdir("file"); QFile file("1.dat");
if (file.open(file.ReadOnly)) { QByteArray mydata = file.readAll(); file.close();
mydata.remove(0, 8);
// здесь переформатирование (Пока не понимаю, как сделать)
QImage::Format f = QImage::Format_ARGB32; im = QImage::fromData(mydata, &f);
QPainter Tochka; Tochka.begin(this);
Tochka.translate(50, 50);
Tochka.drawImage(0, 0, im, 0, 0, 720, 492);
Tochka.end();
Таже самая ошибка и на той же строчке кода. В чём же дело?Можно ли обратится к QByteArray, как к двухмерному массиву? Если да, то я без проблем сделаю "переформатирование".
|
|
« Последнее редактирование: 20-05-2013 10:00 от zuze »
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #22 : 20-05-2013 10:34 » |
|
а, это я невнимательно поспотрел. Для получения указателя на начад\ло буфера данных надо вызвать метод data() но, блин, это из справки можно было уже и так понять )) перейти к "двухмерности" - только вручную. К примеру, сначала в массиве структур S идёт первая строка, потом вторая, тогда индекс структуры со строкой row и столбцом col будет равен , где Cols - размер строки (то есть количество колонок) S* pArrayOfS=(S*) mydata.data(); uint32_t i=5*Cols+7 ; pArrayOfS[i]; //это ссылка на элемент S с нужным индексом (5,7)
собственно, S - это структура, описывающая один пиксел. Для конвертации будет удобно использовать похожую структуру с переставленными битовыми полями
|
|
|
Записан
|
|
|
|
zuze
Опытный
Offline
Пол:
Россия, Москва
|
|
« Ответ #23 : 20-05-2013 12:16 » |
|
Для получения указателя на начад\ло буфера данных надо вызвать метод
data()
Как я понял, надо в место:im = QImage::fromData(mydata, &f);
написать:im = QImage::fromData(mydata.data(), &f);
Но это приводит к ошибке, а именно:invalid conversion from 'char*' to 'const uchar*' initializing argument 1 of 'static QImage QImage::fromData(const uchar *, int, const char*)' invalid conversion from 'QImage::Format*' to 'int' initializing argument 2 of 'static QImage QImage::fromData(const uchar *, int, const char*)' В добавок если я начну "переформатирование" в двухмерный массив, то я уже не смогу воспользоваться методом fromData(), который необходим для повышение скорости. Может есть какое другое "переформатирование" которое бы в конкретном варианте подошло?
|
|
|
Записан
|
|
|
|
darkelf
Молодой специалист
Offline
|
|
« Ответ #24 : 20-05-2013 13:36 » |
|
zuze, как вариант, попробуйте написать im = QImage::fromData((const uchar*)mydata.data(), &f)
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #25 : 20-05-2013 15:44 » |
|
zuze, ты можешь получить неконстантный указатель на буфер mydata - data(). Через него ты меняешь элементы к нужному виду (это я и назвал переформатированием), не меняя размер буфера (и, естественно, не залазя за его границы!). Потом этот объект mydata и используешь в методе QImage::fromData QImage fromData ( const QByteArray & data, const char * format = 0 )
|
|
|
Записан
|
|
|
|
zuze
Опытный
Offline
Пол:
Россия, Москва
|
|
« Ответ #26 : 21-05-2013 05:36 » |
|
zuze, как вариант, попробуйте написать im = QImage::fromData((const uchar*)mydata.data(), &f)
Попробовал, ошибки остались, но уменьшились, остались только:invalid conversion from 'QImage::Format*' to 'int' initializing argument 2 of 'static QImage QImage::fromData(const uchar *, int, const char*)'
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #27 : 21-05-2013 05:41 » |
|
zuze, это потому, что там ещё длину массива надо передать. (Ты прототипы функций то гляди)
а я предлагаю использовать метод, где передаётся сразу ссылка на QByteArray
|
|
|
Записан
|
|
|
|
zuze
Опытный
Offline
Пол:
Россия, Москва
|
|
« Ответ #28 : 21-05-2013 05:53 » |
|
zuze, это потому, что там ещё длину массива надо передать. (Ты прототипы функций то гляди)
а я предлагаю использовать метод, где передаётся сразу ссылка на QByteArray
Я не могу понять, выбираю "QImage::fromData(const uchar *, const char*)", а при компиляции запускается "QImage::fromData(const uchar *, int, const char*)", почему же так происходит?
|
|
|
Записан
|
|
|
|
Алексей++
глобальный и пушистый
Глобальный модератор
Offline
Сообщений: 13
|
|
« Ответ #29 : 21-05-2013 05:57 » |
|
выбираю "QImage::fromData(const uchar *, const char*)",
такой перегрузки нет. Есть только две: QImage fromData ( const uchar * data, int size, const char * format = 0 ) QImage fromData ( const QByteArray & data, const char * format = 0 )
|
|
|
Записан
|
|
|
|
|