【问题标题】:Replacing RGB values in numpy array by integer is extremely slow用整数替换 numpy 数组中的 RGB 值非常慢
【发布时间】:2016-01-16 17:17:51
【问题描述】:

我想将 numpy 数组的 rgb 值替换为单个整数表示。我的代码可以工作,但是太慢了,我现在正在迭代每个元素。我可以加快速度吗?我是 numpy 的新手。

from skimage import io

# dictionary of color codes for my rgb values
_color_codes = {
    (255, 200, 100): 1,
    (223, 219, 212): 2,
    ...
}

# get the corresponding color code for the rgb vector supplied
def replace_rgb_val(rgb_v):
    rgb_triple = (rgb_v[0], rgb_v[1], rgb_v[2])
    if rgb_triple in _color_codes:
        return _color_codes[rgb_triple]
    else:
        return -1

# function to replace, this is where I iterate
def img_array_to_single_val(arr):
    return np.array([[replace_rgb_val(arr[i][j]) for j in range(arr.shape[1])] for i in range(arr.shape[0])])


# my images are square so the shape of the array is (n,n,3)
# I want to change the arrays to (n,n,1)
img_arr = io.imread(filename)
# this takes from ~5-10 seconds, too slow!
result = img_array_to_single_val(img_arr)

【问题讨论】:

    标签: python arrays numpy image-processing rgb


    【解决方案1】:

    以相反的方式替换颜色值。查找每个 RGB 三元组,并在新数组中设置相应的索引:

    def img_array_to_single_val(arr, color_codes):
        result = numpy.ndarray(shape=arr.shape[:2], dtype=int)
        result[:,:] = -1
        for rgb, idx in color_codes.items():
            result[(arr==rgb).all(2)] = idx
        return result
    

    让我们分开颜色索引分配:首先arr==rgb 将每个像素 rgb 值与列表rgb 进行比较,得到一个 n x n x 3 - 布尔数组。只有当所有三个颜色部分都相同时,我们才找到匹配项,因此.all(2) 减少最后一个轴,导致一个 n x n - 布尔数组,True 与 rgb 匹配的每个像素。最后一步是,使用这个掩码来设置对应像素的索引。

    可能更快,首先将 RGB 数组转换为 int32,然后进行索引转换:

    def img_array_to_single_val(image, color_codes):
        image = image.dot(numpy.array([65536, 256, 1], dtype='int32'))
        result = numpy.ndarray(shape=image.shape, dtype=int)
        result[:,:] = -1
        for rgb, idx in color_codes.items():
            rgb = rgb[0] * 65536 + rgb[1] * 256 + rgb[2]
            result[arr==rgb] = idx
        return result
    

    对于非常大或非常多的图像,您应该首先创建直接颜色映射:

    color_map = numpy.ndarray(shape=(256*256*256), dtype='int32')
    color_map[:] = -1
    for rgb, idx in color_codes.items():
        rgb = rgb[0] * 65536 + rgb[1] * 256 + rgb[2]
        color_map[rgb] = idx
    
    def img_array_to_single_val(image, color_map):
        image = image.dot(numpy.array([65536, 256, 1], dtype='int32'))
        return color_map[image]
    

    【讨论】:

      【解决方案2】:

      如果您不追求想要创建的特定效果,手动遍历每个像素并创建 256**3 个项目的字典只是为了获得另一个调色板,这对我来说似乎很奇怪。如果您只想将图像展平为整数值,可以使用 skimage rg2gray(img) 函数。这将为您提供图片亮度。

      您可以使用 pylabs 颜色图来获得另一种表示形式:

      import matplotlib.pylab as plt
      import skimage 
      import matplotlib.cm as cm
      
      img = io.imread("Fox.jpg")
      gray_img = skimage.color.rgb2gray(img)
      plt.imshow(img, cmap=cm.Jet)
      plt.show()
      

      【讨论】:

        【解决方案3】:

        这里可以推荐两种完全矢量化的解决方案。

        方法#1:使用NumPy's powerful broadcasting capability -

        # Extract color codes and their IDs from input dict
        colors = np.array(_color_codes.keys())
        color_ids = np.array(_color_codes.values())
        
        # Initialize output array
        result = np.empty((img_arr.shape[0],img_arr.shape[1]),dtype=int)
        result[:] = -1
        
        # Finally get the matches and accordingly set result locations
        # to their respective color IDs
        R,C,D = np.where((img_arr == colors[:,None,None,:]).all(3))
        result[C,D] = color_ids[R]
        

        方法 #2: 使用 cdist from scipy.spatial.distance 可以替换 approach #1 的最后步骤,就像这样 -

        from scipy.spatial.distance import cdist
        
        R,C = np.where(cdist(img_arr.reshape(-1,3),colors)==0)
        result.ravel()[R] = color_ids[C]
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-08-11
          • 1970-01-01
          • 2019-02-26
          • 2015-03-02
          • 2018-07-12
          • 2013-09-11
          • 2015-02-23
          相关资源
          最近更新 更多