Python基于紋理背景和聚類算法實(shí)現(xiàn)圖像分割詳解
一.基于紋理背景的圖像分割
該部分主要講解基于圖像紋理信息(顏色)、邊界信息(反差)和背景信息的圖像分割算法。在OpenCV中,GrabCut算法能夠有效地利用紋理信息和邊界信息分割背景,提取圖像目標(biāo)物體。該算法是微軟研究院基于圖像分割和摳圖的課題,它能有效地將目標(biāo)圖像分割提取,如圖1所示[1]。

GrabCut算法原型如下所示:
mask, bgdModel, fgdModel = grabCut(img, mask, rect, bgdModel, fgdModel, iterCount[, mode])
– image表示輸入圖像,為8位三通道圖像
– mask表示蒙板圖像,輸入/輸出的8位單通道掩碼,確定前景區(qū)域、背景區(qū)域、不確定區(qū)域。當(dāng)模式設(shè)置為GC_INIT_WITH_RECT時(shí),該掩碼由函數(shù)初始化
– rect表示前景對(duì)象的矩形坐標(biāo),其基本格式為(x, y, w, h),分別為左上角坐標(biāo)和寬度、高度
– bdgModel表示后臺(tái)模型使用的數(shù)組,通常設(shè)置為大小為(1, 65)np.float64的數(shù)組
– fgdModel表示前臺(tái)模型使用的數(shù)組,通常設(shè)置為大小為(1, 65)np.float64的數(shù)組
– iterCount表示算法運(yùn)行的迭代次數(shù)
– mode是cv::GrabCutModes操作模式之一,cv2.GC_INIT_WITH_RECT 或 cv2.GC_INIT_WITH_MASK表示使用矩陣模式或蒙板模式
下面是Python的實(shí)現(xiàn)代碼,通過調(diào)用np.zeros()函數(shù)創(chuàng)建掩碼、fgbModel和bgModel,接著定義rect矩形范圍,調(diào)用函數(shù)grabCut()實(shí)現(xiàn)圖像分割。由于該方法會(huì)修改掩碼,像素會(huì)被標(biāo)記為不同的標(biāo)志來指明它們是背景或前景。接著將所有的0像素和2像素點(diǎn)賦值為0(背景),而所有的1像素和3像素點(diǎn)賦值為1(前景),完整代碼如下所示。
# -*- coding: utf-8 -*-
# By: Eastmount
import cv2
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
#讀取圖像
img = cv2.imread('nv.png')
#灰度化處理圖像
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#設(shè)置掩碼、fgbModel、bgModel
mask = np.zeros(img.shape[:2], np.uint8)
bgdModel = np.zeros((1,65), np.float64)
fgdModel = np.zeros((1,65), np.float64)
#矩形坐標(biāo)
rect = (100, 100, 500, 800)
#圖像分割
cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 5,
cv2.GC_INIT_WITH_RECT)
#設(shè)置新掩碼:0和2做背景
mask2 = np.where((mask==2)|(mask==0), 0, 1).astype('uint8')
#設(shè)置字體
matplotlib.rcParams['font.sans-serif']=['SimHei']
#顯示原圖
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.subplot(1,2,1)
plt.imshow(img)
plt.title('(a)原始圖像')
plt.xticks([]), plt.yticks([])
#使用蒙板來獲取前景區(qū)域
img = img*mask2[:, :, np.newaxis]
plt.subplot(1,2,2)
plt.imshow(img)
plt.title('(b)目標(biāo)圖像')
plt.colorbar()
plt.xticks([]), plt.yticks([])
plt.show()
輸出圖像如圖2所示,圖2(a)為原始圖像,圖2(b)為圖像分割后提取的目標(biāo)人物,但人物右部分的背景仍然存在。如何移除這些背景呢?這里需要使用自定義的掩碼進(jìn)行提取,讀取一張灰色背景輪廓圖,從而分離背景與前景,希望讀者下來實(shí)現(xiàn)該功能。

二.基于K-Means聚類算法的區(qū)域分割
K-Means聚類是最常用的聚類算法,最初起源于信號(hào)處理,其目標(biāo)是將數(shù)據(jù)點(diǎn)劃分為K個(gè)類簇,找到每個(gè)簇的中心并使其度量最小化。該算法的最大優(yōu)點(diǎn)是簡(jiǎn)單、便于理解,運(yùn)算速度較快,缺點(diǎn)是只能應(yīng)用于連續(xù)型數(shù)據(jù),并且要在聚類前指定聚集的類簇?cái)?shù)[2]。
下面是K-Means聚類算法的分析流程,步驟如下:
- 第一步,確定K值,即將數(shù)據(jù)集聚集成K個(gè)類簇或小組;
- 第二步,從數(shù)據(jù)集中隨機(jī)選擇K個(gè)數(shù)據(jù)點(diǎn)作為質(zhì)心(Centroid)或數(shù)據(jù)中心;
- 第三步,分別計(jì)算每個(gè)點(diǎn)到每個(gè)質(zhì)心之間的距離,并將每個(gè)點(diǎn)劃分到離最近質(zhì)心的小組,跟定了那個(gè)質(zhì)心;
- 第四步,當(dāng)每個(gè)質(zhì)心都聚集了一些點(diǎn)后,重新定義算法選出新的質(zhì)心;
- 第五步,比較新的質(zhì)心和老的質(zhì)心,如果新質(zhì)心和老質(zhì)心之間的距離小于某一個(gè)閾值,則表示重新計(jì)算的質(zhì)心位置變化不大,收斂穩(wěn)定,則認(rèn)為聚類已經(jīng)達(dá)到了期望的結(jié)果,算法終止;
- 第六步,如果新的質(zhì)心和老的質(zhì)心變化很大,即距離大于閾值,則繼續(xù)迭代執(zhí)行第三步到第五步,直到算法終止。
圖29-3是對(duì)身高和體重進(jìn)行聚類的算法,將數(shù)據(jù)集的人群聚集成三類。

在圖像處理中,通過K-Means聚類算法可以實(shí)現(xiàn)圖像分割、圖像聚類、圖像識(shí)別等操作,本小節(jié)主要用來進(jìn)行圖像顏色分割。假設(shè)存在一張100×100像素的灰度圖像,它由10000個(gè)RGB灰度級(jí)組成,我們通過K-Means可以將這些像素點(diǎn)聚類成K個(gè)簇,然后使用每個(gè)簇內(nèi)的質(zhì)心點(diǎn)來替換簇內(nèi)所有的像素點(diǎn),這樣就能實(shí)現(xiàn)在不改變分辨率的情況下量化壓縮圖像顏色,實(shí)現(xiàn)圖像顏色層級(jí)分割。
在OpenCV中,Kmeans()函數(shù)原型如下所示:
retval, bestLabels, centers = kmeans(data, K, bestLabels, criteria, attempts, flags[, centers])
– data表示聚類數(shù)據(jù),最好是np.flloat32類型的N維點(diǎn)集
– K表示聚類類簇?cái)?shù)
– bestLabels表示輸出的整數(shù)數(shù)組,用于存儲(chǔ)每個(gè)樣本的聚類標(biāo)簽索引
– criteria表示算法終止條件,即最大迭代次數(shù)或所需精度。在某些迭代中,一旦每個(gè)簇中心的移動(dòng)小于criteria.epsilon,算法就會(huì)停止
– attempts表示重復(fù)試驗(yàn)kmeans算法的次數(shù),算法返回產(chǎn)生最佳緊湊性的標(biāo)簽
– flags表示初始中心的選擇,兩種方法是cv2.KMEANS_PP_CENTERS ;和cv2.KMEANS_RANDOM_CENTERS
– centers表示集群中心的輸出矩陣,每個(gè)集群中心為一行數(shù)據(jù)
下面使用該方法對(duì)灰度圖像顏色進(jìn)行分割處理,需要注意,在進(jìn)行K-Means聚類操作之前,需要將RGB像素點(diǎn)轉(zhuǎn)換為一維的數(shù)組,再將各形式的顏色聚集在一起,形成最終的顏色分割。
# -*- coding: utf-8 -*-
# By: Eastmount
import cv2
import numpy as np
import matplotlib.pyplot as plt
#讀取原始圖像灰度顏色
img = cv2.imread('scenery.png', 0)
#獲取圖像高度、寬度
rows, cols = img.shape[:]
#圖像二維像素轉(zhuǎn)換為一維
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)
#設(shè)置標(biāo)簽
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]))
#用來正常顯示中文標(biāo)簽
plt.rcParams['font.sans-serif']=['SimHei']
#顯示圖像
titles = ['原始圖像', '聚類圖像']
images = [img, dst]
for i in range(2):
plt.subplot(1,2,i+1), plt.imshow(images[i], 'gray'),
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
輸出結(jié)果如圖4所示,左邊為灰度圖像,右邊為K-Means聚類后的圖像,它將灰度級(jí)聚集成四個(gè)層級(jí),相似的顏色或區(qū)域聚集在一起。

下面代碼是對(duì)彩色的圖像進(jìn)行顏色分割處理,它將彩色的圖像聚集成2類、4類和64類。
# -*- coding: utf-8 -*-
# By: Eastmount
import cv2
import numpy as np
import matplotlib.pyplot as plt
#讀取原始圖像
img = cv2.imread('scenery.png')
#圖像二維像素轉(zhuǎn)換為一維
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)
#設(shè)置標(biāo)簽
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)
#圖像轉(zhuǎn)換回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))
#圖像轉(zhuǎn)換為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)
#用來正常顯示中文標(biāo)簽
plt.rcParams['font.sans-serif']=['SimHei']
#顯示圖像
titles = ['原始圖像', '聚類圖像 K=2', '聚類圖像 K=4',
'聚類圖像 K=8', '聚類圖像 K=16', '聚類圖像 K=64']
images = [img, dst2, dst4, dst8, dst16, dst64]
for i in range(6):
plt.subplot(2,3,i+1), plt.imshow(images[i], 'gray'),
plt.title(titles[i])
plt.xticks([]),plt.yticks([])
plt.show()
輸出結(jié)果如圖5所示,它對(duì)比了原始圖像和各K-Means聚類處理后的圖像。當(dāng)K=2時(shí),聚集成2種顏色;當(dāng)K=4時(shí),聚集成4種顏色;當(dāng)K=8時(shí),聚集成8種顏色;當(dāng)K=16時(shí),聚集成16種顏色;當(dāng)K=64時(shí),聚集成64種顏色。

同樣,如果是人物圖像顯示如圖6所示,比如小珞珞。

三.總結(jié)
本文主要講解了常用的圖像分割方法,包括基于紋理背景和聚類算法的圖像分割方法。希望讀者能結(jié)合本文知識(shí)點(diǎn),圍繞自己的研究領(lǐng)域或工程項(xiàng)目進(jìn)行深入的學(xué)習(xí),實(shí)現(xiàn)所需的圖像處理。
到此這篇關(guān)于Python基于紋理背景和聚類算法實(shí)現(xiàn)圖像分割詳解的文章就介紹到這了,更多相關(guān)Python圖像分割內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Python使用樹狀圖實(shí)現(xiàn)可視化聚類詳解
- python 層次聚類算法圖文示例
- Python K-means實(shí)現(xiàn)簡(jiǎn)單圖像聚類的示例代碼
- Python使用OpenCV和K-Means聚類對(duì)畢業(yè)照進(jìn)行圖像分割
- Python實(shí)現(xiàn)K-means聚類算法并可視化生成動(dòng)圖步驟詳解
- 在Python中使用K-Means聚類和PCA主成分分析進(jìn)行圖像壓縮
- python基于K-means聚類算法的圖像分割
- python聚類算法解決方案(rest接口/mpp數(shù)據(jù)庫/json數(shù)據(jù)/下載圖片及數(shù)據(jù))
- 使用python實(shí)現(xiàn)3D聚類圖示例代碼
相關(guān)文章
Pandas數(shù)據(jù)合并的兩種實(shí)現(xiàn)方法
本文主要介紹了Pandas數(shù)據(jù)合并的兩種實(shí)現(xiàn)方法,DataFrame數(shù)據(jù)合并主要使用merge()方法和concat()方法,具有一定的參考價(jià)值,感興趣的可以了解一下2023-11-11
python使用ctypes調(diào)用dll遇到的坑解決記錄
這篇文章主要為大家介紹了python使用ctypes調(diào)用dll遇到的坑解決記錄,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
python求兩個(gè)時(shí)間的時(shí)間差(實(shí)例代碼)
我們?cè)谟胮ython進(jìn)行分析的時(shí)候,可能會(huì)碰到計(jì)算兩個(gè)日期的時(shí)間差。下面為大家介紹一下如何計(jì)算兩個(gè)時(shí)間的時(shí)間差,需要的朋友可以參考下2022-11-11
用python標(biāo)準(zhǔn)庫difflib比較兩份文件的異同詳解
今天小編就為大家分享一篇用python標(biāo)準(zhǔn)庫difflib比較兩份文件的異同詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-11-11
使用Python實(shí)現(xiàn)Oracle數(shù)據(jù)庫自動(dòng)巡檢程序
這篇文章主要為大家詳細(xì)介紹了如何創(chuàng)建一個(gè)Oracle數(shù)據(jù)庫自動(dòng)巡檢程序,以確保數(shù)據(jù)庫的順暢運(yùn)行,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-01-01
python定間隔取點(diǎn)(np.linspace)的實(shí)現(xiàn)
今天小編就為大家分享一篇python定間隔取點(diǎn)(np.linspace)的實(shí)現(xiàn),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2019-11-11

