Алгоритмы уменьшения изображения - PullRequest
18 голосов
/ 26 мая 2011

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

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

Ответы [ 6 ]

28 голосов
/ 26 мая 2011

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

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

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

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

Skipping every other pixel

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

Average 2x2

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

enter image description here

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

6 голосов
/ 26 мая 2011

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

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

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

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

4 голосов
/ 04 апреля 2012

Если скорость является проблемой, как уже упоминалось, я рекомендую взять блок 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

2 голосов
/ 24 августа 2012

Я пытался обобщить решение Тило Келера (но в 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

Iиспользую 32-битные значения ARGB.

1 голос
/ 26 мая 2011

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

...