Press "Enter" to skip to content

原力计划OpenCV-Python实战(番外篇)——利用 K-Means 聚类进行色彩量化

本站内容均来自兴趣收集,如不慎侵害的您的相关权益,请留言告知,我们将尽快删除.谢谢.

 

OpenCV-Python实战(番外篇)——利用 K-Means 聚类进行色彩量化

 

K-Means
聚类算法的目标是将n
个样本划分(聚类)为K
个簇,在博文《OpenCV与机器学习的碰撞》
中,我们已经学习利用OpenCV
提供了cv2.kmeans()
函数实现K-Means
聚类算法,该算法通过找到簇的中心并将输入样本分组到簇周围,同时通过简单的示例了解了K-Means
算法的用法。在本文中,我们将学习如何利用K-Means
聚类进行色彩量化,以减少图像中颜色数量。

 

利用 K-Means 聚类进行色彩量化

 

色彩量化问题可以定义为减少图像中颜色数量的过程。色彩量化对于某些设备显示图像非常关键,这些设备可能由于内存限制等原因只能显示有限颜色,因此,在这些设备上显示色彩通常需要在准确性和减少颜色数量之间进行权衡,在利用K-Means
聚类进行色彩量化时,权衡两者是通过正确设置K
参数来进行的。

 

利用K-Means
聚类算法来执行色彩量化,簇中心数据由 3 个特征组成,它们对应于图像每个像素的 B、G 和 R 值。因此,关键是将图像转换为数据:

 

data = np.float32(image).reshape((-1, 3))

 

为了观察如何权衡准确性和颜色数,我们使用不同 K 值 (3 、 5 、 10 、 20 和 40) 执行聚类过程,以查看生成的图像如何变化,如果我们想要只有 3 种颜色 (K = 3) 的结果图像,需要执行以下操作:

 

 

    1. 加载 BGR 图像:
img = cv2.imread('example.jpg')

使用color_quantization()
函数执行色彩量化:

def color_quantization(image, k):
    # 将图像转换为数据
    data = np.float32(image).reshape((-1, 3))
    # 算法终止条件
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 20, 1.0)
    # K-Means 聚类
    ret, label, center = cv2.kmeans(data, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
    # 簇中心
    center = np.uint8(center)
    # 将具有 k 颜色中心的图像转换为 uint8
    result = center[label.flatten()]
    result = result.reshape(img.shape)
    return result
color_3 = color_quantization(img, 3)

 

 

color_quantization()
函数中,关键点是利用cv2.kmeans()
方法。最后,可以用 k 种颜色来构建图像,用它们对应的中心值替换每个像素值,程序的运行结果如下所示:

 

 

完整代码

 

利用 K-Means 聚类进行色彩量化的完整代码如下所示:

 

import numpy as np
import cv2
from matplotlib import pyplot as plt
def show_img_with_matplotlib(color_img, title, pos):
    img_RGB = color_img[:, :, ::-1]
    ax = plt.subplot(2, 4, pos)
    plt.imshow(img_RGB)
    plt.title(title, fontsize=8)
    plt.axis('off')
def color_quantization(image, k):
    # 将图像转换为数据
    data = np.float32(image).reshape((-1, 3))
    # 算法终止条件
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 20, 1.0)
    # K-Means 聚类
    ret, label, center = cv2.kmeans(data, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
    # 簇中心
    center = np.uint8(center)
    # 将具有 k 颜色中心的图像转换为 uint8
    result = center[label.flatten()]
    result = result.reshape(img.shape)
    return result
fig = plt.figure(figsize=(16, 8))
plt.suptitle("Color quantization using K-means clustering algorithm", fontsize=14, fontweight='bold')
# 图片加载
img = cv2.imread('example.png')
show_img_with_matplotlib(img, "original image", 1)
# 使用不同 K 值进行色彩量化
for i in range(7):
    color = color_quantization(img, (i+1) * 10)
    show_img_with_matplotlib(color, "color quantization (k = {})".format((i+1) * 10), i+2)
plt.show()

 

显示色彩量化后的色彩分布

 

可以扩展以上程序使其显示色彩量化后的色彩分布,该色彩分布显示了分配给每个聚类中心的像素数。只需扩展color_quantization()
函数已被修改为包含所需功能:

 

import collections
def color_quantization(image, k):
    # 将图像转换为数据
    data = np.float32(image).reshape((-1, 3))
    # 算法终止条件
    criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 20, 1.0)
    # K-Means 聚类
    ret, label, center = cv2.kmeans(data, k, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)
    # 簇中心
    center = np.uint8(center)
    # 将具有 k 颜色中心的图像转换为 uint8
    result = center[label.flatten()]
    result = result.reshape(img.shape)
    # 统计分配给每个聚类中心的像素数
    counter = collections.Counter(label.flatten())
    print(counter)
    # 计算输入图像的总像素数
    total = img.shape[0] * img.shape[1]
    # 为色彩分布图像指定宽度和高度:
    desired_width = img.shape[1]
    
    desired_height = 70
    desired_height_colors = 50
    # 初始化色彩分布图像
    color_distribution = np.ones((desired_height, desired_width, 3), dtype='uint8') * 255
    start = 0
    for key, value in counter.items():
        # 归一化
        value_normalized = value / total * desired_width
        end = start + value_normalized
        # 绘制与当前颜色对应的矩形
        cv2.rectangle(color_distribution, (int(start), 0), (int(end), desired_height_colors), center[key].tolist(), -1)
        start = end
    return np.vstack((color_distribution, result))

 

上述代码中,使用collections.Counter()
来统计分配给每个聚类中心的像素数:

 

counter = collections.Counter(label.flatten())

 

例如,如果 K = 10,则可以得到如下结果:

 

Counter({
 7: 37199, 3: 36302, 0: 29299, 5: 23987, 6: 23895, 1: 20077, 9: 19814, 8: 18427, 4: 16221, 2: 14779})

 

构建色彩分布图像后,将其与色彩量化后的图像连接在一起:

 

np.vstack((color_distribution, result))

 

程序的输出如下所示:

 

 

从上图可以看出,使用K-Means
聚类算法应用色彩量化后改变参数 k (10、20、30、40、50、60 和 70) 的结果,k 值越大产生的图像越逼真。

 

Note:除了 color_quantization() 函数外,由于其他代码并未修改,因此不再另外给出。

 

相关链接

 

OpenCV-Python实战(13)——OpenCV与机器学习的碰撞

Be First to Comment

发表回复

您的电子邮箱地址不会被公开。