[Python与图像处理]利用Python与Kmeans聚类分析图像主色彩

如何使用OpenCV,Python和k-means聚类算法来查找图像中最主要的颜色

  该任务可用于分析一张优秀摄影作品的色彩分布,并建立色卡图,将其用于本地调色。
K-Means聚类,那么k-means究竟是什么意思呢?
  K-means是一种聚类算法。目标是将n个数据点分成k个簇。 n个数据点中的每一个都将被分配给具有最接近平均值的簇。每个簇的平均值称为“质心”或“中心”。
  总的来说,应用k均值产生原始n个数据点的k个单独的簇。特定集群内的数据点被认为与属于其他集群的数据点彼此“更相似”。
  在我们的任务中,我们将聚类RGB图像的像素强度。给定MxN大小的图像,我们因此具有MxN个像素,每个像素由三个分量组成:红色,绿色和蓝色。我们将这些MxN像素视为我们的数据点,并使用k-means对它们进行聚类。
  k-means的一个条件是我们需要指定我们想要提前生成的集群数量,有些算法会自动选择k的最佳值,但在这里不做讨论。
具体的效果如下图所示:

[Python与图像处理]利用Python与Kmeans聚类分析图像主色彩_第1张图片
[Python与图像处理]利用Python与Kmeans聚类分析图像主色彩_第2张图片

代码如下所示,需要指定图像位置与聚类类别数目:

#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()

你可能感兴趣的:(Python-Opencv,Python,色彩分析,Kmeans,图像处理)