作者 | Juan De Dios Santos
来源 | Medium
编辑 | 代码医生团队
与生活中的许多事物一样,颜色偏好是一种非常内在的,独特的人的品质。有一种最喜欢的颜色,但更重要的是,愿意说对拥有的许多东西都有一个首选的基调。例如,喜欢鞋子的特定颜色,另一个适合的手机壳,在拍摄照片时倾向于某些颜色。
除了作为一名数据从业者,也是一名业余摄影师,几天前,在编辑图像时,意识到我有一个很受欢迎的颜色列表,通常在不同的对象或照片的某些部分使用。例如,喜欢我的天空,无论是灰色,还是强烈的蓝色,果岭有点淡黄色,还有黑暗,更像是“阴影”。
为了证实,并找到一种方式来交叉对数据和摄影的热情,决定使用机器学习,尤其是经典的无监督学习算法,k-means聚集我的一些图像的像素并学习什么领先或主导的颜色是。此外,为了进一步理解照片并补充分析的主要部分,将使用维度降低算法t-分布随机邻域嵌入或t-SNE 将图像投影到另一种表示。
数据
在这个实验中,将找到最近访问奥地利和新加坡时拍摄的九张照片的主要颜色。
工具
这个实验是用Python完成的,它使用scikit-learn库来拟合k-means模型,OpenCV用于操作图像,而HyperTools用于使用t-SNE投影空间。
https://scikit-learn.org/?source=post_page---------------------------
https://opencv.org/?source=post_page---------------------------
https://hypertools.readthedocs.io/en/latest/?source=post_page---------------------------
本实验
来看看在新加坡拍摄的这张照片。看到什么颜色?哪个是最常见的?对这些人来说,这很容易。首先,可能会说几种灰色,蓝色和一点橙色。算法说什么?可以自动化吗?当然,但在到达那里之前,想使用t-SNE投射红色,绿色和蓝色通道,以便更好地了解这里真正发生的事情。
t-SNE通常用于通过对相似对象进行分组并将其与附近点建模来将高维数据嵌入到二维或三维中,而“不同对象由远点表示”。该算法的这种特性使其适用于“聚类”数据,即使它已经是低维的,例如在这种情况下。
以下三个图像是前一图像的不同颜色通道的t-SNE表示。
红色通道的2D t-SNE投影
绿色通道的2D t-SNE投影
蓝色通道的2D t-SNE投影
在每个图像上,可以看到不同的像素组。对这些蛇类组的解释是,每个组都描述了该色彩通道中的相似色调。例如,红色通道图有五个不同的组,它们可能代表不同的红色调,例如浅色调和饱和色调。但是,这些群体是主要的颜色吗?来看看。
在拟合模型之前,不得不重塑图像数据。默认情况下,彩色图像是由图片的宽度,长度和三个颜色通道组成的3D矩阵。对于此应用程序,将把这个向量空间转换为由width*lenght行和3列(每种颜色一个)组成的2D数据帧。然后可以集群。
该实验的聚类算法是k-means,一种无监督学习算法,以这样一种方式聚类数据观察,即每个点与其他点相似。对于这个项目,去了k=10,意味着将获得10种主色。
以下代码显示了该过程。
代码语言:javascript复制import cv2
import numpy as np
import matplotlib.pyplot as plt
import hypertools as hyp
import numpy as np
from sklearn.cluster import KMeans
from os import listdir
def get_leading_colors(directory):
for filename in listdir(directory):
img = cv2.imread(directory filename)
# by default, cv2 uses BGR so we need to change it to RGB
img_data = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
r, g, b = cv2.split(img_data)
# plot a t-SNE projection of each color channel
hyp.plot(r, '.', reduce='TSNE', ndims=2, color='red',
title='2D t-SNE projection of the red channel',
size=[14, 8])
hyp.plot(g, '.', reduce='TSNE', ndims=2, color='green',
title='2D t-SNE projection of the green channel',
size=[14, 8])
hyp.plot(b, '.', reduce='TSNE', ndims=2, color='blue',
title='2D t-SNE projection of the blue channel',
size=[14, 8])
# row * column, and number of color channels (3 because of RGB)
img = img.reshape((img_data.shape[0] * img_data.shape[1], 3))
# the number of clusters indicate how many leading colors we want
model = KMeans(n_clusters=k, init='random', random_state=88)
model.fit(img)
hist = compute_histogram(model)
rect = draw_leading_color_plot(hist, model.cluster_centers_)
plt.axis('off')
plt.imshow(rect)
plt.show()
一旦对数据进行了聚类,就需要找到一种方法来提取这些信息并将其可视化。所以,建立了一个直方图,使用聚类的结果作为输入,并k作为箱数。结果是频率计数列表,指示每个标签下有多少像素。然后对列表进行标准化,以获得每个标签下像素百分比的列表。简而言之,在这一部分中,总结了每个集群中有多少像素。
这是功能。
代码语言:javascript复制def compute_histogram(model):
labels_list = np.arange(0, k 1)
# this histogram says how many pixels fall into one of the bins
(hist, _) = np.histogram(model.labels_, bins=labels_list)
hist = hist.astype('float')
hist /= hist.sum()
return hist
最后,将绘制一个由前导颜色组成的矩形,其中每个颜色块的长度与上面计算的百分比成比例。
代码语言:javascript复制def draw_leading_color_plot(hist, centroids):
# the first two values of np.zeros(...) represent the size of the rectangle
# the 3 is because of RGB
plot_width = 700
plot_length = 150
plot = np.zeros((plot_length, plot_width, 3), dtype='uint8')
start = 0
for (percent, color) in sorted(zip(hist, centroids), key=lambda x: x[0], reverse=True):
end = start (percent * plot_width)
# append the leading colors to the rectangle
cv2.rectangle(plot, (int(start), 0), (int(end), plot_length),
color.astype('uint8').tolist(), -1)
print(color)
start = end
# return the rectangle chart
return plot
现在看看结果。这些是新加坡形象的主要色彩。
右侧的条形表示算法学习的主要颜色。
图像右侧的条形是算法找到的主要颜色。前两种颜色是灰色调,主要出现在云,水和图像的阴影中。接下来有蓝调,存在于天空和水中。最后,还有来自树木的果岭。
同意算法的发现吗?
看看图像的其他例子及其主要颜色。前四张照片来自新加坡,其余来自奥地利。根据地区的不同,能否在选择的颜色中找到任何特色?
一座漂亮的建筑。注意白色是主色之一。
樟宜机场令人惊叹的Rain Vortex。不是50灰色,但几乎在那里。
鱼尾狮。这个由蓝色和绿色制成。
滨海湾金沙。该算法发现朴实的色调是最常见的色彩。
山和反射。这个的主色似乎来自天空和树林。
因斯布鲁克。这个有棕褐色的氛围。
另一座山及其倒影。老实说,很惊讶算法没有找到蓝色。
自然框架。白人,黑人和蓝调。
结论和回顾
在本文中,展示了一种使用k-means和Python查找图像主导颜色的技术。就个人而言,对结果感到高兴和满意。即使结果并不完美 - 一些明显的主要颜色未被检测到 - 会说它能够捕捉到在图像中通常使用的颜色 - 灰色,深蓝色和棕色。
在使用无监督学习时,没有正确或错误的答案,因为过程中涉及许多变量,最关键的一个是质心的初始位置。这个问题导致算法学习不想要的东西,在这个特定的用例中,这意味着产生一种主要颜色,实际上它不是最常见的颜色之一。替代本文中描述的方法(老实说,可能产生更准确结果的方法),将是一种更具编程性和直接性的方法,必须迭代图片以构建频率计数。
这个实验的源代码可以在GitHub上找到
https://github.com/juandes/wanderdata-scripts/tree/master/images?source=post_page---------------------------