python基於K-means聚類演算法的影象分割
阿新 • • 發佈:2020-01-09
1 K-means演算法
實際上,無論是從演算法思想,還是具體實現上,K-means演算法是一種很簡單的演算法。它屬於無監督分類,通過按照一定的方式度量樣本之間的相似度,通過迭代更新聚類中心,當聚類中心不再移動或移動差值小於閾值時,則就樣本分為不同的類別。
1.1 演算法思路
- 隨機選取聚類中心
- 根據當前聚類中心,利用選定的度量方式,分類所有樣本點
- 計算當前每一類的樣本點的均值,作為下一次迭代的聚類中心
- 計算下一次迭代的聚類中心與當前聚類中心的差距
- 如4中的差距小於給定迭代閾值時,迭代結束。反之,至2繼續下一次迭代
1.2 度量方式
根據聚類中心,將所有樣本點分為最相似的類別。這需要一個有效的盤踞,平方差是最常用的度量方式,如下
2 應用於影象分割
我們知道:無論是灰度圖還是RGB彩色圖,實際上都是存有灰度值的矩陣,所以,影象的資料格式決定了在影象分割方向上,使用K-means聚類演算法是十分容易也十分具體的。
2.1 Code
匯入必要的包
import numpy as np import random
損失函式
def loss_function(present_center,pre_center): ''' 損失函式,計算上一次與當前聚類中的差異(畫素差的平方和) :param present_center: 當前聚類中心 :param pre_center: 上一次聚類中心 :return: 損失值 ''' present_center = np.array(present_center) pre_center = np.array(pre_center) return np.sum((present_center - pre_center)**2)
分類器
def classifer(intput_signal,center): ''' 分類器(通過當前的聚類中心,給輸入影象分類) :param intput_signal: 輸入影象 :param center: 聚類中心 :return: 標籤矩陣 ''' input_row,input_col= intput_signal.shape # 輸入影象的尺寸 pixls_labels = np.zeros((input_row,input_col)) # 儲存所有畫素標籤 pixl_distance_t = [] # 單個元素與所有聚類中心的距離,臨時用 for i in range(input_row): for j in range(input_col): # 計算每個畫素與所有聚類中心的差平方 for k in range(len(center)): distance_t = np.sum(abs((intput_signal[i,j]).astype(int) - center[k].astype(int))**2) pixl_distance_t.append(distance_t) # 差異最小則為該類 pixls_labels[i,j] = int(pixl_distance_t.index(min(pixl_distance_t))) # 清空該list,為下一個畫素點做準備 pixl_distance_t = [] return pixls_labels
基於k-means演算法的影象分割
def k_means(input_signal,center_num,threshold): ''' 基於k-means演算法的影象分割(適用於灰度圖) :param input_signal: 輸入影象 :param center_num: 聚類中心數目 :param threshold: 迭代閾值 :return: ''' input_signal_cp = np.copy(input_signal) # 輸入訊號的副本 input_row,input_col = input_signal_cp.shape # 輸入影象的尺寸 pixls_labels = np.zeros((input_row,input_col)) # 儲存所有畫素標籤 # 隨機初始聚類中心行標與列標 initial_center_row_num = [i for i in range(input_row)] random.shuffle(initial_center_row_num) initial_center_row_num = initial_center_row_num[:center_num] initial_center_col_num = [i for i in range(input_col)] random.shuffle(initial_center_col_num) initial_center_col_num = initial_center_col_num[:center_num] # 當前的聚類中心 present_center = [] for i in range(center_num): present_center.append(input_signal_cp[initial_center_row_num[i],initial_center_row_num[i]]) pixls_labels = classifer(input_signal_cp,present_center) num = 0 # 用於記錄迭代次數 while True: pre_centet = present_center.copy() # 儲存前一次的聚類中心 # 計算當前聚類中心 for n in range(center_num): temp = np.where(pixls_labels == n) present_center[n] = sum(input_signal_cp[temp].astype(int)) / len(input_signal_cp[temp]) # 根據當前聚類中心分類 pixls_labels = classifer(input_signal_cp,present_center) # 計算上一次聚類中心與當前聚類中心的差異 loss = loss_function(present_center,pre_centet) num = num + 1 print("Step:"+ str(num) + " Loss:" + str(loss)) # 當損失小於迭代閾值時,結束迭代 if loss <= threshold: break return pixls_labels
3 分類效果
聚類中心個數=3,迭代閾值為=1
聚類中心個數=3,迭代閾值為=1
4 GitHub
click me
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。