📜  使用Python提取图像的主色

📅  最后修改于: 2022-05-13 01:55:38.071000             🧑  作者: Mango

使用Python提取图像的主色

让我们看看如何使用Python提取图像的主色。聚类在许多现实世界的应用中使用,聚类的一个这样的现实世界示例是从图像中提取主色。

任何图像都由像素组成,每个像素代表图像中的一个点。一个像素包含三个值,每个值的范围在0 到 255之间,表示红色绿色蓝色分量的数量。这些组合形成像素的实际颜色。为了找到主色,使用了 k-means 聚类的概念。 k-means 聚类的一个重要用途是分割卫星图像以识别表面特征。

下面显示的卫星图像包含河谷的地形。

河谷地形

各种颜色通常属于不同的特征,k-means 聚类可用于将它们聚类成组,然后可以将其识别为各种表面,如水、植被等,如下所示。

集群组(水,开阔地,......)

寻找主色的工具

  • matplotlib.image.imread -它将 JPEG 图像转换为包含每个像素的 RGB 值的矩阵。
  • matplotlib.pyplot.imshow -此方法将在对 RGB 值执行 k-means 聚类后显示聚类中心的颜色。

现在让我们深入研究一个示例,对下图执行 k-means 聚类:

示例图片

可以看出,该图像中有三种主色,蓝色阴影,红色阴影黑色阴影。

步骤 1:该过程的第一步是使用图像类的 imread 方法将图像转换为像素。

Python3
# Import image class of matplotlib
import matplotlib.image as img
 
# Read batman image and print dimensions
batman_image = img.imread('batman.png')
print(batman_image.shape)


Python3
# Importing the modules
import pandas as pd
from scipy.cluster.vq import whiten
 
# Store RGB values of all pixels in lists r, g and b
r = []
g = []
b = []
for row in batman_image:
    for temp_r, temp_g, temp_b, temp in row:
        r.append(temp_r)
        g.append(temp_g)
        b.append(temp_b)
 
# only printing the size of these lists
# as the content is too big
print(len(r))
print(len(g))
print(len(b))
 
# Saving as DataFrame
batman_df = pd.DataFrame({'red' : r,
                          'green' : g,
                          'blue' : b})
 
# Scaling the values
batman_df['scaled_color_red'] = whiten(batman_df['red'])
batman_df['scaled_color_blue'] = whiten(batman_df['blue'])
batman_df['scaled_color_green'] = whiten(batman_df['green'])


Python3
# Preparing data to construct elbow plot.
distortions = []
num_clusters = range(1, 7)  #range of cluster sizes
 
# Create a list of distortions from the kmeans function
for i in num_clusters:
    cluster_centers, distortion = kmeans(batman_df[['scaled_color_red',
                                                    'scaled_color_blue',
                                                    'scaled_color_green']], i)
    distortions.append(distortion)
     
# Create a data frame with two lists, num_clusters and distortions
elbow_plot = pd.DataFrame({'num_clusters' : num_clusters,
                           'distortions' : distortions})
 
# Create a line plot of num_clusters and distortions
sns.lineplot(x = 'num_clusters', y = 'distortions', data = elbow_plot)
plt.xticks(num_clusters)
plt.show()


Python3
cluster_centers, _ = kmeans(batman_df[['scaled_color_red',
                                       'scaled_color_blue',
                                       'scaled_color_green']], 3)
 
dominant_colors = []
 
# Get standard deviations of each color
red_std, green_std, blue_std = batman_df[['red',
                                          'green',
                                          'blue']].std()
 
for cluster_center in cluster_centers:
    red_scaled, green_scaled, blue_scaled = cluster_center
 
    # Convert each standardized value to scaled value
    dominant_colors.append((
        red_scaled * red_std / 255,
        green_scaled * green_std / 255,
        blue_scaled * blue_std / 255
    ))
 
# Display colors of cluster centers
plt.imshow([dominant_colors])
plt.show()


Python3
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
 
batman_image = img.imread('batman.jpg')
 
r = []
g = []
b = []
for row in batman_image:
    for temp_r, temp_g, temp_b, temp in row:
        r.append(temp_r)
        g.append(temp_g)
        b.append(temp_b)
  
batman_df = pd.DataFrame({'red' : r,
                          'green' : g,
                          'blue' : b})
 
batman_df['scaled_color_red'] = whiten(batman_df['red'])
batman_df['scaled_color_blue'] = whiten(batman_df['blue'])
batman_df['scaled_color_green'] = whiten(batman_df['green'])
 
cluster_centers, _ = kmeans(batman_df[['scaled_color_red',
                                    'scaled_color_blue',
                                    'scaled_color_green']], 3)
 
dominant_colors = []
 
red_std, green_std, blue_std = batman_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()


输出 :

(187, 295, 4)

输出是 M*N*3 矩阵,其中 M 和 N 是图像的尺寸。

第 2 步:在此分析中,我们将共同查看所有像素,无论位置如何。所以在这一步中,所有的 RGB 值都被提取并存储在它们对应的列表中。创建列表后,将它们存储到 Pandas DataFrame 中,然后缩放 DataFrame 以获得标准化值。

Python3

# Importing the modules
import pandas as pd
from scipy.cluster.vq import whiten
 
# Store RGB values of all pixels in lists r, g and b
r = []
g = []
b = []
for row in batman_image:
    for temp_r, temp_g, temp_b, temp in row:
        r.append(temp_r)
        g.append(temp_g)
        b.append(temp_b)
 
# only printing the size of these lists
# as the content is too big
print(len(r))
print(len(g))
print(len(b))
 
# Saving as DataFrame
batman_df = pd.DataFrame({'red' : r,
                          'green' : g,
                          'blue' : b})
 
# Scaling the values
batman_df['scaled_color_red'] = whiten(batman_df['red'])
batman_df['scaled_color_blue'] = whiten(batman_df['blue'])
batman_df['scaled_color_green'] = whiten(batman_df['green'])

输出 :

55165
55165
55165

第 3 步:现在,使用肘图方法找到 k-means 中的聚类数。这不是找到集群数量的绝对方法,但有助于给出关于集群的指示。

肘部图:聚类中心和失真(观测值与相应质心之间的平方差之和)之间的线图。

下面是生成肘部图的代码:

Python3

# Preparing data to construct elbow plot.
distortions = []
num_clusters = range(1, 7)  #range of cluster sizes
 
# Create a list of distortions from the kmeans function
for i in num_clusters:
    cluster_centers, distortion = kmeans(batman_df[['scaled_color_red',
                                                    'scaled_color_blue',
                                                    'scaled_color_green']], i)
    distortions.append(distortion)
     
# Create a data frame with two lists, num_clusters and distortions
elbow_plot = pd.DataFrame({'num_clusters' : num_clusters,
                           'distortions' : distortions})
 
# Create a line plot of num_clusters and distortions
sns.lineplot(x = 'num_clusters', y = 'distortions', data = elbow_plot)
plt.xticks(num_clusters)
plt.show()

肘部图绘制如下所示:

输出 :

肘部图

可以看出,在 x 轴上的 3 处形成了一个合适的弯头,这意味着簇的数量等于 3(给定图像中存在三种主色)。

第四步:得到的聚类中心是标准化的RGB值

Standardized value = Actual value / Standard Deviation

使用 imshow() 方法显示主要颜色,该方法将 RGB 值缩放到 0 到 1 的范围。为此,您需要将聚类中心的标准化值乘以相应的标准偏差。由于实际的 RGB 值取最大范围为 255,因此将相乘结果除以 255 即可得到 0-1 范围内的缩放值。

Python3

cluster_centers, _ = kmeans(batman_df[['scaled_color_red',
                                       'scaled_color_blue',
                                       'scaled_color_green']], 3)
 
dominant_colors = []
 
# Get standard deviations of each color
red_std, green_std, blue_std = batman_df[['red',
                                          'green',
                                          'blue']].std()
 
for cluster_center in cluster_centers:
    red_scaled, green_scaled, blue_scaled = cluster_center
 
    # Convert each standardized value to scaled value
    dominant_colors.append((
        red_scaled * red_std / 255,
        green_scaled * green_std / 255,
        blue_scaled * blue_std / 255
    ))
 
# Display colors of cluster centers
plt.imshow([dominant_colors])
plt.show()

这是显示给定图像的三种主色的结果图。

输出 :

显示主色的绘图

请注意,这三种颜色类似于视觉检查图像的三种颜色。

以下是不带注释的完整代码:

Python3

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
 
batman_image = img.imread('batman.jpg')
 
r = []
g = []
b = []
for row in batman_image:
    for temp_r, temp_g, temp_b, temp in row:
        r.append(temp_r)
        g.append(temp_g)
        b.append(temp_b)
  
batman_df = pd.DataFrame({'red' : r,
                          'green' : g,
                          'blue' : b})
 
batman_df['scaled_color_red'] = whiten(batman_df['red'])
batman_df['scaled_color_blue'] = whiten(batman_df['blue'])
batman_df['scaled_color_green'] = whiten(batman_df['green'])
 
cluster_centers, _ = kmeans(batman_df[['scaled_color_red',
                                    'scaled_color_blue',
                                    'scaled_color_green']], 3)
 
dominant_colors = []
 
red_std, green_std, blue_std = batman_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()