内容来自OpenCV-Python Tutorials 自己翻译整理 目标: GrabCut算法原理与应用
创建交互式程序完成前景提取 原理:
首先用矩形将要选择的前景区域选定,其中前景区域应该完全包含在矩形框当中。然后算法进行迭代式分割,知道达到效果最佳。但是有时分割结果不好,例如前景当成背景,背景当成前景。测试需要用户修改。用户只需要在非前景区域用鼠标划一下即可。
如文档中的图片,运动员和足球被蓝色矩形保卫,其中有数个用白色标记修改的,表示前景区域,黑色表示背景区域。 首先,输入矩形框,矩形框外部区域都是背景。内部一定包含前景。 电脑对输入图像进行初始化,标记前景和背景的像素。 使用高斯混合模型(GMM)对前景和背景建模。 根据输入,GMM会学习并创建新的像素分布。对未知的像素(前景或背景不确定),根据他们与已知的分类像素关系进行分类。(类似聚类操作) 这样会根据像素的分布创建一幅图,图中节点是像素。除了像素点是节点以外,还有Source_node和Sink_node两个节点。所有的前景图像斗鱼Source_node相连。背景与Sink_node相连。 像素是否连接到Source_node/end_node依赖于权值,这个权值由像素属于同一类,也就是前景或者背景的概率来决定。如果像素的颜色有很大区别,那么他们之间的权重就很小。 使用mincut算法对图像进行分割。它会根据最小代价方程对图像分成source_node和sink_node。代价方程是指裁剪所有边上权重的和。裁剪完成后,所有连接到source_node的判定为前景,sink_node上的为背景。 继续此过程,直到分类收敛。 此网站有关于GrabCut算法的详细讲解 示例: cv2.grabCut()函数参数 img 输入图像 mask 蒙板图像,确定前景区域,背景区域,不确定区域,可以设置为cv2.GC_BGD,cv2.GC_FGD,cv2.GC_PR_BGD,cv2.GC_PR_FGD,也可以输入0,1,2,3 rect 前景的矩形,格式为(x,y,w,h),分别为左上角坐标和宽度,高度 bdgModel, fgdModel 算法内部是用的数组,只需要创建两个大小为(1,65)np.float64的数组。 iterCount 迭代次数 mode cv2.GC_INIT_WITH_RECT 或 cv2.GC_INIT_WITH_MASK,使用矩阵模式还是蒙板模式。 import numpy as np import cv2 from matplotlib import pyplot as plt
img = cv2.imread('1.jpg') mask = np.zeros(img.shape[:2],np.uint8) bgdModel = np.zeros((1,65),np.float64) fgdModel = np.zeros((1,65),np.float64) rect = (50,50,450,290)#划定区域 cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)#函数返回值为mask,bgdModel,fgdModel mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')#0和2做背景
img = img*mask2[:,:,np.newaxis]#使用蒙板来获取前景区域
cv2.imshow('p',img) cv2.waitKey(0) 计算完成后mask里面值为0到3,其中0表示背景,1表示前景,2表示可能是背景,3表示可能是前景
代码中将0和2合并为背景 1和3合并为前景 样例中的图片结果如下 可以看到得到的结果并不准确,现在在这幅图片得到的蒙板上面添加标记,用白色(像素值为0)标记前景,黑色(像素值为255)标记背景。再次进行迭代计算,最后得到不错的结果 样例中的图片如下
|