Каков наилучший способ применить функцию к измерениям строки / столбца массива numpy? - PullRequest
0 голосов
/ 12 октября 2018

У меня есть 3-мерный массив NumPy.Интуитивно это двухмерно, где каждая позиция строки-столбца представляет цвет RGB, который сохраняется как вектор из трех чисел.(Было бы намного проще, если бы цвет был сохранен как тройка!) У меня есть функция (основанная на ответе здесь ), которая преобразует тройку RGB в имя цвета.Есть ли простой способ (помимо вложенных циклов) применить эту функцию к элементам row-col массива.(Применение его непосредственно к самому массиву не работает, поскольку numpy пытается применить функцию к каждому элементу вектора RGB.)

Спасибо.

Ответы [ 3 ]

0 голосов
/ 12 октября 2018

Вы можете использовать map и попробовать, например:

list(map(your_RGB2Name_function, 2D_np_array))

Предположим, у вас есть функция, которая работает со списком чисел

def dummy_fct(numlist):
    return '-'.join(map(str, numlist))

dummy_fct([1,2,3])
Out: '1-2-3'

, которая, очевидно, работает не так, как задуманоприменительно к списку многих из этих числовых списков

dummy_fct([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
Out: '[1, 2, 3]-[4, 5, 6]-[7, 8, 9]'

тогда вы можете использовать map, который выполняет итерацию через итерацию (внешний список здесь или, в вашем случае, второе измерение вашей цифры)массив) и применяет функцию к каждому подсписку:

list(map(dummy_fct, [[1, 2, 3], [4, 5, 6], [7, 8, 9]]))
Out: ['1-2-3', '4-5-6', '7-8-9']
0 голосов
/ 12 октября 2018

Если ваша функция не предназначена для приема векторных аргументов, тогда нет никакой магии, кроме той, которая использует циклы и просто скрывает их или, может быть, некоторые jit shenanigans, но я не эксперт по последним.

Re магия, которая тайно накладывает петли, это было бы np.vectorize.Чтобы он передавал в вашу функцию одномерные подпространства, вы можете использовать ключевое слово signature 1005 *

pseudo_vect_func = np.vectorize(your_func, ('O',), signature='(m)->()')

Я также добавил параметр otypes, потому что без него векторизация, похоже, вслепую идет на U1, то есть усечениепосле первой буквы

Если вы хотите действительно векторизованную операцию, вот метод с нуля.

Если у вас есть список или словарь с (имя цвета, (r, g, b)) значений и в порядке с минимальным соответствием расстояния, тогда вы можете использовать KDTrees для эффективного поиска:

import numpy as np
from scipy.spatial import cKDTree as KDTree

# set up lookup

# borrow a list of named colors from matplotlib
from matplotlib import colors
named_colors = {k: tuple(int(v[i:i+2], 16) for i in range(1, 7, 2))
                for k, v in colors.cnames.items()}

no_match = named_colors['purple']

# make arrays containing the RGB values ...
color_tuples = list(named_colors.values())
color_tuples.append(no_match)
color_tuples = np.array(color_tuples)
# ... and another array with the names in same order
color_names = list(named_colors)
color_names.append('no match')
color_names = np.array(color_names)
# build tree
tree = KDTree(color_tuples[:-1])

def img2colornames(img, tolerance):
    # find closest color in tree for each pixel in picture
    dist, idx = tree.query(img, distance_upper_bound=tolerance)
    # look up their names
    return color_names[idx]

# an example
result = img2colornames(face(), 40)
# show a small patch
import Image
Image.fromarray(face()[410:510, 325:425]).show()
# same as names, downsampled
print(result[415:510:10, 330:425:10])

Вывод:

enter image description here

[['darkgrey' 'silver' 'dimgray' 'darkgrey' 'black' 'darkslategrey'
  'silver' 'silver' 'dimgray' 'darkgrey']
 ['darkslategrey' 'gray' 'darkgrey' 'gray' 'darkslategrey' 'gray'
  'darkgrey' 'lightsteelblue' 'darkslategrey' 'darkslategrey']
 ['darkolivegreen' 'no match' 'dimgray' 'dimgray' 'darkslategrey' 'gray'
  'slategray' 'lightslategrey' 'dimgray' 'darkslategrey']
 ['dimgray' 'dimgray' 'gray' 'dimgray' 'dimgray' 'darkslategrey'
  'dimgray' 'dimgray' 'black' 'darkseagreen']
 ['no match' 'no match' 'darkolivegreen' 'dimgray' 'dimgray' 'no match'
  'darkkhaki' 'darkkhaki' 'no match' 'dimgray']
 ['darkkhaki' 'darkkhaki' 'darkkhaki' 'tan' 'tan' 'no match'
  'darkslategrey' 'no match' 'darkslategrey' 'dimgray']
 ['no match' 'no match' 'no match' 'no match' 'no match' 'no match'
  'no match' 'no match' 'no match' 'dimgray']
 ['no match' 'black' 'no match' 'no match' 'no match' 'no match'
  'no match' 'no match' 'no match' 'darkslategrey']
 ['darkkhaki' 'no match' 'olivedrab' 'darkolivegreen' 'darkolivegreen'
  'darkolivegreen' 'darkolivegreen' 'darkolivegreen' 'darkolivegreen'
  'darkolivegreen']
 ['darkseagreen' 'no match' 'no match' 'no match' 'no match' 'no match'
  'no match' 'no match' 'no match' 'no match']]
0 голосов
/ 12 октября 2018

IIUC, вы можете просто использовать np.dstack и reshape, или np.dstack и concatenate

np.dstack(arr).reshape(-1,3)
# equivalent:
np.concatenate(np.dstack(arr))

Например:

arr = np.random.randint(0,256,(3,5,5))
>>> arr
array([[[150,  38,  34,  41,  24],
        [ 76, 135,  93, 149, 142],
        [150, 123, 198,  11,  34],
        [ 24, 179, 132, 175, 218],
        [ 46, 233, 138, 215,  97]],

       [[194, 153,  29, 200, 133],
        [247, 101,  18,  70, 112],
        [164, 225, 141, 196, 131],
        [ 15,  86,  22, 234, 166],
        [163,  97,  94, 205,  56]],

       [[117,  56,  28,   1, 104],
        [138, 138, 148, 241,  44],
        [ 73,  57, 179, 142, 140],
        [ 55, 160, 240, 189,  13],
        [244,  36,  56, 241,  33]]])

>>> np.dstack(arr).reshape(-1,3)
array([[150, 194, 117],
       [ 38, 153,  56],
       [ 34,  29,  28],
       [ 41, 200,   1],
       [ 24, 133, 104],
       [ 76, 247, 138],
       [135, 101, 138],
       [ 93,  18, 148],
       [149,  70, 241],
       [142, 112,  44],
       [150, 164,  73],
       [123, 225,  57],
       [198, 141, 179],
       [ 11, 196, 142],
       [ 34, 131, 140],
       [ 24,  15,  55],
       [179,  86, 160],
       [132,  22, 240],
       [175, 234, 189],
       [218, 166,  13],
       [ 46, 163, 244],
       [233,  97,  36],
       [138,  94,  56],
       [215, 205, 241],
       [ 97,  56,  33]])

Используя предоставленную функциюв ответе, который вы связали , вы можете получить самые близкие цвета этого изображения:

>>> [get_colour_name(i)[1] for i in np.dstack(arr).reshape(-1,3)]
['darkseagreen', 'forestgreen', 'black', 'limegreen', 'seagreen', 'mediumaquamarine', 'grey', 'indigo', 'blueviolet', 'sienna', 'yellowgreen', 'yellowgreen', 'rosybrown', 'lightseagreen', 'darkcyan', 'midnightblue', 'palevioletred', 'blueviolet', 'powderblue', 'goldenrod', 'dodgerblue', 'chocolate', 'sienna', 'gainsboro', 'saddlebrown']
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...