Какой самый быстрый способ загрузки и изменения размера изображения? - PullRequest
5 голосов
/ 07 мая 2009

Мне нужно отобразить миниатюры изображений в заданном каталоге. Я использую TFileStream для чтения файла изображения перед загрузкой изображения в компонент изображения. Затем размер растрового изображения изменяется до размера миниатюры и назначается компоненту TImage в TScrollBox.

Вроде бы нормально, но с большими изображениями сильно тормозит.

Существует ли более быстрый способ загрузки (образа) файлов с диска и изменения их размера?

Спасибо, Питер

Ответы [ 6 ]

5 голосов
/ 07 мая 2009

Я дополню ответ skamradt попыткой придумать его как можно быстрее. Для этого вам следует

  • оптимизировать ввод / вывод
  • использовать несколько потоков, чтобы использовать несколько ядер ЦП и поддерживать работу даже одного ядра ЦП во время чтения (или записи) файлов

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

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

Для достижения наилучших результатов чтение (и запись) файлов также не должно происходить в основном потоке (GUI) вашего приложения. Это предполагает следующий дизайн:

  • Один поток читает файлы в объекты TGraphic и помещает их в потокобезопасный список.
  • Пусть пул потоков ожидает список файлов в исходном размере, и один поток обрабатывает один объект TGraphic, изменяет его размер в другой объект TGraphic и добавляет его в другой потокобезопасный список.
  • Уведомлять поток графического интерфейса пользователя о каждом миниатюрном изображении, добавленном в список, чтобы его можно было отобразить.
  • Если миниатюры должны быть записаны в файл, сделайте это также в ветке чтения (объяснение см. Выше).

Edit:

Перечитывая ваш вопрос, я замечаю, что вам может понадобиться изменить размер только одного изображения, и в этом случае, конечно, достаточно одного фонового потока. В любом случае я оставлю свой ответ на месте, может быть, он когда-нибудь пригодится кому-то еще. Это то, что я узнал из одного из моих последних проектов, где финальная программа могла нуждаться в немного большей скорости, но использовала только около 75% четырехъядерного компьютера в пиковые периоды времени. Отключение ввода-вывода от обработки имело бы значение.

5 голосов
/ 07 мая 2009

Не совсем. Что вы можете сделать, так это изменить их размер в фоновом потоке и использовать изображение «заполнитель» до тех пор, пока изменение размера не будет выполнено. Затем я бы сохранил эти изображения с измененным размером в какой-то файл кэша для последующей обработки (это делает Windows и вызывает кэш thumbs.db в текущем каталоге).

У вас есть несколько вариантов самой архитектуры потоков. Один поток, который делает все изображения, или пул потоков, где поток знает только, как обрабатывать одно изображение. Библиотека AsyncCalls - это еще один способ, благодаря которому все довольно просто.

4 голосов
/ 07 мая 2009

Я часто использую TJPEGImage с Scale: = jsEighth (в Delphi 7). Это действительно быстро, потому что декомпрессия JPEG может пропустить много данных, чтобы заполнить растровое изображение только восьмой ширины и высоты.

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

1 голос
/ 07 мая 2009

Я занимаюсь бизнесом, и просто загружаю изображения в графический процессор с помощью OpenGL. (обычно 20x 2048x2000x8bpp в секунду), bmp на текстуру и масштабирование видеокарты (win32, заголовки opengl Майка Лишке)

Загрузка такого изображения стоит 5-10 мс в зависимости от конкретной видеокарты (если она не встроена, а серии NVIDIA 7300 или новее. Также могут быть реализованы новейшие интегрированные графические процессоры). Масштабирование и отображение стоит 300US. Это означает, что клиенты могут перемещаться и масштабироваться как сумасшедшие, не касаясь приложения. Я рисую наложение (которое раньше было tmetafile, но теперь это собственный формат) поверх него.

Моя самая большая картинка - 4096x7000x8bpp, которая показывает и масштабируется менее чем за 30 мс. (GF 8600)

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

(некоторые типичные размеры: Серия nv6x00: 2k * 2k, но загрузка практически безубыточна по сравнению с GDI Серия nv7x00: 4k * 4k Для меня базовые карты. GF7300 как $ 20-40 серия nv8x00: 8k * 8k )

Обратите внимание, что это может быть не для всех. Но если вам повезло указать аппаратные ограничения, это может сработать. Основная проблема - это ноутбуки, такие как Thinkpad, графические процессоры которых старше, чем ноутбук avg, которые, в свою очередь, часто отстают от настольных компьютеров.

Я выбрал OpenGL, а не DirectX, потому что он более статичен во времени и легче найти примеры, не относящиеся к игре.

0 голосов
/ 13 мая 2009

Попробуйте взглянуть на библиотеку Graphics32 : она очень хорошо рисует и работает отлично с растровыми изображениями. Это потокобезопасный пример с хорошим примером, и он абсолютно бесплатный.

0 голосов
/ 08 мая 2009

Использование возможностей Windows для создания миниатюр. Помните, что скрытые файлы Thumbs.db в папках, которые содержат изображения?

Я реализовал нечто подобное, но в VB. Мое программное обеспечение может создавать эскизы из 100 файлов (смешанного размера) примерно за 10 секунд.

Я не могу конвертировать его в Delphi.

...