Python 基于颜色值将多维Numpy数组转换为二维数组
我有一个图像,它被读取为uint8数组,形状Python 基于颜色值将多维Numpy数组转换为二维数组,python,arrays,image,numpy,indexing,Python,Arrays,Image,Numpy,Indexing,我有一个图像,它被读取为uint8数组,形状(512512,3)。 现在,我想将此数组转换为一个uint8数组,该数组的形状(512512,1),其中第三个轴上的每个像素值根据以下颜色/类别编码从颜色值[255,0,0]转换为单个类别标签值[3]: 1 : [0, 0, 0], 2 : [0, 0, 255], 3 : [255, 0, 0], 4 : [150, 30, 150], 5 : [255, 65, 255], 6 : [150, 80, 0], 7 : [1
(512512,3)
。
现在,我想将此数组转换为一个uint8数组,该数组的形状(512512,1)
,其中第三个轴上的每个像素值根据以下颜色/类别编码从颜色值[255,0,0]
转换为单个类别标签值[3]
:
1 : [0, 0, 0],
2 : [0, 0, 255],
3 : [255, 0, 0],
4 : [150, 30, 150],
5 : [255, 65, 255],
6 : [150, 80, 0],
7 : [170, 120, 65],
8 : [125, 125, 125],
9 : [255, 255, 0],
10 : [0, 255, 255],
11 : [255, 150, 0],
12 : [255, 225, 120],
13 : [255, 125, 125],
14 : [200, 100, 100],
15 : [0, 255, 0],
16 : [0, 150, 80],
17 : [215, 175, 125],
18 : [220, 180, 210],
19 : [125, 125, 255]
最有效的方法是什么?我曾想过遍历所有类并使用
numpy.where
,但这显然很耗时。您可以使用巨型查找表。设cls为dtype=np.uint8
的[[0,0,0],[0,0255],…]
LUT = np.zeros(size=(256,256,256), dtype='u1')
LUT[cls[:,0],cls[:,1],cls[:,2]] = np.arange(cls.shape[1])+1
img_as_cls = LUT[img[...,0],img[...,1], img[...,2]]
此解决方案为每像素0(1)。由于LUT中的一小部分条目被实际使用,因此它的缓存效率也相当高。在我的机器上处理1000x1000个图像大约需要10毫秒
通过将3色通道转换为24位整数,可以稍微改进解决方案。
这是密码
def scalarize(x):
# compute x[...,2]*65536+x[...,1]*256+x[...,0] in efficient way
y = x[...,2].astype('u4')
y <<= 8
y +=x[...,1]
y <<= 8
y += x[...,0]
return y
LUT = np.zeros(2**24, dtype='u1')
LUT[scalarize(cls)] = 1 + np.arange(cls.shape[0])
simg = scalarize(img)
img_to_cls = LUT[simg]
def标量化(x):
#以有效的方式计算x[…,2]*65536+x[…,1]*256+x[…,0]
y=x[…,2].aType('u4')
y这是一个基于视图的-
# https://stackoverflow.com/a/45313353/ @Divakar
def view1D(a, b): # a, b are arrays
# This function gets 1D view into 2D input arrays
a = np.ascontiguousarray(a)
b = np.ascontiguousarray(b)
void_dt = np.dtype((np.void, a.dtype.itemsize * a.shape[-1]))
return a.view(void_dt).ravel(), b.view(void_dt).ravel()
def img2label(a, maps):
# Get one-dimension reduced view into input image and map arrays.
# We need to reshape image to 2D, then feed it to view1D to get 1D
# outputs and then reshape 1D image to 2D
A,B = view1D(a.reshape(-1,a.shape[-1]),maps)
A = A.reshape(a.shape[:2])
# Trace back positions of A in B using searchsorted. This gives us
# original order, which is the final output.
sidx = B.argsort()
return sidx[np.searchsorted(B,A,sorter=sidx)]
如果标签从1
开始,则可能需要将1
添加到输出中
样本运行-
In [100]: # Mapping array
...: maps = np.array([[0, 0, 0],[0, 0, 255],\
...: [255, 0, 0],[150, 30, 150]],dtype=np.uint8)
...:
...: # Setup random image array
...: idx = np.array([[0,2,1,3],[1,3,2,0]])
...: img = maps[idx]
In [101]: img2label(img, maps) # should retrieve back idx
Out[101]:
array([[0, 2, 1, 3],
[1, 3, 2, 0]])
一种方法:分别创建带有True
值的布尔数组,其中输入的像素值与调色板值之一匹配,然后使用算术组合它们。因此:
palette = [
[0, 0, 0],
[0, 0, 255],
[255, 0, 0],
# etc.
]
def palettized(data, palette):
# Initialize result array
shape = list(data.shape)
shape[-1] = 1
result = np.zeros(shape)
# Loop and add each palette index component.
for value, colour in enumerate(palette, 1):
result += (data == colour).all(axis=2) * value
return result
如果大图像中的颜色值在类数组中不存在,该怎么办?您实际上是在尝试对图像进行调色板处理-看看这里,您是否可以对其工作原理进行更多的说明?@KarlKnechtel补充了一些说明。scalarize
看起来是一个聪明的添加。