python - 为什么这些代码不能直观地显示从图像中提取的正确颜色?

标签 python matplotlib scipy

所以我正在开发一个程序,可以从图片中提取最多 4 种最常见的颜色。现在,我正在努力直观地显示最常见的颜色,但是,在阅读图像后,我:

  • 无法获得正确的 RGB 代码的输出(它没有为我输出) 和
  • 弹出的图表要么显示全黑,要么显示图片中没有的 3 种随机颜色。

有什么建议或帮助吗?我已经尝试了一切可以的方法,我不知道为什么它不能很好地读取颜色。谢谢。

代码:

import matplotlib.image as img
import matplotlib.pyplot as plt
from scipy.cluster.vq import whiten
from scipy.cluster.vq import kmeans
import pandas as pd
import numpy as np

bimage = img.imread('Images/build2.jpg') #read image (this part works)
print(bimage.shape)

r = []
g = []
b = []
for row in bimage:
    for temp_r, temp_g, temp_b in row:
        r.append(temp_r)
        g.append(temp_g)
        b.append(temp_b)

bimage_df = pd.DataFrame({'red': r,
                          'green': g,
                          'blue': b})

bimage_df['scaled_color_red'] = whiten(bimage_df['red'])               #supposed to give color codes
bimage_df['scaled_color_blue'] = whiten(bimage_df['blue'])
bimage_df['scaled_color_green'] = whiten(bimage_df['green'])

cluster_centers, _ = kmeans(bimage_df[['scaled_color_red',             #to find most common colors
                                       'scaled_color_blue',
                                       'scaled_color_green']], 3)

dominant_colors = []

red_std, green_std, blue_std = bimage_df[['red',
                                          'green',
                                          'blue']].std()

for cluster_center in cluster_centers:
    red_scaled, green_scaled, blue_scaled = cluster_center
    dominant_colors.append((
        red_scaled * red_std / 255,
        green_scaled * green_std / 255,
        blue_scaled * blue_std / 255
    ))

plt.imshow([dominant_colors])
plt.show()

我使用的图像:

enter image description here

我也尝试过使用这种方法进行输出和另一种类型的图表,但这给了我所有黑色或紫色,不相关的颜色。我曾为此引用过 geeks4geeks,也无法解决问题。任何帮助将不胜感激。

最佳答案

主要问题是 whiten 的使用不适用于示例图像的方法:

美白文档:

Before running k-means, it is beneficial to rescale each feature dimension of the observation set by its standard deviation (i.e. “whiten” it - as in “white noise” where each frequency has equal power). Each feature is divided by its standard deviation across all observations to give it unit variance.

归一化方法假设噪声呈正态分布。
样本图像不是自然图像(没有噪声),并且归一化过程不适合给定图像。

建议将图像转换为LAB,而不是标准化色彩空间,其中色彩距离更好地匹配感知距离。
将颜色保持为 RGB 格式可能就足够了......

交换绿色和蓝色 channel 是另一个问题。


我们可以使用 NumPy 数组操作来代替 for 循环(这不是错误,只是更快):

fimage = bimage.astype(float)  # Convert image from uint8 to float (kmeans requires floats).
r = fimage[:, :, 0].flatten().tolist()  # Convert red elements to list
g = fimage[:, :, 1].flatten().tolist()  # Convert grenn elements to list
b = fimage[:, :, 2].flatten().tolist()  # Convert blue elements to list

bimage_df = pd.DataFrame({'red': r,
                          'green': g,
                          'blue': b})

应用 kmeans 并进行 100 次迭代(默认值为 20,可能还不够):

cluster_centers, _ = kmeans(bimage_df[['red',             #Find rhe 4 most common colors
                                       'green',
                                       'blue']], 4, iter=100)  # The default is 20 iterations, use 100 iterations for better convergence

在使用plt.imshow之前,我们必须将颜色转换为uint8类型(我们也可以转换为范围[0, 1]),否则显示的颜色是将是白色(饱和)。

dominant_colors = np.round(cluster_centers).astype(np.uint8)  # Round and convert to uint8

plt.imshow([dominant_colors])
plt.show()

代码示例:

import matplotlib.image as img
import matplotlib.pyplot as plt
#from scipy.cluster.vq import whiten
from scipy.cluster.vq import kmeans
import pandas as pd
import numpy as np

bimage = img.imread('Images/build2.jpg') #read image (this part works)
print(bimage.shape)

#r = []
#g = []
#b = []
#for row in bimage:
#    for temp_r, temp_g, temp_b in row:
#        r.append(temp_r)
#        g.append(temp_g)
#        b.append(temp_b)

# Use NumPy array operations, instead of using a for loop.
fimage = bimage.astype(float)  # Convert image from uint8 to float (kmeans requires floats).
r = fimage[:, :, 0].flatten().tolist()  # Convert red elements to list
g = fimage[:, :, 1].flatten().tolist()  # Convert grenn elements to list
b = fimage[:, :, 2].flatten().tolist()  # Convert blue elements to list

bimage_df = pd.DataFrame({'red': r,
                          'green': g,
                          'blue': b})

# Don't use whiten
#bimage_df['scaled_color_red'] = whiten(bimage_df['red'])               #supposed to give color codes
#bimage_df['scaled_color_blue'] = whiten(bimage_df['blue'])
#bimage_df['scaled_color_green'] = whiten(bimage_df['green'])
#cluster_centers, _ = kmeans(bimage_df[['scaled_color_red',             #to find most common colors
#                                       'scaled_color_blue',
#                                       'scaled_color_green']], 3)

cluster_centers, _ = kmeans(bimage_df[['red',             #Find the 4 most common colors
                                       'green',
                                       'blue']], 4, iter=100)  # The default is 20 iterations, use 100 iterations for better convergence

dominant_colors = np.round(cluster_centers).astype(np.uint8)  # Round and convert to uint8
print(dominant_colors)

# Since whiten is not used, we don't need the STD
#red_std, green_std, blue_std = bimage_df[['red',
#                                          'green',
#                                          'blue']].std()
#for cluster_center in cluster_centers:
#    red_scaled, green_scaled, blue_scaled = cluster_center
#    dominant_colors.append((
#        red_scaled * red_std / 255,
#        green_scaled * green_std / 255,
#        blue_scaled * blue_std / 255
#    ))

plt.imshow([dominant_colors])
plt.show()

结果:
enter image description here

关于python - 为什么这些代码不能直观地显示从图像中提取的正确颜色?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75217946/

相关文章:

python - 在 vscode/jupyter 中调试外部模块代码

python - Scipy/python 中分段函数的优化

python - Python中2个稀疏矩阵的特殊逐行乘法

python - 如何使用 matplotlib 从 csv 绘制特定日期和时间的数据?

python - 如何在 python 中从 .obj 文件获取坐标?

python - 在 matplotlib 中绘制多个图时出现索引错误

python - 如何在python中使用向量化 'solve_ivp'实现='True'

javascript - 除以 0 和 0.00

python - 放大 pygame 中的窗口导致滞后

python - 如何恢复运行在 docker 容器中的 errbot 的 backup.py 插件数据