python中opencv K均值聚類的實(shí)現(xiàn)示例
K均值聚類
- 預(yù)測(cè)的是一個(gè)離散值時(shí),做的工作就是“分類”。
- 預(yù)測(cè)的是一個(gè)連續(xù)值時(shí),做的工作就是“回歸”。
機(jī)器學(xué)習(xí)模型還可以將訓(xùn)練集中的數(shù)據(jù)劃分為若干個(gè)組,每個(gè)組被稱為一個(gè)“簇(cluster)”。這種學(xué)習(xí)方式被稱為“聚類(clusting)”,它的重要特點(diǎn)是在學(xué)習(xí)過程中不需要用標(biāo)簽對(duì)訓(xùn)練樣本進(jìn)行標(biāo)注。也就是說,學(xué)習(xí)過程能夠根據(jù)現(xiàn)有訓(xùn)練集自動(dòng)完成分類(聚類)。
根據(jù)訓(xùn)練數(shù)據(jù)是否有標(biāo)簽,可以將學(xué)習(xí)劃分為監(jiān)督學(xué)習(xí)和無監(jiān)督學(xué)習(xí)。
K近鄰、支持向量機(jī)都是監(jiān)督學(xué)習(xí),提供有標(biāo)簽的數(shù)據(jù)給算法學(xué)習(xí),然后對(duì)數(shù)據(jù)分類
聚類是無監(jiān)督學(xué)習(xí),事先并不知道分類標(biāo)簽是什么,直接對(duì)數(shù)據(jù)分類。
聚類能夠?qū)⒕哂邢嗨茖傩缘膶?duì)象劃分到同一個(gè)集合(簇)中。
聚類方法能夠應(yīng)用于所有對(duì)象,簇內(nèi)的對(duì)象越相似,聚類算法的效果越好。
K均值聚類的基本步驟
K均值聚類是一種將輸入數(shù)據(jù)劃分為k個(gè)簇的簡單的聚類算法,該算法不斷提取當(dāng)前分類的中心點(diǎn)(也稱為質(zhì)心或重心),并最終在分類穩(wěn)定時(shí)完成聚類。
從本質(zhì)上說,K均值聚類是一種迭代算法。
在實(shí)際處理過程中需要進(jìn)行多輪的迭代,直到分組穩(wěn)定不再發(fā)生變化,即可認(rèn)為分組完成。
K均值聚類算法的基本步驟如下:
- 隨機(jī)選取k個(gè)點(diǎn)作為分類的中心點(diǎn)。
- 將每個(gè)數(shù)據(jù)點(diǎn)放到距離它最近的中心點(diǎn)所在的類中。
- 重新計(jì)算各個(gè)分類的數(shù)據(jù)點(diǎn)的平均值,將該平均值作為新的分類中心點(diǎn)。
- 重復(fù)步驟2和步驟3,直到分類穩(wěn)定。
可以是隨機(jī)選取k個(gè)點(diǎn)作為分類的中心點(diǎn),也可以是隨機(jī)生成k個(gè)并不存在于原始數(shù)據(jù)中的數(shù)據(jù)點(diǎn)作為分類中心點(diǎn)。
距離最近: 要進(jìn)行某種形式的距離計(jì)算。(在具體實(shí)現(xiàn)時(shí),可以根據(jù)需要采用不同形式的距離度量方法。)
K均值聚類模塊
OpenCV提供了函數(shù)cv2.kmeans()來實(shí)現(xiàn)K均值聚類。
該函數(shù)的語法格式為:
retval, bestLabels, centers=cv2.kmeans(data, K, bestLabels, criteria, attempts, flags)
- data:輸入的待處理數(shù)據(jù)集合,應(yīng)該是np.float32類型,每個(gè)特征放在單獨(dú)的一列中。
- K:要分出的簇的個(gè)數(shù),即分類的數(shù)目,最常見的是K=2,表示二分類。
- bestLabels:表示計(jì)算之后各個(gè)數(shù)據(jù)點(diǎn)的最終分類標(biāo)簽(索引)。實(shí)際調(diào)用時(shí),參數(shù)bestLabels的值設(shè)置為None。
- criteria:算法迭代的終止條件。當(dāng)達(dá)到最大循環(huán)數(shù)目或者指定的精度閾值時(shí),算法停止繼續(xù)分類迭代計(jì)算。該參數(shù)由3個(gè)子參數(shù)構(gòu)成,分別為type、max_iter和eps。
- type表示終止的類型,可以是三種情況
- cv2.TERM_CRITERIA_EPS:精度滿足eps時(shí),停止迭代。
- cv2.TERM_CRITERIA_MAX_ITER:迭代次數(shù)超過閾值max_iter時(shí),停止迭代。
- cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER:上述兩個(gè)條件中的任意一個(gè)滿足時(shí),停止迭代。
- type表示終止的類型,可以是三種情況
- max_iter:最大迭代次數(shù)。
- eps:精確度的閾值。
- attempts:在具體實(shí)現(xiàn)時(shí),為了獲得最佳分類效果,可能需要使用不同的初始分類值進(jìn)行多次嘗試。指定attempts的值,可以讓算法使用不同的初始值進(jìn)行多次(attempts次)嘗試。
- flags:表示選擇初始中心點(diǎn)的方法,主要有以下3種。
- cv2.KMEANS_RANDOM_CENTERS:隨機(jī)選取中心點(diǎn)。
- cv2.KMEANS_PP_CENTERS:基于中心化算法選取中心點(diǎn)。
- cv2.KMEANS_USE_INITIAL_LABELS:使用用戶輸入的數(shù)據(jù)作為第一次分類中心點(diǎn);如果算法需要嘗試多次(attempts 值大于1時(shí)),后續(xù)嘗試都是使用隨機(jī)值或者半隨機(jī)值作為第一次分類中心點(diǎn)。
- retval:距離值(也稱密度值或緊密度),返回 每個(gè)點(diǎn)到相應(yīng)中心點(diǎn)距離的平方和(是一個(gè)數(shù))。
- bestLabels:各個(gè)數(shù)據(jù)點(diǎn)的最終分類標(biāo)簽(索引)。
- centers:每個(gè)分類的中心點(diǎn)數(shù)據(jù)。
簡單例子
例1:
隨機(jī)生成一組數(shù)據(jù),使用函數(shù)cv2.kmeans()對(duì)其分類。
- 一組數(shù)據(jù)在[0,50]區(qū)間
- 另一組數(shù)據(jù)在[200,250]區(qū)間
- 使用函數(shù)cv2.kmeans()對(duì)它們分類。
主要步驟如下:
數(shù)據(jù)預(yù)處理
使用隨機(jī)函數(shù)隨機(jī)生成兩組數(shù)據(jù),并將它們轉(zhuǎn)換為函數(shù)cv2.kmeans()可以處理的格式。
設(shè)置參數(shù)
設(shè)置函數(shù)cv2.kmeans()的參數(shù)形式。將參數(shù)criteria的值設(shè)置為“(cv2.TERM_CRITERIA_EPS+ cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)”,在達(dá)到一定次數(shù)或者滿足一定精度時(shí)終止迭代。
調(diào)用函數(shù)cv2.kmeans()
調(diào)用函數(shù)cv2.kmeans(),獲取返回值,用于后續(xù)步驟的操作。
確定分類
根據(jù)函數(shù)cv2.kmeans()返回的標(biāo)簽(“0”和“1”),將原始數(shù)據(jù)分為兩組
顯示結(jié)果
繪制經(jīng)過分類的數(shù)據(jù)及中心點(diǎn),觀察分類結(jié)果。
完整程序:
import numpy as np? import cv2? from matplotlib import pyplot as plt? # 隨機(jī)生成兩組數(shù)組? # 生成60個(gè)值在[0,50]內(nèi)的數(shù)據(jù)? num1 = np.random.randint(0,50,60)? # 生成60個(gè)值在[200,250]內(nèi)的數(shù)據(jù)? num2 = np.random.randint(200,250,60)? # 組合數(shù)據(jù)為num num = np.hstack((num1, num2)) # 使用reshape函數(shù)將其轉(zhuǎn)換為(120,1) ? num = num.reshape((120,1)) ?#每個(gè)數(shù)據(jù)為1列 # 轉(zhuǎn)換為float32類型? num = np.float32(num)? # 調(diào)用kmeans模塊? # 設(shè)置參數(shù)criteria的值? criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)? # 設(shè)置參數(shù)flags的值? flags = cv2.KMEANS_RANDOM_CENTERS? # 調(diào)用函數(shù)kmeans? retval, bestLabels, centers = cv2.kmeans(num,2, None, criteria,10, flags)? # 打印返回值? print(retval)? print(bestLabels)? print(centers)? # 獲取分類結(jié)果? n1 = num[bestLabels==0]? n2 = num[bestLabels==1]? ? ?? # 繪制分類結(jié)果? # 繪制原始數(shù)據(jù)? plt.plot(np.ones(len(n1)),n1,'ro')? plt.plot(np.ones(len(n2)),n2,'bo')? # 繪制中心點(diǎn)? #plt.plot([1],centers[0],'rx')? #plt.plot([1],centers[1],'bx')? plt.show()? ?
例2:
有兩種物體:
- 物體1的長和寬都在 [0,20] 內(nèi)
- 物體2的長和寬都在[40,60] 內(nèi)
使用隨機(jī)數(shù)模擬兩種物體的長度和寬度,并使用函數(shù)cv2.kmeans()對(duì)它們分類。
根據(jù)題目要求,主要步驟如下:
- 隨機(jī)生成數(shù)據(jù),并將它們轉(zhuǎn)換為函數(shù)cv2.kmeans()可以處理的形式。
- 設(shè)置函數(shù)cv2.kmeans()的參數(shù)形式。
- 調(diào)用函數(shù)cv2.kmeans()。
- 根據(jù)函數(shù)cv2.kmeans()的返回值,確定分類結(jié)果。
- 繪制經(jīng)過分類的數(shù)據(jù)及中心點(diǎn),觀察分類結(jié)果。
import numpy as np? import cv2? from matplotlib import pyplot as plt? # 隨機(jī)生成兩組數(shù)值? #長和寬都在[0,20]內(nèi)? m1 = np.random.randint(0,20, (30,2))? #長和寬的大小都在[40,60]? m2 = np.random.randint(40,60, (30,2))? # 組合數(shù)據(jù)? m = np.vstack((m1, m2))? # 轉(zhuǎn)換為float32類型? m = np.float32(m)? # 調(diào)用kmeans模塊? # 設(shè)置參數(shù)criteria值? criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)? # 調(diào)用kmeans函數(shù)? ret, label, center=cv2.kmeans(m,2, None, criteria,10, cv2.KMEANS_RANDOM_CENTERS)? ? ?? '''? #打印返回值? print(ret)? print(label)? print(center)? '''? # 根據(jù)kmeans的處理結(jié)果,將數(shù)據(jù)分類,兩大類? res1 = m[label.ravel()==0]? res2 = m[label.ravel()==1]? # 繪制分類結(jié)果數(shù)據(jù)及中心點(diǎn)? plt.scatter(res1[:,0], res1[:,1], c = 'g', marker = 's')? plt.scatter(res2[:,0], res2[:,1], c = 'r', marker = 'o')? plt.scatter(center[0,0], center[0,1], s = 200, c = 'b', marker = 'o')? plt.scatter(center[1,0], center[1,1], s = 200, c = 'b', marker = 's')? plt.xlabel('Height'), plt.ylabel('Width')? plt.show()?
例3:
使用函數(shù)cv2.kmeans()將灰度圖像處理為只有兩個(gè)灰度級(jí)的二值圖像。
需要對(duì)灰度圖像內(nèi)的色彩進(jìn)行分類,將所有的像素點(diǎn)劃分為兩類。然后,用這兩類的中心點(diǎn)像素值替代原有像素值,滿足題目的要求。
主要步驟如下:
圖像預(yù)處理
讀取圖像,并將圖像轉(zhuǎn)換為函數(shù)cv2.kmeans()可以處理的形式。
在讀取圖像時(shí),如果是3個(gè)通道的RGB圖像,需要將圖像的RGB值處理為一個(gè)單獨(dú)的特征值。具體實(shí)現(xiàn)時(shí),用函數(shù)cv2.reshape()完成對(duì)圖像特征值的調(diào)整。
為了滿足函數(shù)cv2.kmeans()的要求,需要將圖像的數(shù)據(jù)類型轉(zhuǎn)換為numpy.float32類型。
設(shè)置函數(shù)cv2.kmeans()的參數(shù)形式
設(shè)置參數(shù)criteria的值為“(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0)”,讓函數(shù)cv2.kmeans()在達(dá)到一定精度或者達(dá)到一定迭代次數(shù)時(shí),即停止迭代。
設(shè)置參數(shù)K的值為2,將所有像素劃分為兩類。
調(diào)用函數(shù)cv2.kmeans()
調(diào)用函數(shù)cv2.kmeans(),得到距離值、分類中心點(diǎn)和分類標(biāo)簽,用于后續(xù)操作。
值替換
將像素點(diǎn)的值替換為當(dāng)前分類的中心點(diǎn)的像素值。
顯示變換前后的圖像
分別顯示原始圖像和二值化圖像。
import numpy as np import cv2 import matplotlib.pyplot as plt # 讀取待處理圖像 img = cv2.imread('./img/hand2.png') # 使用reshape將一個(gè)像素點(diǎn)的RGB值作為一個(gè)單元處理 data = img.reshape((-1,3)) # n行 3列 # 轉(zhuǎn)換為kmeans可以處理的類型 data = np.float32(data) # 調(diào)用kmeans模塊 criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10, 1.0) K =2 ret, label, center=cv2.kmeans(data, K, None, criteria,10, cv2.KMEANS_RANDOM_CENTERS) # 轉(zhuǎn)換為uint8數(shù)據(jù)類型,將每個(gè)像素點(diǎn)都賦值為當(dāng)前分類的中心點(diǎn)像素值 # 將center的值轉(zhuǎn)換為uint8 center = np.uint8(center) # 使用center內(nèi)的值替換原像素點(diǎn)的值 res1 = center[label.flatten()] # 根據(jù)索引來取值,最后結(jié)果的大小同索引的大小 # 使用reshape調(diào)整替換后的圖像 res2 = res1.reshape((img.shape)) # 顯示處理結(jié)果 plt.subplot(121) plt.imshow(img[:,:,::-1]) plt.axis('off') plt.subplot(122) plt.imshow(res2[:,:,::-1]) plt.axis('off') plt.show()
調(diào)整程序中的K值,就能改變圖像的顯示結(jié)果。例如,K=8,則可以讓圖像顯示8個(gè)灰度級(jí)。
到此這篇關(guān)于python中opencv K均值聚類的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)opencv K均值聚類內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于騰訊云服務(wù)器部署微信小程序后臺(tái)服務(wù)(Python+Django)
這篇文章主要介紹了基于騰訊云服務(wù)器部署微信小程序后臺(tái)服務(wù)(Python+Django),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2019-05-05關(guān)于Python網(wǎng)絡(luò)爬蟲框架scrapy
這篇文章主要介紹了關(guān)于Python網(wǎng)絡(luò)爬蟲框架scrapy,爬蟲框架是實(shí)現(xiàn)爬蟲功能的一個(gè)軟件結(jié)構(gòu)和功能組件的集合,需要的朋友可以參考下2023-04-04使用python爬蟲實(shí)現(xiàn)抓取動(dòng)態(tài)加載數(shù)據(jù)
這篇文章主要給大家介紹了如何用python爬蟲抓取豆瓣電影“分類排行榜”中的電影數(shù)據(jù),比如輸入“犯罪”則會(huì)輸出所有犯罪影片的電影名稱、評(píng)分,文中通過代碼示例和圖文介紹的非常詳細(xì),需要的朋友可以參考下2024-01-01Yolov5多邊形標(biāo)簽和JSON數(shù)據(jù)格式轉(zhuǎn)換
通過labelme對(duì)圖進(jìn)行標(biāo)注后,得到的是json文件,而Yolov5對(duì)數(shù)據(jù)進(jìn)行模型構(gòu)建的時(shí)候,讀取需要的是txt格式的文件。所以需要先通過Python進(jìn)行文件格式的轉(zhuǎn)換,需要的朋友可以參考下2023-05-05解決ImportError: cannot import name ‘Imput
您遇到的ImportError: cannot import name ‘Imputer‘錯(cuò)誤提示表明您嘗試導(dǎo)入一個(gè)名為’Imputer’的模塊或類,但是該模塊或類無法找到,本文小編給大家介紹了如何解決這個(gè)問題,需要的朋友可以參考下2023-10-10python實(shí)現(xiàn)簡易學(xué)生信息管理系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)簡易學(xué)生信息管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-09-09python opencv 圖像處理之圖像算數(shù)運(yùn)算及修改顏色空間
這篇文章主要介紹了python opencv 圖像處理之圖像算數(shù)運(yùn)算及修改顏色空間,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下2022-08-08Python利用flask sqlalchemy實(shí)現(xiàn)分頁效果
這篇文章主要為大家詳細(xì)介紹了利用flask sqlalchemy實(shí)現(xiàn)分頁效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-07-07IDEA創(chuàng)建python項(xiàng)目詳細(xì)圖文教程
在開始編寫Python代碼之前,需要在IDEA中配置Python環(huán)境,下面這篇文章主要給大家介紹了關(guān)于IDEA創(chuàng)建python項(xiàng)目的相關(guān)資料,文中通過圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10