Як працює JPG

Як працює JPG

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

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

Суть

Схема стиснення JPG розбита на кілька фаз. Малюнок нижче описує їх на високому рівні, і ми пройдемося по кожному етапу нижче.

Перетворення кольорового простору

Одним з ключових принципів стиснення даних із втратами є те, що людські датчики не настільки точні, як обчислювальні системи. По-науковому, людське око має лише фізичну здатність розрізняти близько 10 мільйонів різних кольорів. Однак є багато речей, які можуть вплинути на те, як людське око сприймає колір; ідеально підкреслюється кольоровими ілюзіями або тим фактом, що ця сукня зламала Інтернет. Суть полягає в тому, що людським оком можна добре маніпулювати по відношенню до кольорів, які воно сприймає.

Квантування є формою цього ефекту при стисненні зображення з втратами, однак JPG застосовує інший підхід до цього: кольорові моделі . Кольорова палітра є конкретною організацією квітів, а його колірна модель являє собою математичну формулу для того, як представлені цих квітів (наприклад , трійки в RGB або четвірки в CMYK).

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

Наприклад, нижче наведено конкретний колір, який представлений у кольорових моделях RGB та CMYK, вони однакові для людського ока, але можуть бути представлені з різним набором числових значень.

JPG перетворює з RGB на кольорову модель Y, Cb, Cr; До складу якого входять Яскравість (Y), Хрома-блакитний (Cb) та Хрома-червоний (Cr). Причиною цього є те, що психовізуальні експерименти (зокрема, як мозок працює з інформацією, яку бачить око) демонструють, що людське око є більш чутливим до яскравості, ніж кольоровості, а це означає, що ми можемо нехтувати більшими змінами кольоровості, не впливаючи на сприйняття образу. Таким чином, ми можемо вносити агресивні зміни в канали CbCr, перш ніж людське око помітить.

Зменшення вибірки

Одним із цікавих результатів колірного простору YCbCr є те, що отримані в результаті Cb / Cr канали мають менш дрібно деталізовані деталі; вони містять менше інформації, ніж Y-канал.

Як результат, алгоритм JPG змінює розмір каналів Cb та Cr приблизно до ¼ їх початкового розміру (зауважте, є певний нюанс у тому, як це робиться, про що я тут не розповідаю ...), що називається зменшенням дискретизації .

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

Зображення розділене на 8x8 блоків пікселів

Відтепер JPG виконує всі операції з 8x8 блоками пікселів. Це робиться тому, що ми, як правило, очікуємо, що між блоками 8x8 не буде великих розбіжностей, навіть на дуже складних фотографіях спостерігається певна схожість між собою в локальних районах; ця подібність є тим, чим ми скористаємося під час нашого стиснення пізніше.

Варто зазначити, що на даний момент ми представляємо один із перших поширених «артефактів» кодування JPG. «Кольорове кровотеча» - це місце, коли кольори по гострих краях можуть «кровоточити» на інший бік. Це пояснюється тим, що в каналах кольоровості, які виражають колір пікселів, кожен блок з 4 пікселів усереднений в один колір, і деякі з цих блоків перетинають гострий край.

Дискретне перетворення косинусів

До цього моменту все було досить приручено. Кольорові простори, зменшення дискретизації та блокування - це прості речі у світі стиснення зображень. Але зараз… тепер з’являється справжня математика.

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

Наприклад, якщо ми маємо цей графік нижче:

Ви бачите, що це насправді сума cos (x) + cos (2x) + cos (4x)

Можливо, кращим відображенням цього є фактичне декодування зображення, враховуючи ряд косинусних функцій у двовимірному просторі. Щоб показати це, я представляю один з найдивовижніших GIF-файлів в Інтернеті: кодування блоку пікселів розміром 8x8 за допомогою косинусів у 2D-просторі:

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

Як бачите, підсумовуючи різні значення косинусів до ваги, ми можемо відновити своє початкове зображення (досить добре ...)

Це фундаментальне підґрунтя того, як працює дискретна косинусна трансформація. Ідея полягає в тому, що будь-який блок 8x8 може бути представлений як сума зважених косинусних перетворень на різних частотах. Фокус у всій цій справі полягає у з’ясуванні, які косинусні входи використовувати і як їх слід зважувати разом.

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

Що стосується проблеми «як їх слід зважувати разом», просто (HA!) Застосуйте цю формулу.

Я пощаджую вас, що означають усі ці значення, ви можете переглянути їх на сторінці Вікіпедії.

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

Ця матриця, G, представляє базові ваги, які слід використовувати для реконструкції зображення (невелике десяткове значення в нижній правій частині анімації вище). В основному, для кожної бази ми множимо її на вагу в цій матриці, підсумовуємо все разом і отримуємо отримане зображення.

На даний момент ми більше не працюємо в кольорових просторах, а навпаки, безпосередньо з матрицею G (базові ваги), все подальше стиснення здійснюється безпосередньо на цій матриці.

Проблема тут полягає в тому, що ми тепер перетворили вирівняні за байтами цілі значення у реальні числа. Що ефективно роздуває нашу інформацію (переходячи від 1 байта до 1 плаваючого (4 байти)). Щоб вирішити це питання і почати виробляти більш значне стиснення, ми переходимо до фази квантування.

Квантування

Отже, ми не хочемо стискати дані з плаваючою точкою. Це роздуло б наш потік і не було б ефективним. З цією метою ми хотіли б знайти спосіб перетворити матрицю ваг назад у значення в просторі [0,255]. Безпосередньо ми могли б це зробити, знайшовши мінімальне / максимальне значення для матриці (-415,38 та 77,13 відповідно) та розділивши кожне число в цьому діапазоні, отримавши значення між [0,1], на яке ми множимо на 255 щоб отримати наше остаточне значення.

Наприклад: [34.12- -415.38] / [77.13 - -415.38] * 255 = 232

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

Натомість JPG йде іншим маршрутом. Замість того, щоб використовувати діапазон значень у матриці як значення масштабування, він замість цього використовує попередньо розраховану матрицю факторів квантування. Ці QF не повинні бути частиною потоку, швидше вони можуть бути частиною самого кодека.

Цей приклад показує загальновживану матрицю коефіцієнтів квантування, по одній для кожного базового зображення,

Тепер ми використовуємо матриці Q та G для обчислення нашої квантованої матриці коефіцієнта DCT:

Наприклад, використовуючи значення G [0,0] = - 415,37 та Q [0,0] = 16:

Результат - остаточна матриця:

Зверніть увагу, наскільки простішою стає матриця - тепер вона містить велику кількість записів, малих чи нульових, що полегшує стиснення.

Швидко в сторону, ми застосовуємо цей процес до каналів Y, CbCr незалежно, і як такі нам потрібні дві різні матриці: одна для Y, а інша для каналів C:

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

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

Стиснення

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

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

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

Результатом нашої матриці яркостей у такому порядку стає:

−26, −3,0, −3, −2, −6,2, −4,1, −3,1,1,5,1,2, −1,1, −1,2,0,0 , 0,0,0, -1, -1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 , 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0

Коли дані перебувають у такому форматі, наступні кроки є простими: виконайте RLE на послідовності, а потім застосуйте до результатів деякий статистичний кодер (Huffman / Arithmetic / ANS).

І Бум. Тепер ваш блок закодований у форматі JPG.

Розуміння параметра якості

Тепер, коли ви зрозуміли, як насправді створюються файли JPG, варто переглянути концепцію параметра якості, який ви зазвичай бачите під час експорту зображень JPG із Photoshop (чи чогось іншого).

Цей параметр, який ми будемо називати q, є цілим числом від 1 до 100. Ви повинні думати про q як про показник якості зображення: вищі значення q відповідають зображенням вищої якості та більшим розмірам файлів.

Це значення якості використовується під час фази квантування для відповідного масштабування факторів квантування. Отже, для кожної вагової ваги крок квантування тепер нагадує круглий (Gi, k / alpha * Qi, k)

Де символ альфа створюється в результаті параметра якості.

Коли або альфа, або Q [x, y] збільшено (пам’ятайте, що великі значення альфа відповідають меншим значенням параметра якості q), більше інформації втрачається, і розмір файлу зменшується .

Таким чином, якщо вам потрібен менший файл, за рахунок більшої кількості візуальних артефактів, ви можете встановити більш низьке значення якості на етапі експорту.

Зверніть увагу вище, на зображенні найнижчої якості, як ми бачимо чіткі ознаки стадії блокування, а також стадії квантування.

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

Висновок

Як тільки ви зрозумієте, як працює алгоритм JPG, стає очевидним кілька речей:

  1. Правильне значення якості для кожного зображення важливо, щоб знайти компроміс між якістю зображення та розміром файлу.
  2. Оскільки цей процес базується на блоці, артефакти, як правило, трапляються в блоковості або "дзвонять"
  3. Оскільки оброблені блоки не змішуються між собою, JPG, як правило, ігнорує можливість стиснення великих ділянок подібних блоків разом. Вирішення цього питання - це те, що добре робить формат WebP.

І якщо ви хочете пограти з усім цим самі, все це божевілля можна звести до ~ 1000 рядкового файлу.

ГЕЙ!

Хочете знати, як зменшити свої файли JPG?

Хочете знати, як працюють файли PNG, або як їх зменшити?

Хочете більше стиснення даних? Купуйте мою книгу!