使用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()