Швидкий ресайз джипегов на відеокарті

У програмах по роботі з зображеннями досить часто зустрічається завдання ресайза джипегов (картинок, стиснутих за алгоритмом JPEG). У цьому випадку відразу зробити ресайз можна і потрібно спочатку декодувати вихідні дані. Нічого складного і нового в цьому немає, але якщо це потрібно робити багато мільйонів разів в добу, то особливу важливість набуває оптимізація продуктивності такого рішення, яке повинно бути дуже швидким.

Така задача часто зустрічається при організації віддаленого хостингу для сховища картинок, оскільки більшість камер і телефонів знімають саме в форматі JPEG. Щодня фото архіви провідних веб-сервісів (соціальних мереж, форумів, фото хостингів і багатьох інших) поповнюються значною кількістю таких зображень, тому питання про те, як саме зберігати такі картинки, вкрай важливий. Для зменшення розміру вихідного трафіку і для поліпшення часу відгуку на запит користувача, що багато веб-сервіси зберігають кілька десятків файлів для одного зображення в різних дозволах. Швидкість відгуку виходить хорошою, але місця ці копії займають багато. Це основна проблема, хоча є й інші мінуси такого підходу.

Ідея рішення цієї проблеми складається в тому, щоб не зберігати на сервері багато варіантів вихідного зображення в різних дозволах, а динамічно створювати потрібну картинку з заданими розмірами з заздалегідь приготованого оригіналу, причому якомога швидше. Таким чином, в реальному часі можна створити зображення потрібного дозволу і відразу відправити користувачеві. Дуже важливо, що дозвіл цього зображення відразу можна зробити таким, щоб пристрій користувача не робило екранний ресайз, так як в ньому просто не буде потреби.

Використання інших форматів, відмінних від JPEG, у якості базових для організації такого сховища зображень не здається виправданим. Звичайно, є стандартні, широко використовувані формати, які дають краще стиснення при аналогічній якості (JPEG2000, WebP), але швидкість кодування і декодування таких зображень дуже мала в порівнянні з JPEG, тому має сенс вибрати саме JPEG якості базового формату для зберігання оригінальних фотографій, які за необхідності будуть отмасштабированы в реальному часі після отримання запиту від користувача.

Звичайно, крім джипегов на кожному сайті найчастіше є зображення у форматах PNG і GIF, але зазвичай їх відносна кількість невелика, а фотографії в цих форматах зберігаються вкрай рідко. Тому помітного впливу на розглянуту задачу ці формати не внесуть в більшості випадків.

Опис алгоритму ресайза на льоту

Отже, вхідними даними є файли формату JPEG, причому для досягнення швидкого декодування (це вірно як для CPU, так і для GPU), стиснуті зображення повинні мати вбудовані рестарт-маркери. Ці маркери описані в стандарті JPEG і частина кодеків вміє з ними працювати, інші вміють їх не помічати. Якщо таких маркерів у джипегов немає, їх можна заздалегідь додати за допомогою утиліти jpegtran. При додаванні маркерів зображення не змінюється, але розмір файлу стає трохи більше. В результаті отримуємо наступну схему роботи:

  1. Отримуємо дані зображення з пам’яті CPU
  2. Якщо є колірний профіль, отримуємо його з EXIF секції і зберігаємо
  3. Копіюємо картинку на відеокарту
  4. Декодируем JPEG
  5. Робимо ресайз за алгоритмом Ланцоша (зменшення)
  6. Накладаємо різкість
  7. Кодуємо зображення у форматі JPEG
  8. Копіюємо зображення на хост
  9. Додаємо в отриманий файл вихідний колірний профіль

Можна зробити і більш точне рішення, коли перед ресайзом накладається зворотна гамма на кожну компоненту пікселя, щоб ресайз був у лінійному просторі, а потім гаму застосувати знову, але вже після шарпа. Фактична різниця для користувача невелика, але вона існує, а обчислювальні витрати для такої модифікації мінімальні. Потрібно лише вставити накладення зворотної та прямої гами в загальну схему обробки.

Читайте також  Як зробити пошук користувачів з Github використовуючи Angular

Також можливий варіант рішення, коли декодування джипегов виконується на багатоядерний ПРОЦЕСОР з допомогою бібліотеки libjpeg-turbo. У цьому випадку кожна картинка декодується в окремому потоці CPU, а всі інші дії виконуються на відеокарті. При наявності великої кількості ядер CPU так може вийти навіть швидше, але буде серйозний програш у латентності. Якщо латентність при декодуванні джипега на одному ядрі CPU є припустимою, то цей варіант може виявитися дуже швидким, особливо для випадку, коли вихідні джипеги мають невелику роздільну здатність. При збільшенні роздільної здатності вихідного зображення, час декодування джипега в одному потоці CPU буде збільшуватися, тому цей варіант може підійти тільки для невеликих дозволів.

Базові вимоги до задачі ресайза для вебу

— Бажано не зберігати на сервері десятки копій кожного зображення в різних дозволах, а швидко створювати потрібну картинку з правильним роздільною здатністю відразу при отриманні запиту. Це важливо для зменшення розміру сховища, так як в противному випадку доведеться зберігати багато різних копій кожного зображення.
— Завдання потрібно вирішити максимально швидко. Це питання про якість послуги, що надається з точки зору зменшення часу відгуку на запит користувача.
— Якість отриманого зображення має бути високим.
— Розмір файлу для відправленого зображення повинен бути як можна менше, а його роздільна здатність в точності повинно відповідати розміру вікна, в якому воно з’явиться. Тут важливі наступні моменти:
а). Якщо розмір зображення не буде збігатися розміром вікна, то пристрій користувача (телефон, планшет, ноутбук) перед виведенням зображення на екран зробить апаратний ресайз після декодування. В OpenGL цей апаратний ресайз робиться тільки за билинейному алгоритмом, який часто викликає появу муару (розлучень) та інших артефактів на зображеннях, що містять дрібні деталі.
б). Екранний ресайз додатково споживає енергію пристрою.
в). Якщо для вирішення завдання використовувати серію заздалегідь отмасштабированных зображень, то не завжди вийде точно потрапити в потрібний розмір, а значить, доведеться посилати зображення більшого дозволу. Збільшений розмір зображення призводить до більшого трафіку, чого теж хотілося б уникнути.

Опис загальної схеми роботи

1. Отримуємо від користувачів зображення в будь-яких форматах і в будь-яких дозволів. Оригінали зберігаємо в окремій базі даних (якщо потрібно).
2. В офлайні з допомогою ImageMagick, OpenCV або аналогічного софта, зберігаємо колірний профіль, перетворимо вихідні оригінальні зображення до стандартного формату BMP або PPM, після чого робимо ресайз до дозволу 1К чи 2К і стискаємо в JPEG, потім утилітою jpegtran додаємо рестарт-маркери з заданим фіксованим інтервалом.
3. Складаємо базу даних з таких 1К чи 2К зображень.
4. При отриманні запиту від користувача отримуємо інформацію про зображення і розмір вікна, де повинно бути показано це зображення.
5. Зображення знаходимо в базі даних і відправляємо ресайзеру.
6. Ресайзер отримує файл зображення, декодує, робить ресайз, шарп, кодує і вставляє вихідний колірний профіль отриманий джипег. Після цього віддає картинку зовнішній програмі.
7. На кожній відеокарті можна запустити кілька потоків, а в комп’ютері можна встановити декілька відеокарт — таким чином досягається масштабування продуктивності.
8. Все це можна зробити на базі відеокарт NVIDIA Tesla (наприклад, Р40 або V100), оскільки відеокарти NVIDIA GeForce не призначені для безперервної тривалої роботи, а у NVIDIA Quadro є багато відео виходів, які в даному випадку не потрібні. Для вирішення цієї задачі вимоги до розміру пам’яті GPU мінімальні.
9. Також бази з приготованими зображеннями можна динамічно виділити кеш для часто використовуваних файлів. Там має сенс зберігати часто використовувані зображення за статистикою попереднього періоду.

Читайте також  Проблематика сови і глобуса: підключення двох збірок з ідентичними просторами імен і назв класів

Параметри програми

1. Ширина і висота нового зображення. Вони можуть бути будь-якими і їх краще ставити в явному вигляді.
2. Режим проріджування JPEG (subsampling). Є три варіанти: 4:2:0, 4:2:2 і 4:4:4, але зазвичай використовують 4:4:4 або 4:2:0. Максимальна якість у 4:4:4, мінімальний розмір кадру 4:2:0. Проріджування робиться для цветоразностных компонент, які зір людини сприймає не так добре, як яркостную. Для кожного режиму проріджування є свій оптимальний інтервал для рестарт-маркерів для досягнення максимальної швидкості кодування чи декодування.
3. Якість стиснення JPEG і режим проріджування при створенні бази даних зображень.
4. Шарп робиться у вікні 3х3, сігмою (радіусом) можна управляти.
5. Якість стиснення JPEG і режим проріджування при кодуванні фінальної картинки. Зазвичай якість не менше 90% означає, що це стиск «візуально без втрат», тобто непідготовлений користувач не повинен побачити артефакти алгоритму JPEG при стандартних умовах перегляду. Вважається, що для підготовленого користувача потрібно 93-95%. Чим більше це значення, тим більше розмір кадру, відправляється користувачеві, і тим більше час декодування і кодування.

Важливі обмеження

Рестарт-маркери. Ми можемо швидко декодувати на відеокарті зображення у форматі JPEG тільки в тому випадку, якщо всередині нього знаходяться рестарт-маркери. В офіційному стандарті JPEG ці маркери описано, це стандартний параметр. Якщо рестарт-маркерів немає, то розпаралелити декодування картинки на відеокарті можна, що призведе до дуже малої швидкості декодера. Тому потрібна база приготованих зображень, в яких є ці маркери.

Фіксований алгоритм для кодека зображень. Декодування і кодування зображень за алгоритмом JPEG є на сьогоднішній день найшвидшим варіантом.

Дозвіл зображень в приготовленої базі даних може бути будь-яким, а в якості варіантів ми розглянемо 1К і 2К (можна взяти і 4К). Також можна зробити не тільки зменшення, але і збільшення зображень при ресайзе.

Продуктивність швидкого ресайза

Ми протестували додаток для швидкого ресайза з комплекту Fastvideo SDK на відеокарті NVIDIA Tesla V100 (OS Windows Server 2016, 64-bit, драйвер 24.21.13.9826) на 24-бітних зображеннях 1k_wild.ppm і 2k_wild.ppm з роздільною здатністю 1К і 2К (1280х720 і 1920х1080). Тести проведені для різної кількості потоків, запущених на одній відеокарті. При цьому потрібно не більше 110 МБайт пам’яті на відеокарті на один потік. На 4 потоку потрібно не більше 440 МБайт.

Спочатку стискаємо вихідні зображення в JPEG c якістю 90%, з проріджуванням 4:2:0 або 4:4:4. Потім декодируем і робимо ресайз в 2 рази по ширині і висоті, робимо шарп, потім знову кодуємо c якістю 90% в 4:2:0 або 4:4:4. Вихідні дані лежать в оперативній пам’яті, фінальна картинка розміщується там же.

Час роботи вважається від початку завантаження вихідної картинки з RAM до збереження в RAM обробленого зображення. Час ініціалізації програми та виділення пам’яті на відеокарті не включені до вимірювання.

Приклад командного рядка 24-бітного зображення 1К
PhotoHostingSample.exe -i 1k_wild.90.444.jpg -o 1k_wild.640.jpg -outputWidth 640 -q 90 -s 444 -sharp_after 0.95 -repeat 200

Бенчмарк для обробки одного зображення 1K в одному потоці

Декодування (включаючи пересилання даних на відеокарту): 0,70 мс
Ресайз в два рази (по ширині і по висоті): 0,27 мс
Шарп: 0,02 мс
Кодування JPEG (включаючи пересилання даних з відеокарти): 0,20 мс
Сумарний час на один кадр: 1,2 мс

Продуктивність для 1К

 

Якість Проріджування Ресайз Потоки Частота кадрів (Гц)
1 90% 4:4:4 / 4:2:0 2 рази 1 868 / 682
2 90% 4:4:4 / 4:2:0 2 рази 2 1039 / 790
3 90% 4:4:4 / 4:2:0 2 рази 3 993 / 831
4 90% 4:4:4 / 4:2:0 2 рази 4 1003 / 740

 

Продуктивність для 2К

 

Якість Проріджування Ресайз Потоки Частота кадрів (Гц)
1 90% 4:4:4 / 4:2:0 2 рази 1 732 / 643
2 90% 4:4:4 / 4:2:0 2 рази 2 913 / 762
3 90% 4:4:4 / 4:2:0 2 рази 3 891 / 742
4 90% 4:4:4 / 4:2:0 2 рази 4 923 / 763
Читайте також  Імплементація катсцен і послідовностей дій в іграх

Проріджування 4:2:0 для вихідного зображення зменшує швидкість роботи, зате розміри початкового і кінцевого файлів стають менше. При переході на 4:2:0 ступінь паралелізму падає в 4 рази, так як тепер блок 16х16 розглядається як одне ціле, тому в цьому режимі швидкість роботи нижче, ніж для 4:4:4.

Продуктивність в основному визначається стадією декодування JPEG, оскільки на цій стадії картинка має максимальний дозвіл, а обчислювальна складність цієї стадії обробки вище, ніж всі інші.

Резюме

Результати тестів показали, що для відеокарти NVIDIA Tesla V100 швидкість обробки 1К і 2К зображень максимальна при запуску 2-4 потоків одночасно, і становить від 800 до 1000 кадрів в секунду на одну відеокарту. Обробка 1К картинок виконується швидше, ніж 2К, а робота з зображеннями 4:2:0 завжди виконується повільніше, ніж з 4:4:4. Для одержання остаточного результату по продуктивності, потрібно точно визначити всі параметри програми та оптимізувати її під конкретну модель відеокарти.

Латентність порядку однієї мілісекунди — це непоганий результат. Наскільки відомо, таку латентність можна отримати для аналогічної задачі ресайза на CPU (навіть при відсутності необхідності кодування і декодування джипегов), так що це ще один важливий аргумент на користь застосування відеокарт у високопродуктивних рішеннях по обробці зображень.

Для обробки одного мільярда джипегов на добу з дозволами 1K або 2K, може знадобитися до 16 відеокарт NVIDIA Tesla V100. Деякі з наших замовників вже використовують це рішення, інші тестують його в своїх завданнях.

Ресайз джипегов на відеокарті може бути дуже корисний не тільки для веб-сервісів. Є величезна кількість високопродуктивних додатків по обробці зображень, де такий функціонал може бути затребуваний. Наприклад, швидкий ресайз дуже часто необхідний практично для будь-якої схеми обробки зображень, отриманих від камер, перед виведенням зображення на монітор. Таке рішення може працювати для Windows/Linux на будь-яких відеокартах NVIDIA: Tegra K1/X1/X2/Xavier, GeForce GT/GTX/RTX, Quadro, Tesla.

Переваги рішення з швидким ресайзом на відеокарті

— Значне зменшення розміру сховища для вихідних зображень
— Скорочення первинних витрат на вартість інфраструктури (залізо і софт)
— Поліпшення якості сервісу завдяки малому часу відгуку
— Скорочення вихідного трафіку
— Менше споживання енергії на пристроях користувачів
— Надійність і швидкість представленого рішення, яке вже було протестовано на величезних наборах даних
— Зменшення часу розробки для виведення на ринок таких програм для ОС Linux і Windows
— Масштабованість рішення, яке може працювати як на одиночної відеокарти, так і в складі кластера
— Швидке повернення інвестицій для таких проектів

Кому це може бути цікаво

Бібліотека для швидкого ресайза джипегов може застосовуватися в високонавантажених веб-сервісах, великих онлайн-магазинах, соціальних мережах, системах онлайн менеджменту фотографій, електронної комерції, практично в будь-якому програмному забезпеченні для керування підприємств великого розміру.

Розробники можуть використовувати цю бібліотеку, яка забезпечує латентність порядку декількох мілісекунд ресайза джипегов з роздільною здатністю 1К, 2К і 4К на відеокарті.

По всій видимості, цей підхід може виявитися більш швидким, ніж рішення NVIDIA DALI для швидкого декодування джипегов, ресайза і підготовки зображень на етапі тренування нейромереж для Deep Learning.

Що ще можна зробити

  • Крім ресайза і шарпа можна в існуючий алгоритм додати кроп, повороти на 90/180/270, накладення ватермарка, управління яскравістю і контрастом.
  • Оптимізація рішення для відеокарт NVIDIA Tesla P40 і V100.
  • Додаткова оптимізація продуктивності декодера JPEG.
  • Режим пачки для декодування джипегов на відеокарті.

Степан Лютий

Обожнюю технології в сучасному світі. Хоча частенько і замислююся над тим, як далеко вони нас заведуть. Не те, щоб я прям і знаюся на ядрах, пікселях, коллайдерах і інших парсеках. Просто приходжу в захват від того, що може в творчому пориві вигадати людський розум.

You may also like...

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *