Pull to refresh

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

Level of difficultyMedium
Reading time10 min
Views4.9K

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Новые методы

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

МЕТОД

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

scaleSmooth

15,64%

waifu2х (Арт - Anime Style, Cliparts)

15,72%

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

16,93%

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

16,97%

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

17,02%

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

17,13%

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

17,19%

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

17,26%

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

17,29%

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

17,39%

superXBR 2x

17,51%

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

17,69%

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

17,71%

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

17,72%
17,72%

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

17,79%

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

17,79%

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

17,81%

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

17,83%

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

17,86%

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

17,87%

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

17,89%

окно Ланцоша радиусом 3px (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%

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

17,95%

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

18,02%

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

18,03%

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

18,05%

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

18,05%

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

18,06%

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

18,12%

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

18,15%

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

18,19%

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

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
билинейная интерполяция Photoshop
+ корректировка Ланцошем

18,29%
18,31%

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

18,32%

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

18,33%

окно Ланцоша радиусом 1px (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%

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

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,5px + корректировка Ланцошем

21,95%

Real-ESRGAN-anime + корректировка Ланцошем
Бикубическая GDI + корректировка Ланцошем

23,10%
23,48%

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

26,51%

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

27,01%

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

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

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

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

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

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

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

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

Вторая статья цикла: https://habr.com/ru/articles/821309/

Tags:
Hubs:
Total votes 14: ↑13 and ↓1+17
Comments44

Articles