欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python基于均值漂移算法和分水嶺算法實(shí)現(xiàn)圖像分割

 更新時(shí)間:2023年01月11日 08:39:04   作者:Eastmount  
圖像分割是將圖像分成若干具有獨(dú)特性質(zhì)的區(qū)域并提取感興趣目標(biāo)的技術(shù)和過程。這篇文章將詳細(xì)講解基于均值漂移算法和分水嶺算法的圖像分割,需要的可以參考一下

一.基于均值漂移算法的圖像分割

均值漂移(Mean Shfit)算法是一種通用的聚類算法,最早是1975年Fukunaga等人在一篇關(guān)于概率密度梯度函數(shù)的估計(jì)論文中提出[1]。它是一種無參估計(jì)算法,沿著概率梯度的上升方向?qū)ふ曳植嫉姆逯?。Mean Shift算法先算出當(dāng)前點(diǎn)的偏移均值,移動該點(diǎn)到其偏移均值,然后以此為新的起始點(diǎn),繼續(xù)移動,直到滿足一定的條件結(jié)束。

圖像分割中可以利用均值漂移算法的特性,實(shí)現(xiàn)彩色的圖像分割。在OpenCV中提供的函數(shù)為pyrMeanShiftFiltering(),該函數(shù)嚴(yán)格來說并不是圖像分割,而是圖像在色彩層面的平滑濾波,它可以中和色彩分布相近的顏色,平滑色彩細(xì)節(jié),侵蝕掉面積較小的顏色區(qū)域,所以在OpenCV中它的后綴是濾波“Filter”,而不是分割“segment”。該函數(shù)原型如下所示:

dst = pyrMeanShiftFiltering(src, sp, sr[, dst[, maxLevel[, termcrit]]])

– src表示輸入圖像,8位三通道的彩色的圖像

– dst表示輸出圖像,需同輸入圖像具有相同的大小和類型

– sp表示定義漂移物理空間半徑的大小

– sr表示定義漂移色彩空間半徑的大小

– maxLevel表示定義金字塔的最大層數(shù)

– termcrit表示定義的漂移迭代終止條件,可以設(shè)置為迭代次數(shù)滿足終止,迭代目標(biāo)與中心點(diǎn)偏差滿足終止,或者兩者的結(jié)合

均值漂移pyrMeanShiftFiltering()函數(shù)的執(zhí)行過程是如下:

  • 構(gòu)建迭代空間。以輸入圖像上任一點(diǎn)P0為圓心,建立以sp為物理空間半徑,sr為色彩空間半徑的球形空間,物理空間上坐標(biāo)為x和y,色彩空間上坐標(biāo)為RGB或HSV,構(gòu)成一個(gè)空間球體。其中x和y表示圖像的長和寬,色彩空間R、G、B在0至255之間。
  • 求迭代空間的向量并移動迭代空間球體重新計(jì)算向量,直至收斂。在上一步構(gòu)建的球形空間中,求出所有點(diǎn)相對于中心點(diǎn)的色彩向量之和,移動迭代空間的中心點(diǎn)到該向量的終點(diǎn),并再次計(jì)算該球形空間中所有點(diǎn)的向量之和,如此迭代,直到在最后一個(gè)空間球體中所求得向量和的終點(diǎn)就是該空間球體的中心點(diǎn)Pn,迭代結(jié)束。
  • 更新輸出圖像dst上對應(yīng)的初始原點(diǎn)P0的色彩值為本輪迭代的終點(diǎn)Pn的色彩值,完成一個(gè)點(diǎn)的色彩均值漂移。
  • 對輸入圖像src上其他點(diǎn),依次執(zhí)行上述三個(gè)步驟,直至遍歷完所有點(diǎn)后,整個(gè)均值偏移色彩濾波完成。

下面的代碼是圖像均值漂移的實(shí)現(xiàn)過程:

# -*- coding: utf-8 -*-
# By: Eastmount
import cv2
import numpy as np
import matplotlib.pyplot as plt

#讀取原始圖像灰度顏色
img = cv2.imread('scenery.png') 

spatialRad = 50 #空間窗口大小
colorRad = 50 #色彩窗口大小
maxPyrLevel = 2 #金字塔層數(shù)

#圖像均值漂移分割
dst = cv2.pyrMeanShiftFiltering( img, spatialRad, colorRad, maxPyrLevel)

#顯示圖像
cv2.imshow('src', img)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()

當(dāng)漂移物理空間半徑設(shè)置為50,漂移色彩空間半徑設(shè)置為50,金字塔層數(shù) 為2,輸出的效果圖如圖1所示。

當(dāng)漂移物理空間半徑設(shè)置為20,漂移色彩空間半徑設(shè)置為20,金字塔層數(shù) 為2,輸出的效果圖如圖2所示。對比可以發(fā)現(xiàn),半徑為20時(shí),圖像色彩細(xì)節(jié)大部分存在,半徑為50時(shí),森林和水面的色彩細(xì)節(jié)基本都已經(jīng)丟失。

寫到這里,均值偏移算法對彩色的圖像的分割平滑操作就完成了,為了達(dá)到更好地分割目的,借助漫水填充函數(shù)進(jìn)行下一步處理,在下一篇文章將詳細(xì)介紹,這里只是引入該函數(shù)。完整代碼如下所示:

# -*- coding: utf-8 -*-
# By: Eastmount
import cv2
import numpy as np
import matplotlib.pyplot as plt

#讀取原始圖像灰度顏色
img = cv2.imread('scenery.png') 

#獲取圖像行和列
rows, cols = img.shape[:2]

#mask必須行和列都加2且必須為uint8單通道陣列
mask = np.zeros([rows+2, cols+2], np.uint8) 

spatialRad = 100 #空間窗口大小
colorRad = 100   #色彩窗口大小
maxPyrLevel = 2  #金字塔層數(shù)

#圖像均值漂移分割
dst = cv2.pyrMeanShiftFiltering( img, spatialRad, colorRad, maxPyrLevel)

#圖像漫水填充處理
cv2.floodFill(dst, mask, (30, 30), (0, 255, 255),
              (100, 100, 100), (50, 50, 50),
              cv2.FLOODFILL_FIXED_RANGE)

#顯示圖像
cv2.imshow('src', img)
cv2.imshow('dst', dst)
cv2.waitKey()
cv2.destroyAllWindows()

輸出的效果圖如圖3所示,它將天空染成黃色。

二.基于分水嶺算法的圖像分割

圖像分水嶺算法(Watershed Algorithm)是將圖像的邊緣輪廓轉(zhuǎn)換為“山脈”,將均勻區(qū)域轉(zhuǎn)換為“山谷”,從而提升分割效果的算法[3]。分水嶺算法是基于拓?fù)淅碚摰臄?shù)學(xué)形態(tài)學(xué)的分割方法,灰度圖像根據(jù)灰度值把像素之間的關(guān)系看成山峰和山谷的關(guān)系,高亮度(灰度值高)的地方是山峰,低亮度(灰度值低)的地方是山谷。接著給每個(gè)孤立的山谷(局部最小值)不同顏色的水(Label),當(dāng)水漲起來,根據(jù)周圍的山峰(梯度),不同的山谷也就是不同顏色的像素點(diǎn)開始合并,為了避免這個(gè)現(xiàn)象,可以在水要合并的地方建立障礙,直到所有山峰都被淹沒。所創(chuàng)建的障礙就是分割結(jié)果,這個(gè)就是分水嶺的原理[3]。

分水嶺算法的計(jì)算過程是一個(gè)迭代標(biāo)注過程,主要包括排序和淹沒兩個(gè)步驟。由于圖像會存在噪聲或缺失等問題,該方法會造成分割過度。OpenCV提供了watershed()函數(shù)實(shí)現(xiàn)圖像分水嶺算法,并且能夠指定需要合并的點(diǎn),其函數(shù)原型如下所示:

markers = watershed(image, markers)

– image表示輸入圖像,需為8位三通道的彩色的圖像

– markers表示用于存儲函數(shù)調(diào)用之后的運(yùn)算結(jié)果,輸入/輸出32位單通道圖像的標(biāo)記結(jié)構(gòu),輸出結(jié)果需和輸入圖像的尺寸和類型一致。

下面是分水嶺算法實(shí)現(xiàn)圖像分割的過程。假設(shè)存在一幅彩色硬幣圖像,如圖4所示,硬幣相互之間挨著。

第一步,通過圖像灰度化和閾值化處理提取圖像灰度輪廓,采用OTSU二值化處理獲取硬幣的輪廓。

# -*- coding: utf-8 -*-
# By: Eastmount
import numpy as np
import cv2
from matplotlib import pyplot as plt

#讀取原始圖像
img = cv2.imread('coin.jpg')

#圖像灰度化處理
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

#圖像閾值化處理
ret, thresh = cv2.threshold(gray, 0, 255, 
cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

#顯示圖像
cv2.imshow('src', img)
cv2.imshow('res', thresh)
cv2.waitKey()
cv2.destroyAllWindows()

輸出結(jié)果如圖5所示。

第二步,通過形態(tài)學(xué)開運(yùn)算過濾掉小的白色噪聲。同時(shí),由于圖像中的硬幣是緊挨著的,所以不能采用圖像腐蝕去掉邊緣的像素,而是選擇距離轉(zhuǎn)換,配合一個(gè)適當(dāng)?shù)拈撝颠M(jìn)行物體提取。這里引入一個(gè)圖像膨脹操作,將目標(biāo)邊緣擴(kuò)展到背景,以確定結(jié)果的背景區(qū)域。

# -*- coding: utf-8 -*-
# By: Eastmount
import numpy as np
import cv2
from matplotlib import pyplot as plt

#讀取原始圖像
img = cv2.imread('coin.jpg')

#圖像灰度化處理
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

#圖像閾值化處理
ret, thresh = cv2.threshold(gray, 0, 255,
                            cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

#圖像開運(yùn)算消除噪聲
kernel = np.ones((3,3),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)

#圖像膨脹操作確定背景區(qū)域
sure_bg = cv2.dilate(opening,kernel,iterations=3)

#距離運(yùn)算確定前景區(qū)域
dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)
ret, sure_fg = cv2.threshold(dist_transform, 0.7*dist_transform.max(), 255, 0)

#尋找未知區(qū)域
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)

#用來正常顯示中文標(biāo)簽
plt.rcParams['font.sans-serif']=['SimHei']

#顯示圖像
titles = ['原始圖像', '閾值化', '開運(yùn)算',
          '背景區(qū)域', '前景區(qū)域', '未知區(qū)域']  
images = [img, thresh, opening, sure_bg, sure_fg, unknown]  
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é)果如圖6所示,包括原始圖像、閾值化處理、開運(yùn)算、背景區(qū)域、前景區(qū)域、未知區(qū)域等。由圖可知,在使用閾值過濾的圖像里,確認(rèn)了圖像的硬幣區(qū)域,而在有些情況,可能對前景分割更感興趣,而不關(guān)心目標(biāo)是否需要分開或挨著,那時(shí)可以采用腐蝕操作來求解前景區(qū)域。

第三步,當(dāng)前處理結(jié)果中,已經(jīng)能夠區(qū)分出前景硬幣區(qū)域和背景區(qū)域。接著我們創(chuàng)建標(biāo)記變量,在該變量中標(biāo)記區(qū)域,已確認(rèn)的區(qū)域(前景或背景)用不同的正整數(shù)標(biāo)記出來,不確認(rèn)的區(qū)域保持0,使用cv2.connectedComponents()函數(shù)來將圖像背景標(biāo)記成0,其他目標(biāo)用從1開始的整數(shù)標(biāo)記。注意,如果背景被標(biāo)記成0,分水嶺算法會認(rèn)為它是未知區(qū)域,所以要用不同的整數(shù)來標(biāo)記。

最后,調(diào)用watershed()函數(shù)實(shí)現(xiàn)分水嶺圖像分割,標(biāo)記圖像會被修改,邊界區(qū)域會被標(biāo)記成0,完整代碼如下所示。

# -*- coding: utf-8 -*-
# By: Eastmount
import numpy as np
import cv2
from matplotlib import pyplot as plt

#讀取原始圖像
img = cv2.imread('coin.jpg')

#圖像灰度化處理
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

#圖像閾值化處理
ret, thresh = cv2.threshold(gray, 0, 255,
                            cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)

#圖像開運(yùn)算消除噪聲
kernel = np.ones((3,3),np.uint8)
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)

#圖像膨脹操作確定背景區(qū)域
sure_bg = cv2.dilate(opening,kernel,iterations=3)

#距離運(yùn)算確定前景區(qū)域
dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)
ret, sure_fg = cv2.threshold(dist_transform, 0.7*dist_transform.max(), 255, 0)

#尋找未知區(qū)域
sure_fg = np.uint8(sure_fg)
unknown = cv2.subtract(sure_bg, sure_fg)

#標(biāo)記變量
ret, markers = cv2.connectedComponents(sure_fg)

#所有標(biāo)簽加一,以確保背景不是0而是1
markers = markers+1

#用0標(biāo)記未知區(qū)域
markers[unknown==255]=0

#分水嶺算法實(shí)現(xiàn)圖像分割
markers = cv2.watershed(img, markers)
img[markers == -1] = [255,0,0]

#用來正常顯示中文標(biāo)簽
plt.rcParams['font.sans-serif']=['SimHei']

#顯示圖像
titles = ['標(biāo)記區(qū)域', '圖像分割']  
images = [markers, img]  
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()

最終分水嶺算法的圖像分割如圖7所示,它將硬幣的輪廓成功提取。

圖8是采用分水嶺算法提取圖像Windows中心輪廓的效果圖。

分水嶺算法對微弱邊緣具有良好的響應(yīng),圖像中的噪聲、物體表面細(xì)微的灰度變化,都會產(chǎn)生過度分割的現(xiàn)象。但同時(shí)應(yīng)當(dāng)看出,分水嶺算法對微弱邊緣具有良好的響應(yīng),是得到封閉連續(xù)邊緣的保證。另外,分水嶺算法所得到的封閉的集水盆,為分析圖像的區(qū)域特征提供了可能。

三.總結(jié)

本文主要講解了圖像分割方法,包括基于均值漂移算法的圖像分割方法、基于分水嶺算法的圖像分割方法,通過這些處理能有效分割圖像的背景和前景,識別某些圖像的區(qū)域。

以上就是Python基于均值漂移算法和分水嶺算法實(shí)現(xiàn)圖像分割的詳細(xì)內(nèi)容,更多關(guān)于Python圖像分割的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評論