您的位置:首页 > 运维架构

【笔记】OpenCV3 图像分割-用grabCut做前景检测

2019-06-04 13:07 519 查看
版权声明:qdwork https://blog.csdn.net/hopena/article/details/90766386

grabCut算法的大致思路,摘抄。。。。

  1. 在图片中定义(一个或者多个)包含物体的矩形。
  2. 矩形外的区域被自动认为是背景。
  3. 对于用户定义的矩形区域,可用背景中的数据来区分它里面的前景和背景区域。
  4. 用高斯混合模型(GMM)来对背景和前景建模,并将未定义的像素标记为可能的前景或者背景。
  5. 图像中的每一个像素都被看做通过虚拟边与周围像素相连接,而每条边都有一个属于前景或者背景的概率,这是基于它与周边像素颜色上的相似性。
  6. 每一个像素(即算法中的节点)会与一个前景或背景节点连接。
  7. 在节点完成连接后(可能与背景或前景连接),若节点之间的边属于不同终端(即一个节点属于前景,另一个节点属于背景),则会切断他们之间的边,这就能将图像各部分分割出来
[code]def grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode=None)

输入参数:

img: 输入图像

mask: 掩码图像,用来确定哪些区域是背景、前景,哪些可能是前景/背景

[code]0 GC_BGD    定义了明显的背景像素。
1 GC_FGD    定义了一个明显的前景(对象)像素。
2 GC_PR_BGD 定义了可能的背景像素。
3 GC_PR_FGD 定义了可能的前景像素。

rect: mode为rect模式时有效 包含前景的矩形(x,y,w,h),以外的部分为背景

bgdModel、fgdModel:背景、前景数组,算法用

itterCount: 算法迭代的次数

mode: cv2.GC_INIT_WITH_RECT,cv2.GC_INIT_WITH_MASK两种模式

 

测试下试试,在代码中加入了鼠标事件,来获取在图形绘制的rect,用来给算法限定前景的范围

  1. 鼠标按下时,设置绘制边框模式setrect_flag为True,且记录下点击的点
  2. 鼠标左键按下,并拖动时,记录鼠标点坐标,用于在移动时绘制矩形框
  3. 鼠标左键松开时,记录下坐标点,完成矩形框绘制
[code]file_name = 'img/renma.jpg'
setrect_flag = False
has_rect = False
set_rect = [1,1,1,1]
cut_flag = False

def onMouse(event,x,y,flags, param):
global setrect_flag,has_rect,set_rect,cut_flag
if event == cv2.EVENT_LBUTTONDOWN:
print("left mouse click...")
setrect_flag = True
has_rect = False
set_rect[0] = x
set_rect[1] = y
set_rect[2] = x
set_rect[3] = y
if event ==  cv2.EVENT_MOUSEMOVE and flags == cv2.EVENT_FLAG_LBUTTON:
if setrect_flag:
set_rect[2] = x
set_rect[3] = y
elif event == cv2.EVENT_LBUTTONUP:
print("left mouse up...")
if setrect_flag:
setrect_flag = False
has_rect = True
cut_flag = True
set_rect[2] = x
set_rect[3] = y
print(x,y)
elif event == cv2.EVENT_RBUTTONDOWN:
print("right mouse down...")
has_rect = False
setrect_flag = False

 

  1. 在main处绘制出原图,并记录
  2. 循环判断,当为绘制矩形框模式时,绘制出矩形框
  3. cut_flag 用来判断是否已经完成剪切,如果已完成,就不用处理,不然会一直处理。。。
  4. 在里面判断鼠标按下与松开的位置,来确定最终的前景确认框的rect ,左上角坐标,及宽高
[code]if __name__ == "__main__":

cv2.namedWindow('pic', cv2.WINDOW_AUTOSIZE)
cv2.setMouseCallback('pic', onMouse)

img = cv2.imread(file_name, cv2.IMREAD_COLOR)
imgold = img.copy()
cv2.imshow('pic', img)

while True:
# 画区域中
if setrect_flag:
img = imgold.copy()
cv2.rectangle(img,(set_rect[0],set_rect[1]),(set_rect[2],set_rect[3]),(255,0,0),1)
cv2.imshow('pic',img)
else:
if cut_flag:
if has_rect and (set_rect[0] - set_rect[2]) != 0 and (set_rect[1] - set_rect[3]) != 0:
# 默认往右下拖动
rect = [set_rect[0],set_rect[1],abs(set_rect[2]-set_rect[0]),abs(set_rect[3]-set_rect[1])]
if set_rect[2] < set_rect[0] and set_rect[3] < set_rect[1]:#往左上拖动
rect[0] = set_rect[2]
rect[1] = set_rect[3]
elif set_rect[2] < set_rect[0] and set_rect[3] > set_rect[1]:#往左下拖动
rect[0] = set_rect[2]
rect[1] = set_rect[1]
elif set_rect[2] > set_rect[0] and set_rect[3] < set_rect[1]:#往右上拖动
rect[0] = set_rect[0]
rect[1] = set_rect[3]
img = imgold.copy()
st = time.time()
print('begin cut pic...')
cuppic(img,rect)
print("cut over , it takes {:.3f}".format(time.time()-st))
cut_flag = False
else:
cv2.imshow('pic', imgold)

pressKey = cv2.waitKey(20)
if cv2.getWindowProperty('pic', cv2.WND_PROP_AUTOSIZE) < 1:
break
if pressKey == 27:  # ESC
print('退出。。。。。')
break

cv2.destroyAllWindows()

 

调用分隔算法

  1. 用图像等大的数据初始化掩码
  2. 创建以0填充的前景和背景模型, 输入必须是单通道的浮点型图像, 1行, 13x5 = 65的列 即(1,65)
  3. 自定义区域
  4. 分割
  5. 将0,2合并为0, 1,3合并为1
  6. 与图像合并,取出前景
[code]def cuppic(img, rect):
print("set rect to ",rect)
mask = np.zeros(img.shape[:2], np.uint8)
bgdModel = np.zeros((1,65), np.float64)
fgdModel = np.zeros((1,65), np.float64)

bgrect = tuple(rect)
cv2.grabCut(img, mask, bgrect, bgdModel, fgdModel, 16, cv2.GC_INIT_WITH_RECT)

mask2 = np.where((mask == 2)|(mask==0),0,1).astype('uint8')
imgnew = img*mask2[:,:,np.newaxis]
cv2.imshow('new',imgnew)

效果

 

 

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐