19 使用 GrabCut 算法的交互式前景提取——opencv的各种 ...
目标[*]我们将看到GrabCut算法来提取图像中的前景
[*]我们将为此创建一个交互式应用程序。
理论
GrabCut算法由来自英国剑桥微软研究院的Carsten Rother,Vladimir Kolmogorov和Andrew Blake设计。在他们的论文“GrabCut”中:使用迭代图形切割进行交互式前景提取。需要一种算法来以最少的用户交互进行前景提取,结果是GrabCut。
从用户的角度来看,它是如何工作的?最初,用户在前景区域周围绘制一个矩形(前景区域应完全位于矩形内)。然后,算法对其进行迭代分割以获得最佳结果。做。但在某些情况下,分割不会很好,例如,它可能已将某些前景区域标记为背景,反之亦然。在这种情况下,用户需要进行精细的修饰。只需在图像上给出一些笔触,其中存在一些错误的结果。笔画基本上说“嘿,这个区域应该是前景,你标记了它背景,在下一次迭代中纠正它”或相反的背景。然后在下一次迭代中,您将获得更好的结果。
那么在后台会发生什么呢?
用户输入矩形。此矩形之外的所有内容都将被视为确定的背景(这就是之前提到的矩形应包含所有对象的原因)。矩形内的所有内容都是未知的。同样,任何指定前台和背景的用户输入都被视为硬标记,这意味着它们在此过程中不会更改。 计算机根据我们提供的数据进行初始标记。它标记前景和背景像素(或硬标签) 现在使用高斯混合模型(GMM)来模拟前景和背景。 根据我们提供的数据,GMM学习并创建新的像素分布。也就是说,根据未知像素在颜色统计方面与其他硬标记像素的关系,对未知像素进行标记,要么标记可能的前景或可能的背景(就像聚类一样)。 根据此像素分布构建图形。图形中的节点是像素。将添加另外两个节点:源节点和接收器节点。每个前景像素都连接到源节点,每个背景像素都连接到接收器节点。 将像素连接到源节点/结束节点的边缘的权重由像素成为前景/背景的概率定义。像素之间的权重由边缘信息或像素相似性定义。如果像素颜色差异很大,它们之间的边缘将获得较低的权重。 然后使用最小切割算法来分割图形。它将图形切割成两个具有最小成本函数的分离源节点和接收器节点。成本函数是被切割的边的所有权重之和。剪切后,连接到源节点的所有像素都将成为前台,连接到接收器节点的像素将成为背景。 该过程将继续,直到分类收敛。 如下图所示(图片提供:http://www.cs.ru.ac.za/research/g02m1682/)
演示
现在我们采用OpenCV的grabcut算法。OpenCV具有函数cv.grabCut()。我们将首先看到它的参数:
[*]img - 输入图像
[*]mask - 这是一个蒙版图像,我们指定哪些区域是背景,前景或可能的背景/前景等。它由以下标志完成,cv.GC_BGD,cv.GC_FGD,cv.GC_PR_BGD,cv.GC_PR_FGD,或者只是将0,1,2,3传递给图像。
[*]rect - 它是矩形的坐标,它包含格式为(x,y,w,h)的前景对象
[*]bdgModel,fgdModel - 这些是算法内部使用的数组。您只需创建两个大小为 (1,65) 的 np.float64 类型零数组。
[*]iterCount - 算法应运行的迭代次数。
[*]mode - 它应该是cv.GC_INIT_WITH_RECT或cv.GC_INIT_WITH_MASK或组合,它决定了我们是绘制矩形还是最终的修饰笔触。
首先,让我们看看矩形模式。我们加载图像,创建类似的遮罩图像。我们创建fgdModel和bgdModel。我们给出矩形参数。一切都很简单。让算法运行 5 次迭代。模式应该cv.GC_INIT_WITH_RECT,因为我们使用的是矩形。然后运行抓取。它修改蒙版图像。在新蒙版图像中,像素将标有四个标志,表示上面指定的背景/前景。因此,我们修改了蒙版,以便将所有0像素和2像素设置为0(即背景),将所有1像素和3像素设置为1(即前景像素)。现在,我们的最终面罩已经准备好了。只需将其与输入图像相乘即可获得分割图像。
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img = cv.imread('messi5.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)
cv.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv.GC_INIT_WITH_RECT)
mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
img = img*mask2[:,:,np.newaxis]
plt.imshow(img)
plt.colorbar()
plt.show()
哎呀,梅西的头发不见了。谁喜欢没有头发的梅西?我们需要把它带回来。因此,我们将用1像素(确定前景)进行精细修饰。同时,地面的某些部分已经出现了我们不想要的图片,还有一些徽标。我们需要删除它们。在那里,我们给出了一些0像素的修饰(确定背景)。因此,正如我们现在所说,我们在之前的情况下修改了生成的蒙版。
我实际做的是,我在绘画应用程序中打开输入图像,并在图像中添加另一层。在油漆中使用画笔工具,我在这个新图层上用黑色标记了白色和不需要的背景(如徽标,地面等)的错过的前景(头发,鞋子,球等)。然后用灰色填充剩余的背景。然后在OpenCV中加载该蒙版图像,编辑了我们在新添加的蒙版图像中获得的原始蒙版图像以及相应的值。检查以下代码:
# newmask is the mask image I manually labelled
newmask = cv.imread('newmask.png',0)
# wherever it is marked white (sure foreground), change mask=1
# wherever it is marked black (sure background), change mask=0
mask = 0
mask = 1
mask, bgdModel, fgdModel = cv.grabCut(img,mask,None,bgdModel,fgdModel,5,cv.GC_INIT_WITH_MASK)
mask = np.where((mask==2)|(mask==0),0,1).astype('uint8')
img = img*mask[:,:,np.newaxis]
plt.imshow(img)
plt.colorbar()
plt.show()
就是这样。在这里,您可以直接进入掩码模式,而不是在矩形模式下初始化。只需在蒙版图像中用2像素或3像素(可能的背景/前景)标记矩形区域即可。然后用 1 个像素标记我们的sure_foreground,就像我们在第二个示例中所做的那样。然后直接应用具有蒙版模式的 grabCut 功能。
参考:https://docs.opencv.org/4.0.1/d8/d83/tutorial_py_grabcut.html
页:
[1]