opencv3計算機視覺+Python(四)
阿新 • • 發佈:2018-02-12
rate 步驟 運行 sha 簡單 前景 open spa 階段
使用分水嶺和GrabCut算法進行物體分割
用GrabCut算法進行圖像分割
在OpenCV中,實現了grabcut分割算法,該算法可以方便的分割出前景圖像,操作簡單,而且分割的效果很好。算法的原理參見papaer:“GrabCut” — Interactive Foreground Extraction using Iterated Graph Cuts
比如下面的一副圖,我們只要選定一個四邊形框,把框中的圖像作為grabcut的一個輸入參數,表示該框中的像素可能屬於前景,但框外的部分一定屬於背景。
GrabCut算法實現步驟為:
1.在圖片中定義含有(一個或多個)物體的矩形
2.矩形外的區域被自動認為是背景
3.對於用戶定義的矩形區域,可用背景中的數據來區別它裏面的前景和背景區域
4.用高斯混合模型(GMM)來對背景和前景建模,並將未定義的像素標記為可能的前景或背景。
5.圖像中的每一個像素都被看作通過虛擬邊與周圍像素相連接,而每條邊都有一個屬於前景或背景的概率,這基於它與周圍像素顏色上的相似性。
6.每一個像素(即算法中的節點)會與一個前景或背景節點連接
7.在節點完成連接後(可能與背景或前景連接),若節點之間的邊屬於不同終端(即一個節點屬於前景,另一個節點屬於背景),則會切斷它們之間的邊(這就是算法名中的切割部分),這就能將圖像各部分分割出來。
import numpy as np import cv2from matplotlib import pyplot as plt img=cv2.imread(‘1.jpg‘) mask=np.zeros(img.shape[:2],np.uint8)#創建一個掩模
#創建以0填充的前景和背景模型 bgdModel=np.zeros((1,65),np.float64) fgdModel=np.zeros((1,65),np.float64) rect=(100,160,400,670)#創建矩形 cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)#使用了指定的空模型和掩模來運行GrabCut,並且實際上是用一個矩形來初始化這個操作 #做完這些後,我們的掩模已經變成包含0~3之間的值。值為0和2的將轉為0,值為1,3的將轉為1.然後保存在mask2中。這樣就可以用mask2過濾出所有的0值像素(理論上會完整保留所有前景像素) mask2=np.where((mask==0)|(mask==2),0,1).astype(‘uint8‘) img=img*mask2[:,:,np.newaxis] plt.subplot(121),plt.imshow(img) plt.title("grabcut"),plt.xticks([]),plt.yticks([]) plt.subplot(122),plt.imshow(cv2.cvtColor(cv2.imread("1.jpg"),cv2.COLOR_BGR2RGB)) plt.title("original"),plt.xticks([]),plt.yticks([]) plt.show()
使用分水嶺算法進行圖像分割
把圖像中的低密度的區域(變化很少)想象成山谷,圖像中高密度的區域(變化很多)想象成山峰。開始向山谷中註入水直到不同的山谷中的水開始匯聚。為了阻止不同山谷的水匯聚,可以設置一些柵欄,最後得到的柵欄就是圖像分割。
import numpy as np import cv2 from matplotlib import pyplot as plt img=cv2.imread("1.jpg") gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#顏色轉為灰度 ret,thresh=cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)#可為圖像設一個閾值 kernel=np.ones((3,3),np.uint8) opening=cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel,iterations=2)#去除噪聲 sure_bg=cv2.dilate(opening,kernel,iterations=3) dist_transform=cv2.distanceTransform(opening,cv2.DIST_L2,5)#可以通過distanceTransform來獲取確定的前景區域。也就是說,這是圖像中最可能是前景的區域,越是遠離背景區域的邊界點越可能屬於前景,這裏用了閾值來決定那些區域是前景 ret,sure_fg=cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0) #這個階段之後,所得到的前景和背景中有重合的部分該怎麽辦?首先需要確定這些區域,這可從sure_bg與sure_fg的集合相減得到 sure_fg=np.uint8(sure_fg) unknown=cv2.subtract(sure_bg,sure_fg) #現在有了這些區域,就可以設定柵欄來阻止水匯聚,這是通過connectedComponents函數完成。 ret,markers=cv2.connectedComponents(sure_fg) markers=markers+1 markers[unknown==255]=0 #把柵欄繪制成紅色 markers=cv2.watershed(img,markers) img[markers==-1]=[255,0,0] plt.imshow(img) plt.show()
opencv3計算機視覺+Python(四)