<h2>如何修正错误</h2>
<p>发生此错误有两个潜在原因:</p>
<ol>
<li>文件名拼写错误。</li>
<li>图像文件不在当前工作目录中。</li>
</ol>
<p>若要解决此问题,应确保文件名拼写正确(请执行区分大小写的检查,以防万一),并且图像文件位于当前工作目录中(此处有两个选项:您可以更改IDE中的当前工作目录或指定文件的完整路径)。</p>
<h2>平均颜色与主色</h2>
<p>然后要计算“平均颜色”,你必须决定你所指的是什么。在灰度图像中,它只是整个图像灰度的平均值,但对于颜色来说,没有所谓的“平均值”。实际上,颜色通常是通过三维矢量来表示的,而灰度则是标量。平均标量是可以的,但平均向量是没有意义的。</p>
<p>将图像分割成彩色分量并取其平均值是一种可能的方法。然而,这种方法可能会产生一种毫无意义的色彩。你可能真正想要的是主色而不是平均色。</p>
<h2>实施</h2>
<p>让我们慢慢地检查代码。我们首先导入必要的模块并读取图像:</p>
<pre><code>import cv2
import numpy as np
from skimage import io
img = io.imread('https://i.stack.imgur.com/DNM65.png')[:, :, :-1]
</code></pre>
<p>然后,我们可以按照与@Ruan B提出的方法类似的方法计算每个色通道的平均值:</p>
<pre><code>average = img.mean(axis=0).mean(axis=0)
</code></pre>
<p>接下来,我们应用<a href="https://en.wikipedia.org/wiki/K-means_clustering" rel="noreferrer">k-means clustering</a>创建一个具有图像最具代表性颜色的调色板(在这个玩具示例中,<code>n_colors</code>被设置为<code>5</code>)。</p>
<pre><code>pixels = np.float32(img.reshape(-1, 3))
n_colors = 5
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 200, .1)
flags = cv2.KMEANS_RANDOM_CENTERS
_, labels, palette = cv2.kmeans(pixels, n_colors, None, criteria, 10, flags)
_, counts = np.unique(labels, return_counts=True)
</code></pre>
<p>最后,主色是在量化图像上出现频率最高的调色板颜色:</p>
<pre><code>dominant = palette[np.argmax(counts)]
</code></pre>
<h2>结果比较</h2>
<p>为了说明这两种方法之间的差异,我使用了以下示例图像:</p>
<p><a href="https://i.stack.imgur.com/DNM65.png" rel="noreferrer"><img src="https://i.stack.imgur.com/DNM65.png" alt="lego"/></a></p>
<p>所获得的平均颜色值,即其成分是三个色通道平均值的颜色,以及通过k-平均值聚类计算出的主色是相当不同的:</p>
<pre><code>In [30]: average
Out[30]: array([91.63179156, 69.30190754, 58.11971896])
In [31]: dominant
Out[31]: array([179.3999 , 27.341282, 2.294441], dtype=float32)
</code></pre>
<p>让我们看看这些颜色看起来如何,以便更好地理解这两种方法之间的差异。下图左侧显示的是平均颜色。很明显,计算出的平均颜色不能正确地描述原始图像的颜色内容。事实上,在原始图像中没有一个像素有这种颜色。图的右侧显示了按重要性(出现频率)降序从上到下排序的五种最具代表性的颜色。这个调色板很明显地表明,主色调是红色,这与原始图像中最大的均匀颜色区域对应于红色乐高玩具的事实是一致的。</p>
<p><a href="https://i.stack.imgur.com/b6rP7.png" rel="noreferrer"><img src="https://i.stack.imgur.com/b6rP7.png" alt="Results"/></a></p>
<p>这是用于生成上图的代码:</p>
<pre><code>import matplotlib.pyplot as plt
avg_patch = np.ones(shape=img.shape, dtype=np.uint8)*np.uint8(average)
indices = np.argsort(counts)[::-1]
freqs = np.cumsum(np.hstack([[0], counts[indices]/counts.sum()]))
rows = np.int_(img.shape[0]*freqs)
dom_patch = np.zeros(shape=img.shape, dtype=np.uint8)
for i in range(len(rows) - 1):
dom_patch[rows[i]:rows[i + 1], :, :] += np.uint8(palette[indices[i]])
fig, (ax0, ax1) = plt.subplots(1, 2, figsize=(12,6))
ax0.imshow(avg_patch)
ax0.set_title('Average color')
ax0.axis('off')
ax1.imshow(dom_patch)
ax1.set_title('Dominant colors')
ax1.axis('off')
plt.show(fig)
</code></pre>
<h2>TL;DR应答</h2>
<p>总之,尽管平均颜色的计算——正如@Ruan B.的答案中所建议的那样——从数学角度来看在技术上是正确的,但得到的结果可能不能充分代表图像的颜色内容。一种更合理的方法是通过矢量量化(聚类)来确定主色。</p>