#python #numpy
#python #numpy
Вопрос:
Я работаю с 2d-массивом «пикселей» (кортежи rgb int), и мне нужен эффективный способ применить некоторые операции numpy к каждому элементу. В частности, я пытаюсь найти пиксели в пределах нескольких цветовых оттенков целевого цвета, чтобы позже изолировать их с помощью numpy.nonzero
Использование циклов For в этом случае занимает десятки секунд, поэтому я собираюсь поэлементно применить операции numpy для достижения того же результата.
Я хочу применить
Вычитание кортежей :
pixel_diff = numpy.subtract( pixel_a, pixel_b)
Абсолютное значение кортежа:
pixel_abs = numpy.abs( pixel_diff )
Сравнение кортежей:
pixel_bool = pixel_abs < int_tolerance
Tuple all ():
is_similar = numpy.all(pixel_bool)
Попытка применить любую из этих операций вслепую к моему массиву приводит к недопустимым ошибкам продвижения, поэтому я полагаю, что вместо этого должен быть правильный способ сделать это.
Комментарии:
1. Почему вы продолжаете ссылаться на кортежи? Если вы передаете кортежи методам numpy, они преобразуются в массивы до того, как действительно может быть выполнена какая-либо работа.
2. как именно выглядит ваш
pixels
массив?3. Массив (на моей машине) имеет 2d-форму
(1920, 1080)
с dtype[('x0', int), ('x1', int), ('x2', int)]
. До сих пор я только слышал, что этот формат упоминается как «массив кортежей». — если 3d-массив был бы для меня более полезным, я могу легко изменить форму.4. Ммм, это больше похоже на структурированный массив , и мне непонятно, почему библиотека возвращает такой объект, а не 2D-массив одного типа. Что это за библиотека?
5. Вы можете преобразовать в эквивалентные представления, чтобы избежать ошибок. Смотрите мой ответ.
Ответ №1:
import numpy as np
#create a RGB array of 1000x1000x3 and separate into colors
R, G, B = np.random.randint(0, 255, size = (1000, 1000, 3))
#find all pixels less than 100, 100, 100
np.logical_and((R<100), (G<100), (B<100))
Вы можете изменить последнюю строку в соответствии с вашими потребностями в цвете. Как есть, последняя строка занимает около 1,5 мс на одном ядре.
Комментарии:
1. Кажется надежным решением — хотя, чтобы было ясно, это применение операции путем реструктуризации массива в 3 2d массива целых чисел? (Мне придется изменить форму и разделить, чтобы протестировать мой вариант использования)
2. Да, чтобы получить максимальную отдачу от векторизации numpy, вам следует реструктурировать вашу проблему таким образом, чтобы обеспечить операции с массивом на месте, которые намного быстрее, чем переход от элемента к элементу.
3. @Mike: (a) Строка присваивания выдает ошибку. Это сработало бы, только если rhs имели форму
(3,1000,1000)
. (b) Ссылаясь на ваш комментарий выше, «поэлементно» не означает, что он не может быть «на месте»4. @fountainhead а) приведенный выше код сработал для меня. возможно, вы столкнулись с проблемой, связанной с соглашением об определении изображений rgb. б) это правда, это была неосторожная формулировка с моей стороны.
5. @Mike: Я попробовал еще раз, и я получаю ошибку: «Ошибка значения: слишком много значений для распаковки (ожидается 3)».
R, G, B = np.random.randint(0, 255, size = (1000, 1000, 3))
. В этой строке просто используетсяrandint()
функция, которой наплевать на соглашения rgb. Он пытается создать массив1000x1000x3
, который эквивалентен1000
подмассивам каждого размера1000x3
, и распаковать его в3
переменные. Несоответствие находится между1000
и3
. Это просто не сработает.
Ответ №2:
Вы можете преобразовать в эквивалентное неструктурированное представление (без каких-либо дополнительных затрат на создание копии базовых данных):
my_3dview_of_ints = my_2d_of_3tuples.view(dtype=int)
где my_2d_of_3tuples
находится ваш текущий структурированный массив (массив кортежей)
Затем вы можете выполнять свои обычные операции с массивом numpy в этом представлении, не сталкиваясь с какими-либо ошибками типа.
Например, если ваш массив выглядит следующим образом:
[[(207, 27, 185) ( 90, 197, 52) ( 58, 153, 145) (239, 42, 39)]
[(218, 23, 195) (226, 92, 170) ( 21, 114, 190) (192, 145, 48)]]
тогда представление, созданное выше, будет выглядеть следующим образом:
[[[207 27 185]
[ 90 197 52]
[ 58 153 145]
[239 42 39]]
[[218 23 195]
[226 92 170]
[ 21 114 190]
[192 145 48]]]
Например:
pixel_a = my_3dview_of_ints[0,0] # pixel [207,27,185] at [0,0]
pixel_b = my_3dview_of_ints[1,1] # pixel [226,92,170] at [1,1]
pixel_diff = numpy.subtract( pixel_a, pixel_b) # Gives [-12,-65,5]
Вы даже можете изменить определенные элементы в представлении, и изменения автоматически отразятся в соответствующем местоположении в вашем исходном структурированном массиве:
my_3dview_of_ints[3,3] = pixel_a # Assign [207, 27,185] to location [3,3]