简体   繁体   English

用整数替换numpy数组中的RGB值非常慢

[英]Replacing RGB values in numpy array by integer is extremely slow

I want to replace the rgb values of a numpy array to single integer representations. 我想将numpy数组的rgb值替换为单个整数表示。 My code works but it's too slow, I am iterating over every element right now. 我的代码有效,但速度太慢,我正在迭代每个元素。 Can I speed this up? 我可以加快速度吗? I am new to numpy. 我是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)

Replace the color values the other way round. 反过来替换颜色值。 Look for each RGB-triple, and set the corresponding index in a new array: 查找每个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

Let's take the color-index assignment apart: First arr==rgb compares each pixel-rgb-values with the list rgb , leading to anxnx 3 - boolean array. 让我们将颜色索引分配分开:首先arr==rgb将每个像素-rgb值与列表rgb ,得到anxnx 3 - 布尔数组。 Only if all three color-parts are the same, we found a match, so .all(2) reduces the last axis, leeding to anxn - boolean array, with True for every pixel matching rgb . 只有当所有三个颜色部分都相同时,我们才发现一个匹配,所以.all(2)减少了最后一个轴,导致了焦虑 - 布尔数组,对于匹配rgb每个像素都是True Last step is, to use this mask to set the index of the corresponding pixels. 最后一步是,使用此掩码设置相应像素的索引。

Even faster, it might be, to first convert the RGB-array to int32, and then do the index translation: 更快,可能是,首先将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

For really large or many images you should first create a direct color mapping: 对于非常大或很多图像,您应首先创建直接颜色映射:

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]

Two fully vectorized solutions could be suggested here. 这里可以提出两个完全矢量化的解决方案。

Approach #1: Using NumPy's powerful broadcasting capability - 方法#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]

Approach #2: Using cdist from scipy.spatial.distance one can replace the final steps from approach #1 , like so - 方法#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]

Going through every pixel manually and creating a dict of 256**3 items just to get another color palette seems strange to me if you are not after a specific effect you want to create. 如果您没有想要创建特定效果,那么手动浏览每个像素并创建256 ** 3项目的字典以获得另一个调色板对我来说似乎很奇怪。 If you just want to flatten the image to integer values you can use the skimage rg2gray(img) function. 如果您只想将图像展平为整数值,可以使用skimage rg2gray(img)函数。 This will give you the pictures luminance. 这将为您提供图片亮度。

You can use pylabs colormaps to get another representation: 您可以使用pylabs colormaps来获取另一种表示:

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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM