Pull to refresh

Comments 15

еще накину идей для статей на будущее :)
ресайзинг картинок на GPU: AMD/OpenCL, NVidia/OpenCL, NVidia/CUDA… можно будет добавить Vulkan и DX12
а OpenCL(возможно и Vulkan) можно еще и на CPU протестить, взяв SDK от Intel и от AMD

Еще бы сравнить GPU-based методами, а так полагаю там много времени уходит на копирование данных в памяти, но можно было бы сравнить уменьшение сразу пачки картинок в целый набор типоразмеров.
Сравнить достаточно просто: скорее всего даже самая простая реализация в лоб на самой медленной карте последнего поколения (GF 1050) будет упираться только в шину. Скорость 16x PCIe 3.0 примерно 11 Гб/c. Для ресайза 2560*1600 → 320*200 по шине нужно прокачать примерно 16 Мб данных. Это будет примерно 690 операций/секунду.

Результаты Pillow-SIMD 3.4 на одном ядре с AVX2 для той же операции с бикубическим фильтром — 175 операций/секунду. Сопоставимый по стоимости процессор для выбранной видеокарты будет 4-ядерный i5, то есть на всех ядрах теоретически будет 700 операций/секунду. На практике может быть немного поменьше: ресайз на двух ядрах дает двухкратный прирост, а вот для четырех ядер надо проверять.

Другое дело, что на видеокарте можно сделать не только ресайз, а что-то еще интересное. Самый шик был бы делать на видеокарте декодирование из JPEG и других графических форматов, тогда было бы пофиг на скорость шины. Но что-то пока нет открытых кодеков популярных форматов. И даже те, что есть, требуют специально подготовленных джипегов, с рестарт-маркерами. С остальными форматами все еще хуже.

Для улучшения качества ресайза при уменьшении изображения можно было считать интегральное изображение, затем его уменьшать теми же сплайнами, затем дифференцировать его обратно. Т.е. делать это за 3 операции: интегрирование ->
ресайз -> дифференцирование. Каждая из этих операций разделяема по направлениям. Если использовать эту схему, то количество семплов, приходящихся на каждый пиксель выходной картинки, никак не будет зависеть от коэффициента масштабирования. Алиасинг полностью исчезнет.

Почти все видеокарты поддерживают аппаратное декодирование MPEG2. А опорный кадр (I frame) MPEG2, по сути, и есть JPEG.

Кроме того, можно делать свёртки в фазовом домене, сразу после декодирования VLC, не проводя iDCT преобразование — это если пользоваться софтверным декодером JPEG.

Померил на реальном железе с i5-4430:


Текущая версия Pillow-SIMD 4.1.0


2560×1600 → 26x16 bic      1002 op/s
2560×1600 → 320x200 bic    630 op/s
2560×1600 → 2048x1280 bic  153 op/s
2560×1600 → 5478x3424 bic  40 op/s

Pillow-SIMD с улучшениями, которые пока не вошли ни в одну версию:


2560×1600 → 26x16 bic      1028 op/s
2560×1600 → 320x200 bic    730 op/s
2560×1600 → 2048x1280 bic  242 op/s
2560×1600 → 5478x3424 bic  59 op/s

Теоретический максимум по шине PCIe 3.0 16x


2560×1600 → 26x16 bic      671 op/s
2560×1600 → 320x200 bic    661 op/s
2560×1600 → 2048x1280 bic  409 op/s
2560×1600 → 5478x3424 bic  120 op/s
Обычно типовая задача — это нарезка закачанной пользователем картинки сразу в несколько (2..8) различных типоразмеров. То есть закачивать исходную картинку мы будем только один раз, а нарезать — несколько.
Сколько у вас ушло человекочасов на создание этого ресайзера?
Числа с плавающей точкой Хранят приблизительное значение с определенной точностью

кхм, а это как?
по мне так в пз хранится не приблизительное а вполне определенное число, кратное 2^m.

Сравнить достаточно просто: скорее всего даже самая простая реализация в лоб на самой медленной карте последнего поколения (GF 1050) будет упираться только в шину. Скорость 16x PCIe 3.0 примерно 11 Гб/c. Для ресайза 2560*1600 → 320*200 по шине нужно прокачать примерно 16 Мб данных. Это будет примерно 690 операций/секунду.

Можно совместить копирования и вычисления с помощью CUDA Streams, тогда теоретический потолок пропускной способности поднимется в два раза, хотя на практике так быстро пока не получается. К тому же, очень часто алгоритм ресайза находится не в самом начале общей схемы обработки изображений и все данные уже находятся в памяти видеокарты, т.е. их никуда не нужно копировать. Поэтому мы для тестов производительности измеряем время работы алгоритма на GPU без учёта копирований.

Для проверки производительности алгоритма мы используем два теста: сжатие изображений 2К и 4К в 2 раза по каждой оси и уменьшение размеров изображения на 1 пиксел по ширине и по высоте. Во втором тесте размер данных почти не изменяется и для оценки производительности вычислений такой подход кажется более оправданным.
Другое дело, что на видеокарте можно сделать не только ресайз, а что-то еще интересное. Самый шик был бы делать на видеокарте декодирование из JPEG и других графических форматов, тогда было бы пофиг на скорость шины. Но что-то пока нет открытых кодеков популярных форматов.

Мы именно так и делаем, т.е. вся обработка изображений выполняется на видеокарте. Получается очень быстро и можно делать ресайз джипегов на лету, задавая индивидуальные параметры ресайза для каждой картинки. При этом скорость декодирования джипегов у нас чуть ниже, чем скорость ресайза. Здесь можно посмотреть наши бенчмарки для ресайза и декодирования.
И даже те, что есть, требуют специально подготовленных джипегов, с рестарт-маркерами. С остальными форматами все еще хуже.

Да, без рестарт-маркеров не получается параллельное декодирование джипегов (декодирование по Хаффману). Но можно без потери качества добавить рестарт-маркеры самостоятельно с помощью утилиты jpegtran. Рестарт-маркеры являются частью стандарта JPEG, так что это разумный и вполне официальный подход для решения задач быстрого декодирования.
В php эту библиотеку как-то можно использовать?
Напрямую нет, нужно взять нашу dll/so и сделать обёртку.
Вот бы кто-нибудь сделал, цены бы не было.
Пожалуйста сформулируйте задачу и покажите примеры использования. Тут или в личку.
Sign up to leave a comment.

Articles