Более быстрый способ настройки значений пикселей PIL

Я пишу скрипт для хроматического ключа (зеленый экран) и сочиняю несколько видео, используя Python и PIL (подушка). Я могу набрать изображения в формате 720p, но над зеленым пятном осталось немного. Понятно, но я пишу процедуру по удалению этого разлива... однако я борюсь с тем, сколько времени это займет. Я могу, вероятно, получить лучшую скорость, используя хитрые трюки, но я не настолько знаком с этим. Есть идеи?

Вот моя рутина отчаяния. Требуется PIL-изображение и число чувствительности, но я пока оставляю его равным 1... он работает хорошо. Я вхожу в чуть более 4 секунд для кадра 720p, чтобы устранить этот разлив. Для сравнения подпрограмма ключа цветности выполняется примерно за 2 секунды на кадр.

def despill(img, sensitivity=1):
    """
    Blue limits green.
    """
    start = time.time()
    print '\t[*] Starting despill'
    width, height = img.size
    num_channels = len(img.getbands())
    out = Image.new("RGBA", img.size, color=0)
    for j in range(height):
        for i in range(width):
            #r,g,b,a = data[j,i]
            r,g,b,a = img.getpixel((i,j))
            if g > (b*sensitivity):
                out_g = (b*sensitivity)
            else:
                out_g = g
            # end if

            out.putpixel((i,j), (r,out_g,b,a))
        # end for
    # end for
    out.show()
    print '\t[+] done.'
    print '\t[!] Took: %0.1f seconds' % (time.time()-start)
    exit()
    return out
# end despill

Вместо putpixel я попытался записать значения выходных пикселей в пустой массив, а затем преобразовать массив в изображение PIL, но это составляло в среднем чуть более 5 секунд... так что это было как-то быстрее. Я знаю, что putpixel не самый быстрый вариант, но я в растерянности...

1 ответ

Решение

putpixel медленный, и подобные циклы еще медленнее, так как они выполняются интерпретатором Python, который чертовски медлителен. Обычное решение состоит в том, чтобы немедленно преобразовать изображение в пустой массив и решить проблему с векторизованными операциями над ним, которые выполняются в сильно оптимизированном C-коде. В вашем случае я бы сделал что-то вроде:

arr = np.array(img)
g = arr[:,:,1]
bs = arr[:,:,2]*sensitivity
cond = g>bs
arr[:,:,1] = cond*bs + (~cond)*g
out = Image.fromarray(arr)

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

Другие вопросы по тегам