Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/14.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何有效地将三通道图像的每个像素映射到一个通道?_Python_Arrays_Image_Performance_Numpy - Fatal编程技术网

Python 如何有效地将三通道图像的每个像素映射到一个通道?

Python 如何有效地将三通道图像的每个像素映射到一个通道?,python,arrays,image,performance,numpy,Python,Arrays,Image,Performance,Numpy,我正在编写一个python程序来预处理图像,将其用作语义分割任务的标签。原始图像有三个通道,其中代表每个像素的三个值的向量表示该像素的类标签。例如,[0,0,0]的像素可以是类1,[0,0255]可以是类2,依此类推 我需要将这些图像转换为一个单通道图像,像素值从0开始,然后依次递增以表示每个类。基本上,我需要将旧图像中的[0,0,0]转换为新图像中的0,[0,0255]转换为1,依此类推 这些图像具有相当高的分辨率,宽度和高度都超过2000像素。我需要对数百张图像执行此操作。当前的方法是迭代每

我正在编写一个python程序来预处理图像,将其用作语义分割任务的标签。原始图像有三个通道,其中代表每个像素的三个值的向量表示该像素的类标签。例如,[0,0,0]的像素可以是类1,[0,0255]可以是类2,依此类推

我需要将这些图像转换为一个单通道图像,像素值从0开始,然后依次递增以表示每个类。基本上,我需要将旧图像中的[0,0,0]转换为新图像中的0,[0,0255]转换为1,依此类推

这些图像具有相当高的分辨率,宽度和高度都超过2000像素。我需要对数百张图像执行此操作。当前的方法是迭代每个像素,并用相应的标量值替换三维值

filename="file.png"
label_list = [[0,0,0], [0,0,255]] # for example. there are more classes like this
image = imread(filename)
new_image = np.empty((image.shape[0], image.shape[1]))
for i in range(image.shape[0]):
    for j in range(image.shape[1]):
        for k, label in enumerate(label_list):
            if np.array_equal(image[i][j], label):
                new_image[i][j] = k
                break   
imsave("newname.png", new_image)
问题是上面的程序效率很低,并且每个映像都要运行几分钟。这太多了,无法处理我所有的图像,因此我需要改进它

首先,我认为通过将
label\u list
转换为一个numpy数组,可以删除最里面的循环。但是,我不知道如何做
np.where
在二维数组中找到一维数组,以及它是否会改进任何东西

从中,我尝试定义一个函数并将其直接应用于图像。但是,我需要将每个三维标签映射到一个标量。字典不能包含列表作为键。有没有更好的方法来做到这一点,它会有帮助吗

有没有办法提高(大量提高)效率,或者有没有更好的办法来完成上述计划

谢谢。

方法#1

下面是一种使用
视图
np.searchsorted
-

# https://stackoverflow.com/a/45313353/ @Divakar
def view1D(a, b): # a, b are 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()

# Trace back a 2D array back to given labels
def labelrows(a2D, label_list):
    # Reduce array and labels to 1D
    a1D,b1D = view1D(a2D, label_list)

    # Use searchsorted to trace back label indices
    sidx = b1D.argsort()
    return sidx[np.searchsorted(b1D, a1D, sorter=sidx)]
因此,要将其用于
3D
图像阵列,我们需要将高度和宽度合并为一个维度,并保持颜色通道的暗度,然后使用标签功能

方法#2

针对具有
[0255]
范围的图像元素进行了调整,我们可以利用矩阵乘法进行降维,从而进一步提高性能,如下所示-

def labelpixels(img3D, label_list):
    # scale array
    s = 256**np.arange(img.shape[-1])

    # Reduce image and labels to 1D
    img1D = img.reshape(-1,img.shape[-1]).dot(s)
    label1D = np.dot(label_list, s)

    # Use searchsorted to trace back label indices
    sidx = label1D.argsort()
    return sidx[np.searchsorted(label1D, img1D, sorter=sidx)]
关于如何扩展图像大小写和验证的示例运行-

In [194]: label_list = [[0,255,255], [0,0,0], [0,0,255], [255, 0, 255]]

In [195]: idx = [2,0,3,1,0,3,1,2] # We need to retrieve this back

In [196]: img = np.asarray(label_list)[idx].reshape(2,4,3)

In [197]: img
Out[197]: 
array([[[  0,   0, 255],
        [  0, 255, 255],
        [255,   0, 255],
        [  0,   0,   0]],

       [[  0, 255, 255],
        [255,   0, 255],
        [  0,   0,   0],
        [  0,   0, 255]]])

In [198]: labelrows(img.reshape(-1,img.shape[-1]), label_list)
Out[198]: array([2, 0, 3, 1, 0, 3, 1, 2])

In [217]: labelpixels(img, label_list)
Out[217]: array([2, 0, 3, 1, 0, 3, 1, 2])
最后,输出需要重新整形为
2D
-

In [222]: labelpixels(img, label_list).reshape(img.shape[:-1])
Out[222]: 
array([[2, 0, 3, 1],
       [0, 3, 1, 2]])

非常感谢。这几乎就是我需要的。然而,虽然我希望将每个三维向量映射到一个标量,但我希望保持空间配置-输出将是另一个图像,在本例中,它将是
数组([[2,0,3,1],[0,3,1,2]])
。我可以通过将上面获得的1D阵列重新映射到新图像来实现这一点,但有没有办法直接做到这一点?@Gooddedes是的,在最后一步使用重塑。@Gooddedes不,我们需要256的幂,这样每个通道都有足够的偏移量/“范围”。因此,第一个通道的范围为256,第二个通道的范围为256*256,依此类推。