如果匹配颜色,则创建numpy rgb数组的布尔掩码

时间:2017-12-13 21:36:44

标签: python arrays numpy rgb

我想识别位于两种颜色之间的所有黄色像素,例如[255,255,0]是亮黄色,[200,200,50]是中间黄色。

c = color_array = np.array([ 
  [255, 255, 0],  # bright yellow
  [200, 200, 50]])  # mid yellow

所以rgb范围可以表示为:

(min, max) tuple... 
r (200, 255)
g (200, 255)
b (0, 50)

我有2D(图像高度x图像宽度)[r,g,b]数组:

image = np.random.randint(0, 255, (5, 4, 3))
array([[[169, 152,  65],
    [ 46, 123,  39],
    [116, 190, 227],
    [ 95, 138, 243]],
   [[120,  75, 156],
    [ 94, 168, 139],
    [131,   0,   0],
    [233,  43,  28]],
   [[195,  65, 198],
    [ 33, 161, 231],
    [125,  31, 101],
    [ 56, 123, 151]],
   [[118, 124, 220],
    [241, 221, 137],
    [ 71,  65,  23],
    [ 91,  75, 178]],
   [[153, 238,   7],
    [  2, 154,  45],
    [144,  33,  94],
    [ 52, 188,   4]]])

如果r,g,b值在颜色数组中的2个颜色值之间的范围内,我想生成一个带有True的二维数组。

[[T, F, F, T], 
 [T, F, F, T],
  ...       ]]

我一直在努力让索引正确。

2 个答案:

答案 0 :(得分:1)

我可以想象几种方法来解决这个问题:

单向将分别比较所有元素:

c = color_array

within_box = np.all(
    np.logical_and(
        np.min(c, axis=0) < image,
        image < np.max(c, axis=0)
    ),
    axis=-1
)

对于

的所有像素,这将是True
200 < R < 255 and 200 < G < 255 and 0 < B < 50

这相当于在RGB color space(更大的框)中查找由color_array定义的小子集(框)内的所有像素。

替代解决方案将在color_arraycalculate each pixel's individual euclidean distance to that line中的两个点之间划线:

distance = np.linalg.norm(np.cross(c[1,:] - c[0,:], c[0,:] - image), axis=-1)/np.linalg.norm(c[1,:] - c[0,:])

之后,您可以找到距该行一定距离内的所有像素,即

within_distance = distance < 25

第三个解决方案是计算每个像素的欧氏距离与两种颜色的平均值:

distance_to_mean = np.linalg.norm(image - np.mean(c, axis=0), axis=-1)

查找限制内的所有像素可以解释为在两个极限颜色的平均颜色周围找到球体中的所有像素。例如。如果你选择距离是两点之间距离的一半

within_sphere = distance_to_mean < (np.linalg.norm(c) / 2)

你得到的所有像素都落在一个球体内,因为两种限制颜色都会精确地触及表面的两端

当然,如果您希望所有感知相似的像素都达到两种限制颜色,则应将数据转换为感知色彩空间,例如Lab

import skimage
image_lab = skimage.color.rgb2lab(image / 255)
color_array_lab = skimage.color.rgb2lab(color_array[np.newaxis, ...] / 255)

并在该空间中进行计算。

答案 1 :(得分:0)

这是一个不是特别优雅的解决方案,但应该有效:

def color_mask(array, r_lim, g_lim, b_lim):
    """
    array : m x n x 3 array of colors
    *_lim are 2-element tuples, where the first element is expected to be <= the second.
    """
    r_mask = ((array[..., 0] >= r_lim[0]) & (array[..., 0] <= r_lim[1]))
    g_mask = ((array[..., 1] >= g_lim[0]) & (array[..., 1] <= g_lim[1]))
    b_mask = ((array[..., 2] >= b_lim[0]) & (array[..., 2] <= b_lim[1]))
    return r_mask & g_mask & b_mask

你可以使用numpy的广播规则轻松扩展它以处理最后一维中的任意数量的颜色:

def color_mask(array, *lims):
    lims = np.asarray(lims)
    lower = (array >= lims[:, 0])
    upper = (array <= lims[:, 1])
    return np.logical_and.reduce(upper & lower, axis=2)