2017-02-14 7 views
1

У меня есть PNG-изображение с размерами 1024x1024, которое содержит RGB-кодированные данные о высоте. я прочитал в изображение с помощью asarray из numpy:Быстрый способ декодирования изображения RGB в python

rgb_data = np.asarray(image) 

Какие результаты в 3D-массив с размерами (1024, 1024, 4). (Я использую RGBA)

Мне нужно запустить некоторые фильтры (гауссовы, медианные) по этим данным, но мне нужно запустить их на декодированных данных о высоте.

Данные рельефа могут быть расшифрованы с помощью следующей функции:

def decodeRGB(pixel): 
    return (pixel[0] * 256 + pixel[1] + pixel[2]/256) - 32768 

После декодирования у меня будет 2D массив с размерами (1024, 1024), который содержит декодированные данные высотных отметок. (Фактическая высота над уровнем моря)

То, что я до сих пор это:

rgb_data = np.asarray(image) 
decoded_data = np.zeros(tile.size) 

for rownum in range(width): 
    for colnum in range(height): 
     decoded_data[rownum][colnum] = decodeRGB(rgb_data[rownum][colnum]) 

К сожалению, это решение довольно медленно. Это займет ок. 10 секунд для изображения 1024 на 1024.

Есть ли более эффективный способ реализовать это?

Основная проблема заключается в том, что размеры массива меняются. Я собираюсь из массива (1024, 1024, 4) в массив (1024, 1024).

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

Большое спасибо за помощь!

+0

Python не является хорошим выбором для чтения, вычисления данных пикселя изображения. Получите язык 'LOW_LEVEL'! – dsgdfg

+1

@dsgdfg Конечно, чистый Python не известен своей скоростью, но именно поэтому Numpy популярен: он может работать с многомерными массивами машинных данных с использованием скомпилированного кода, поэтому арифметика и цикл происходят на скомпилированной скорости, _not_ на довольно медленный темп байт-кода Python, который управляет объектами Python на виртуальной машине. –

+0

'64-разрядный адрес Бит-машины + Виртуальный адрес табуляции + Основной адрес потоковой передачи + адрес обратной линии потока. Возможно, работа над проектами @Sandro, но не все время. Сохраните адреса ram в ram, почему еще производитель производит модуль PCI-калькулятора '? – dsgdfg

ответ

4

Воспользуйтесь векторизации:

r = rgb_data[..., 0] 
g = rgb_data[..., 1] 
b = rgb_data[..., 2] 
decoded_data = (256*r + g + b/256) - 32768 

Например rgb_data[..., 0] выбирает все1024x1024 красные значения сразу, 256*r умножает все из них с 256 за один раз, и так далее. Так как интерпретируемые для циклов в вашем коде имеют существенные накладные расходы, избегая их, они должны значительно ускорить преобразование.

Или вы могли бы использовать одну подкрылок:

decoded_data = (rgb_data[..., :3] * (256, 1, 1/256)).sum(axis=-1) - 32768 

Есть еще несколько способов, похожих по духу. Посмотрите на комментарии к этому сообщению для хорошей коллекции однострочных.

+1

Или даже просто 'rgb_data @ [256, 1, 1/256, 0] - 32768' – Eric

+0

@ Эрик :-) Но умножение и добавление всех этих нулей - такая трата. Тем не менее, очень красиво! –

+0

Затем перейдите к 'rgb_data [...,: 3] @ [256, 1, 1/256] - 32768'. Следует использовать меньше памяти, чем строить все, а затем суммировать – Eric

3

Вы можете в векторном выражении использовать этот очень мощный np.einsum. Просто сделайте вектор преобразования из ваших коэффициентов.

def decodeRGBArray(rgb_data): 
    transf = np.array([256., 1., 1./256., 0.]) 
    return np.einsum('ijk,k->ij', rgb_data, transf) - 32768