好奇的小老鼠——使用FCM对图片像素进行聚类

FCM

FCM,英文全程Fuzzy C-Means(FCM),关于FCM,网络上有不少文章,笔者之前也写过一篇介绍FCM的文章,👉《机器学习之聚类——模糊聚类FCM》,感兴趣的读者可以看一下哈!!

图片像素聚类

众所周知,图片是由二维平面上的像素点组成的,灰度图的每个像素点都对应一个像素值 ( 0 − 255 0-255 0255),而彩色图片的像素点会对应三原色以及透明度四个值。
在这里插入图片描述
本文会将图片转换为灰度图,然后对像素点进行聚类,在对灰度图像素点进行聚类时,有一点非常重要,因为灰度图的每个像素点都只对应一个像素值,所以对灰度图像素的聚类可以视为对一维数据的聚类问题。

看,我们的操作对象就是这个好奇的小老鼠,读者也可以换成其他的图片哟!

在这里插入图片描述

代码

FCM部分代码(fcm.py):

import numpy as np


class FCM:
    def __init__(self, K, m=2, eps=0.05):
        # 聚类个数
        self.K = K
        # 加权参数
        self.m = m
        # 终止容限
        self.eps = eps
        # 最优相似度矩阵
        self.U = None
        # 最终的聚类中心
        self.centers = None
        # 目标函数值
        self.obj_val = None

    def init_by_centers(self, data, centers):
        # 初始化隶属度矩阵
        self.U = np.random.random((len(data), self.K))
        # 样本到聚类中心的距离
        dist = np.zeros((len(data), self.K))
        for i, x in enumerate(data):
            for j, c in enumerate(centers):
                dist[i][j] = np.linalg.norm(x - c, 2)
        # 计算新的隶属度矩阵
        for i, x in enumerate(data):
            for j, c in enumerate(centers):
                self.U[i][j] = 1./np.sum((dist[i][j]/dist[i]) ** (2/(self.m-1)))
        # 最初的目标函数值
        self.obj_val = np.sum((self.U ** self.m) * (dist ** 2))

    def train(self, data):
        if len(data.shape) == 1:
            data = data[:, np.newaxis]
        if self.U is None:
            # 初始化隶属度矩阵
            self.U = np.random.random((len(data), self.K))
            # 保证每个样本属于所有类的概率是1
            self.U = np.divide(self.U, np.sum(self.U, axis=1)[:, np.newaxis])

        while True:
            temp_U = self.U ** self.m
            # 计算聚类中心
            self.centers = np.divide(np.dot(temp_U.T, data), np.sum(temp_U.T, axis=1)[:, np.newaxis])
            # 样本到聚类中心的距离
            dist = np.zeros((len(data), self.K))
            for i, x in enumerate(data):
                for j, c in enumerate(self.centers):
                    dist[i][j] = np.linalg.norm(x - c, 2)
            # 计算新的隶属度矩阵
            for i, x in enumerate(data):
                for j, c in enumerate(self.centers):
                    temp_U[i][j] = 1./np.sum((dist[i][j]/dist[i]) ** (2/(self.m-1)))
            # 判断是否收敛
            if np.sum(abs(temp_U-self.U)) < self.eps:
                break
            # 更新隶属度矩阵
            self.U = temp_U
            # 更新目标函数值
            self.obj_val = np.sum((self.U ** self.m) * (dist ** 2))
        # 返回样本最大隶属度对应的类别
        return np.argmax(self.U, axis=1)

    def __str__(self) -> str:
        return f"K:{self.K}, m:{self.m}, eps:{self.eps}, U:{self.U}, centers:{self.centers}, dist: {self.dist}"

图片像素聚类主程序代码:

from matplotlib import pyplot as plt
import time
import cv2
from fcm import *


# 导入图片
def import_image(img_path):
    # 导入图片并转换成灰度图像,其中的像素值是0-255,uint8类型
    img = cv2.imread(img_path, 0)
    # 图片尺寸
    h, w = img.shape
    img = img.astype('float')
    return img, h, w


def run():
    # 开始计时
    begin = time.time()
    img_path = "./mouse.jpeg"
    # 聚类的数量
    c = 2
    # 导入图像
    img, h, w = import_image(img_path)
    # 去重后的图片像素值
    pixel_data = np.unique(img.flatten())
    # FCM模型
    my_fcm = FCM(K=c, m=2, eps=0.01)
    # 优化
    y = my_fcm.train(pixel_data)
    end = time.time()
    print("总共花费了时间{}".format(end - begin))
    print("像素值聚类中心:{}".format(my_fcm.centers.flatten()))
    print("目标函数值:{}".format(my_fcm.obj_val))
    # 像素值及其对应的类别标签
    pixel_label = dict()
    for d, l in zip(pixel_data, y):
        pixel_label[d] = l
    # 按像素类别生成新的图片
    img_new = np.zeros((h, w))
    # 遍历每一个像素
    for i in range(h):
        for j in range(w):
            img_new[i][j] = int(pixel_label[img[i][j]])

    # 绘制图片
    plt.imshow(img_new, cmap='gray')
    plt.gca().xaxis.set_major_locator(plt.NullLocator())
    plt.gca().yaxis.set_major_locator(plt.NullLocator())
    plt.show()
    # plt.savefig('fcm_mouse.png', dpi=800)


if __name__ == "__main__":
    run()

输出图片如下,还是挺好玩的吧
在这里插入图片描述
作者这水平有限,有不足之处欢迎留言指正

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
FCM(Fuzzy C-Means)聚类分析是一种基于模糊理论的聚类方法,它可以将数据集中的数据点分为若干个模糊的聚类。在 R 语言中,可以使用 `fclust` 包进行 FCM 聚类分析。下面是一个简单的例子,演示如何使用 `fclust` 包进行 FCM 聚类分析并确定聚类个数。 首先,我们需要安装和加载 `fclust` 包: ```r install.packages("fclust") library(fclust) ``` 然后,我们可以使用 `iris` 数据集来演示 FCM 聚类分析。假设我们想要将 `iris` 数据集中的花卉样本分为 2-5 个聚类。可以使用以下代码: ```r # 加载 iris 数据集 data(iris) # 将数据集中的前 4 列作为聚类变量 x <- iris[, 1:4] # 定义聚类个数的范围 k_range <- 2:5 # 创建一个空列表,用于存储每个聚类个数下的聚类结果 fcm_result <- list() # 循环遍历每个聚类个数,进行 FCM 聚类分析 for (k in k_range) { # 进行 FCM 聚类分析 fcm_result[[as.character(k)]] <- fcm(x, k = k, m = 2, maxiter = 100) } # 输出每个聚类个数下的聚类结果 fcm_result ``` 在上面的代码中,我们使用 `fcm` 函数进行 FCM 聚类分析,并将聚类结果存储在 `fcm_result` 列表中。循环遍历了聚类个数的范围,分别进行FCM 聚类分析,并将结果存储在 `fcm_result` 中相应的列表项中。 最后,我们可以绘制每个聚类个数下的模糊聚类结果,并使用一些评价指标来确定最佳的聚类个数。以下是绘制聚类结果和确定最佳聚类个数的代码: ```r # 定义画图函数 plot_clusters <- function(clusters, x) { plot(x[,1], x[,2], col = clusters$cluster, pch = 19, main = paste("FCM Clustering with k =", clusters$k)) } # 循环遍历每个聚类个数,绘制聚类结果 par(mfrow = c(2, 2)) for (i in 1:length(fcm_result)) { plot_clusters(fcm_result[[i]], x) } # 定义评价指标函数 eval_clusters <- function(clusters, x) { # 模糊系数 fc <- clusters$membership m <- 2 n <- nrow(x) k <- clusters$k # 平均模糊熵 fce <- (-1/n) * sum(apply(fc, 2, function(f) sum(f * log(f)))) # Davies-Bouldin 指数 db <- davies.bouldin(x, clusters$cluster) # Calinski-Harabasz 指数 ch <- calinski.harabasz(x, clusters$cluster) # 输出评价指标 cat("k =", k, "\n") cat("FC:", fce, "\n") cat("DB:", db, "\n") cat("CH:", ch, "\n\n") } # 循环遍历每个聚类个数,计算评价指标 for (i in 1:length(fcm_result)) { eval_clusters(fcm_result[[i]], x) } ``` 在上面的代码中,我们定义了一个 `plot_clusters` 函数来绘制模糊聚类结果,并使用 `par` 函数将绘图区域分成 2x2 的 4 个子区域。然后,我们定义了一个 `eval_clusters` 函数来计算一些评价指标,包括模糊系数、Davies-Bouldin 指数和 Calinski-Harabasz 指数。最后,我们循环遍历每个聚类个数,分别绘制聚类结果和计算评价指标。 通过观察聚类结果和评价指标,我们可以得出最佳的聚类个数。在上面的例子中,我们使用了 2-5 个聚类进行分析,并且在评价指标方面,我们可以选择最小化模糊系数和 Davies-Bouldin 指数,最大化 Calinski-Harabasz 指数。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

肥猪猪爸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值