摘要:本篇文章主要講解基於理論的圖像分割方法,通過K-Means聚類演算法實現圖像分割或顏色分層處理。 本文分享自華為雲社區《[Python圖像處理] 十九.圖像分割之基於K-Means聚類的區域分割》,作者: eastmount。 本篇文章主要講解基於理論的圖像分割方法,通過K-Means聚類演算法實 ...
摘要:本篇文章主要講解基於理論的圖像分割方法,通過K-Means聚類演算法實現圖像分割或顏色分層處理。
本文分享自華為雲社區《[Python圖像處理] 十九.圖像分割之基於K-Means聚類的區域分割》,作者: eastmount。
本篇文章主要講解基於理論的圖像分割方法,通過K-Means聚類演算法實現圖像分割或顏色分層處理。基礎性文章,希望對你有所幫助。
- 一.K-Means原理
- 二.K-Means聚類分割灰度圖像
- 三.K-Means聚類對比分割彩色圖像
註意 :該部分知識均為楊秀璋查閱資料撰寫,未經授權禁止轉載,謝謝!!如果有問題隨時私聊我,只望您能從這個系列中學到知識,一起加油喔~
該系列在github所有源代碼:https://github.com/eastmountyxz/ImageProcessing-Python
一.K-Means聚類原理
第一部分知識主要參考自己的新書《Python網路數據爬取及分析從入門到精通(分析篇)》和之前的博客 [Python數據挖掘課程] 二.Kmeans聚類數據分析。
K-Means聚類是最常用的聚類演算法,最初起源於信號處理,其目標是將數據點劃分為K個類簇,找到每個簇的中心並使其度量最小化。該演算法的最大優點是簡單、便於理解,運算速度較快,缺點是只能應用於連續型數據,並且要在聚類前指定聚集的類簇數。
下麵是K-Means聚類演算法的分析流程,步驟如下:
- 第一步,確定K值,即將數據集聚集成K個類簇或小組。
- 第二步,從數據集中隨機選擇K個數據點作為質心(Centroid)或數據中心。
- 第三步,分別計算每個點到每個質心之間的距離,並將每個點劃分到離最近質心的小組,跟定了那個質心。
- 第四步,當每個質心都聚集了一些點後,重新定義演算法選出新的質心。
- 第五步,比較新的質心和老的質心,如果新質心和老質心之間的距離小於某一個閾值,則表示重新計算的質心位置變化不大,收斂穩定,則認為聚類已經達到了期望的結果,演算法終止。
- 第六步,如果新的質心和老的質心變化很大,即距離大於閾值,則繼續迭代執行第三步到第五步,直到演算法終止。
下圖是對身高和體重進行聚類的演算法,將數據集的人群聚集成三類。
二.K-Means聚類分割灰度圖像
在圖像處理中,通過K-Means聚類演算法可以實現圖像分割、圖像聚類、圖像識別等操作,本小節主要用來進行圖像顏色分割。假設存在一張100×100像素的灰度圖像,它由10000個RGB灰度級組成,我們通過K-Means可以將這些像素點聚類成K個簇,然後使用每個簇內的質心點來替換簇內所有的像素點,這樣就能實現在不改變解析度的情況下量化壓縮圖像顏色,實現圖像顏色層級分割。
在OpenCV中,Kmeans()函數原型如下所示:
retval, bestLabels, centers = kmeans(data, K, bestLabels, criteria, attempts, flags[, centers])
- data表示聚類數據,最好是np.flloat32類型的N維點集
- K表示聚類類簇數
- bestLabels表示輸出的整數數組,用於存儲每個樣本的聚類標簽索引
- criteria表示演算法終止條件,即最大迭代次數或所需精度。在某些迭代中,一旦每個簇中心的移動小於criteria.epsilon,演算法就會停止
- attempts表示重覆試驗kmeans演算法的次數,演算法返回產生最佳緊湊性的標簽
- flags表示初始中心的選擇,兩種方法是cv2.KMEANS_PP_CENTERS ;和cv2.KMEANS_RANDOM_CENTERS
- centers表示集群中心的輸出矩陣,每個集群中心為一行數據
下麵使用該方法對灰度圖像顏色進行分割處理,需要註意,在進行K-Means聚類操作之前,需要將RGB像素點轉換為一維的數組,再將各形式的顏色聚集在一起,形成最終的顏色分割。
# coding: utf-8 import cv2 import numpy as np import matplotlib.pyplot as plt #讀取原始圖像灰度顏色 img = cv2.imread('scenery.png', 0) print img.shape #獲取圖像高度、寬度 rows, cols = img.shape[:] #圖像二維像素轉換為一維 data = img.reshape((rows * cols, 1)) data = np.float32(data) #定義中心 (type,max_iter,epsilon) criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0) #設置標簽 flags = cv2.KMEANS_RANDOM_CENTERS #K-Means聚類 聚集成4類 compactness, labels, centers = cv2.kmeans(data, 4, None, criteria, 10, flags) #生成最終圖像 dst = labels.reshape((img.shape[0], img.shape[1])) #用來正常顯示中文標簽 plt.rcParams['font.sans-serif']=['SimHei'] #顯示圖像 titles = [u'原始圖像', u'聚類圖像'] images = [img, dst] for i in xrange(2): plt.subplot(1,2,i+1), plt.imshow(images[i], 'gray'), plt.title(titles[i]) plt.xticks([]),plt.yticks([]) plt.show()
輸出結果如圖所示,左邊為灰度圖像,右邊為K-Means聚類後的圖像,它將灰度級聚集成四個層級,相似的顏色或區域聚集在一起。
三.K-Means聚類對比分割彩色圖像
下麵代碼是對彩色圖像進行顏色分割處理,它將彩色圖像聚集成2類、4類和64類。
# coding: utf-8 import cv2 import numpy as np import matplotlib.pyplot as plt #讀取原始圖像 img = cv2.imread('scenery.png') print img.shape #圖像二維像素轉換為一維 data = img.reshape((-1,3)) data = np.float32(data) #定義中心 (type,max_iter,epsilon) criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0) #設置標簽 flags = cv2.KMEANS_RANDOM_CENTERS #K-Means聚類 聚集成2類 compactness, labels2, centers2 = cv2.kmeans(data, 2, None, criteria, 10, flags) #K-Means聚類 聚集成4類 compactness, labels4, centers4 = cv2.kmeans(data, 4, None, criteria, 10, flags) #K-Means聚類 聚集成8類 compactness, labels8, centers8 = cv2.kmeans(data, 8, None, criteria, 10, flags) #K-Means聚類 聚集成16類 compactness, labels16, centers16 = cv2.kmeans(data, 16, None, criteria, 10, flags) #K-Means聚類 聚集成64類 compactness, labels64, centers64 = cv2.kmeans(data, 64, None, criteria, 10, flags) #圖像轉換回uint8二維類型 centers2 = np.uint8(centers2) res = centers2[labels2.flatten()] dst2 = res.reshape((img.shape)) centers4 = np.uint8(centers4) res = centers4[labels4.flatten()] dst4 = res.reshape((img.shape)) centers8 = np.uint8(centers8) res = centers8[labels8.flatten()] dst8 = res.reshape((img.shape)) centers16 = np.uint8(centers16) res = centers16[labels16.flatten()] dst16 = res.reshape((img.shape)) centers64 = np.uint8(centers64) res = centers64[labels64.flatten()] dst64 = res.reshape((img.shape)) #圖像轉換為RGB顯示 img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) dst2 = cv2.cvtColor(dst2, cv2.COLOR_BGR2RGB) dst4 = cv2.cvtColor(dst4, cv2.COLOR_BGR2RGB) dst8 = cv2.cvtColor(dst8, cv2.COLOR_BGR2RGB) dst16 = cv2.cvtColor(dst16, cv2.COLOR_BGR2RGB) dst64 = cv2.cvtColor(dst64, cv2.COLOR_BGR2RGB) #用來正常顯示中文標簽 plt.rcParams['font.sans-serif']=['SimHei'] #顯示圖像 titles = [u'原始圖像', u'聚類圖像 K=2', u'聚類圖像 K=4', u'聚類圖像 K=8', u'聚類圖像 K=16', u'聚類圖像 K=64'] images = [img, dst2, dst4, dst8, dst16, dst64] for i in xrange(6): plt.subplot(2,3,i+1), plt.imshow(images[i], 'gray'), plt.title(titles[i]) plt.xticks([]),plt.yticks([]) plt.show()
輸出結果如下圖所示,當K=2顏色聚集成兩種,當K=64顏色聚集成64種。