Python, кластеризация K-средних в OpenCV

задняя часть

Python, кластеризация K-средних в OpenCV

В этом блоге вы узнаете, что такое кластеризация K-средних и как использовать функцию cv2.kmeans() для кластеризации данных.

  • Кластер K-средних Кластеризация K-средних
  • cv2.kmeans() для кластеризации данных

1. Рендеринг

После выборки для создания 5 стопок точек и кластеризации нарисуйте каждую классификацию разным цветом.Диаграмма эффекта 1 выглядит следующим образом: 在这里插入图片描述 Также сгенерируйте 5 стопок кластеризации точек 5, и диаграмма эффекта выглядит следующим образом: 在这里插入图片描述 После выборки для создания 10 стопок точек, кластеризации диаграмма эффекта выглядит следующим образом: 在这里插入图片描述 График кластеризации одной функции:Размер футболки делится только на 3 типа в зависимости от роста在这里插入图片描述 2 карты кластера функций:Размер футболки сгруппирован по росту и весу,在这里插入图片描述

Квантование цвета для уменьшения количества цветов и получения нового изображения, исходное изображение VS кластеризация 15 цветопередачи выглядит следующим образом:

Чем больше количество сгруппированных цветов, тем медленнее алгоритм, но тем ближе он выглядит к исходному изображению.在这里插入图片描述

2. Принцип

2.1 Что такое кластеризация K-средних?

Рассмотрим компанию, которая представит на рынке футболку нового типа. Очевидно, что им придется делать модели разных размеров, чтобы вместить людей всех размеров. Поэтому компания сделала данные о росте и весе человека и нарисовала их на диаграмме, как показано ниже:在这里插入图片描述Компания не может производить футболки всех размеров. Вместо этого они делят людей на маленьких, средних и больших и производят только эти три модели, которые подходят всем.Это разделение людей на три группы может быть выполнено с помощью кластеризации k-средних, алгоритм дает нам 3 лучших размера, которые удовлетворят всех. Если нет, компания может разделить людей на большее количество групп, возможно, на пять.,Как показано ниже:在这里插入图片描述

2.2 Процесс кластеризации K-средних

Кластеризация K-средних — это итеративный процесс, и самая простая кластеризация K-средних состоит из следующих 4 шагов.

  1. Допустим есть куча точек, которые нужно разделить на 2 категории;
  2. Две точки C1 и C2 выбираются случайным образом в качестве центроидов и рассчитываются расстояния от окружающих точек до C1 и C2.
  3. После деления вычислить среднее значение всех точек в классе C1 как новый центроид C1 и вычислить среднее значение всех точек в классе C2 как новый центроид C2;
  4. Процесс итерации 2, 3 завершается в соответствии с заданным условием (сколько раз процесс итерации достигает или достигает заданной точности).
  5. Окончательная сходимость — это расстояние от C1 до всех его точек + расстояние от C2 до всех его точек = минимальное значение.

在这里插入图片描述

这些点使得测试数据与其对应的质心之间的距离之和最小。

Вышеупомянутые 4 шага — это только верхний уровень кластеризации K-средних. Алгоритм имеет множество оптимизаций, таких как: как выбрать начальные центроиды, как ускорить итерационный процесс.

Итеративный процесс можно аппроксимировать следующими рисунками, которые представляют четыре вышеупомянутых процесса соответственно.

На следующем рисунке повторяются шаги 1 и 2, случайным образом выбирается точка в качестве центральной точки и вычисляется расстояние для классификации; 在这里插入图片描述 На следующем рисунке повторно вычисляется центроид и для получения графика результатов повторяются шаги 3 и 4. Вы можете видеть, что после нескольких итераций случайные точки делятся на 2 группы точек, красную и синюю; центральные точки также относительно центрированы и относительно обычный. 在这里插入图片描述

2.3 cv2.kmeans(z, 2, None, criteria, 10, flags)

compactness, labels, centers = cv2.kmeans(z, 2, None, criteria, 10, flags)

Потребление:

  • образцы: тип данных np.float32, каждая функция помещается в столбец.
  • nclusters(K) : последнее необходимое количество кластеров
  • creteria: критерии завершения итерации. При выполнении этого условия итерация алгоритма останавливается. На самом деле это должен быть кортеж из 3-х аргументов.

(тип, max_iter, эпсилон):a - тип условия завершения: имеет 3 флага, cv2.TERM_CRITERIA_EPS - остановить итерацию алгоритма при достижении заданной точности epsilon. cv2.TERM_CRITERIA_MAX_ITER — остановить алгоритм после указанного количества итераций max_iter. cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER — остановить итерацию при выполнении любого из вышеперечисленных условий.

б - максимальное количество итераций - целое число, указывающее максимальное количество итераций. c - точность - требуемая точность

  • попыток : флаг, указывающий, сколько раз выполнять алгоритм с разными начальными метками. Алгоритм возвращает метку, обеспечивающую наилучшую компактность. Эта компактность возвращается в качестве вывода.
  • flags : Этот флаг используется, чтобы указать, как взять начальный центр. Обычно для этого используются два флага: cv2.KMEANS_PP_CENTERS и cv2.KMEANS_RANDOM_CENTERS.

возвращаемое значение:

  • компактность: компактность, которая относится к сумме квадратов расстояний от каждой точки до соответствующего центра
  • labels: массив меток, где каждый элемент помечен «0», «1»...
  • center: массив кластерных центров

3. Исходный код

3.1 Кластеризация после точек отбора проб

# K均值聚类随机生成一堆点并聚类demo

from __future__ import print_function

import cv2 as cv
import numpy as np
from numpy import random


def make_gaussians(cluster_n, img_size):
    points = []
    ref_distrs = []
    for _i in range(cluster_n):
        mean = (0.1 + 0.8 * random.rand(2)) * img_size
        a = (random.rand(2, 2) - 0.5) * img_size * 0.1
        cov = np.dot(a.T, a) + img_size * 0.05 * np.eye(2)
        n = 100 + random.randint(900)
        pts = random.multivariate_normal(mean, cov, n)
        points.append(pts)
        ref_distrs.append((mean, cov))
    points = np.float32(np.vstack(points))
    return points, ref_distrs


def main():
    cluster_n = 5
    img_size = 300

    # 生成明亮的调色板
    colors = np.zeros((1, cluster_n, 3), np.uint8)
    colors[0, :] = 255
    colors[0, :, 0] = np.arange(0, 180, 180.0 / cluster_n)
    colors = cv.cvtColor(colors, cv.COLOR_HSV2BGR)[0]

    while True:
        print('sampling distributions...')
        points, _ = make_gaussians(cluster_n, img_size)

        term_crit = (cv.TERM_CRITERIA_EPS, 30, 0.1)
        _ret, labels, _centers = cv.kmeans(points, cluster_n, None, term_crit, 10, 0)

        img = np.zeros((img_size, img_size, 3), np.uint8)
        for (x, y), label in zip(np.int32(points), labels.ravel()):
            c = list(map(int, colors[label]))

            cv.circle(img, (x, y), 1, c, -1)

        cv.imshow('kmeans', img)
        ch = cv.waitKey(0)
        if ch == 27:
            break

    print('Done')


if __name__ == '__main__':
    print(__doc__)
    main()
    cv.destroyAllWindows()

3.2 Кластеризация по одному признаку, кластеризация по нескольким признакам и количественная оценка цвета

# OpenCV实现K-Means Cluster K均值聚类
# 输入参数
# - samples: np.float32 数据类型,每个特征放在一个列中。
# - nclusters(K) : 最后需要的簇数
# - creteria: 迭代终止标准。当满足此条件时,算法迭代停止。实际上,它应该是一个包含 3 个参数的元组。它们是(类型、max_iter、epsilon):
#  a - 终止条件的类型:它有 3 个标志,如下所示:cv2.TERM_CRITERIA_EPS - 如果达到指定的准确度 epsilon,则停止算法迭代。
#                                             cv2.TERM_CRITERIA_MAX_ITER - 在指定的迭代次数 max_iter 后停止算法。
#                                             cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER - 当满足上述任何条件时停止迭代。
# b - 最大迭代次数 - 指定最大迭代次数的整数。
# c - 精度 - 要求的准确性
# - attempts :标记以指定使用不同的初始标签执行算法的次数。该算法返回产生最佳紧凑性的标签。这种紧凑性作为输出返回。
# - flags :此标志用于指定如何采用初始中心。通常为此使用两个标志:cv2.KMEANS_PP_CENTERS 和 cv2.KMEANS_RANDOM_CENTERS。

#
# 输出参数
#
# - compactness: 紧凑度,指每个点到其相应中心的距离平方和
# - labels: 标签数组,其中每个元素都标记为“0”、“1”.....
# - centers: 聚簇中心的数组

# 1. 只有一个特征的数据(T恤问题,只根据身高)
import numpy as np
import cv2
from matplotlib import pyplot as plt

x = np.random.randint(25, 100, 25)
y = np.random.randint(175, 255, 25)
z = np.hstack((x, y))
z = z.reshape((50, 1))
z = np.float32(z)
plt.hist(z, 256, [0, 256]), plt.show()

# 每当运行 10 次算法迭代或达到 epsilon = 1.0 的准确度时,停止算法并返回
# 定义终止准则 criteria = ( type, max_iter = 10 , epsilon = 1.0 )
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)

# 设置标志(只是为了避免代码中的换行符)
flags = cv2.KMEANS_RANDOM_CENTERS

# 应用K均值聚类算法
compactness, labels, centers = cv2.kmeans(z, 2, None, criteria, 10, flags)

A = z[labels == 0]
B = z[labels == 1]

# 以红色绘制 A,以蓝色绘制 B,以黄色绘制它们的质心。
plt.hist(A, 256, [0, 256], color='r')
plt.hist(B, 256, [0, 256], color='b')
plt.hist(centers, 32, [0, 256], color='y')
plt.title("one feature res")
plt.show()

# 2. 具有多重数据的特征(T恤问题,根据身高、体重)
import numpy as np
import cv2
from matplotlib import pyplot as plt

X = np.random.randint(25, 50, (25, 2))  # 身高
Y = np.random.randint(60, 85, (25, 2))  # 体重
Z = np.vstack((X, Y))

# 转换为 np.float32
Z = np.float32(Z)

# 定义终止准则以及应用KMeans聚类
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
ret, label, center = cv2.kmeans(Z, 2, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)

# 分离数据,并拉平flatten
A = Z[label.ravel() == 0]
B = Z[label.ravel() == 1]

# 绘制数据
plt.scatter(A[:, 0], A[:, 1])
plt.scatter(B[:, 0], B[:, 1], c='r')
plt.scatter(center[:, 0], center[:, 1], s=80, c='y', marker='s')
plt.xlabel('Height'), plt.ylabel('Weight')
plt.title("two features res")
plt.show()

## 3. 颜色量化
# 颜色量化是减少图像中颜色数量的过程。这样做的原因之一是减少内存。有时某些设备可能有限制,以至于它只能产生有限数量的颜色。
# 在这些情况下,也会执行颜色量化。这里我们使用 k-means 聚类进行颜色量化。有3个特征,例如 R、G、B。需要将图像重塑为 Mx3 大小的数组(M 是图像中的像素数)。
# 在聚类之后将质心值(也是 R、G、B)应用于所有像素,这样生成的图像将具有指定数量的颜色,最后需要将其重塑回原始图像的形状。
import numpy as np
import cv2

img = cv2.imread('images/ml.jpg')
Z = img.reshape((-1, 3))

# 转换 np.float32
Z = np.float32(Z)

# 定义终止准则以及应用KMeans聚类
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)
K = 15
ret, label, center = cv2.kmeans(Z, K, None, criteria, 10, cv2.KMEANS_RANDOM_CENTERS)

# 转换回uint8, 制作原始图像
center = np.uint8(center)
res = center[label.flatten()]
res2 = res.reshape((img.shape))

cv2.imshow("origin",img)
cv2.imshow('res2', res2)
cv2.waitKey(0)
cv2.destroyAllWindows()

Ссылаться на