OpenCV計算機視覺實戰(16)——圖像分割技術
- 0. 前言
- 1. 分水嶺算法
- 1.1 應用場景
- 1.2 實現過程
- 2. GrabCut 交互式分割
- 2.1 應用場景
- 2.2 實現過程
- 3. FloodFill
- 3.1 應用場景
- 3.2 實現過程
- 小結
- 系列鏈接
0. 前言
圖像分割是計算機視覺中將像素劃分為具有特定語義或結構的區域。面對目標緊密相連或前景背景對比不明顯的復雜場景,僅憑簡單的閾值往往捉襟見肘。本文深入講解并演示了三種經典而高效的分割方法——分水嶺算法借鑒地形水漫模型精準分離粘連目標,GrabCut
交互式摳圖通過最小割迭代優化實現細節豐富的前景提取,以及 FloodFill
以種子點為起點快速覆蓋同質區域。
1. 分水嶺算法
將灰度圖看作地形高程圖,把“低谷”視為種子點,利用梯度圖構造“水漫”過程,最終在“山脊線”處形成分割邊界,適合處理前景連通但邊界黯淡的場景。
1.1 應用場景
- 重疊目標分離:當前景對象相互粘連時(如重疊的硬幣、細胞團),分水嶺能精確沿“山脊”將它們分開
- 紋理分割:結合梯度圖,能處理前景背景亮度相近但紋理不同的場景
- 預分割:常作為后續目標檢測或特征提取的預處理步驟,提供連通組件
1.2 實現過程
- 讀取圖像與預處理
- 轉灰度并做高斯模糊,減少噪聲
- 計算梯度圖 (
Sobel
或Laplacian
) 以突出邊緣
- 二值化與距離變換
- 對圖像做閾值化,得到粗略二值前景
- 對前景做距離變換并歸一化
- 標記種子區域
- 對距離變換結果做閾值,提取“確實前景”作為種子標記
- 將未知區域標為
0
,背景標為1
- 調用分水嶺
cv2.watershed
會修改標記矩陣,將邊界點標記為–1
- 在原圖上將邊界涂為紅色
import cv2
import numpy as np# 1. 讀取與預處理
img = cv2.imread('2.jpeg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
blur = cv2.GaussianBlur(gray, (5, 5), 0)# 2. 梯度與二值化
grad = cv2.Laplacian(blur, cv2.CV_8U, ksize=3)
_, binary = cv2.threshold(blur, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)# 3. 距離變換與種子標記
dist = cv2.distanceTransform(binary, cv2.DIST_L2, 5)
_, fg = cv2.threshold(dist, 0.4 * dist.max(), 255, 0)
fg = np.uint8(fg)
bg = cv2.dilate(binary, np.ones((3,3), np.uint8), iterations=3)
unknown = cv2.subtract(bg, fg)# 4. 連通組件與標記
_, markers = cv2.connectedComponents(fg)
markers = markers + 1 # 背景標記為 1
markers[unknown == 255] = 0 # 未知區域標記為 0# 5. 分水嶺
markers = cv2.watershed(img, markers)
output = img.copy()
output[markers == -1] = [0, 0, 255] # 邊界標紅cv2.imshow('Watershed Segmentation', output)
cv2.waitKey(0)
cv2.destroyAllWindows()
關鍵函數解析:
cv2.distanceTransform(src, distType, maskSize)
:計算二值圖中每個前景像素到最近背景的距離,用于挖掘前景核心區域cv2.connectedComponents(src)
:對前景二值圖進行連通組件標記,生成初始標記矩陣cv2.watershed(image, markers)
:以markers
為種子,在彩色圖像上執行分水嶺算法,輸出帶邊界的標記圖
2. GrabCut 交互式分割
GrabCut
利用圖割 (Graph Cut
) 模型結合少量用戶標注(矩形或前景/背景涂抹),自動學習前景與背景像素分布,實現高質量分割,適合人物/物體摳圖。
2.1 應用場景
- 半自動摳圖:用戶只需框選對象,后續可用筆刷細化邊緣,比如頭發、樹葉等復雜輪廓
- 視頻摳像:在關鍵幀交互后,將模型應用于相鄰幀,實現半自動背景替換
- 圖形編輯工具:集成
GrabCut
,讓非專業用戶也能輕松摳圖
2.2 實現過程
- 讀取圖像與定義感興趣區域 (
Region of Interest
,ROI
)- 用戶給定一個大致含前景的矩形框
rect
- 用戶給定一個大致含前景的矩形框
- 初始化掩碼與模型
mask
初始化為全 “可能背景”bgModel
與fgModel
用于內部高斯混合模型 (Gaussian Mixture Model
,GMM
)
- 調用 GrabCut
cv2.grabCut
根據rect
或用戶刷涂的mask
迭代優化- 模型會不斷更新前景/背景分布
- 提取結果
- 將
mask
中標記為前景/可能前景的像素保留,其余設為背景
- 將
import cv2
import numpy as npimg = cv2.imread('2.jpeg')
mask = np.zeros(img.shape[:2], np.uint8)# 1. 用戶定義矩形 ROI (x,y,w,h)
rect = (50, 50, img.shape[1]-100, img.shape[0]-100)# 2. 初始化模型
bgModel = np.zeros((1,65), np.float64)
fgModel = np.zeros((1,65), np.float64)# 3. 執行 GrabCut
cv2.grabCut(img, mask, rect, bgModel, fgModel, 5, cv2.GC_INIT_WITH_RECT)# 4. 構建前景掩碼并應用
mask2 = np.where((mask==cv2.GC_FGD)|(mask==cv2.GC_PR_FGD),255,0).astype('uint8')
result = cv2.bitwise_and(img, img, mask=mask2)cv2.imshow('GrabCut Result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()
關鍵函數解析:
cv2.grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode)
:在指定rect
區域或已有mask
上運行GrabCut
mode=cv2.GC_INIT_WITH_RECT
:使用矩形初始化mode=cv2.GC_INIT_WITH_MASK
:根據用戶細化涂抹結果再運行
mask
標簽值:GC_BGD(0)
,GC_FGD(1)
,GC_PR_BGD(2)
,GC_PR_FGD(3)
,可提取出最終前景
3. FloodFill
FloodFill
從給定種子點開始,將相似像素“漫水填充”到邊界,可用于區域生長、缺陷檢測與交互式標注。
3.1 應用場景
- 缺陷檢測:從劃痕起點填充,快速定位裂紋區域
- 交互式分割:點擊圖像生成精確區域掩碼,配合
GrabCut
等方法 - 色塊分割:在質感均勻的背景或卡通圖像中,快速提取色塊
3.2 實現過程
- 讀取圖像
- 指定種子點
(x, y)
- 設置填充參數
loDiff
/upDiff
:允許填充的像素與種子點最大差異flags
:控制填充方式、掩碼使用
- 調用
FloodFill
- 返回填充后的像素數與更新后的圖像
import cv2
import numpy as npimg = cv2.imread('1.jpeg')
h, w = img.shape[:2]# 1. 構建掩碼,需比原圖多兩像素邊緣
mask = np.zeros((h+2, w+2), np.uint8)# 2. 漫水填充參數
seed_point = (700, 500)
newVal = (0, 0, 255) # 填充顏色:紅色
loDiff = (20, 20, 20) # 下限差異
upDiff = (20, 20, 20) # 上限差異
flags = 4 | cv2.FLOODFILL_FIXED_RANGE | (255<<8)# 3. 執行 FloodFill
num, img_flood, mask, rect = cv2.floodFill(img.copy(), mask, seed_point,newVal, loDiff, upDiff, flags)cv2.imshow('FloodFill Result', img_flood)
cv2.waitKey(0)
cv2.destroyAllWindows()
關鍵函數解析
cv2.floodFill(image, mask, seedPoint, newVal, loDiff, upDiff, flags)
:從seedPoint
開始填充,loDiff
/upDiff
控制像素相似度flags
參數含義:cv2.FLOODFILL_FIXED_RANGE
:像素差異相對種子點cv2.FLOODFILL_MASK_ONLY
:僅更新mask
小結
本節從分水嶺的高程地圖思路切入,講解如何借助距離變換與連通組件構建水漫分割,再通過 GrabCut
的圖割模型與用戶交互實現更高精度的前景去背,最后以 FloodFill
的種子驅動方式演示快速區域生長。三者各有側重,卻可互為補充:分水嶺適合自動化預分割,GrabCut
適合復雜邊緣細化,FloodFill
則勝在簡單直觀和交互式應用。
系列鏈接
OpenCV計算機視覺實戰(1)——計算機視覺簡介
OpenCV計算機視覺實戰(2)——環境搭建與OpenCV簡介
OpenCV計算機視覺實戰(3)——計算機圖像處理基礎
OpenCV計算機視覺實戰(4)——計算機視覺核心技術全解析
OpenCV計算機視覺實戰(5)——圖像基礎操作全解析
OpenCV計算機視覺實戰(6)——經典計算機視覺算法
OpenCV計算機視覺實戰(7)——色彩空間詳解
OpenCV計算機視覺實戰(8)——圖像濾波詳解
OpenCV計算機視覺實戰(9)——閾值化技術詳解
OpenCV計算機視覺實戰(10)——形態學操作詳解
OpenCV計算機視覺實戰(11)——邊緣檢測詳解
OpenCV計算機視覺實戰(12)——圖像金字塔與特征縮放
OpenCV計算機視覺實戰(13)——輪廓檢測詳解
OpenCV計算機視覺實戰(14)——直方圖均衡化
OpenCV計算機視覺實戰(15)——霍夫變換詳解