【OpenCV】基于GrabCut算法的交互式前景提取
介绍
GrabCut 算法是一种用于图像分割的交互式前景提取技术,它结合了图割(Graph Cut)方法和迭代优化过程。该算法最初由 Rother, Kolmogorov 和 Blake 在 2004 年提出,并因其高效性和准确性而被广泛应用于计算机视觉领域。OpenCV 提供了 cv2.grabCut() 函数来实现这一算法,使得开发者可以方便地在应用程序中使用。
GrabCut 算法的基本原理
- 初始化:用户通过绘制矩形或自由手绘的方式标记出大致的前景区域(即对象所在的位置),同时还可以选择性地标记背景区域。
- 构建图形模型:基于用户的输入,算法会为每个像素创建一个节点,并且在相邻像素之间建立边。这些边的权重反映了像素间的相似度,通常基于颜色信息。
- 概率分布估计:对于已知的前景和背景区域,分别拟合高斯混合模型(GMMs, Gaussian Mixture Models),用以描述其颜色分布特性。
- 能量函数最小化:定义一个能量函数,其中包含数据项(反映像素与各自GMM之间的匹配程度)和平滑项(鼓励相邻像素具有相同的标签)。然后利用图割算法找到使能量函数最小化的解决方案。
- 迭代改进:根据前一次迭代的结果更新GMM参数,并重复上述步骤直至收敛或达到预定次数。
理论
GrabCut 算法由英国剑桥微软研究院 Carsten Rother,Vladimir Kolmogorov和Andrew Blake发明,并在他们的论文“GrabCut”:使用迭代图切割中提出。该算法需要最少的人工交互做前景提取,被称为 GrabCut。
从用户角度来看,该算法是如何工作的呢?最初用户在前景区域周围绘制一个矩形(该矩形需要完全框住所有的前景区域) 。然后算法对其进行迭代分割,得到最佳结果。但在某些情况下,分割的不是那么理想,比如说,它可能把一些前景区域标成了背景,或者反过来。如果发生了这样的情况,用户需要进行仔细的修正。只要在有错误结果的地方“划一下”就行了。“划一下”基本的意思是说,这个区域应该是前景,你标记它为背景,在下一次迭代中更正它。"* 或者如果区域是背景,也如此类推。然后再下一次迭代中,你就会得到更好的结果。
见下图。第一名球员和足球被包围在一个蓝色矩形中。然后进行一些具有白色笔划(表示前景)和黑色笔划(表示背景)的最终修饰。我们得到了一个很好的结果。

那背景会发生什么?
- 用户输入矩形。这个矩形之外的所有东西都将被视为确定的背景(这就是之前提到的矩形应该包括所有对象的原因)。矩形内的一切都是未知的。类似地,任何指定前景和背景的用户输入都被视为硬标签,这意味着它们不会在过程中发生变化。
- 计算机根据我们提供的数据进行初始标记。它标记前景和背景像素(或硬标记)
- 现在使用高斯混合模型(GMM)来模拟前景和背景。
- 根据我们提供的数据,GMM 学习并创建新的像素分布。也就是说,未知像素被标记为可能的前景或可能的背景,这取决于其在颜色统计方面与其他硬标记像素的关系(它就像聚类一样)。
- 从该像素分布构建图形。图中的节点是像素。添加了另外两个节点,源节点和 Sink 节点。每个前景像素都连接到源节点,每个背景像素都连接到 Sink 节点。
- 连接像素到源节点/端节点的边的权重由像素是前景/背景的概率来定义。像素之间的权重由边缘信息或像素相似性定义。如果像素颜色存在较大差异,则它们之间的边缘将获得较低的权重。
- 然后使用 mincut 算法来分割图形。它将图形切割成两个分离源节点和汇聚节点,具有最小的成本函数。成本函数是被切割边缘的所有权重的总和。切割后,连接到 Source 节点的所有像素变为前景,连接到 Sink 节点的像素变为背景。
- 该过程一直持续到分类收敛为止。
如下图所示(图片提供: "GrabCut" )

演示
现在我们使用 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 - 这些是内部算法使用的数组。您只需创建两个大小为(n = 1.65)的 np.float64 类型零数组。
- iterCount - 算法运行的迭代次数。
- 模式 - 它应该是 **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 = cv.imread('newmask.png',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 模式下初始化,而是直接进入掩膜模式。只需用 2 像素或 3 像素(可能的背景/前景)标记蒙版图像中的矩形区域。然后像我们在第二个例子中那样用 1 像素标记我们的 sure_foreground。然后直接应用具有掩膜模式的 grabCut 函数。
相关文章:
【OpenCV】基于GrabCut算法的交互式前景提取
介绍 GrabCut 算法是一种用于图像分割的交互式前景提取技术,它结合了图割(Graph Cut)方法和迭代优化过程。该算法最初由 Rother, Kolmogorov 和 Blake 在 2004 年提出,并因其高效性和准确性而被广泛应用于计算机视觉领域。OpenCV…...
【Flask+OpenAI】利用Flask+OpenAI Key实现GPT4-智能AI对话接口demo - 从0到1手把手全教程(附源码)
文章目录 前言环境准备安装必要的库 生成OpenAI API代码实现详解导入必要的模块创建Flask应用实例配置OpenAI API完整代码如下(demo源码)代码解析 利用Postman调用接口 了解更多AI内容结尾 前言 Flask作为一个轻量级的Python Web框架,凭借其…...
最短路----Dijkstra算法详解
简介 迪杰斯特拉(Dijkstra)算法是一种用于在加权图中找到单个源点到所有其他顶点的最短路径的算法。它是由荷兰计算机科学家艾兹格迪科斯彻(Edsger Dijkstra)在1956年提出的。Dijkstra算法适用于处理带有非负权重的图。迪杰斯特拉…...
ORB-SLAM3源码学习:G2oTypes.cc: void EdgeInertial::computeError 计算预积分残差
前言 这部分函数涉及了g2o的内容以及IMU相关的推导内容,需要你先去进行这部分的学习。 1.函数声明 void EdgeInertial::computeError() 2.函数定义 涉及到的IMU的公式: {// TODO Maybe Reintegrate inertial measurments when difference between …...
Unity协程机制详解
Unity的协程(Coroutine)是一种异步编程的机制,允许在多个帧之间分割代码的执行,而不阻塞主线程。与传统的多线程不同,Unity的协程在主线程中运行,并不会开启新的线程。 什么是协程? 协程是一种…...
2024年【高压电工】最新解析及高压电工考试总结
高压电工考试是电力行业从业人员必须通过的资格考试之一,它不仅检验了考生对高压电技术的掌握程度,还考验了考生在实际操作中的安全意识和应急处理能力。为了帮助广大考生更好地备考,本文整理了10道2024年高压电工考试的最新解析及总结试题&a…...
OELOVE 6.0城市列表模板
研究了好久OELOVE6.0源码,一直想将城市列表给单独整出来,做地区排名,但是PHP程序都是加密的,非常难搞,做二开都是要命的处理不了,在这里有一个简单方法可以处理城市列表,并且可以自定义TDK&…...
如何将你的 Ruby 应用程序从 OpenSearch 迁移到 Elasticsearch
作者:来自 Elastic Fernando Briano 将 Ruby 代码库从 OpenSearch 客户端迁移到 Elasticsearch 客户端的指南。 OpenSearch Ruby 客户端是从 7.x 版 Elasticsearch Ruby 客户端分叉而来的,因此代码库相对相似。这意味着当将 Ruby 代码库从 OpenSearch 迁…...
day1数据结构,关键字,内存空间存储与动态分区,释放
小练习 在堆区空间连续申请5个int类型大小空间,用来存放从终端输入的5个学生成绩,然后显示5个学生成绩,再将学生成绩升序排序,排序后,再次显示学生成绩。显示和排序分别用函数完成(两种排序方法࿰…...
1_linux系统网络性能如何优化——几种开源网络协议栈比较
之前合集《计算机网络从入门到放弃》第一阶段算是已经完成了。都是理论,没有实操,让“程序猿”很难受,操作性不如 Modbus发送的报文何时等到应答和 tcp通信测试报告单1——connect和send。开始是想看linux内核网络协议栈的源码,然…...
【问题记录】07 MAC电脑,使用FileZilla(SFTP)连接堡垒机不成功
项目场景: 使用MAC电脑,以子账号(非root)的形式登录,连接堡垒机CLB(传统型负载均衡),使用FileZilla(SFTP)进行FTP文件传输。 问题描述: MAC电脑…...
前端报错npm ERR cb() never called问题
环境使用node版本v14.21.3,npm版本6.14.18 1.问题描述 1.1使用npm install后报错 npm ERR! cb() never called!npm ERR! This is an error with npm itself. Please report this error at: npm ERR! ? ? <https://npm.community>npm ERR! A complete log…...
康谋方案 | 多源相机数据采集与算法集成测试方案
目录 一、相机组成 二、多源相机采集与测试方案 三、应用案例分享 四、结语 在智能化技术快速发展当下,图像数据的采集与处理逐渐成为自动驾驶、工业等领域的一项关键技术。高质量的图像数据采集与算法集成测试都是确保系统性能和可靠性的关键。随着技术的不断进…...
Graspness 端到端抓取点估计 | 环境搭建 | 模型推理测试
在复杂场景中实现抓取检测,Graspness是一种端到端的方法; 输入点云数据,输出抓取角度、抓取深度、夹具宽度等信息。 开源地址:https://github.com/rhett-chen/graspness_implementation?tabreadme-ov-file 论文地址࿱…...
交换机是如何避免数据碰撞的(详细解释 + 示例)
交换机是如何避免数据碰撞的(详细解释 示例) 1. 独立冲突域 交换机的每个端口都形成一个独立的冲突域。这意味着通过交换机连接的每个设备都拥有自己的通信通道,互不干扰。 示例: 假设一个交换机有4个端口,分别连接…...
魅族手机刷官方系统
从魅族官网下载固件 https://flyme.cn/firmware.html 找到自己的型号,里面有历史版本、最新版,按照需求下载。 下载的是update.zip,改名就不能升级了 方法1 直接点击下载的update.zip包就可以升级。 方法2 将文件移动到文件管理的根目录&a…...
女人想要的,是那份懂她的情绪价值
女人想要的,是那份懂她的情绪价值 在情感的世界里,我们常常听到这样的声音:“我不需要你帮我解决问题,我只希望你能懂我。”这句话,简单却深刻,它揭示了女性在情感需求上的一个独特面向——她们渴望的&…...
[python SQLAlchemy数据库操作入门]-10.性能优化:提升 SQLAlchemy 在股票数据处理中的速度
哈喽,大家好,我是木头左! 当处理大量数据时,如股票数据,默认的ORM操作可能会显得效率低下。本文将探讨如何通过一些技巧和策略来优化SQLAlchemy ORM的性能,从而提升其在股票数据处理中的速度。 1. 选择合适的数据类型 在定义模型时,选择合适的数据类型对于性能至关重要…...
【网络取证篇】取证实战之PHP服务器镜像网站重构及绕密分析
【网络取证篇】取证实战之PHP服务器镜像网站重构及绕密分析 在裸聊敲诈、虚假理财诈骗案件类型中,犯罪分子为了能实现更低成本、更快部署应用的目的,其服务器架构多为常见的初始化网站架构,也称为站库同体服务器!也就是说网站应用…...
[python]使用 Pandas 处理 Excel 数据:分割与展开列操作
在数据处理的过程中,时常需要对 Excel 表格中的数据进行清洗与转换,下面介绍使用 Python 中的 Pandas 库对 Excel 文件中的数据进行操作,具体包括分割列、展开数据、清除空格以及格式转换等操作。 目标: 读取一个没有表头的 Exc…...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...
CocosCreator 之 JavaScript/TypeScript和Java的相互交互
引擎版本: 3.8.1 语言: JavaScript/TypeScript、C、Java 环境:Window 参考:Java原生反射机制 您好,我是鹤九日! 回顾 在上篇文章中:CocosCreator Android项目接入UnityAds 广告SDK。 我们简单讲…...
自然语言处理——Transformer
自然语言处理——Transformer 自注意力机制多头注意力机制Transformer 虽然循环神经网络可以对具有序列特性的数据非常有效,它能挖掘数据中的时序信息以及语义信息,但是它有一个很大的缺陷——很难并行化。 我们可以考虑用CNN来替代RNN,但是…...
解析奥地利 XARION激光超声检测系统:无膜光学麦克风 + 无耦合剂的技术协同优势及多元应用
在工业制造领域,无损检测(NDT)的精度与效率直接影响产品质量与生产安全。奥地利 XARION开发的激光超声精密检测系统,以非接触式光学麦克风技术为核心,打破传统检测瓶颈,为半导体、航空航天、汽车制造等行业提供了高灵敏…...
从“安全密码”到测试体系:Gitee Test 赋能关键领域软件质量保障
关键领域软件测试的"安全密码":Gitee Test如何破解行业痛点 在数字化浪潮席卷全球的今天,软件系统已成为国家关键领域的"神经中枢"。从国防军工到能源电力,从金融交易到交通管控,这些关乎国计民生的关键领域…...
Xela矩阵三轴触觉传感器的工作原理解析与应用场景
Xela矩阵三轴触觉传感器通过先进技术模拟人类触觉感知,帮助设备实现精确的力测量与位移监测。其核心功能基于磁性三维力测量与空间位移测量,能够捕捉多维触觉信息。该传感器的设计不仅提升了触觉感知的精度,还为机器人、医疗设备和制造业的智…...
MySQL的pymysql操作
本章是MySQL的最后一章,MySQL到此完结,下一站Hadoop!!! 这章很简单,完整代码在最后,详细讲解之前python课程里面也有,感兴趣的可以往前找一下 一、查询操作 我们需要打开pycharm …...
DAY 26 函数专题1
函数定义与参数知识点回顾:1. 函数的定义2. 变量作用域:局部变量和全局变量3. 函数的参数类型:位置参数、默认参数、不定参数4. 传递参数的手段:关键词参数5 题目1:计算圆的面积 任务: 编写一…...
车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...
Linux操作系统共享Windows操作系统的文件
目录 一、共享文件 二、挂载 一、共享文件 点击虚拟机选项-设置 点击选项,设置文件夹共享为总是启用,点击添加,可添加需要共享的文件夹 查询是否共享成功 ls /mnt/hgfs 如果显示Download(这是我共享的文件夹)&…...
