it-swarm.com.ru

Алгоритмы уменьшения изображения

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

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

17
sleeping.ninja

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

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

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

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

Skipping every other pixel

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

Average 2x2

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

enter image description here

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

27
Mark Ransom

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

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

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

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

6
R..

Если скорость, как уже упоминалось, является проблемой, я рекомендую взять блок 2х2 и вычислить среднее значение в качестве полученного пикселя. Качество не самое лучшее, чего можно достичь, но близко к. Вы можете спровоцировать этот алгоритм, чтобы показать его слабые стороны, но на большинстве изображений вы не увидите различий, которые бы оправдывали многократно большее время вычислений. У вас также нет никаких накладных расходов памяти. Если цветовое разрешение можно снизить до 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. Можно ли обобщить это?

Кстати, для не-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.

2
Mark Summerfield

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

1
Nemo
0
Seth Robertson