Подтвердить что ты не робот

Алгоритмы понижающей дискретизации изображений

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

Я изначально планировал пропускать пиксели. Это лучший способ пойти? Из того, что я прочитал, изображение, созданное пропуском пикселей, слишком резкое. Может кто-то, кто пробовал этот комментарий. Мои изображения содержат данные в виде карты типа this.

4b9b3361

Ответ 1

Пропуск пикселей приведет к сглаживанию, где изменения высокой частоты (например, чередующиеся полосы света/темные полосы) преобразуются в низкие частоты (например, постоянный свет или темный).

Самый быстрый способ уменьшить до половины без сглаживания - это усреднить 2x2 пикселя в один пиксель. Лучшие результаты могут быть получены с более сложными ядрами восстановления, но они будут зависеть от скорости.

Изменить: Вот несколько примеров обсуждаемых методов.

Пропуск любого другого пикселя - вы можете видеть, что результаты не очень хороши, если посмотреть на легенду с левой стороны. Это почти нечитаемо:

Skipping every other pixel

Усреднение каждой сетки 2x2 - текст теперь острый и читаемый:

Average 2x2

Гауссовское размытие, как было предложено R. - немного размыто, но более читаемо до определенной точки. Количество размытия можно настроить, чтобы дать разные результаты:

enter image description here

R. также корректно относится к кривой Гамма, влияющей на результаты, но это должно быть видно только в самых сложных приложениях. Мои примеры были выполнены без гамма-коррекции.

Ответ 2

Для уменьшения масштаба, усреднение по площади (см. ответ "Отказ" ) близко к лучшему, которое вы получите.

Основной другой соперник - гауссовый, с чуть большим радиусом. Это немного увеличит смазывание, что можно рассматривать как недостаток, но сделает размытие более однородным, а не зависимым от выравнивания пикселов mod 2.

Если это не сразу ясно, что я имею в виду, рассмотрим шаблоны пикселей 0,0,2,2,0,0 и 0,0,0,2,2,0. При усреднении по площади они будут уменьшаться до 0,2,0 и 0,1,1 соответственно, то есть один будет резким и ярким, а другой будет размытым и тусклым. Используя более длинный фильтр, оба будут размыты, но они будут выглядеть более похожими, что, по-видимому, имеет значение для наблюдателей-людей.

Еще один вопрос, который следует учитывать, - гамма. Если гамма не является линейной, два пикселя с интенсивностью k будут иметь гораздо меньшую общую интенсивность, чем один пиксель интенсивности 2*k. Если ваш фильтр выполняет достаточное размытие, это может не иметь особого значения, но с фильтром, равным среднему по площади, это может быть серьезной проблемой. Единственное, что я знаю, это применить и отменить гамма-кривую до и после масштабирования...

Ответ 3

Если скорость является проблемой, как уже упоминалось, я рекомендую взять блок 2x2 и вычислить среднее значение в качестве результирующего пикселя. Качество не лучшее, что может быть достигнуто, но близко. Вы можете спровоцировать этот алгоритм, чтобы показать его недостатки, но на большинстве изображений вы не увидите разницы, которая оправдывала бы многократно большее время вычисления. У вас также нет накладных расходов на память. Если разрешение цвета можно снизить до 6 бит на канал, вот довольно быстрый способ предотвратить разложение каналов ARGB (здесь предполагается 32-битный ARGB):

destPixel[x,y] = ((sourcePixel[2*x  ,2*y  ]>>2)&0x3f3f3f3f) +
                 ((sourcePixel[2*x+1,2*y  ]>>2)&0x3f3f3f3f) +
                 ((sourcePixel[2*x  ,2*y+1]>>2)&0x3f3f3f3f) +
                 ((sourcePixel[2*x+1,2*y+1]>>2)&0x3f3f3f3f);

Побочный эффект этого алографита заключается в том, что при сохранении в PNG размер файла становится меньше. Вот как это выглядит: Test image downscaled with the above algorithm

Ответ 4

Я попытался обобщить решение Thilo Köhler (но на Python):

STRIDE = 2
MASK = 0x3F3F3F3F
color = 0
for Δx, Δy in itertools.product(range(STRIDE), repeat=2):
    color += (get_pixel(x + Δx, y + Δy) // STRIDE) & MASK

Это отлично подходит для масштабирования на 2 (результат размера четверти), но не работает для масштабирования по 3 или 4 или другим значениям int. Можно ли обобщить это?

BTW для не-Pythonistas цикл for выше эквивалентен этому (за исключением того, что первая версия масштабируется, изменяя STRIDE):

for Δx, Δy in [(0, 0), (0, 1), (1, 0), (1, 1)]:
    color += (get_pixel(x + Δx, y + Δy) // STRIDE) & MASK

Я использую 32-разрядные значения ARGB.

Ответ 5

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