Image Gurus: Оптимизирую мою функцию прозрачности Python PNG - PullRequest
5 голосов
/ 15 июня 2010

Мне нужно заменить все белые (иш) пиксели в изображении PNG альфа-прозрачностью.

Я использую Python в AppEngine и поэтому не имею доступа к таким библиотекам, как PIL, imagemagick и т. Д. AppEngine имеет библиотеку изображений, но в основном используется для изменения размера изображения.

Я нашел отличный маленький модуль pyPNG и сумел запустить небольшую функцию, которая делает то, что мне нужно:

make_transparent.py

псевдокод для основного цикла будет выглядеть примерно так:

for each pixel:
    if pixel looks "quite white":
        set pixel values to transparent
    otherwise:
        keep existing pixel values

и (при условии 8-битных значений) "довольно белый" будет:

where each r,g,b value is greater than "240" 
AND each r,g,b value is within "20" of each other

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

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

Спасибо!

Ответы [ 4 ]

1 голос
/ 15 июня 2010

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

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

(отказ от ответственности: Я не имиджевый гуру = /)

1 голос
/ 16 июня 2010

Это все еще посещает каждый пиксель, но может быть быстрее:

new_pixels = []
for row in pixels:
    new_row = array('B', row)
    i = 0
    while i < len(new_row):
        r = new_row[i]
        g = new_row[i + 1]
        b = new_row[i + 2]
        if r>threshold and g>threshold and b>threshold:
            m = int((r+g+b)/3)
            if nearly_eq(r,m,tolerance) and nearly_eq(g,m,tolerance) and nearly_eq(b,m,tolerance):
                new_row[i + 3] = 0
        i += 4
    new_pixels.append(new_row)

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

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

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

0 голосов
/ 16 июня 2010

Кажется, что проблема больше связана с циклами в Python, чем с изображениями.

Петли Python чрезвычайно медленные, лучше их избегать и использовать вместо них встроенные операторы циклов.

Здесь, если вы хотите скопировать изображение, вы можете использовать понимание списка:

def make_transparent(pixel):
  if pixel looks "quite white": return transparent
  else: return pixel

newImage = [make_transparent(p) for p in oldImage]
0 голосов
/ 15 июня 2010

Я совершенно уверен, что для этого нет короткого пути. Вы должны посетить каждый пиксель.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...