В этом цикле статей мы ищем метод апскейлинга, дающий минимальную ошибку, на примере полихромных клип-артов с множеством мелких деталей и градиентом
Существует проблема?
Проведём эксперимент - возьмём небольшую чёткую картинку, на ней всё понятно (скрытых деталей мельче разрешения не наблюдается):
Увеличим быстрыми стандартными способами:
Проблемы видны невооружённым глазом: сильное размытие, проявляется сеточная структура
А если мы вооружимся, то увидим куда более сложную проблему. Для начала уменьшим изображения обратно теми же методами и получим:
Они и тут теперь размытые, кроме бикубической интерполяции, хотя мы лишь увеличивали размер файла (то есть потерь могло бы и не быть).
Сравним более тщательно (красным показано, где ошибки):
Поэтому при работе с изображениями используйте хотя бы бикубическую интерполяцию при изменении размера слоёв и редактор, который это может. В чём проблема, спросите Вы – просто не надо два раза применять интерполяцию. Но почему вообще ошибка возникает, даже пусть незначительная?
А потому что интерполяция решает вообще другую задачу и никоим образом не относится к увеличению изображений, она даёт приблизительный результат, но быстро, поэтому её принято использовать для этих целей (даже там, где скорость не критична):
А задача интерполяции – угадать неизвестные значения точек, стоящих между точками, значения которых известны. Мы же изначально не знаем точное значение ни одной точки, а лишь среднее значение точек в области пикселя (пиксель имеет размер, точка - нет) и пытаемся угадать среднее значение точек в более малом пикселе, входящем в исходный пиксель. Кому удобнее визуально воспринимать информацию – есть в виде видео:
Условие средних значений
Почему среднее?
Во-первых, сглаживание или супер-семплинг. Оно везде:
Со сглаживанием всё выглядит красивее и натуральнее (обратите внимание, что разрешение одинаковое, хотя кажется, что со сглаживанием больше), поэтому куда ни ткни, оно там будет. И с этим надо считаться. Исключение составляют только пиксель-арты и небольшой процент видеоигр без включенного сглаживания и непрофессиональных цифровых рисунков.
А что с фото? А там оно тоже есть, только по другой причине:
Проблема использования интерполяции
Допустим, мы имеем средние значения точек на 5 пикселях и нам надо увеличить масштаб в 8 раз до 40 пикселей:
Что будет, если попробуем воспользоваться интерполяцией?
Кривая интерполяции проходит ровно через средние значения, но сами значения при этом меняются, причём в сторону сближения друг с другом, поэтому результирующее изображение будет размытым. А самое главное – нам не нужно проходить через средние значения, точное значение по центру может быть почти каким угодно, учитывая минимальную и максимальную границу яркости. Кстати, интерполяции плевать на эти границы:
Так причём тут вообще интерполяция? А мы до сих пор её везде применяем.
Разве что она даёт скорость, необходимую при обработке в реальном времени, как например, при воспроизведении видео. Кстати, поэтому видео в 144p сейчас смотреть невозможно – не потому, что не хватает каких-то деталей, а просто, потому что всё размыто или в сеточку или и то и другое вместе.
Эх, были бы у нас мощности для точных, а не приблизительных алгоритмов, пусть даже и без восстановления мелких деталей (распознавания номеров машин и лиц по размазне в этом цикле статей не будет)…
Как повысить точность?
Ну, допустим, будут у нас бесконечные мощности на каких-нибудь позитронно-квантовых компьютерах. А что это за алгоритмы-то?
Самый банальный способ отказа от интерполяции, раз она такая проблемная – метод ближайшего соседа. Он, кстати, ещё быстрее интерполяции, но
Ок, что у нас есть ещё? Что насчёт нейросетей?
Но тут другая проблема – если просто для визуального удовольствия – то это почти всегда лучший вариант. Для лучшего результата, правда, возможно, придётся вручную исправить несколько галлюцинаций – нейросети пытаются создать детали, о которых у нас нет информации, и могут угадать/придумать их совершенно неверно и вот уже любой фильм/фотография любого года в суперкачестве ну или если не повезёт – в другой стилистике. Совершенно другой случай, если апскейлинг Вам нужен для научных целей – качество – не означает точность, и тут у Вас будут большие ошибки именно из-за этих деталей. А если Вы историк – то это вообще ужас – в ходу может оказаться «улучшенная» фотография 1845 года, где вместо грязи на руке крестьянина появился пистолет.
Раз качество - это не то, что мы хотим, то, видимо, нужно искать точность - минимальную ошибку
Сравнение по получающейся ошибке
Поэтому далее будем сравнивать методы апскейлинга по средней ошибке от оригинала:
Возьмём за оригинал полихромный цифровой рисунок клип-арт с градиентами и множеством мелких деталей 1024 х 1024 px, например, такой:
И попытаемся увеличить масштаб в 128 раз, используя разные методы, и сравним среднюю ошибку с оригиналом.
Почему мы взяли такой узкий класс изображений, только один его пример, и вычисляем среднюю ошибку, а не, например, среднеквадратичную? Это лишь моя первая статья, посвящённая этой теме, и в следующих частях (подписываемся ☺) будут рассмотрены все возможные случаи, а пока просто познакомимся с существующими методами и изобретём новые.
Новые методы
Кстати, что будет, если попытаться сгладить кривую, убрав разрывы, но сохраняя средние значения и установив границы возможных значений?
Получится метод scaleSmooth (гладкий, плавный), который я разработал специально для этого случая. Исходники и exe доступны на https://github.com/no4ni/scaleSmooth/
К сожалению, чтобы выполнить столько условий, придётся сделать много последовательных расчётов, поэтому он очень медленный и никакая видеокарта, как нейросетям, здесь не поможет. Но мы же допустили, что у нас в наличии большие мощности, в том числе огроменная тактовая частота процессора (хотя чтобы им пользоваться уже сейчас достаточно и просто наличия терпения – всё в разумных пределах – до суток на несколько изображений). Однако, если Вы можете оптимизировать или подсказать как оптимизировать алгоритм, милости просим в коммиты или комментарии.
Объяснение принципа и визуализация работы алгоритма в видео:
А если наоборот увеличить разрывы насколько это возможно, сохраняя средние значения?
Получится метод scaleRough (грубый), который я разработал специально для этого случая. Исходники и exe доступны также на гитхаб
Он также медленный и, если Вы поможете оптимизировать или подсказать как оптимизировать алгоритм, милости просим в коммиты или комментарии. Объяснение принципа и визуализация работы алгоритма в том же видео.
Попробуем их на этом примере?
Можно сказать, что scaleSmooth выдаёт вероятности того, что насколько тот или иной пиксель оригинала был светлее или темнее, а scaleRough выдаёт одну реализацию из этого для монохрома (в случае с тремя каналами – 8 цветов). Можно ли угадать оригинал более точно, чем scaleSmooth, используя его вероятности?
А что, если мы возьмём несколько монохромных реализаций, соблюдающих условие средних значений, и возьмём среднее от них? По идее появится больше цветов и линии станут не такими рваными. Так появился scaleFurry (пушистый, меховой):
Визуализация работы метода и наглядное сравнение с работой scaleRough - здесь Исходники и exe для «поиграться» в том же репозитории на гитхаб.
Однако, не всегда получается добиться абсолютного соблюдения условия средних значений (в частности из-за дискретности значений уменьшенного изображения, оно всегда представлено не с абсолютной точностью, а с небольшой погрешностью, обычно ±0,2% от размера границ допустимых значений). Тогда нам поможет корректировка – более подробно здесь
Как сделать границы объектов и вообще линии ровнее (не прямее, а глаже), но при этом убрать размытость? Как совместить не совместимое? Придётся отказаться от главного – условия средних значений, но если всё правильно сделать – мы потом сможем восстановить это условие. Так у меня родился contrastBoldScale:
Исходники и exe также в том же репозитории. Наглядная работа под капотом - в этом видео
Но после корректировки контрастность приходит в норму, однако, сеточная структура стала гораздо заметнее и мелкие детали также утеряны:
Сравнение всех методов
Ну что же пришло время сравнить все методы, как с условием средних значений, так и нейросетей (видеосравнение), а также интерполяций, других оконных функций, алгоритмов для пиксель-арта и др. (видеосравнение, здесь же waifu) на этом же изображении (волк ШБ):
«+ корректировка Ланшоцем» – значит, что метод без корректировки Ланшоцем радиусом 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/
Я считаю, неплохой старт?
Но, конечно, прибегать к этому всему нужно только тогда, когда достать изображение большего разрешения невозможно или ошибка не так критична, как время, затраченное на получение более детальных данных:
Другие эксперименты с изображениями - здесь