![](/img/trans.png)
[英]Numpy array : how to convert values of a 2D array into a 3D one-hot array
[英]How to convert RGB image to one-hot encoded 3d array based on color using numpy?
简单地说,我正在尝试做的是类似于这个问题: 将RGB图像转换为索引图像 ,但不是单通道索引图像,我想得到n通道图像,其中img[h, w]
是一个 - 编码矢量。 例如,如果输入图像为[[[0, 0, 0], [255, 255, 255]]
,并且索引0指定为黑色,1指定为白色,则所需输出为[[[1, 0], [0, 1]]]
。
就像之前提到的问题一样,我已经天真地实现了这个,但是代码运行得非常慢,我相信使用numpy的正确解决方案会明显加快。
另外,正如上一篇文章中所建议的那样,我可以将每个图像预处理为灰度级并对图像进行单热编码,但我想要一个更通用的解决方案。
假设我要将白色指定为0,红色指定为1,蓝色指定为2,黄色指定为3:
(255, 255, 255): 0
(255, 0, 0): 1
(0, 0, 255): 2
(255, 255, 0): 3
,我有一个由这四种颜色组成的图像,其中图像是一个3D数组,包含每个像素的R,G,B值:
[
[[255, 255, 255], [255, 255, 255], [255, 0, 0], [255, 0, 0]],
[[ 0, 0, 255], [255, 255, 255], [255, 0, 0], [255, 0, 0]],
[[ 0, 0, 255], [ 0, 0, 255], [255, 255, 255], [255, 255, 255]],
[[255, 255, 255], [255, 255, 255], [255, 255, 0], [255, 255, 0]]
]
,这就是我想要将每个像素更改为索引的单热编码值。 (由于将2d索引值数组更改为单个编码值的3d数组很容易,因此获取2d索引值数组也很好。)
[
[[1, 0, 0, 0], [1, 0, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]],
[[0, 0, 1, 0], [1, 0, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]],
[[0, 0, 1, 0], [0, 0, 1, 0], [1, 0, 0, 0], [1, 0, 0, 0]],
[[1, 0, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1], [0, 0, 0, 1]]
]
在这个例子中,我使用了RGB组件为255或0的颜色,但我不希望解决方案依赖于这一事实。
我们可以生成每个像素颜色的十进制等值。 每个通道的值为0
或255
,总共有8
可能性,但似乎我们只对其中的四种颜色感兴趣。
然后,我们将有两种方法来解决它:
其中一个将涉及从0
开始到最终颜色的十进制等值的唯一索引,全部按顺序进行,最后初始化输出数组并分配到其中。
另一种方法是使用那些十进制等值对比颜色的broadcasted
比较。
接下来列出了这两种方法 -
def indexing_based(a):
b = (a == 255).dot([4,2,1]) # Decimal equivalents
colors = np.array([7,4,1,6]) # Define colors decimal equivalents here
idx = np.empty(colors.max()+1,dtype=int)
idx[colors] = np.arange(len(colors))
m,n,r = a.shape
out = np.zeros((m,n,len(colors)), dtype=int)
out[np.arange(m)[:,None], np.arange(n), idx[b]] = 1
return out
def broadcasting_based(a):
b = (a == 255).dot([4,2,1]) # Decimal equivalents
colors = np.array([7,4,1,6]) # Define colors decimal equivalents here
return (b[...,None] == colors).astype(int)
样品运行 -
>>> a = np.array([
... [[255, 255, 255], [255, 255, 255], [255, 0, 0], [255, 0, 0]],
... [[ 0, 0, 255], [255, 255, 255], [255, 0, 0], [255, 0, 0]],
... [[ 0, 0, 255], [ 0, 0, 255], [255, 255, 255], [255, 255, 255]],
... [[255, 255, 255], [255, 255, 255], [255, 255, 0], [255, 255, 0]],
... [[255, 255, 255], [255, 0, 0], [255, 255, 0], [255, 0 , 0]]])
>>> indexing_based(a)
array([[[1, 0, 0, 0],
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 1, 0, 0]],
[[0, 0, 1, 0],
[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 1, 0, 0]],
[[0, 0, 1, 0],
[0, 0, 1, 0],
[1, 0, 0, 0],
[1, 0, 0, 0]],
[[1, 0, 0, 0],
[1, 0, 0, 0],
[0, 0, 0, 1],
[0, 0, 0, 1]],
[[1, 0, 0, 0],
[0, 1, 0, 0],
[0, 0, 0, 1],
[0, 1, 0, 0]]])
>>> np.allclose(broadcasting_based(a), indexing_based(a))
True
我的解决方案看起来像这样,应该适用于任意颜色:
color_dict = {0: (0, 255, 255),
1: (255, 255, 0),
....}
def rgb_to_onehot(rgb_arr, color_dict):
num_classes = len(color_dict)
shape = rgb_arr.shape[:2]+(num_classes,)
arr = np.zeros( shape, dtype=np.int8 )
for i, cls in enumerate(color_dict):
arr[:,:,i] = np.all(rgb_arr.reshape( (-1,3) ) == color_dict[i], axis=1).reshape(shape[:2])
return arr
def onehot_to_rgb(onehot, color_dict):
single_layer = np.argmax(onehot, axis=-1)
output = np.zeros( onehot.shape[:2]+(3,) )
for k in color_dict.keys():
output[single_layer==k] = color_dict[k]
return np.uint8(output)
我还没有测试它的速度,但至少,它工作:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.