本文將實現(xiàn)一個與人(鼠標)交互從而分割背景的程序。
1.理論介紹
用戶指定前景的大體區(qū)域,剩下為背景區(qū)域,還可以明確指出某些地方為前景或者背景,GrabCut算法采用分段迭代的方法分析前景物體形成模型樹,最后根據(jù)權(quán)重決定某個像素是前景還是背景。
算法:GrabCut(img, mask, rect, bgdModel, fgdModel, 5, //iteratormode)
img:要分割的圖像
mask:生稱的掩碼(以原圖像大小為基準),該算法會把mask分為4部分,像素點的值為0,1,2,3四種值嗎,其中每種值代表不同的意思。
rect:用戶指定的矩形區(qū)域,元組的形式(起始坐標x, y , width,height)
bgdModel:1行65列的0矩陣,元素類型為float64。
fgdModel:1行65列的0矩陣,元素類型為float64。
5:迭代次數(shù)iterator
mode:第一次找用RECT,以后迭代用MASK
2. 鼠標交互
下面是一個鼠標交互的程序,可以通過點擊鼠標滑動鼠標在圖像上作圖。
不太清楚的讀者可以參考下面博客:Opencv(圖像處理)-基于Python-繪圖功能
代碼如下:
import cv2
import numpy as np
'''
該api可以在圖上作圖
點擊并滑動鼠標可以在圖上畫出矩形框
'''
# 定義一個類來封裝該方法
class MouseStich:
startX = 0
startY = 0
rect_flag = False
def onmouse(self, event, x, y, flags, param):
# print("onmouse")
if event == cv2.EVENT_LBUTTONDOWN:
self.rect_flag = True
self.startX = x
self.startY = y
# print("LBUTTONDOWN")
elif event == cv2.EVENT_LBUTTONUP:
# print("LBUTTONUP")
self.rect_flag = False
cv2.rectangle(self.img,
(self.startX, self.startY),
(x, y),
(0, 0, 255),
3)
elif event == cv2.EVENT_MOUSEMOVE:
# print("MOUSEMOVE")
# 每次都在新的圖像上畫
if self.rect_flag == True:
self.img = self.img2.copy()
cv2.rectangle(self.img,
(self.startX, self.startY),
(x, y),
(0, 255, 0),
3)
def run(self):
print("run....")
# 綁定鼠標事件的窗口
cv2.namedWindow('input')
cv2.setMouseCallback('input', self.onmouse)
# 暫存一個img2
self.img = cv2.imread('./image/lena.jpg')
self. img2 = self.img.copy()
# 讀取圖片,在該窗口顯示
while(1):
# 展示原圖,被畫的圖
cv2.imshow('input', self.img)
k = cv2.waitKey(100) & 0xff
if k == ord('q'):
break
MouseStich().run()
3. GrabCut
將GrabCut需要的參數(shù)構(gòu)造好后,傳進去,獲得mask掩模,然后我們用np.where把像素值是1,3的位置改成255,目的是用bitwise_and函數(shù)提取出前景區(qū)域。
import cv2
import numpy as np
'''
該api可以在圖上作圖
點擊并滑動鼠標可以在圖上畫出矩形框
'''
# 定義一個類來封裝該方法
class MouseStich:
startX = 0
startY = 0
rect_flag = False
rect = (0, 0, 0, 0)
def onmouse(self, event, x, y, flags, param):
# print("onmouse")
if event == cv2.EVENT_LBUTTONDOWN:
self.rect_flag = True
self.startX = x
self.startY = y
# print("LBUTTONDOWN")
elif event == cv2.EVENT_LBUTTONUP:
# print("LBUTTONUP")
self.rect_flag = False
cv2.rectangle(self.img,
(self.startX, self.startY),
(x, y),
(0, 0, 255),
3)
elif event == cv2.EVENT_MOUSEMOVE:
# print("MOUSEMOVE")
# 每次都在新的圖像上畫
if self.rect_flag == True:
# 每次都在新的圖像上畫move
self.img = self.img2.copy()
cv2.rectangle(self.img,
(self.startX, self.startY),
(x, y),
(0, 255, 0),
3)
# 構(gòu)造矩形的信息
self.rect = (min(self.startX, x), min(self.startY, y),
abs(self.startX - x), abs(self.startY - y))
def run(self):
print("run....")
# 綁定鼠標事件的窗口
cv2.namedWindow('input')
cv2.setMouseCallback('input', self.onmouse)
self.img = cv2.imread('./image/lena.jpg')
self. img2 = self.img.copy()
# 定義一個與圖片相同大小的掩碼
self.mask = np.zeros(self.img.shape[:2], dtype=np.uint8)
self.output = np.zeros(self.img.shape, dtype=np.uint8)
# 讀取圖片,在該窗口顯示
while(1):
# 展示原圖,被畫的圖
cv2.imshow('input', self.img)
cv2.imshow('output', self.output)
k = cv2.waitKey(100) & 0xff
if k == ord('q'):
break
if k == ord('g'):
bgdmodel = np.zeros((1, 65), np.float64)
fgdmodel = np.zeros((1, 65), np.float64)
cv2.grabCut(self.img2, self.mask, self.rect,
bgdmodel, fgdmodel,
1,
cv2.GC_INIT_WITH_RECT)
# 構(gòu)造提取前景的淹沒
mask2 = np.where((self.mask==1)|(self.mask==3), 255, 0).astype('uint8')
self.output = cv2.bitwise_and(self.img2, self.img2, mask=mask2)
MouseStich().run()
展示效果:先使用鼠標畫出區(qū)域,然后按’g’分割圖片。
文章來源:http://www.zghlxwxcb.cn/news/detail-599848.html
以上是關(guān)于GrabCut算法的實戰(zhàn)內(nèi)容,如有問題歡迎在評論區(qū)討論。文章來源地址http://www.zghlxwxcb.cn/news/detail-599848.html
到了這里,關(guān)于OpenCV4圖像處理-圖像交互式分割-GrabCut的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!