如果我们能知道一张图像中最多的颜色是什么,可以帮助我们解决很多实际问题。比如在农业领域,我们要判断水果的成熟度,可以通过看水果的颜色是否在一定范围内来判断水果是否成熟。接下来我们将使用Python和Numpy、Matplotlib、OpenCV等一些常用库来解决这个问题。01.准备步骤1:添加包我们将在这里加载基本包。另外,既然要使用Jupyter进行编程,小伙伴们不要忘记加上%matplotlibinline命令。第二步:加载和显示示例图像我们将并排显示两个图像,因此我们需要创建一个辅助函数。接下来我们将加载一些我们将在本教程中使用的示例图像,并使用上述函数显示它们。02.常用方法方法一:平均第一种方法是最简单(但效果不佳)的方法——求平均像素值即可。使用numpy的average函数,我们可以轻松获得行和宽度的平均像素值-axis=(0,1)img_temp=img.copy()img_temp[:,:,0],img_temp[:,:,1],img_temp[:,:,2]=np.average(img,axis=(0,1))img_temp_2=img_2.copy()img_temp_2[:,:,0],img_temp_2[:,:,1],img_temp_2[:,:,2]=np.average(img_2,axis=(0,1))show_img_compar(img,img_temp)show_img_compar(img_2,img_temp_2)从上图可以看出,average方法可能会产生错误的结果,它给出的最常见的颜色可能不是我们想要的颜色,因为平均值考虑了所有像素值。当我们有高对比度图像时(一张图像中既有“浅色”也有“深色”),这个问题可能会很严重。在第二张图片中,这一点更加清晰。它为我们提供了一种在图像中根本不可见的新颜色。方法二:最高像素频率第二种方法比第一种方法更准确。我们的工作是计算每个像素值出现的次数。Numpy为我们提供了一个函数来完成这个任务。但首先,我们必须重塑图像数据结构以仅提供3个值的列表(每个R、G和B通道强度一个)。我们可以使用numpy的reshape函数来获取像素值列表。现在我们有了正确结构化的数据,我们可以开始使用numpy中的unique函数计算像素值的频率。img_temp=img.copy()unique,counts=np.unique(img_temp.reshape(-1,3),axis=0,return_counts=True)img_temp[:,:,0],img_temp[:,:,1],img_temp[:,:,2]=unique[np.argmax(counts)]img_temp_2=img_2.copy()unique,counts=np.unique(img_temp_2.reshape(-1,3),axis=0,return_counts=True)img_temp_2[:,:,0],img_temp_2[:,:,1],img_temp_2[:,:,2]=unique[np.argmax(counts)]show_img_compar(img,img_temp)show_img_compar(img_2,img_temp_2)它比第一个更有意义吗?最常见的颜色是黑色区域。但是,如果我们不仅采用一种最常见的颜色,而且采用更多颜色呢?使用相同的概念,我们可以采用N种最常见的颜色。换句话说,我们如何处理最常见的不同颜色簇。方法三:使用K均值聚类我们可以使用著名的K均值聚类将颜色组聚类在一起。defpalette(簇):width=300palette=np.zeros((50,width,3),np.uint8)steps=width/clusters.cluster_centers_.shape[0]foridx,centersinnumerate(clusters.cluster_centers_):palette[:,int(idx*steps):(int((idx+1)*steps)),:]=centersreturnpaletteclt_1=clt.fit(img.reshape(-1,3))show_img_compar(img,palette(clt_1))clt_2=clt.fit(img_2.reshape(-1,3))show_img_compar(img_2,palette(clt_2))简单!现在,我们需要的是一个能立即显示上方颜色簇的函数。我们只需要创建一个高度为50像素、宽度为300像素的图像来显示颜色组/调色板。对于每个颜色簇,我们将其分配给我们的调色板。是不是很漂亮?K-means聚类在图像中最常见的颜色方面给出了极好的结果。在第二张图片中,我们可以看到调色板中的棕色阴影太多。这很可能是因为我们选择了太多的集群。让我们看看是否可以通过选择较小的k值来修复它。defpalette(簇):width=300palette=np.zeros((50,width,3),np.uint8)steps=width/clusters.cluster_centers_.shape[0]foridx,centersinnumerate(clusters.cluster_centers_):palette[:,int(idx*steps):(int((idx+1)*steps)),:]=centersreturnpaletteclt_3=KMeans(n_clusters=3)clt_3.fit(img_2.reshape(-1,3))show_img_compar(img_2,调色板(clt_3))由于我们使用了K-means聚类,我们仍然必须自己确定合适的聚类数。三集群似乎是一个不错的选择。但是我们仍然可以改进这些结果,仍然可以解决聚类问题。否则我们如何显示集群在整个图像中的比例?方法四:K-Means+ProportionalDisplay我们需要做的就是修改我们的调色板函数。我们不使用固定步长,而是将每个簇的宽度更改为与该簇中的像素数成比例。fromcollectionsimportCounterdefpalette_perc(k_cluster):width=300palette=np.zeros((50,width,3),np.uint8)n_pixels=len(k_cluster.labels_)counter=Counter(k_cluster.labels_)#counthowmanypixelsperclusterperc={}foriincounter:perc[i]=np.round(计数器[i]/n_pixels,2)perc=dict(sorted(perc.items()))#forloggingpurposesprint(perc)print(k_cluster.cluster_centers_)step=0foridx,centersinenumerate(k_cluster.cluster_centers_):palette[:,step:int(step+perc[idx]*width+1),:]=centersstep+=int(perc[idx]*width+1)returnpaletteclt_1=clt.fit(img.reshape(-1,3))show_img_compar(img,palette_perc(clt_1))clt_2=clt.fit(img_2.reshape(-1,3))show_img_compar(img_2,palette_perc(clt_2))它不仅给了我们图像中最常见的颜色。这也为我们提供了每个像素出现的比例。03.结论我们介绍了几种使用Python和最著名的库获取图像中最常见颜色的技术。另外,我们看到了这些技术的优缺点。使用k>1的K-means寻找最常见的颜色是迄今为止寻找图像中最常见颜色的最佳解决方案之一。
