如果匹配颜色,则创建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的高度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值在颜色数组中的两个颜色值之间,我想产生一个具有true的2D数组。

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

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

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

一种方式是单独比较所有元素:

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_array定义的小子集(一个框)内的所有像素。

AN 替代解决方案是在color_array中的两个点之间沿界限,并计算每个像素的单个欧几里得距离到该线:

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

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

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

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

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

您得到的所有像素都属于 wich wich the colting collimit colles的范围,完全触及了表面的相对端

当然,如果您想要所有的像素感知上相似的与您的两种限制颜色,则应将数据转换为感知性颜色空间,例如实验室

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

并在该空间中进行计算。

这是一个并非特别优雅的解决方案,但应该起作用:

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)

最新更新