【问题标题】:How to find dominant color RGB using histograms?如何使用直方图找到主色 RGB?
【发布时间】:2021-07-22 02:09:25
【问题描述】:

我目前正在开发一系列测试代码来探索处理图像数据的不同方式,其中一个主要主题是颜色提取。

我开发了以下 Python 代码,给定图像,它能够提取其对应的具有 R、G 和 B 值的直方图:

# Reading original image, in full color
img = mpimg.imread('/content/brandlogos/Images/14 (48).jpg')

# Displaying the image
imgplot = plt.imshow(img)
plt.show()

# Creating a tuple to select colors of each channel line
colors = ("r", "g", "b")
channel_ids = (0, 1, 2)

# Making an histogram with three lines, one for each color
# The X limit is 255, for RGB values
plt.xlim([0,256])
for channel_id, c in zip(channel_ids, colors):
  histogram, bin_edges = np.histogram(
      img[:, :, channel_id], bins = 256, range=(0,256)
  )
  plt.plot(bin_edges[0:-1], histogram, color=c )

# Displaying the histogram
plt.xlabel("Color Value")
plt.ylabel("Pixels")

plt.show()

例子:

但是,我现在想根据直方图信息找到最主要颜色的 RGB 值。

预期输出:(87, 74, 163)(或类似的东西)

我将如何找到三个颜色通道的最高 bin 计数,并将它们组合成一种颜色?

【问题讨论】:

  • 您需要为 RGB 值构建 3D 直方图(联合直方图),而不是为每个通道构建单独的直方图(边际直方图)。在 3D 直方图中,您可以找到最高峰,您可以找到权重最大的峰,或其他任何数量的东西。这取决于您如何定义“主色”。
  • 主色是指像素数最多的 R、G 和 B。例如,如果我在上面展示的直方图中找到峰值,我会得到非常接近 (87, 74, 163) 的值。这就是我打算以编程方式执行的操作:找到三个通道中每个通道的“颜色值”峰值。
  • 您不能对每个频道执行此操作。您需要使用联合直方图。最高峰适用于像您的示例这样具有大部分平坦区域的图像,但不适用于自然图像,我们认为一种颜色可以分布在直方图的许多区域中。这就是为什么我问你的定义。您的所有图片都像您示例中的图片吗?
  • 我所有的图片都是公司标志。它们在细节和形状上差异很大,但通常由纯色和文字组成。

标签: python image-processing colors histogram


【解决方案1】:

您可以专注于图像中的unique 颜色,并找到计数最高的颜色:

import matplotlib.image as mpimg
import numpy as np

img = np.uint8(mpimg.imread('path/to/your/image.png') * 255)
img = np.reshape(img, (np.prod(img.shape[:2]), 3))
res = np.unique(img, axis=0, return_counts=True)
dom_color = res[0][np.argmax(res[1]), :]
print(dom_color)

或者,您可以使用 Pillow 的getcolors,并获得计数最高的那个:

from PIL import Image

img = Image.open('path/to/your/image.png')
dom_color = sorted(img.getcolors(2 ** 24), reverse=True)[0][1]
print(dom_color)

如果需要,两者都可以轻松提供第二、第三、...主色。

对于一些像这样的标志

主色为:

[208  16  18]

分别

(208, 16, 18)
----------------------------------------
System information
----------------------------------------
Platform:      Windows-10-10.0.16299-SP0
Python:        3.9.1
PyCharm:       2021.1.1
Matplotlib:    3.4.1
NumPy:         1.20.2
Pillow:        8.2.0
----------------------------------------

编辑:也许,为了给直方图方法一个对手,正如 Cris 在 cmets 中所解释的那样,请看这张图片:

这很难看,但是有三种不同类型的红色,最大的矩形的 RGB 值为(208, 0, 18)

现在,让我们将您的直方图方法与 Pillow 的 getcolors 进行比较:

import numpy as np
from PIL import Image

adv = np.zeros((512, 512, 3), np.uint8)
adv[:200, :200, :] = [208, 16, 18]
adv[:200, 200:, :] = [208, 16, 0]
adv[200:, :200, :] = [0, 16, 18]
adv[200:, 200:, :] = [208, 0, 18]

# Histogram approach
dom_color = []
for channel_id in [0, 1, 2]:
    dom_color.append(np.argmax(np.histogram(adv[..., channel_id], bins=256, range=(0, 256))[0]))
print(dom_color)
# [208, 16, 18]

# Pillow's getcolors
dom_color = sorted(Image.fromarray(adv).getcolors(2 ** 24), reverse=True)[0][1]
print(dom_color)
# (208, 0, 18)

攻击者被构建为在(208, 16, 18) 处给出直方图峰值。尽管如此,主要颜色是(208, 0, 18),因为我们可以很容易地从图像(或代码)中得出。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-09-16
    • 2017-05-15
    • 1970-01-01
    • 1970-01-01
    • 2021-08-01
    • 2012-04-22
    • 2014-03-10
    • 1970-01-01
    相关资源
    最近更新 更多