[英]How to convert RGB image to one-hot encoded 3d array based on color using numpy?
Simply put, what I'm trying to do is similar to this question: Convert RGB image to index image , but instead of 1-channel index image, I want to get n-channel image where img[h, w]
is a one-hot encoded vector. 简单地说,我正在尝试做的是类似于这个问题: 将RGB图像转换为索引图像 ,但不是单通道索引图像,我想得到n通道图像,其中
img[h, w]
是一个 - 编码矢量。 For example, if the input image is [[[0, 0, 0], [255, 255, 255]]
, and index 0 is assigned to black and 1 is assigned to white, then the desired output is [[[1, 0], [0, 1]]]
. 例如,如果输入图像为
[[[0, 0, 0], [255, 255, 255]]
,并且索引0指定为黑色,1指定为白色,则所需输出为[[[1, 0], [0, 1]]]
。
Like the previous person asked the question, I have implemented this naively, but the code runs quite slowly, and I believe a proper solution using numpy would be significantly faster. 就像之前提到的问题一样,我已经天真地实现了这个,但是代码运行得非常慢,我相信使用numpy的正确解决方案会明显加快。
Also, as suggested in the previous post, I can preprocess each image into grayscale and one-hot encode the image, but I want a more general solution. 另外,正如上一篇文章中所建议的那样,我可以将每个图像预处理为灰度级并对图像进行单热编码,但我想要一个更通用的解决方案。
Say I want to assign white to 0, red to 1, blue to 2, and yellow to 3: 假设我要将白色指定为0,红色指定为1,蓝色指定为2,黄色指定为3:
(255, 255, 255): 0
(255, 0, 0): 1
(0, 0, 255): 2
(255, 255, 0): 3
, and I have an image which consists of those four colors, where image is a 3D array containing R, G, B values for each pixel: ,我有一个由这四种颜色组成的图像,其中图像是一个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]]
]
, and this is what I want to get where each pixel is changed to one-hot encoded values of index. ,这就是我想要将每个像素更改为索引的单热编码值。 (Since changing a 2d array of index values to 3d array of one-hot encoded values is easy, getting a 2d array of index values is fine too.)
(由于将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]]
]
In this example I used colors where RGB components are either 255 or 0, but I don't want to solutions rely on that fact. 在这个例子中,我使用了RGB组件为255或0的颜色,但我不希望解决方案依赖于这一事实。
We could generate the decimal equivalents of each pixel color. 我们可以生成每个像素颜色的十进制等值。 With each channel having
0
or 255
as the value, there would be total 8
possibilities, but it seems we are only interested in four of those colors. 每个通道的值为
0
或255
,总共有8
可能性,但似乎我们只对其中的四种颜色感兴趣。
Then, we would have two ways to solve it : 然后,我们将有两种方法来解决它:
One would involve making unique indices from those decimal equivalents starting from 0
till the final color, all in sequence and finally initializing an output array and assigning into it. 其中一个将涉及从
0
开始到最终颜色的十进制等值的唯一索引,全部按顺序进行,最后初始化输出数组并分配到其中。
Other way would be to use broadcasted
comparisons of those decimal equivalents against the colors. 另一种方法是使用那些十进制等值对比颜色的
broadcasted
比较。
These two methods are listed next - 接下来列出了这两种方法 -
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)
Sample run - 样品运行 -
>>> 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
My solution looks like this and should work for arbitrary colors: 我的解决方案看起来像这样,应该适用于任意颜色:
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)
I haven't tested it for speed yet, but at least, it works :) 我还没有测试它的速度,但至少,它工作:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.