- 1. 学习如何在你的电脑上配置OpenCV-Python环境!
- 1.1 开始了解OpenCV-Python
- 1.2 在 Windows 下安装 OpenCV-Python
- 1.3 在 Fedora 环境下安装 OpenCV-Python
- 1.4 在 Debian(Ubuntu)中配置 OpenCV-Python
- 1.5 在Docker中安装OpenCV-Python
- 1.6 在树莓派配置OpenCV-Python
- 2. OpenCV中的GUI功能
- 2.1 开始使用图像
- 2.2 开始使用视频
- 2.3 OpenCV 中的绘图函数
- 2.4 以鼠标为画笔
- 2.5 用滑块控制条做调色板
- 3. OpenCV中的GUI功能
- 3.1 图片基本操作
- 3.2 图像算术操作
- 3.3 性能评估与改进技巧
- 4. OpenCV中的图像处理
- 4.1 更换颜色空间
- 4.2 对图像进行几何变换
- 4.3 图像二值化处理
- 4.4 平滑图像
- 4.5 形态学转换
- 4.6 图像梯度
- 4.7 Canny边缘检测
- 4.8 图像金字塔
- 4.9.1 直方图:查找,绘制,分析
- 4.9.2 直方图均衡化
- 4.9.3 二维直方图
- 4.9.4 直方图反投影
- 4.10 OpenCV中的图像变换
- 4.10.1 傅立叶变换
- 4.11 模板匹配
- 4.12 霍夫直线变换
- 4.13 霍夫圆变换
- 4.14 基于分水岭算法的图像分割
- 4.14 使用 GrabCut 算法交互式前景提取
- 5. 特征检测和描述符
- 5.1 理解特征
- 5.2 Harris 角点检测
- 5.3 Shi-Tomasi 角点检测 & 适合用来跟踪的特征
- 5.4 介绍SIFT(尺度不变特征转换)
- 5.5 介绍SURF(加速稳健特征)
- 5.6 角点检测的FAST算法
- 5.7 BRIEF特征点描述算法
- 5.8 ORB 特征描述符(Oriented FAST and Rotated BRIEF)
- 5.9 特征匹配
- 5.10 特征匹配和使用单应性匹配来搜索物体
- 6. 视频分析
- 6.1 Meanshift和Camshift
- 6.2 光流
- 6.3 背景分割
- 7. 相机校准和3D重建
- 7.1 相机校准
- 7.2 姿势估计
- 7.3 极线几何
- 7.4 来自立体图像的深度图
- 8. 机器学习
- 8.1 K-最近邻算法
- 8.1.1 了解k-最近邻算法
- 8.1.2 使用kNN进行手写字符的OCR
- 8.2 支持向量机(SVM)
- 8.2.1 理解SVM
- 8.2.2 使用SVM的手写数据的OCR
- 8.3 K-Means聚类
- 8.3.1 理解 K-Means 聚类
- 8.3.2 OpenCV中的K-Means聚类
- 9. 计算摄影学
- 9.1 图像去噪
- 9.2 图像修复
- 9.3 高动态范围(HDR)
- 10. 目标检测
- 10.1 使用 Haar Cascades 的面部识别
- 11. OpenCV-Python 绑定
- 11.1 OpenCV-Python绑定如何工作?
4.14 使用 GrabCut 算法交互式前景提取
目标
在这一章当中
- 我们将看到 GrabCut 算法提取图像中的前景
- 我们将为此创建一个交互式应用程序。
理论基础
GrabCut算法由英国剑桥微软研究院的Carsten Rother,Vladimir Kolmogorov和Andrew Blake设计,并发表在他们的论文《"GrabCut": interactive foreground extraction using iterated graph cuts》中。如果你一个只需要最少量用户交互的前景提取算法,那么GrabCut就是你所需要的。
从用户的角度来看它是如何工作的?最初用户围绕着前景区域绘制一个矩形(前景区域应该完全在矩形内)。然后算法对其进行迭代分割以获得最佳结果。但在某些情况下,分割不会很好,例如,它可能标记了一些前景区域作为背景,或反之。在这种情况下,用户需要做一些修改。只需在图像上点击一些错误的结果就可以了。基本上是这样的:“嘿,这个区域应该是前景的,你把它标记为背景,在下一次迭代中纠正它”,或者对于背景来说正相反。然后在下一次迭代中,你会得到更好的结果。
看到下面的图片。一开始球员和足球被围在一个蓝色的矩形中。然后做一些白色笔画(表示前景)和黑色笔画(表示背景)的修饰。
我们得到一个不错的结果。
那么后台发生了什么?
- 用户输入矩形。这个矩形之外的所有东西都将被视为确定的背景(这就是之前提到你的矩形应该包含所有对象的原因)。矩形内的所有东西都是未知的。类似地,任何指定前景和背景的用户输入都被认为是硬标签,这意味着它们在该过程中不会改变。
- 计算机根据我们提供的数据进行初始标注。它标记前景和背景像素(或硬标签)
- 现在使用高斯混合模型(GMM)来模拟前景和背景。
- 根据我们提供的数据,GMM学习并创建新的像素分布。也就是说,未知像素在颜色统计方面根据其与其他硬标记像素之间的关系被标记为可能的前景或可能的背景(就像聚类一样)。
- 从这个像素分布构建一个图形。图中的节点是像素。另外增加两个节点,Source节点和Sink节点。每个前景像素连接到Source节点,每个背景像素连接到Sink节点。
- 将像素连接到Sorce节点/Sink节点的边的权重由像素为前景/背景的概率定义。像素之间的权重由边缘信息或像素相似性定义。如果像素颜色差异很大,那么它们之间的边的权值将会变得很低。
然后使用mincut算法来分割图形。它将图形切割成两个分离的源节点和最小代价函数的汇聚节点。成本函数是剪切边的所有权重的总和。剪切之后,连接到源节点的所有像素变为前景,连接到源节点的像素变为背景。 - 过程一直持续到分类收敛。
演示
现在我们开始使用OpenCV中的的grabcut算法。 OpenCV有这个函数:cv2.grabCut()
。我们首先来看看它的参数:
img
- 输入图像mask
-这是一个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
或其组合,这个参数决定我们是否绘制矩形或最终的触觉笔触。
首先让我们看看GC_INIT_WITH_RECT
模式。我们加载图像,创建一个类似的蒙版图像。我们创建fgdModel
和bgdModel
。我们给矩形参数。这些都是是直截了当的。让算法运行5次。由于我们使用的是矩形,所以模式应该是cv2.GC_INIT_WITH_RECT
。然后运行grabCut。它会修改蒙版图像。在新的mask图像中,像素将被标记为具有如上所述的表示背景/前景的四个标记。所以我们修改mask,使所有的0像素和2像素被置为0(即背景),并且所有1像素和3像素被置于1(即前景像素)。现在我们最后的mask已经准备好了,只要将它与输入图像相乘即可获得分割过的图像。
import numpy as np
import cv2
from matplotlib import pyplot as plt
img = cv2.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)
cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)
mask2 = np.where((mask2)|(mask0),0,1).astype('uint8')
img = img*mask2[:,:,np.newaxis]
plt.imshow(img),plt.colorbar(),plt.show()
哎呀,梅西的头发不见了。谁喜欢没有头发的梅西?我们需要把它弄回来。所以我们会给出一个很好的值为1的像素的修正(确定前景)。与此同时,地上的一部分进入了图片中,这是我们不想要的,并且一些logo也是这样。我们需要删除它们。在那里,我们给出一些值为0的像素(确定的背景)。所以我们在前面的例子中修改了我们所得到的mask。
我真正做的是,我在绘画应用程序中打开输入图像,并添加另一个图层的图像。在绘画中使用画笔工具,我用白色和不需要的背景(如标志,地面等)在这个新层上标记错过的前景(头发,鞋子,球等)。然后用灰色填充剩余的背景。然后在OpenCV中加载该遮罩图像,编辑原来的遮罩图像,并在新添加的遮罩图像中得到相应的值。检查下面的代码:
# newmask 是一个我手动打好标签的图片
newmask = cv2.imread('newmask.png',0)
# 被标记为白色的部分(确定的前景),将mask改为1
# 被标记为黑色的部分(确定的背景),将mask改为0
mask[newmask == 0] = 0
mask[newmask == 255] = 1
mask, bgdModel, fgdModel = cv2.grabCut(img,mask,None,bgdModel,fgdModel,5,cv2.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。然后直接使用mask模式的grabCut功能。
练习
- OpenCV 示例包含一个样例 grabcut.py,它是一个使用 grabcut 的交互式工具。去试试看。另外看一下这个关于如何使用它的 YouTube的视频。
- 你可以把它做成一个交互式的示例,用鼠标绘制矩形和笔画,创建轨迹栏来调整笔画宽度等。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论