我有一个 3 维 numpy 数组。直观地说,它是二维的,其中每个 row-col 位置代表一种 RGB 颜色,它存储为三个数字的向量。(如果将颜色存储为三元组会容易得多!)我有一个函数(基于此处的答案)将 RGB 三元组转换为颜色名称。有没有一种简单的方法(除了嵌套循环)将该函数应用于数组的行列元素。(将其直接应用于数组本身不起作用,因为 numpy 尝试将该函数应用于 RGB 向量的每个元素。)
谢谢。
如果您的函数不是为接受向量参数而设计的,那么除了使用循环并简单地隐藏它们或者可能是一些 jit 恶作剧的那种之外,就没有魔法了,但我不是后者的专家。
重新秘密应用循环的魔法,那就是np.vectorize。要使其将一维子空间传递给您的函数,您可以使用signature关键字
pseudo_vect_func = np.vectorize(your_func, ('O',), signature='(m)->()')
我还添加了一个 otypes 参数,因为没有它 vectorize 似乎盲目地去U1,即在第一个字母之后截断
如果你想要真正的矢量化操作,这里有一个从头开始的方法。
如果您有一个包含 (color name, (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])
输出:
[['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']]
IIUC,你可以使用np.dstackand reshape, or np.dstackandconcatenate
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']
您可以使用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,它遍历一个可迭代的(这里的外部列表,或者在你的情况下,你的numpy数组的第二维)并将函数应用于每个子列表:
list(map(dummy_fct, [[1, 2, 3], [4, 5, 6], [7, 8, 9]]))
Out: ['1-2-3', '4-5-6', '7-8-9']