Какой самый быстрый способ переназначить значения пикселей в OpenCV на Python?

У меня есть одноканальное изображение gray_image со значениями пикселей [0 .. 255] и таблицей поиска, сопоставляющей эти значения цветам:

lookup = {
 0: [0, 0, 0],
 1: [23, 54, 35],
 ...
 255: [200, 52, 20],
}

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

color_image[y, x] = lookup[gray_image[y, x]]

Вместо того, чтобы перебирать каждый пиксель и настраивать его индивидуально?


person nickponline    schedule 18.12.2020    source источник


Ответы (2)


Предполагая, что ключи таблицы поиска правильно упорядочены, вы можете преобразовать словарь в массив, а затем применить NumPy расширенная индексация следующим образом:

import numpy as np

palette = np.array([row for row in lookup.values()])
color_image = palette[gray_image]

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

palette = np.zeros(shape=(256, 3), dtype=np.uint8)
for key in lookup.keys():
    palette[key] = lookup[key]

Этот подход неявно определяет значение по умолчанию [0, 0, 0], т. е. если таблица поиска не содержит определенного индекса, скажем, n, то пиксели с уровнем серого n будут сопоставлены с [0, 0, 0] (черным).

person Tonechas    schedule 18.12.2020

palette = np.array([lookup[index] for index in range(256)], dtype=np.uint8)
color_image = palette[gray_image]

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

person Christoph Rackwitz    schedule 18.12.2020
comment
добавьте в конце строки color_image = color_image.astype('uint8') потому что вы не сможете показывать картинку в окне. - person voldi; 18.12.2020
comment
Спасибо что подметил это! Я изменил ответ и вместо этого поместил тип на палитру, чтобы сэкономить место и устранить необходимость преобразования шрифта на всем изображении после его поиска. - person Christoph Rackwitz; 18.12.2020
comment
У вас правильный подход, но поскольку OP использует OpenCV, вы можете выполнить поиск, используя cv2.LUT(), и он работает примерно в 20 раз быстрее на изображении 1920x1080 на моей машине. - person Mark Setchell; 20.12.2020
comment
вы должны опубликовать это как ответ - person Christoph Rackwitz; 20.12.2020
comment
Я не хочу брать пункты, которые явно принадлежат вам. - person Mark Setchell; 20.12.2020