Python:模糊C均值聚类(FCM)的图像分割
2023-12-05 本文已影响0人
大龙10
一、FCM
1、定义
- FCM算法是基于对目标函数的优化基础上的一种数据聚类方法。
聚类结果是每一个数据点对聚类中心的隶属程度,该隶属程度用一个数值来表示。该算法允许同一数据属于多个不同的类。
2、优缺点
- FCM算法是一种无监督的模糊聚类方法,在算法实现过程中不需要人为的干预。
这种算法的不足之处:
首先,算法中需要设定一些参数,若参数的初始化选取的不合适,可能影响聚类结果的正确性;
其次,当数据样本集合较大并且特征数目较多时,算法的实时性不太好。
3、HCM与FCM区别
- K-means也叫硬C均值聚类(HCM),而FCM是模糊C均值聚类,它是HCM的延伸与拓展,HCM与FCM最大的区别在于隶属函数(划分矩阵)的取值不同,HCM的隶属函数只取两个值:0和1,而FCM的隶属函数可以取[0,1]之间的任何数。
K-means和FCM都需要事先给定聚类的类别数,而FCM还需要选取恰当的加权指数α,α的选取对结果有一定的影响,α属于[0,+∞)。
二、模糊
- “模糊”:
一个元素可以不同程度的属于某几个子集,也就是说元素对于集合的隶属度可以在[0,1]上取连续值。
三、FCM算法
C是聚类数,N是样本个数。U是隶属度矩阵,V是聚类中心。
-
目标函数:
目标函数 -
更新公式:
-
算法
-
S1:初始化参数:加权指数m,簇心数目C,以及迭代停止阈值ε。
S2:随机初始化隶属度矩阵U,注意满足式(目标函数)。
S3:式(2)更新簇心Vk。
S4:式(1)更新隶属度矩阵U
S5:如果隶属度矩阵U满足式(5)则返回U并结束算法,否则转到S2
四、流程图
五、程序
import numpy as np
import matplotlib.pyplot as plt
import time
star = time.time() # 计时
img = plt.imread('d:\\OpenCVpic\\Happyfish.jpg') # 读取图片信息,存储在一个三维数组中
row = img.shape[0]
col = img.shape[1]
plt.figure(1)
plt.subplot(221)
plt.imshow(img)
def fcm(data, threshold, k, m):
# 0.初始化
data = data.reshape(-1, 3)
cluster_center = np.zeros([k, 3]) # 簇心
distance = np.zeros([k, row*col]) # 欧氏距离
times = 0 # 迭代次数
goal_j = np.array([]) # 迭代终止条件:目标函数
goal_u = np.array([]) # 迭代终止条件:隶属度矩阵元素最大变化量
# 1.初始化U
u = np.random.dirichlet(np.ones(k), row*col).T # 形状(k, col*rol),任意一列元素和=1
# for s in range(50):
while 1:
times += 1
print('循环:', times)
# 2.簇心update
for i in range(k):
cluster_center[i] = np.sum((np.tile(u[i] ** m, (3, 1))).T * data, axis=0) / np.sum(u[i] ** m)
# 3.U update
# 3.1欧拉距离
for i in range(k):
distance[i] = np.sqrt(np.sum((data - np.tile(cluster_center[i], (row * col, 1))) ** 2, axis=1))
# 3.2目标函数
goal_j = np.append(goal_j, np.sum((u**m)*distance**2))
# 3.3 更新隶属度矩阵
oldu = u.copy() # 记录上一次隶属度矩阵
u = np.zeros([k, row * col])
for i in range(k):
for j in range(k):
u[i] += (distance[i] / distance[j]) ** (2 / (m - 1))
u[i] = 1/u[i]
goal_u = np.append(goal_u, np.max(u - oldu)) # 隶属度元素最大变化量
print('隶属度元素最大变化量', np.max(u - oldu), '目标函数', np.sum((u**m)*distance**2))
# 4.判断:隶属度矩阵元素最大变化量是否小于阈值
if np.max(u - oldu) <= threshold:
break
return u, goal_j, goal_u
if __name__ == '__main__':
img_show, goal1_j, goal2_u = fcm(img, 1e-09, 5, 2)
img_show = np.argmax(img_show, axis=0)
# plt.figure(2)
plt.subplot(223)
plt.plot(goal1_j)
plt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
plt.title('目标函数变化曲线')
plt.xlabel('迭代次数')
plt.ylabel('目标函数')
# plt.figure(3)
plt.subplot(224)
plt.plot(goal2_u)
plt.title('隶属度矩阵相邻两次迭代的元素最大变化量变化曲线')
plt.xlabel('迭代次数')
plt.ylabel('隶属度矩阵相邻两次迭代的元素最大变化量')
# plt.figure(1)
plt.subplot(222)
plt.imshow(img_show.reshape([row, col]))
end = time.time()
print('用时:', end - star)
plt.show()
运行结果
七、资料
1、「[凯鲁嘎吉]的博客:聚类——认识FCM算法
https://www.cnblogs.com/kailugaji/
2、「毕业回老家」的博客:基于K-means的图像分割
https://blog.csdn.net/marujie123/article/details/125721608
3、「毕业回老家」的博客:基于模糊C均值聚类(FCM)的图像分割原理
https://blog.csdn.net/marujie123/article/details/125722953