1. Fuzzy
"Fuzzy": An element can belong to certain subsets to varying degrees , that is to say, the degree of membership of an element to a set can take continuous values on [0,1].
Two, steps
2.1 steps
translate:
S1: Initialization parameters: weighting index m, number of cluster centers C, and iteration stop threshold ε .
S2: Randomly initialize the membership matrix U, and pay attention to satisfy the formula (2-2).
S3: Equation (2-3) updates the cluster center c.
S4: Equation (2-4) updates the membership matrix U
S5: If the membership degree matrix U satisfies formula (2-5), return U and end the algorithm, otherwise go to S2
The various formats are as follows:
2.2 Flowchart
One of the more steps in the flowchart is the calculation of the objective function J. This step is optional. In order to observe the change trend of the objective function, we have added the step of calculating the objective function to both the flowchart and the code.
3. Code
import numpy as np
import matplotlib.pyplot as plt
import time
star = time.time() # 计时
img = plt.imread('1.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()
4. How to use the code?
The first step is to put the image to be divided into the project file, like this:
The second step, the fifth line of the code: 'img = plt.imread()', add the picture path in the brackets: "picture name. file format", for example, 1.jpeg, 2.bmp and so on.
5. Running results
1. The threshold of the iteration termination condition: 1e-09; the total number of clusters: 5; m=2, iterated 114 times
2. Iteration termination condition: 1e-09; total number of clusters: 2; m=2, 16 iterations
3. Iteration termination condition: 1e-09; total number of clusters: 5; m=2, iterated 170 times, and took 2306s
Sixth, the termination condition is that the change value of the objective function is less than the threshold:
6.1 Steps
S1: Initialization parameters: weighting index m, number of cluster centers C, and iteration stop threshold ε .
S2: Randomly initialize the membership matrix U, and pay attention to satisfy the formula (2-2).
S3: Equation (2-3) updates the cluster center c.
S4: Equation (2-1) calculates the objective function, if the change value is less than the threshold, return U and end the algorithm, otherwise go to S2
S5: Equation (2-4) updates the membership matrix U
6.2 Flowchart
7. Detailed Code Explanation
7.1 Generate random numbers that sum to 1
7.1.1 Drake Distribution
Generate a two-dimensional array of (m, n), the sum of elements in each row = 1
import numpy as np
x = np.random.dirichlet(np.ones(n), size=m)
7.1.2 Return value
Shape: (1, 20), two-dimensional array.
Convert to vector: x=x[0]
Type: ndarray
7.2 Three-dimensional arrays
7.2.1 3D and 2D
A three-dimensional array of shape (k, m, n), as opposed to k two-dimensional arrays of shape (m, n)
7.2.2 Indexing two-dimensional arrays
Three-dimensional array arr, shape (k, m, n). The first two-dimensional array of arr is arr[0]
7.3 Adding new values to arrays of unknown shape
7.3.1 Application Scenarios
In a cycle, where the total number of cycles is not known, it is necessary to record the results of each cycle. That is, it is necessary to add elements to an array of unknown length.
For example, in the code, the value of the objective function is recorded for each loop, but the total number of loops is not determined each time.
7.3.2 Implementation
First define x as an empty array, and then add new values through x.append().
x = np.array([])
for i in range(n):
…
x.append(data)
There are also some explanations about grammar, you can read the following article, although it is the kmeans algorithm, the programming principle is similar.
Image segmentation based on K-means (detailed explanation of python code) - Programmer Sought