OpenCV 影像分割之grabCut演算法

  • 2019 年 10 月 4 日
  • 筆記

GrabCut演算法的原理涉及到以下知識:

  • K均值聚類
  • 高斯混合模型建模(GMM)
  • max flow/min cut

GrabCut演算法的實現步驟:

  1. 在圖片中定義(一個或者多個)包含物體的矩形。
  2. 矩形外的區域被自動認為是背景。
  3. 對於用戶定義的矩形區域,可用背景中的數據來區分它裡面的前景和背景區域。
  4. 用高斯混合模型(GMM)來對背景和前景建模,並將未定義的像素標記為可能的前景或者背景。
  5. 影像中的每一個像素都被看做通過虛擬邊與周圍像素相連接,而每條邊都有一個屬於前景或者背景的概率,這是基於它與周邊像素顏色上的相似性。
  6. 每一個像素(即演算法中的節點)會與一個前景或背景節點連接。
  7. 在節點完成連接後(可能與背景或前景連接),若節點之間的邊屬於不同終端(即一個節點屬於前景,另一個節點屬於背景),則會切斷他們之間的邊,這就能將影像各部分分割出來。下圖能很好的說明該演算法:

示例程式碼如下:

import cv2  import numpy as np  from matplotlib import pyplot as plt    img = cv2.imread("2.jpg")    mask = np.zeros(img.shape[:2], np.uint8)  bgdModel = np.zeros((1,65), np.float64) #以0填充的背景  fgdModel = np.zeros((1,65), np.float64)#以0填充的前景  #rect = (100,10,300,300)  rect = (1,1, 600, 430)  #grabCut(img, mask, rect, bgdModel, fgdModel, iterCount[, mode]) -> mask, bgdModel, fgdModel  cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 6, cv2.GC_INIT_WITH_RECT)  #做完這些我們的掩碼已經變成包含0~3的值    #將掩碼中0或2 轉為0(背景), 其它(1或3)轉為1(前景)  mask2 = np.where((mask==2)|(mask ==0), 0, 1).astype(np.uint8)  img1 = img*mask2[:,:, np.newaxis]#分割後的前景    plt.subplot(121)  plt.imshow(cv2.cvtColor(img1, cv2.COLOR_BGR2RGB))#BGR模式 轉RGB 模式  plt.title("grabcut")  plt.xticks([]); plt.yticks([]) #不顯示坐標軸刻度  plt.subplot(122)  plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))  plt.title("original")  plt.xticks([]); plt.yticks([])#不顯示坐標軸刻度  plt.show()

分割效果見下圖: