该任务可用于分析一张优秀摄影作品的色彩分布,并建立色卡图,将其用于本地调色。 K-Means聚类,那么k-means究竟是什么意思呢? K-means是一种聚类算法。目标是将n个数据点分成k个簇。 n个数据点中的每一个都将被分配给具有最接近平均值的簇。每个簇的平均值称为“质心”或“中心”。 总的来说,应用k均值产生原始n个数据点的k个单独的簇。特定集群内的数据点被认为与属于其他集群的数据点彼此“更相似”。 在我们的任务中,我们将聚类RGB图像的像素强度。给定MxN大小的图像,我们因此具有MxN个像素,每个像素由三个分量组成:红色,绿色和蓝色。我们将这些MxN像素视为我们的数据点,并使用k-means对它们进行聚类。 k-means的一个条件是我们需要指定我们想要提前生成的集群数量,有些算法会自动选择k的最佳值,但在这里不做讨论。 具体的效果如下图所示:
代码如下所示,需要指定图像位置与聚类类别数目:
#coding:utf-8 #********************************************************************************************************* ''' 说明:利用python/k-means聚类提取图像中的主要色彩,并建立色彩,可用于摄影调色中的图像色彩分析 算法思路: 1)加载RGB图像,并转换为Kmeans可聚类的数据形式; 2)设置聚类中心数目,采用Kmeans聚类; 3)设置色卡图像,显示聚类结果 具体参数:图像resize到(640, 640*ratio),clusters=4 ''' import cv2 import numpy as np import argparse from sklearn.cluster import KMeans import matplotlib.pyplot as plt ap = argparse.ArgumentParser() ap.add_argument("-i", "--image", required = True, help = "Path to the image") ap.add_argument("-c", "--clusters", required = True, type = int,help = "# of clusters") args = vars(ap.parse_args()) if __name__ == '__main__': print( '[INFO] 读取图像......' ) img = cv2.imread( args[ 'image' ] ) if ( img is None ): print( ' Not read img. ' ) #获取初始图像的宽高比例,以便resize不改变图像比例 ratio = img.shape[0] / img.shape[1] img_resize = cv2.resize( img, ( 640, int( 640*ratio ) ), interpolation=cv2.INTER_CUBIC ) #将Opencv中图像默认BGR转换为通用的RGB格式 img_rgb = cv2.cvtColor( img_resize, cv2.COLOR_BGR2RGB ) (height, width, channels) = img_rgb.shape #将图像数据转换为需要进行Kmeans聚类的Data img_data = img_rgb.reshape( height*width, channels ) print( '[INFO] Kmeans 颜色聚类......' ) #调用sklearn中Kmeans函数 kmeans = KMeans( n_clusters = args[ 'clusters' ] ) kmeans.fit(img_data) #建立颜色与标签的对应字典 color_label = {} for i in range( len( kmeans.cluster_centers_ ) ): color_label[i] = kmeans.cluster_centers_[i] print( ' 颜色以及其对应的标签为: {}'.format( color_label ) ) #计算聚类结果, 各颜色及其所含像素数目 color_num = {} for m in range( len( np.unique( kmeans.labels_ ) ) ): print( np.sum( kmeans.labels_ == m ) ) print( color_label[m] )#标签m对应的色彩 color_num[ np.sum( kmeans.labels_ == m ) ] = color_label[m] print( ' 色彩排序前字典映射为: {}'.format( color_num ) ) color_num_sorted = sorted( color_num.items(), key = lambda x:x[0], reverse = True ) print( ' 色彩排序后字典映射为: {}'.format( color_num_sorted) ) color_num_ratio = [] for i in range( len( color_num_sorted ) ): color_num_ratio.append( color_num_sorted[i][0] ) color_num_ratio = color_num_ratio / np.sum( color_num_ratio ) print( ' 色彩数目求取比例之后: {}'.format( color_num_ratio ) ) print( '[INFO] 显示色卡图像......' ) #创建带有色卡的图像 color_card = np.zeros( shape = ( height, width + 100, 3 ), dtype = np.int32 ) #图像左侧区域复制源图像 for i in range(height): for j in range(width): color_card[i][j] = img_rgb[i][j] #图像右侧显示色卡 start = 0 for i in range( len( kmeans.cluster_centers_ ) ): color = color_num_sorted[i][1] row_start = int ( color_num_ratio[i] * height ) #由于前面的比例为小数,转为Int导致最后部分区域没有色彩,采用最后一种颜色进行填充 if i == len( kmeans.cluster_centers_ ) - 1: color_card[start:, width:width+100] = color color_card[start: start +row_start, width:width+100] = color start += row_start plt.imshow( color_card ) plt.show()