如何准确聚合多个像素的CIELAB(或其他颜色空间)颜色值?

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

初始背景

我正在尝试聚合来自图像像素的颜色信息,在这种情况下并考虑Python环境,我有几个由同一台相机生成的具有相同图像大小的.jpg图像,我可以在支持的任何颜色空间中读取这些图像Python(RGB、HSL、HSV、CIELAB、CMYK,...)。每个图像上都有由二值掩模标记的某些分段。一旦我有了这个颜色空间和那个二进制掩码,我就会尝试提取分段对象的一些“平均颜色”。一旦我获得了该图像的所有分段对象的平均颜色,我就会将该信息聚合为单个颜色值。这可能看起来是一个荒谬的问题,但为了正确的颜色信息聚合需要处理某些点,这增加了这种情况的复杂性:

  1. 为了用平均值对某些内容进行分组,+ 和 - 运算需要具有数学意义,以便颜色空间中任何位置的相同几何距离反映相同数量的感知色差。例如,RGB 中的平均值总是倾向于生成棕色(就像当您绘画时,在没有任何标准的情况下混合大量颜色,最终会产生一些棕色的无意义颜色)

  2. 为了使用中值对某些内容进行分组,您需要颜色空间遵循一定的逻辑顺序才能提取中值。例如,在 RGB 中,您不能简单地求中值,因为您无法判断 RGB 值 [120, 100, 127] 是在 [120, 111, 126] 之前还是之后。

  3. 与分割对象的真实颜色相比,jpg 图像格式的压缩以及相机传感器可能会改变捕获的图像颜色。


问题

考虑到这一点,我的问题如下:

  1. 考虑到结果在数学上应该是准确的,为了对每个颜色通道中包含的信息进行聚合操作,最好的颜色空间是什么?我想采用像 CIELAB 这样的统一且独立于设备的颜色空间是有意义的
  2. 哪种数学运算适合聚合问题 1 中所选颜色空间的颜色信息? 均值、中值、众数……
  3. 有什么我可能遗漏的额外考虑吗?

代码示例

我一直在做的一些尝试可以总结为以下函数:

def aggregate_rgb(binary_mask, image):

    # Change bgr to rgb
    rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)

    # Convert mask to boolean
    binary_mask = binary_mask.astype(bool)

    # Extract region inside the mask
    masked_image = rgb_image[binary_mask]

    # Calculate mode RGB values
    mode_rgb = np.zeros(3, dtype=np.uint8)
    # Reshape the masked image to a 2D array where each row represents a pixel and each column represents a channel
    reshaped_masked_image = masked_image.reshape(-1, 3)
    # Compute mode for each channel simultaneously
    channel_modes = mode(reshaped_masked_image, axis=0)

    # Calculate the custom RGB average
    num_pixels = np.sum(binary_mask)
    r = np.sum(masked_image[:, 0].astype('uint16') ** 2)
    g = np.sum(masked_image[:, 1].astype('uint16') ** 2)
    b = np.sum(masked_image[:, 2].astype('uint16') ** 2)


    # Calculate aggregate of RGB values
    mean_rgb = np.round(np.mean(masked_image, axis=0)).astype('uint8')
    median_rgb = np.round(np.median(masked_image, axis=0)).astype('uint8')
    mode_rgb = np.round(channel_modes.mode).astype('uint8')
    custom_mean_rgb = np.sqrt(np.array([r, g, b]) / num_pixels).astype('uint8')


    return mean_rgb, median_rgb, mode_rgb, custom_mean_rgb

这些试验的问题主要在于所选择的色彩空间 (RGB),它往往会给出信息量不大的棕色颜色。我还设法使用此行 cv2.cvtColor(image, cv2.COLOR_BGR2Lab) 读取 CIELAB 颜色空间中的图像,但我再次不知道是否应该单独执行通道的平均值、中值和模式,或者是否有考虑到 L、A 和 B 通道在几何上形成球体,请遵循一定的方程 (https://www.ulprospector.com/knowledge/wp-content/uploads/2024/01/1.-CIELAB-Color-Space .jpg

我使用 cv2 库进行图像显示和色彩空间读数,我的 Python 版本是 3.9.13,在 Windows 10 上的 Visual Studio Code 上运行


参考文献

对于我在这个问题的格式方面可能犯的任何错误,我事先表示歉意,如果您觉得还需要其他内容,我会很乐意添加它。预先感谢您!

我在询问之前检查过的一些有趣的链接:

  1. 计算机颜色被 MinutePhysics 破坏 https://www.youtube.com/watch?v=LKnqECcg6Gw
  2. Sighack 以正确的方式平均颜色https://sighack.com/post/averaging-rgb-colors-the-right-way
  3. 数学和几何意义上的颜色模型https://en.wikipedia.org/wiki/Color_model
  4. 查找相似颜色的最佳色彩空间
  5. CIELAB 色彩空间中图像中每个超像素的平均颜色
opencv colors computer-vision color-space cielab
1个回答
0
投票

在讨论感知时,总是很难就某些定义达成一致,所以我会采用更物理世界的解决方案。

理想的色彩空间是颜色模型 RGB(即 RGB、XYZ 等)。注意:线性版本(所以没有常用的 sRGb,它是伽玛校正)。

如果您保留浮点数学,或者只是允许负值和正值高于颜色空间的正常限制,那么您选择哪个颜色空间(在这种线性颜色模型内)并不重要,结果将是相同(在转换回所需的目标色彩空间之后)。

这种色彩空间很好地描述了物理光,因此您的眼睛平均值(例如,在无法分辨所有像素的距离下)与数学平均值相同。 (再次强调:这仅适用于 RGB(或 XYZ)线性空间。

我建议使用 XYZ (CIE XYZ),因为它经常被用作中间色彩空间,所以你应该有公式来转换它。

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