Точное увеличение растровых изображений

Существует проблема?

Проведём эксперимент — возьмём небольшую чёткую картинку, на ней всё понятно (скрытых деталей мельче разрешения не наблюдается):

1ef563ea3a12ad1ad893e8f50e83320d.png

Увеличим быстрыми стандартными способами:

через GIMP Линейная интерполяция и Кубическая интерполяция (так называются в GIMP)

через GIMP Линейная интерполяция и Кубическая интерполяция (так называются в GIMP)

Билинейная интерполяция (наиболее популярна) и Бикубическая интерполяция

Билинейная интерполяция (наиболее популярна) и Бикубическая интерполяция

Проблемы видны невооружённым глазом: сильное размытие, проявляется сеточная структура

А если мы вооружимся, то увидим куда более сложную проблему. Для начала уменьшим изображения обратно теми же методами и получим:

699c749ebd785723a53449bd372726dd.png

Они и тут теперь размытые, кроме бикубической интерполяции, хотя мы лишь увеличивали размер файла (то есть потерь могло бы и не быть).

Сравним более тщательно (красным показано, где ошибки):

d7f3ba7d8659bc22ffe514dad1631533.png

Поэтому при работе с изображениями используйте хотя бы бикубическую интерполяцию при изменении размера слоёв и редактор, который это может. В чём проблема, спросите Вы — просто не надо два раза применять интерполяцию. Но почему вообще ошибка возникает, даже пусть незначительная?

А потому что интерполяция решает вообще другую задачу и никоим образом не относится к увеличению изображений, она даёт приблизительный результат, но быстро, поэтому её принято использовать для этих целей (даже там, где скорость не критична):

А задача интерполяции — угадать неизвестные значения точек, стоящих между точками, значения которых известны. Мы же изначально не знаем точное значение ни одной точки, а лишь среднее значение точек в области пикселя (пиксель имеет размер, точка — нет) и пытаемся угадать среднее значение точек в более малом пикселе, входящем в исходный пиксель. Кому удобнее визуально воспринимать информацию — есть в виде видео

Условие средних значений

Почему среднее?

Во-первых, сглаживание или супер-семплинг. Оно везде:

656ec165f294f95d313519b755578b75.png

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

А что с фото? А там оно тоже есть, только по другой причине:

Лучей всегда больше, чем мы можем зафиксировать, поэтому мы можем зафиксировать лишь среднюю яркость, попавшую на один элемент. Более того, всегда есть выдержка, пусть и небольшая, усредняющая яркость ещё и по времени. Так что, ни о каких точных значениях точек говорить не приходится.

Лучей всегда больше, чем мы можем зафиксировать, поэтому мы можем зафиксировать лишь среднюю яркость, попавшую на один элемент. Более того, всегда есть выдержка, пусть и небольшая, усредняющая яркость ещё и по времени. Так что, ни о каких точных значениях точек говорить не приходится.

Проблема использования интерполяции

Допустим, мы имеем средние значения точек на 5 пикселях и нам надо увеличить масштаб в 8 раз до 40 пикселей:

8b0a0c27268bdf5f043a0a0b5e2960c7.png

Что будет, если попробуем воспользоваться интерполяцией?

3dd139db952454b4d50d61ef20d212d6.png

Кривая интерполяции проходит ровно через средние значения, но сами значения при этом меняются, причём в сторону сближения друг с другом, поэтому результирующее изображение будет размытым. А самое главное — нам не нужно проходить через средние значения, точное значение по центру может быть почти каким угодно, учитывая минимальную и максимальную границу яркости. Кстати, интерполяции плевать на эти границы:

Интерполяция вышла не только за границы области значений, но и ниже нуля, хотя все значения положительные

Интерполяция вышла не только за границы области значений, но и ниже нуля, хотя все значения положительные

Так причём тут вообще интерполяция? А мы до сих пор её везде применяем.

Разве что она даёт скорость, необходимую при обработке в реальном времени, как например, при воспроизведении видео. Кстати, поэтому видео в 144p сейчас смотреть невозможно — не потому, что не хватает каких-то деталей, а просто, потому что всё размыто или в сеточку или и то и другое вместе.

Что тут вообще происходит? Какое-то размытое месиво!

Что тут вообще происходит? Какое-то размытое месиво!

Эх, были бы у нас мощности для точных, а не приблизительных алгоритмов, пусть даже и без восстановления мелких деталей (распознавания номеров машин и лиц по размазне в этом цикле статей не будет)…

Как повысить точность?

Ну, допустим, будут у нас бесконечные мощности на каких-нибудь позитронно-квантовых компьютерах. А что это за алгоритмы-то?

Самый банальный способ отказа от интерполяции, раз она такая проблемная — метод ближайшего соседа. Он, кстати, ещё быстрее интерполяции, но

хотя условие среднего соблюдено, появилась сеточная структура, коробящая глаз. В природе такие сетки не встречаются, а значит, мы опять используем заранее неверный метод

хотя условие среднего соблюдено, появилась сеточная структура, коробящая глаз. В природе такие сетки не встречаются, а значит, мы опять используем заранее неверный метод

Ок, что у нас есть ещё? Что насчёт нейросетей?

cbecbf286973919622766ff3c9f45c05.png

Real-ESRGAN
Выглядит приемлемо, условие среднего почти соблюдается.

Но тут другая проблема — если просто для визуального удовольствия — то это почти всегда лучший вариант. Для лучшего результата, правда, возможно, придётся вручную исправить несколько галлюцинаций — нейросети пытаются создать детали, о которых у нас нет информации, и могут угадать/придумать их совершенно неверно и вот уже любой фильм/фотография любого года в суперкачестве ну или если не повезёт — в другой стилистике. Совершенно другой случай, если апскейлинг Вам нужен для научных целей — качество — не означает точность, и тут у Вас будут большие ошибки именно из-за этих деталей. А если Вы историк — то это вообще ужас — в ходу может оказаться «улучшенная» фотография 1845 года, где вместо грязи на руке крестьянина появился пистолет.

Раз качество — это не то, что мы хотим, то, видимо, нужно искать

Сравнение по получающейся ошибке

Поэтому далее будем сравнивать методы апскейлинга по средней ошибке от оригинала:

Возьмём за оригинал полихромный цифровой рисунок с градиентами и множеством мелких деталей 1024×1024 px, например, такой:

27f9a3c9af4fcc6c7f447133568a98cb.png

И попытаемся увеличить масштаб в 128 раз, используя разные методы, и сравним среднюю ошибку с оригиналом.

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

Новые методы

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

924b33acc7fc11bd767111f8b41bb249.png

Получится метод scaleSmooth (гладкий, плавный), который я разработал специально для этого случая. Исходники и exe доступны на https://github.com/no4ni/scaleSmooth/

К сожалению, чтобы выполнить столько условий, придётся сделать много последовательных расчётов, поэтому он очень медленный и никакая видеокарта, как нейросетям, здесь не поможет. Но мы же допустили, что у нас в наличии большие мощности, в том числе огроменная тактовая частота процессора (хотя чтобы им пользоваться уже сейчас достаточно и просто наличия терпения — всё в разумных пределах — до суток на несколько изображений). Однако, если Вы можете оптимизировать или подсказать как оптимизировать алгоритм, милости просим в коммиты или комментарии.

Объяснение принципа и визуализация работы алгоритма — здесь

А если наоборот увеличить разрывы насколько это возможно, сохраняя средние значения?

560ea2a0bae9da9c8cf00ab3b19ec8bf.png

Получится метод scaleRough (грубый), который я разработал специально для этого случая. Исходники и exe доступны также на гитхаб

Он также медленный и, если Вы поможете оптимизировать или подсказать как оптимизировать алгоритм, милости просим в коммиты или комментарии. Объяснение принципа и визуализация работы алгоритма — здесь

Попробуем их на этом примере?

scaleSmooth не так размыто, как у бикубической интерполяции, однако всё равно проглядывается сеточная структура (так уже устроены квадратные пиксели), scaleRough выдал почти монохромный результат, но результат интересный, разве что края сильно рваные

scaleSmooth не так размыто, как у бикубической интерполяции, однако всё равно проглядывается сеточная структура (так уже устроены квадратные пиксели), scaleRough выдал почти монохромный результат, но результат интересный, разве что края сильно рваные

Можно сказать, что scaleSmooth выдаёт вероятности того, что насколько тот или иной пиксель оригинала был светлее или темнее, а scaleRough выдаёт одну реализацию из этого для монохрома (в случае с тремя каналами — 8 цветов). Можно ли угадать оригинал более точно, чем scaleSmooth, используя его вероятности?

А что, если мы возьмём несколько монохромных реализаций, соблюдающих условие средних значений, и возьмём среднее от них? По идее появится больше цветов и линии станут не такими рваными. Так появился scaleFurry (пушистый, меховой):

Границы стали не такими рваными, но и не ровными, а пушистыми как облака или как будто на них налепили меха. Кстати, Вы уже можете тут разглядеть буквы Ш Б (кстати scaleFurry очень хорошо себя показывает на монохромных текстах) и ушки сверху?

Границы стали не такими рваными, но и не ровными, а пушистыми как облака или как будто на них налепили меха. Кстати, Вы уже можете тут разглядеть буквы Ш Б (кстати scaleFurry очень хорошо себя показывает на монохромных текстах) и ушки сверху?

Визуализация работы метода и наглядное сравнение с работой scaleRough — здесь Исходники и exe для «поиграться» в том же репозитории на гитхаб.

Однако, не всегда получается добиться абсолютного соблюдения условия средних значений (в частности из-за дискретности значений уменьшенного изображения, оно всегда представлено не с абсолютной точностью, а с небольшой погрешностью, обычно ±0,2% от размера границ допустимых значений). Тогда нам поможет корректировка — более подробно здесь

Как сделать границы объектов и вообще линии ровнее (не прямее, а глаже), но при этом убрать размытость? Как совместить не совместимое? Придётся отказаться от главного — условия средних значений, но если всё правильно сделать — мы потом сможем восстановить это условие. Так у меня родился contrastBoldScale:

72c329d5e255a5b27e92252f60fd727d.png

Границы более-менее ровные, но вокруг еле заметный сеточный ареал и детализация ниже даже исходной, всё становится жирным и всё тяготеет к трём значениям — минимальному, максимальному и среднему, поэтому всё становится очень контрастным

Исходники и exe также в том же репозитории. Наглядная работа под капотом — в этом видео

Но после корректировки контрастность приходит в норму, однако, сеточная структура стала гораздо заметнее и мелкие детали также утеряны:

contrastBoldScale + корректировка Ланшоцем, радиусом 1 исходный пиксель

contrastBoldScale + корректировка Ланшоцем, радиусом 1 исходный пиксель

Сравнение всех методов

Ну что же пришло время сравнить все методы, как с условием средних значений, так и нейросетей (видеосравнение), а также интерполяций, других оконных функций, алгоритмов для пиксель-арта и др. (видеосравнение, здесь же waifu) на этом же изображении (волк ШБ), но, я думаю, что результаты будут приблизительно такими же на любом полихромном цифровом рисунке с градиентами и множеством мелких деталей на таком масштабе (128х):

МЕТОД

СРЕДНЯЯ ОШИБКА

scaleSmooth

15,64%

waifu2х

15,72%

обратный антиалиасинг

16,93%

contrastBoldScale + корректировка Ланшоцем

16,97%

билинейная+ интерполяц. Original + корректировка Ланшоцем

17,02%

бикубическая интеполяция hq + корректировка Ланшоцем

17,13%

2xSal + корректировка Ланшоцем

17,19%

окно Гаусса радиусом 1,2 px + корректировка Ланшоцем

17,26%

билинейная интерполяция hq + корректировка Ланшоцем

17,29%

окно косинуса + корректировка Ланшоцем

17,39%

superXBR 2x

17,51%

окно Хэмминга + корректировка Ланшоцем

17,69%

прямоугольный фильтр + корректировка Ланшоцем

17,71%

базисный сплайн 5 степени + корректировка Ланшоцем

17,72%

мало гало + корректировка Ланшоцем

17,79%

полноцветная векторизация + корректировка Ланшоцем

17,79%

базисный сплайн 3 степени + корректировка Ланшоцем

17,81%

базисный сплайн 2 степени

17,83%

окно Шаума 2 степени

17,86%

базисный сплайн 11 степени + корректировка Ланшоцем

17,87%

окно o-Moms 3 степени + корректировка Ланшоцем

17,89%

окно Ланшоца радиусом 3 px (sinc) + корректировка Ланшоцем 1 px

17,91%

базисный сплайн 9 + корректировка Ланшоцем

17,91%

нет гало + корректировка Ланшоцем

17,93%

окно Уэлша + корректировка Ланшоцем

17,93%

o-Moms 7 степени + корректировка Ланшоцем

17,94%

o-Moms 5 степени + корректировка Ланшоцем

17,95%

базисный сплайн 7 + корректировка Ланшоцем

17,95%

окно Ланшоца радиусом 7 px (sinc) + корректировка Ланшоцем 1 px

17,95%

окно Ланшоца радиусом 8 px (sinc) + корректировка Ланшоцем 1 px

18,02%

окно Ланшоца радиусом 16 px (sinc) + корректировка Ланшоцем 1 px

18,03%

окно Шаума 3 степени + корректировка Ланшоцем

18,05%

бикубическая интерполяция + корректировка Ланшоцем

18,05%

кубическая интерполяция + корректировка Ланшоцем

18,06%

линейная интерполяция + корректировка Ланшоцем

18,12%

окно Гаусса 1,4 px + корректировка Ланшоцем

18,15%

билинейная+ интерполяция + корректировка Ланшоцем

18,19%

Гаусс 1,06 + корректировка Ланшоцем

18,20%

XBR no blend 2x

18,21%

размытие Гауссом + корректировка Ланшоцем

18,29%

XBR no blend 4x

18,26%

XBR 3xm

18,27%

XBR 4x

18,29%

XBR 3x

18,29%

окно Митчелла + корректировка Ланшоцем

18,32%

треугольный фильтр + корректировка Ланшоцем

18,33%

окно Ланшоца радиусом 1 px (sinc)

18,36%

img2go — нейросеть для фото

18,37%

окно косинуса 2 степени + корректировка Ланшоцем

18,39%

XBR no blend 3x

18,40%

HQ 2x Bold

18,41%

XBR no blend modified 3x

18,41%

XBR 2x

18,41%

HQ 4x Bold

18,43%

окно Ханна

18,44%

окно Бартлета-Ханна + корректировка Ланшоцем

18,46%

окно Эрмитта

18,46%

HQ 3x Bold

18,47%

HQ 2x Smart

18,66%

AdvInterp 2x

18,69%

HQ 4x Smart

18,70%

HQ 3x Smart

18,75%

Super Eagle 2x + корректировка Ланшоцем

18,78%

HQ 4x

18,82%

HQ 2x

18,83%

HQ 3x

18,85%

Eagle 2x

18,89%

ближайший сосед

18,95%

gimp-плагин для Scale 2x

18,96%

EPXC

18,97%

AdvInterp 3x

18,98%

окно гаусса радиусом 1 px + корректировка Ланшоцем

19,02%

Eagle 3x

19,04%

пиксельная векторизация

19,10%

EPX3

19,19%

Scale 3x

19,19%

Scale 2x

19,20%

EPXB

19,20%

LQ 2x Smart + корректировка Ланшоцем

19,28%

LQ 4x Smart + корректировка Ланшоцем

19,30%

LQ 3x Smart + корректировка Ланшоцем

19,33%

LQ 4x + корректировка Ланшоцем

19,37%

LQ 3x + корректировка Ланшоцем

19,37%

LQ 4x Bold + корректировка Ланшоцем

19,59%

LQ 2x + корректировка Ланшоцем

19,61%

окно Блэкмана + корректировка Ланшоцем

19,71%

окно Бохмана + корректировка Ланшоцем

19,74%

окно Хеннинга-Пуассона + корректировка Ланшоцем

19,75%

окно Тьюки + корректировка Ланшоцем

19,83%

LQ 3x Bold + корректировка Ланшоцем

19,90%

окно Коши + корректировка Ланшоцем

19,96%

окно Блэкмана-Нуттала + корректировка Ланшоцем

19,99%

окно Блэкмана-Харриса + корректировка Ланшоцем

20,01%

окно Нуттала + корректировка Ланшоцем

20,02%

LQ 2x Bold + корректировка Ланшоцем

20,11%

Real-ESRGAN + корректировка Ланшоцем

20,23%

монохромная векторизация + корректировка Ланшоцем

20,38%

super 2xSal + корректировка Ланшоцем

20,83%

Ultramix — Balanced + корректировка Ланшоцем

20,88%

Remacri

20,93%

окно Пуассона c корректировкой

21,02%

scaleFurry с корректировкой Ланшоцем

21,14%

UltraSharp + корректировка Ланшоцем

21,25%

scaleRough + корректировка Ланшоцем

21,27%

квадратичная гравитация+ корректировка Ланшоцем

21,75%

окно с плоской вершиной

21,80%

окно Гаусса радиусом 0,5 px + корректировка Ланшоцем

21,95%

Real-ESRGAN-anime + корректировка Ланшоцем

23,10%

большой дизеринг+ корректировка Ланшоцем

26,51%

2х-цветный дизеринг+ корректировка Ланшоцем

27,01%

»+ корректировка Ланшоцем» — значит, что метод без корректировки Ланшоцем радиусом 1 исходный пиксель выдаёт более худший результат. Если этого нет, то наоборот корректировка лишь ухудшает результат. Проанализирован пока лишь один метод корректировки, но для начала сойдёт и просто её наличие/отсутствие.

Пока немного выигрывает мой scaleSmooth — чуть меньше размытости, чуть больше точности (поправки, исправления и критика приветствуются в комментариях).

В дальнейшем будут проанализированы корректировки размытием, интерполяцией, Ланшоцем радиусом 3 px, ближайшим соседом, окном Ханна, waifu, scaleSmooth и др., а также методы Preserve details (enlargement), Preserve Details 2.0, Bicubic Smoother, Bicubic Sharper, Bicubic (smooth gradients), FFTzoom, LightInterpolation, PseudoNeuroUpscale, Lanczos2 и xBR-Hybrid на разных изображениях и масштабах.

Больше примеров и наглядности — здесь и здесь

Гитхаб для тех, кто заинтересовался и/или может помочь — https://github.com/no4ni/scaleSmooth/

Я считаю, неплохой старт?

dec17c701016e8b8024da68ceb423ab3.png

Но, конечно, прибегать к этому всему нужно только тогда, когда достать изображение большего разрешения невозможно или ошибка не так критична, как время, затраченное на получение более детальных данных:

a1f33ebbcbde11ed0a48b2afe96e19d0.png

Другие эксперименты с изображениями — здесь

© Habrahabr.ru