使用GrabCut算法进行交互式前景提取 OpenCV-Python v4.7.0

目标

在本章中

  • 我们将看到GrabCut算法来提取图像中的前景。
  • 我们将为此创建一个交互式应用程序。

理论

GrabCut 算法是由英国剑桥微软研究院的 Carsten Rother, Vladimir Kolmogorov 和 Andrew Blake 在他们的论文 GrabCut: interactive foreground extraction using iterated graph cuts . 我们需要一种以最小的用户互动进行前景提取的算法,其结果就是GrabCut。

从用户的角度看,它是如何工作的?最初,用户在前景区域周围画一个矩形(前景区域应该完全在矩形内)。然后算法迭代地对其进行分割,以获得最佳结果。完成了。但在某些情况下,分割不会很好,比如,它可能将一些前景区域标记为背景,反之亦然。在这种情况下,用户需要做精细的润色。只要在有一些错误结果的图像上画一些笔画就可以了。描边基本上是说*"嘿,这个区域应该是前景,你把它标记为背景,在下一次迭代中纠正它 "*或相反的背景。然后在下一次迭代中,你会得到更好的结果。

请看下面的图片。首先,球员和足球被包围在一个蓝色的矩形里。然后用白色笔触(表示前景)和黑色笔触(表示背景)做了一些最后的修饰。我们得到了一个很好的结果。

使用GrabCut算法进行交互式前景提取 OpenCV-Python v4.7.0_第1张图片
那么在后台会发生什么?

  • 用户输入一个矩形。这个矩形以外的所有东西都将被视为确定的背景(这就是前面提到的矩形应该包括所有物体的原因)。矩形内的所有东西都是未知的。同样,任何指定前景和背景的用户输入都被认为是硬标签,这意味着它们在这个过程中不会改变。
  • 计算机根据我们提供的数据做了一个初始标记。它给前景和背景像素贴上标签(或硬标签)。
  • 现在,高斯混合模型(GMM)被用来对前景和背景进行建模。
  • 根据我们提供的数据,GMM学习并创建新的像素分布。也就是说,未知像素被标记为可能的前景或可能的背景,这取决于它与其他硬标记的像素在颜色统计方面的关系(这就像聚类)。
  • 从这个像素分布建立一个图。图中的结点是像素。另外还增加了两个节点,源节点和汇节点。每个前景像素都与源节点相连,每个背景像素都与汇节点相连。
  • 连接像素和源节点/末端节点的边的权重由一个像素是前景/背景的概率定义。像素之间的权重由边缘信息或像素的相似度来定义。如果像素的颜色有很大的差异,它们之间的边缘将得到较低的权重。
  • 然后用最小切割算法来分割图形。它以最小的成本函数将图切割成两个分离的源节点和汇节点。成本函数是所有被切割的边的权重之和。切割后,与源节点相连的所有像素成为前景,与汇节点相连的像素成为背景。
  • 这个过程一直持续到分类结果收敛为止。
    如下图所示(图片来源:http://www.cs.ru.ac.za/research/g02m1682/)。

使用GrabCut算法进行交互式前景提取 OpenCV-Python v4.7.0_第2张图片

演示

现在我们用OpenCV进行抓取算法。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,因为我们使用的是矩形。然后运行grabcut。它修改了遮罩图像。在新的蒙版图像中,像素将被标记为四个标志,表示上述的背景/前景。所以我们修改蒙版,使所有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()

请看下面的结果:
使用GrabCut算法进行交互式前景提取 OpenCV-Python v4.7.0_第3张图片
哎呀,梅西的头发不见了。谁会喜欢没有头发的梅西?我们需要把它带回来。所以我们将用1个像素对其进行精细的修饰(确保前景)。同时,一些我们不想要的地面部分也出现在图片中,还有一些标志。我们需要删除它们。在这里我们给一些0像素的修饰(确定背景)。所以我们要像现在所说的那样,修改我们在以前的案例中得到的蒙版。

我实际做的是,我在paint应用程序中打开输入的图像,并在图像上添加了另一个层。使用画笔工具,我在这个新的图层上用白色标记了遗漏的前景(头发、鞋子、球等),用黑色标记了不需要的背景(如商标、地面等)。然后用灰色填充剩余的背景。然后在OpenCV中加载该蒙版图像,用新添加的蒙版图像中的相应数值编辑我们得到的原始蒙版图像。请看下面的代码:

# newmask是我手动标注的蒙版图像
newmask = cv.imread('newmask.png',0)
# 凡是标有白色的地方(肯定是前景)、 change mask=1
# 凡是标有黑色的地方(确定背景)、 change mask=0
mask[newmask == 0] = 0
mask[newmask == 255] = 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()

请看下面的结果:
使用GrabCut算法进行交互式前景提取 OpenCV-Python v4.7.0_第4张图片
所以,这就是了。在这里,你可以直接进入蒙版模式,而不是在矩形模式下初始化。只要在蒙版图像中用2像素或3像素(可能是背景/前景)标记矩形区域。然后像我们在第二个例子中做的那样,用1像素标记我们的sure_foreground。然后直接应用蒙版模式的grabCut函数。

练习

  1. OpenCV的样本中包含一个grabcut.py,它是一个使用grabcut的互动工具。请查看它。也可以看一下这个YouTube视频,了解如何使用它。
  2. 在这里,你可以把它变成一个交互式的样本,用鼠标绘制矩形和笔画,创建轨迹条来调整笔画宽度等。

你可能感兴趣的:(OpenCV-Python,4.7.0,说明文档,python,opencv,算法)