如何防止 rgb 到 colorID 转换创建 256^3 大小的数组并仍然保持矢量化?

问题描述 投票:0回答:1

在进行像素分割时,我有 256 个不同的 colorID 与某些 RGB 值集匹配,并且需要编写一个脚本来检索分割的 RGB 图片中每个像素的 colorID。将会有很多高分辨率图片,所以我需要一种有效的方法在 python 中实现这一点。我有一个 256x1 png,其中包含 rgb 值作为每个像素的颜色,并且像素从左到右的索引对应于 colorID 值。

我有一个有效的代码,但正如你所看到的,它有一些缺陷。这个想法是将每个图像解构为单个像素并检索每个像素的 RGB 值。然后,这些 RGB 值可以用作索引或键,以使用基于 256x1 png 的转换器检索 colorID。

这是生成从 rgb 到 colorID 的转换器的代码:

def generate_rgb_to_colorID_converter(self):      
        color_palette = Image.open(path_to_image)
        rgb_to_colorID_converter = np.zeros((256, 256, 256), dtype=np.uint8) # rgb values will be used as index and the corresponding colorID will be the elements 
        for x_coord in range(256):
            pixel_coord = (x_coord, 0)
            rgb = color_palette.getpixel(pixel_coord) # Returns decimal rgb value at coordinate in a tuple
            rgb_to_colorID_converter[rgb[0], rgb[1], rgb[2]] = x_coord # Sets the element at given index in the 3D array to the colorID value     
       return rgb_to_colorID_converter

这是将 RGB 值转换为其相应的 colorID 的函数:

def rgb_to_colorID(self, rgb_array, rgb_to_colorID_converter):
        """rgb_array[:, :, 0] returns the r-channel for every pixel while the indexes 1 and 2 does the same for g and b
        [rgb_array[:, :, 0], rgb_array[:, :, 1], rgb_array[:, :, 2]] then returns the rgb-value at every pixel which is used as index in rgb_to_colorID_converter"""
        mapped_image = rgb_to_colorID_converter[rgb_array[:, :, 0], rgb_array[:, :, 1], rgb_array[:, :, 2]]
        return mapped_image

您可能会看到,这段代码的问题在于 rgb_to_colorID_converter 包含 256^3 个元素,而其中只有 256 个实际上保存 colorID 值(其余为零)。使用tracemalloc,这个数组似乎使用了大约16 MB的内存,这只是浪费,因为它只用于256个uint8值。在我的完整系统中运行此代码实现平均需要 0.017 秒才能将 1920x1080 图片从 RGB 转换为具有 colorID 值的灰度。

为了消除这种浪费的内存使用,我通过以下方式重写了函数:

def generate_rgb_to_colorID_converter(self):
    
    
    color_palette = Image.open(path_to_image) 
    rgb_to_colorID_converter = {}
    for x_coord in range(256):
        pixel_coord = (x_coord, 0)
        rgb = color_palette.getpixel(pixel_coord) # Returns decimal rgb value at coordinate in a tuple
        rgb_to_colorID_converter[(rgb[0], rgb[1], rgb[2])] = np.uint8(x_coord) # Sets the element at given index in the 3D array to the colorID value     

    return rgb_to_colorID_converter

def rgb_to_colorID(self, rgb_array, rgb_to_colorID_converter):
    columns = len(rgb_array[0]) # columns av rows of the original array is needed to reshape the colorID array back to the right shape
    rows = len(rgb_array) 
    rgb_array = rgb_array.reshape(-1,3) # Turns the 3D array into a 2D array where each element of the 2D array is a single array containing the rgb values for a single pixel. Makes it easier to loop through the array
    colorID_array = np.empty(len(rgb_array), dtype=np.uint8) # will be filled with the colorID values for each pixel
  
    for pixel_index, pixel in enumerate(rgb_array):
        colorID_array[pixel_index] = rgb_to_colorID_converter[tuple(pixel)] # indexes in the rgb and colorID arrays correspond. tuple(index) correponds to the key of the dictionary

    colorID_array = colorID_array.reshape(rows, columns) # reshapes it back, but its now a 2D array since each pixel only has a single color channel and not 3
    return colorID_array

词典的内存占用非常低。但现在的问题是从rgb到colorID数组的转换速度。在整个系统中,for 循环遍历每个像素并将其从 RGB 更改为 colorID 平均需要 8.1 秒。这根本不能用。考虑到这些统计数据,第一个实施是绝对的赢家。

我真正想问的是如何在第一个实现中缩小 rgb_to_colorID_converter 的数组大小或在第二个实现中加速/替换 for 循环。

python vectorization image-segmentation
1个回答
0
投票

假设性能问题出在元组索引的字典中,您可以用一些较低级别的实现来替换它。

例如,使用 numpy 数组实现哈希表

您可能想要生成随机哈希函数,直到找到一个完美的;不确定这个想法有多有用。

以上都是对性能瓶颈在哪里的大胆猜测。如果您不想相信我(您真的不应该)并且想要系统化它,那么您应该使用分析器。在这种情况下,代码非常小,您特别需要一个line profiler来将问题精确定位到代码中的特定位置。

© www.soinside.com 2019 - 2024. All rights reserved.