OpenCV-Python 交互式前景提取使用GrabCut算法 | 三十五
目标
在本章中,
- 我们将看到GrabCut算法来提取图像中的前景
- 我们将为此创建一个交互式应用程序。
理论
GrabCut算法由英国微软研究院的Carsten Rother,Vladimir Kolmogorov和Andrew Blake设计。在他们的论文“GrabCut”中:使用迭代图割的交互式前景提取。需要用最少的用户交互进行前景提取的算法,结果是GrabCut。
从用户角度来看,它是如何工作的?最初,用户在前景区域周围绘制一个矩形(前景区域应完全位于矩形内部)。然后,算法会对其进行迭代分割,以获得最佳结果。做完了但在某些情况下,分割可能不会很好,例如,可能已将某些前景区域标记为背景,反之亦然。在这种情况下,需要用户进行精修。只需在图像错误分割区域上画些笔画。笔画基本上说 “嘿,该区域应该是前景,你将其标记为背景,在下一次迭代中对其进行校正”或与背景相反。然后在下一次迭代中,你将获得更好的结果。
参见下图。第一名球员和橄榄球被封闭在一个蓝色矩形中。然后用白色笔划(表示前景)和黑色笔划(表示背景)进行最后的修饰。而且我们得到了不错的结果。
那么背景发生了什么呢?
- 用户输入矩形。此矩形外部的所有内容都将作为背景(这是在矩形应包含所有对象之前提到的原因)。矩形内的所有内容都是未知的。同样,任何指定前景和背景的用户输入都被视为硬标签,这意味着它们在此过程中不会更改。
- 计算机根据我们提供的数据进行初始标记。它标记前景和背景像素(或对其进行硬标记),现在使用高斯混合模型(GMM)对前景和背景进行建模。
- 根据我们提供的数据,GMM可以学习并创建新的像素分布。也就是说,未知像素根据颜色统计上与其他硬标记像素的关系而被标记为可能的前景或可能的背景(就像聚类一样)。
- 根据此像素分布构建图形。图中的节点为像素。添加了另外两个节点,即“源”节点和“接收器”节点。每个前景像素都连接到源节点,每个背景像素都连接到接收器节点。
- 通过像素是前景/背景的概率来定义将像素连接到源节点/末端节点的边缘的权重。像素之间的权重由边缘信息或像素相似度定义。如果像素颜色差异很大,则它们之间的边缘将变低。
- 然后使用mincut算法对图进行分割。它将图切成具有最小成本函数的两个分离的源节点和宿节点。成本函数是被切割边缘的所有权重的总和。剪切后,连接到“源”节点的所有像素都变为前景,而连接到“接收器”节点的像素都变为背景。
- 继续该过程,直到分类收敛为止。
如下图所示(图片提供:http://www.cs.ru.ac.za/research/g02m1682/)
示例
现在我们使用OpenCV进行抓取算法。OpenCV为此具有功能cv.grabCut(),我们将首先看到其参数:
- img - 输入图像
- mask - 这是一个掩码图像,在其中我们指定哪些区域是背景,前景或可能的背景/前景等。这是通过以下标志完成的:cv.GC_BGD,cv.GC_FGD, cv.GCPRBGD,cv.GCPRFGD,或直接将
0,1,2,3
传递给图像。 - rect - 它是矩形的坐标,其中包括前景对象,格式为
(x,y,w,h)
- bdgModel, fgdModel - 这些是算法内部使用的数组。你只需创建两个大小为
(1,65)
的np.float64
类型零数组。 - iterCount - 算法应运行的迭代次数。
- model - 应该是cv.GCINITWITH_RECT或cv.GCINITWITH_MASK或两者结合,决定我们要绘制矩形还是最终的修饰笔触。
首先让我们看看矩形模式。我们加载图像,创建类似的mask图像。我们创建fgdModel和bgdModel。我们给出矩形参数。一切都是直截了当的。让算法运行5次迭代。模式应为cv.GCINITWITH_RECT, 因为我们使用的是矩形。然后运行grabcut。修改mask图像。在新的mask图像中,像素将被标记有四个标记,分别表示上面指定的背景/前景。因此,我们修改mask,使所有0像素和2像素都置为0(即背景),而所有1像素和3像素均置为1(即前景像素)。现在,我们的最终mask已经准备就绪。只需将其与输入图像相乘即可得到分割的图像。
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像素的修饰(确保背景)。因此,如现在所说,我们在以前的情况下修改生成的mask。
我实际上所做的是,我在paint应用程序中打开了输入图像,并在图像中添加了另一层。使用画笔中的画笔工具,我在新图层上用白色标记了错过的前景(头发,鞋子,球等),而用白色标记了不需要的背景(例如logo,地面等)。然后用灰色填充剩余的背景。然后将该mask图像加载到OpenCV中,编辑我们在新添加的mask图像中具有相应值的原始mask图像。
检查以下代码:
#newmask是我手动标记过的mask图像
newmask = cv.imread('newmask.png',0)
# 标记为白色(确保前景)的地方,更改mask = 1
# 标记为黑色(确保背景)的地方,更改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()
查看以下结果:
就是这样了。在这里,你无需直接在rect模式下初始化,而可以直接进入mask模式。只需用2像素或3像素(可能的背景/前景)标记mask图像中的矩形区域。然后像在第二个示例中一样,将我们的sure_foreground标记为1像素。然后直接在mask模式下应用grabCut功能。
练习
- OpenCV示例包含一个示例catchcut.py,这是一个使用grabcut的交互式工具。检查。另请观看有关如何使用它的youtube视频。
- 在这里,你可以通过绘制矩形和使用鼠标笔触使其成为交互式示例,创建轨迹栏以调整笔触宽度等。
欢迎关注磐创博客资源汇总站:http://docs.panchuang.net/
欢迎关注PyTorch官方中文教程站:http://pytorch.panchuang.net/
OpenCV中文官方文档:http://woshicver.com/
OpenCV-Python 交互式前景提取使用GrabCut算法 | 三十五的更多相关文章
- Python进阶(三十五)-Fiddler命令行和HTTP断点调试
Python进阶(三十五)-Fiddler命令行和HTTP断点调试 一. Fiddler内置命令 上一节(使用Fiddler进行抓包分析)中,介绍到,在web session(与我们通常所说的se ...
- 孤荷凌寒自学python第三十五天python的文件操作之针对文件操作的os模块的相关内容
孤荷凌寒自学python第三十五天python的文件操作之针对文件操作的os模块的相关内容 (完整学习过程屏幕记录视频地址在文末,手写笔记在文末) 一.打开文件后,要务必记得关闭,所以一般的写法应当 ...
- Python学习之旅(三十五)
Python基础知识(34):电子邮件(Ⅰ) 几乎所有的编程语言都支持发送和接收电子邮件 在使用Python收发邮件前,请先准备好至少两个电子邮件,如xxx@163.com,xxx@sina.com, ...
- python数据结构与算法第十五天【二叉树】
1.树的特点 (1)每个节点有零个或多个子节点: (2)没有父节点的节点称为根节点: (3)每一个非根节点有且只有一个父节点: (4)除了根节点外,每个子节点可以分为多个不相交的子树: 2.树的种类 ...
- OpenCV-Python 图像分割与Watershed算法 | 三十四
目标 在本章中, 我们将学习使用分水岭算法实现基于标记的图像分割 我们将看到:cv.watershed() 理论 任何灰度图像都可以看作是一个地形表面,其中高强度表示山峰,低强度表示山谷.你开始用不同 ...
- 第三十五节,目标检测之YOLO算法详解
Redmon, J., Divvala, S., Girshick, R., Farhadi, A.: You only look once: Unified, real-time object de ...
- python接口自动化(三十五)-封装与调用--流程类接口关联(详解)
简介 流程相关的接口,主要用 session 关联,如果写成函数(如上篇),s 参数每个函数都要带,每个函数多个参数,这时候封装成类会更方便.在这里我们还是以博客园为例,带着小伙伴们实践一下. 接口封 ...
- Java数据结构和算法(十五)——无权无向图
前面我们介绍了树这种数据结构,树是由n(n>0)个有限节点通过连接它们的边组成一个具有层次关系的集合,把它叫做“树”是因为它看起来像一棵倒挂的树,包括二叉树.红黑树.2-3-4树.堆等各种不同的 ...
- Python之路(第三十五篇) 并发编程:操作系统的发展史、操作系统的作用
一.操作系统发展史 第一阶段:手工操作 —— 真空管和穿孔卡片 第一代之前人类是想用机械取代人力,第一代计算机的产生是计算机由机械时代进入电子时代的标志,从Babbage失败之后一直到第二次世界大 ...
随机推荐
- sklearn简单实现机器学习算法记录
sklearn简单实现机器学习算法记录 需要引入最重要的库:Scikit-learn 一.KNN算法 from sklearn import datasets from sklearn.model_s ...
- jenkins-设置定时任务
前言 跑自动化用例每次用手工点击 jenkins 出发自动化用例太麻烦了,我们希望能每天固定时间 跑,这样就不用管了,坐等收测试报告结果就行. 一.定时构建语法 * * * * * (五颗星,中间用 ...
- Spring MVC知识梳理
同上一篇博客,复习梳理SpringMVC知识点,这次的梳理比较快,很多细节没有顾虑到,后期可能会回来补充 1. 整体架构 1.1 在学习了SSM框架后我们来理清三者的应用层面 浏览器发送请求,请求到达 ...
- 使用Vagrant部署虚拟分布式开发和测试环境
同步更新到笔者个人博客,可以访问我的博客查看原文:https://www.rockysky.tech 创建自动化配置开发环境 最近由于最近研究和学习的关系,需要经常配置和搭建多个虚拟机组成的分布式系统 ...
- 一起了解 .Net Foundation 项目 No.13
.Net 基金会中包含有很多优秀的项目,今天就和笔者一起了解一下其中的一些优秀作品吧. 中文介绍 中文介绍内容翻译自英文介绍,主要采用意译.如与原文存在出入,请以原文为准. MVVM Light To ...
- React拖拽组件Dragact V0.1.7:教你优化React组件性能与手感
仓库地址:Dragact手感丝滑的拖拽布局组件 预览地址:支持手机端噢- 上回我们说到,Dragact组件已经进行了一系列的性能优化,然而面对大量数据的时候,依旧比较吃力,让我们来看看,优化之前的Dr ...
- 在centos7使用docker下搭建elasticsearch集群
一 .docker的安装 https://www.cnblogs.com/ghostdot/p/12410242.html 二.创建相关映射文件 cd /home/ mkdir node cd nod ...
- Layabox UI 笔记
1.UI List 官方文档是 https://ldc2.layabox.com/doc/?language=zh&nav=zh-js-3-3-7 通常用List的时候会出现滚动条按钮比例拉 ...
- HashSet底层、及存入对象时候如何保持唯一
HashSet底层.及存入对象时候如何保持唯一 在JDK1.8之前,哈希表底层采用数组+链表实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里. 但是当位于一个桶中的元素较多,即hash ...
- flask修改flask_wtf使其支持json数据的validation验证
flask默认是前后端不分离策略,前端通过flask+wtf表单来传递post,put...等数据. 现在前后端分离是趋势,那么对flask进行一定的修改,变为前后端分离,在前端页面中请求后端,那么请 ...