Python 如何将图像集合中的像素(R、G、B)映射到不同的像素颜色值索引?
假设有600个带注释的语义分割掩码图像,其中包含10种不同的颜色,每种颜色代表一个实体。这些图像是一个numpy形状数组(600,3,72,96),其中n=600,3=RGB通道,72=高度,96=宽度 如何将numpy阵列中的每个RGB像素映射到颜色索引值?例如,颜色列表将是[(128,128,0),(240,128,0),…n],并且numpy数组中的所有(240,128,0)像素将转换为唯一映射中的索引值(=1) 如何以更少的代码高效地实现这一点?我想出了一个解决方案,但速度很慢Python 如何将图像集合中的像素(R、G、B)映射到不同的像素颜色值索引?,python,image,performance,numpy,image-processing,Python,Image,Performance,Numpy,Image Processing,假设有600个带注释的语义分割掩码图像,其中包含10种不同的颜色,每种颜色代表一个实体。这些图像是一个numpy形状数组(600,3,72,96),其中n=600,3=RGB通道,72=高度,96=宽度 如何将numpy阵列中的每个RGB像素映射到颜色索引值?例如,颜色列表将是[(128,128,0),(240,128,0),…n],并且numpy数组中的所有(240,128,0)像素将转换为唯一映射中的索引值(=1) 如何以更少的代码高效地实现这一点?我想出了一个解决方案,但速度很慢 # In
# Input imgs.shape = (N, 3, H, W), where (N = count, W = width, H = height)
def unique_map_pixels(imgs):
original_shape = imgs.shape
# imgs.shape = (N, H, W, 3)
imgs = imgs.transpose(0, 2, 3, 1)
# tupleview.shape = (N, H, W, 1); contains tuples [(R, G, B), (R, G, B)]
tupleview = imgs.reshape(-1, 3).view(imgs.dtype.descr * imgs.shape[3])
# get unique pixel values in images, [(R, G, B), ...]
uniques = list(np.unique(tupleview))
# map uniques into hashed list ({"RXBXG": 0, "RXBXG": 1}, ...)
uniqmap = {}
idx = 0
for x in uniques:
uniqmap["%sX%sX%s" % (x[0], x[1], x[2])] = idx
idx = idx + 1
if idx >= np.iinfo(np.uint16).max:
raise Exception("Can handle only %s distinct colors" % np.iinfo(np.uint16).max)
# imgs1d.shape = (N), contains RGB tuples
imgs1d = tupleview.reshape(np.prod(tupleview.shape))
# imgsmapped.shape = (N), contains uniques-index values
imgsmapped = np.empty((len(imgs1d))).astype(np.uint16)
# map each pixel into unique-pixel-ID
idx = 0
for x in imgs1d:
str = ("%sX%sX%s" % (x[0], x[1] ,x[2]))
imgsmapped[idx] = uniqmap[str]
idx = idx + 1
imgsmapped.shape = (original_shape[0], original_shape[2], original_shape[3]) # (N, H, W)
return (imgsmapped, uniques)
测试它:
import numpy as np
n = 30
pixelvalues = (np.random.rand(10)*255).astype(np.uint8)
images = np.random.choice(pixelvalues, (n, 3, 72, 96))
(mapped, pixelmap) = unique_map_pixels(images)
assert len(pixelmap) == mapped.max()+1
assert mapped.shape == (len(images), images.shape[2], images.shape[3])
assert pixelmap[mapped[int(n*0.5)][60][81]][0] == images[int(n*0.5)][0][60][81]
print("Done: %s" % list(mapped.shape))
这是一种没有错误检查的紧凑矢量化方法-
def unique_map_pixels_vectorized(imgs):
N,H,W = len(imgs), imgs.shape[2], imgs.shape[3]
img2D = imgs.transpose(0, 2, 3, 1).reshape(-1,3)
ID = np.ravel_multi_index(img2D.T,img2D.max(0)+1)
_, firstidx, tags = np.unique(ID,return_index=True,return_inverse=True)
return tags.reshape(N,H,W), img2D[firstidx]
运行时测试和验证-
In [24]: # Setup inputs (3x smaller than original ones)
...: N,H,W = 200,24,32
...: imgs = np.random.randint(0,10,(N,3,H,W))
...:
In [25]: %timeit unique_map_pixels(imgs)
1 loop, best of 3: 2.21 s per loop
In [26]: %timeit unique_map_pixels_vectorized(imgs)
10 loops, best of 3: 37 ms per loop ## 60x speedup!
In [27]: map1,unq1 = unique_map_pixels(imgs)
...: map2,unq2 = unique_map_pixels_vectorized(imgs)
...:
In [28]: np.allclose(map1,map2)
Out[28]: True
In [29]: np.allclose(np.array(map(list,unq1)),unq2)
Out[29]: True
我有3个频道的图像。我有3个通道的像素值,如果一个像素在其3个通道中有这3个值,那么它属于“a”类。 基本上,我想生成一个通道数组,它的数量等于类的数量,每个类在一个特定的通道中是分开的。 这是可以做到的
seg_channel=np.zero((image.shape[0],image.shape[1],num_类))
pixel_class_dict={'1':[128,64,128]。'2':[230,50,140]}num_class=2
对于范围内的通道(num_类):
像素值=像素等级[str(通道)]
对于范围内的i(image.shape[0]):
对于范围内的j(image.shape[1]):
如果列表(图像[i][j])==像素值:
类_通道[i,j,通道]=1
还有另一种方法可以有效地做到这一点
将numpy导入为np
进口cv2
对于self.pixel\u class\u dict中的class\u id:
class\u color=np.array(self.pixel\u class\u dict:[class\u id])
seg_channel[:,:,class_id]=cv2.inRange(掩码,class_颜色,class_颜色)。astype('bool')。astype('float32'))
我就是这么做的:
def rgb2mask(img):
if img.shape[0] == 3:
img = img.rollaxis(img, 0, 3)
W = np.power(256, [[0],[1],[2]])
img_id = img.dot(W).squeeze(-1)
values = np.unique(img_id)
mask = np.zeros(img_id.shape)
cmap = {}
for i, c in enumerate(values):
idx = img_id==c
mask[idx] = i
cmap[tuple(img[idx][0])] = i
return mask, cmap
如果您想根据现有的字典映射值,请查看我在该线程上的答案:hmm。为什么要这样做?似乎只是无缘无故地增加了一步。如果你想用这些颜色索引做任何事情,你必须搜索dict并将它们转换回RGB元组,不是吗?编辑:没关系,我明白了。如果要存储一组图像,存储整数而不是一组元组会更有效,因为您预期一定数量的颜色(10),对吗?是的,颜色的数量是有限的。需要唯一的索引,因为我正在将像素输入预测像素类别的算法,而不是像素颜色。灰度图像(强度为0-10)也可以,但标准工具(=图像查看器、编辑器等)无法轻松显示图像。最后,在预测之后,需要映射回RGB值,是的。实际上,一个数据集的预处理时间从4小时缩短到4分钟:)谢谢!ravel_multi_索引的文档非常稀少,无法真正理解它的作用。最大像素值作为起点意味着什么?据我所知,它以某种方式将这些3元素数组压缩为唯一的整数表示,但这些(大)整数是如何表示的,又代表什么呢?@Mika啊,你真幸运!查看此帖子: