Principle of image segmentation based on fuzzy C-means clustering (FCM) + detailed explanation of python code

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

Guess you like

Origin blog.csdn.net/marujie123/article/details/125722953