OpenCV-Python(28):基于GrabCut 算法交互式前景提取

目标

  • GrabCut 算法原理,使用GrabCut 算法提取图像的前景
  •  创建一个交互是程序完成前景提取

介绍

        GrabCut算法是一种基于图像分割的算法,用于将图像中的前景物体从背景中准确地分离出来。它是由Carsten Rother等人于2004年提出的。

        GrabCut算法的基本思想是通过迭代的方式将图像分成前景和背景两部分。它首先需要用户提供一个包含前景物体的矩形框,然后通过迭代的方式对图像进行分割。在每一次迭代中,算法会根据像素的颜色和纹理信息,以及前景和背景的模型,对像素进行分类。然后,算法会根据分类结果更新前景和背景的模型,并进行下一次迭代。直到算法收敛为止,得到最终的前景和背景分割结果。

步骤

1.用户输入一个包含前景物体的矩形框。
2.使用高斯混合模型(GMM)对前景和背景进行建模。
3.根据像素的颜色和纹理信息,对像素进行分类(前景或背景)。
4.根据分类结果,更新前景和背景的模型。
5.重复步骤3和步骤4,直到算法收敛。
6.根据最终的分类结果,将图像分割成前景和背景两部分。

实现

在OpenCV中,可以使用cv2.grabCut()函数来实现GrabCut算法。函数原型如下:

mask, bgdModel, fgdModel = cv2.grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode=None)

参数说明:

  • img:输入图像。
  • mask:与输入图像大小相同的掩码图像,用于指定前景、背景和未知区域。
  • rect:包含前景物体的矩形框。
  • bgdModel:背景模型。
  • fgdModel:前景模型。
  • iterCount:迭代次数。
  • mode:可选参数,用于指定操作模式(例如,cv2.GC_INIT_WITH_RECT表示使用矩形框初始化模型)。

函数返回值:

  • mask:更新后的掩码图像。
  • bgdModel:更新后的背景模型。
  • fgdModel:更新后的前景模型。

使用GrabCut算法的示例代码如下:

import cv2
import numpy as npimg = cv2.imread('image.jpg')
mask = np.zeros(img.shape[:2], dtype=np.uint8)rect = (50, 50, 200, 200)
bgdModel = np.zeros((1,65), dtype=np.float64)
fgdModel = np.zeros((1,65), dtype=np.float64)iterCount = 5
mode = cv2.GC_INIT_WITH_RECTmask, bgdModel, fgdModel = cv2.grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode)mask = np.where((mask==2)|(mask==0), 0, 1).astype('uint8')
img = img * mask[:, :, np.newaxis]cv2.imshow('Result', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

在上面的代码中,我们首先读取一张图像,并创建一个与图像大小相同的掩码图像。然后,我们定义一个包含前景物体的矩形框,并初始化背景模型和前景模型。接下来,我们调用cv2.grabCut()函数来进行图像分割。最后,根据最终的分类结果,将图像中的前景提取出来并显示出来。

练习 

1.OpenCV 自带的示例中有一个使用grabcut 算法的交互式工具grabcut.py。

下面是OpenCV自带的grabcut.py示例代码的实现:

import numpy as np
import cv2# 定义状态
rect = (0, 0, 1, 1)
drawing = False
rectangle = False
rect_over = False
iterCount = 5
mode = cv2.GC_INIT_WITH_RECT# 鼠标回调函数
def onmouse(event, x, y, flags, param):global rect, drawing, rectangle, rect_overif event == cv2.EVENT_LBUTTONDOWN:if not rectangle:rectangle = Truerect = (x, y, 1, 1)else:rectangle = Falserect_over = Trueelif event == cv2.EVENT_LBUTTONUP:if rectangle:rect = (min(rect[0], x), min(rect[1], y), abs(rect[0] - x), abs(rect[1] - y))drawing = False# 读取图像
img = cv2.imread('image.jpg')# 创建窗口并设置鼠标回调函数
cv2.namedWindow('image')
cv2.setMouseCallback('image', onmouse)while True:# 显示图像if not rectangle:cv2.imshow('image', img)else:temp = img.copy()cv2.rectangle(temp, (rect[0], rect[1]), (rect[0] + rect[2], rect[1] + rect[3]), (0, 255, 0), 2)cv2.imshow('image', temp)# 处理键盘输入k = cv2.waitKey(1) & 0xFFif k == ord('r'):rect = (0, 0, 1, 1)rectangle = Falserect_over = Falseelif k == ord('c'):mode = cv2.GC_INIT_WITH_RECTprint('Draw a rectangle around the object to be segmented')elif k == ord('f'):mode = cv2.GC_INIT_WITH_MASKprint('Mark the areas in the image where the object and background are')elif k == 13: # Enter键breakcv2.destroyAllWindows()# 进行图像分割
mask = np.zeros(img.shape[:2], dtype=np.uint8)
bgdModel = np.zeros((1,65), dtype=np.float64)
fgdModel = np.zeros((1,65), dtype=np.float64)if rect_over:cv2.grabCut(img, mask, rect, bgdModel, fgdModel, iterCount, mode)mask = np.where((mask==2)|(mask==0), 0, 1).astype('uint8')
img = img * mask[:, :, np.newaxis]cv2.imshow('Result', img)
cv2.waitKey(0)
cv2.destroyAllWindows()

在上面的代码中,我们首先定义了一些状态变量,包括矩形框的坐标、绘制状态、矩形框绘制状态和迭代次数等。然后,我们定义了一个鼠标回调函数onmouse(),用于处理鼠标事件。接下来,我们读取图像,并创建一个窗口并设置鼠标回调函数。然后,我们进入一个循环,在循环中显示图像,并处理键盘输入。当用户按下键盘上的特定键时,我们会根据不同的情况进行相应的操作,例如重置矩形框、选择操作模式等。当用户按下回车键时,我们退出循环。然后,我们根据用户选择的操作模式,调用cv2.grabCut()函数进行图像分割。最后,根据最终的分类结果,将图像中的前景提取出来并显示出来。

2.创建一个交互式取样程序,可以绘制矩形,带有滑动条,可以调节笔刷 的粗细等功能的python程式。

        下面是一个交互式取样程序的示例代码,它可以绘制矩形,带有滑动条,可以调节笔刷粗细等功能:

import cv2
import numpy as npdrawing = False  # 是否正在绘制
mode = True  # True表示绘制矩形,False表示绘制圆形
ix, iy = -1, -1  # 绘制起点坐标# 鼠标回调函数
def draw_shape(event, x, y, flags, param):global ix, iy, drawing, modeif event == cv2.EVENT_LBUTTONDOWN:drawing = Trueix, iy = x, yelif event == cv2.EVENT_LBUTTONUP:drawing = Falseif mode:cv2.rectangle(img, (ix, iy), (x, y), (0, 255, 0), -1)else:cv2.circle(img, (x, y), 5, (0, 0, 255), -1)# 创建图像
img = np.zeros((512, 512, 3), np.uint8)# 创建窗口并设置鼠标回调函数
cv2.namedWindow('image')
cv2.setMouseCallback('image', draw_shape)# 创建滑动条
cv2.createTrackbar('Size', 'image', 1, 10, lambda x: None)while True:cv2.imshow('image', img)# 处理键盘输入k = cv2.waitKey(1) & 0xFFif k == ord('m'):mode = not modeelif k == ord('q'):break# 获取滑动条的值size = cv2.getTrackbarPos('Size', 'image')# 更新笔刷的粗细if size > 0:cv2.setMouseCallback('image', draw_shape, param=size)cv2.destroyAllWindows()

在上面的代码中,我们首先定义了一些状态变量,包括是否正在绘制、绘制模式、绘制起点的坐标等。然后,我们定义了一个鼠标回调函数draw_shape(),用于处理鼠标事件。在鼠标按下和抬起的事件中,我们根据绘制模式选择绘制矩形或圆形,并将绘制的形状添加到图像中。接下来,我们创建了一个空白图像,并创建了一个窗口并设置鼠标回调函数。然后,我们创建了一个滑动条,用于调节笔刷的粗细。接下来,我们进入一个循环,在循环中显示图像,并处理键盘输入。当用户按下’m’键时,我们切换绘制模式。当用户按下’q’键时,我们退出循环。然后,我们获取滑动条的值,并根据值更新笔刷的粗细。最后,我们销毁窗口并退出程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/600567.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C#,入门教程(10)——常量、变量与命名规则的基础知识

上一篇: C#,入门教程(09)——运算符的基础知识https://blog.csdn.net/beijinghorn/article/details/123908269 C#用于保存计算数据的元素,称为“变量”。 其中一般不改变初值的变量,称为常变量,简称“常量”。 无论…

QT工具栏开始,退出

QT工具栏开始,退出 //初始化场景QMenuBar *bar menuBar();setMenuBar(bar);QMenu *startbar bar->addMenu("开始");QAction * quitAction startbar->addAction("退出");connect(quitAction , &QAction::triggered,[](){this->c…

Pycharm打包程序为exe文件

Pycharm打包程序为exe文件 【一】导入模块pyinstaller 【1】图片说明 【2】文字说明 根据图片顺序执行 首先点击file进入settings界面,在setting界面找到Project下面的Python Interpretor,点击号进行模块的添加在搜索框中输入pyinstaller,…

三、Kubernetes(K8s)入门(一)

视频教程连接k8s 入门到微服务项目实战.xmind链接:https://pan.baidu.com/s/1q04euH7baE8eXNyG3kPPbA 提取码:jej4比较好的笔记 kubectl命令的语法如下: kubectl [command] [type] [name] [flags]comand:指定要对资源执行的操作…

了解单元测试

一,测试分类 1.1 E2E测试(end to end端到端测试) 属于黑盒测试。 主要通过测试框架,站在用户测试人员的角度,模拟用户的操作进行页面功能的验证,不管内部实现机制,完全模拟浏览器的行为。&am…

任我行CRM系统SmsDataList接口SQL注入漏洞复现 [附POC]

文章目录 任我行CRM系统SmsDataList接口SQL注入漏洞复现 [附POC]0x01 前言0x02 漏洞描述0x03 影响版本0x04 漏洞环境0x05 漏洞复现1.访问漏洞环境2.构造POC3.复现0x06 修复建议任我行CRM系统SmsDataList接口SQL注入漏洞复现 [附POC] 0x01 前言 免责声明:请勿利用文章内的相关…

C++《异常》

前言:C有一套独立的异常处理机制,今天就来做详细的介绍try,catch这两个词等 在C语言中处理错误的方式和缺陷有: 返回错误码。 缺陷: 1.错误码不好设置,比如:除0操作,就不好返回错误码。如果返回一个数字&…

Flume基础知识(八):Flume 拓扑结构全解

1. 简单串联 这种模式是将多个 flume 顺序连接起来了,从最初的 source 开始到最终 sink 传送的 目的存储系统。此模式不建议桥接过多的 flume 数量, flume 数量过多不仅会影响传输速 率,而且一旦传输过程中某个节点 flume 宕机,会…

LC 2807. 在链表中插入最大公约数

2807. 在链表中插入最大公约数 难度 : 中等 题目大意: 给你一个链表的头 head ,每个结点包含一个整数值。 在相邻结点之间,请你插入一个新的结点,结点值为这两个相邻结点值的 最大公约数 。 请你返回插入之后的链表…

thinkphp学习04-控制器定义

控制器,即 controller,控制器文件存放在 controller 目录下; 如果想改变系统默认的控制器文件目录,可以在 config 下 route.php 配置: 将controller修改为controller123,就会报错,说明这个配置…

Sqlmap参数设置

Sqlmap参数设置 🎈🎈🎈🎈🎈🎈🎈🎈🎈🎈🎈🎈🎈🎈 --------------------------------------------注意---------…

易图讯便携式三维电子沙盘实战应用系统

便携式三维电子沙盘采用军工加固三防高性能笔记本,具有IP65级防尘防水防摔性能,以大数据、云计算、虚拟现实、物联网、AI等先进技术为支撑,支持高清卫星影像、DEM高程数据、矢量数据、三维模型、倾斜摄像、BIM、点云、城市白模、等高线、标高…

033 - STM32学习笔记 - TIM定时器(一) - 高级定时器

033 - STM32学习笔记 - TIM定时器(一) - 高级定时器 上节内容学习了基本定时器,其功能比较简单,配置和使用也比较容易,今天在基本定时器的基础上学习一下高级控制定时器的内容。 在F429上一共有两个高级控制定时器和1…

PyTorch|一次画一批图像

想想这样一个场景,我们训练了一个神经网络,输入一些信息,这个网络可以根据信息为我们生成相关图片。 这些图片并不是一张,而是多张,我们想把这些图片一次全部显示出来,而不是一张一张的显示(这…

Python蒸发散物理问题(微积分-线性代数-拉普拉斯和傅立叶变换)

使用Python计算解决土壤物理问题的数值。这里数值过程用于求解微分方程,数值方法将微分转化为代数方程,可以使用传统的线性代数方法求解。 Python拉普拉斯变换求解微分方程示例 假设我们有微分方程 y ′ ′ 2 y ′ 16 y cos ⁡ 4 t y^{\prime \pri…

关于unity的组件VerticalLayoutGroup刷新显示不正常的问题

先说明一下我是如何用到,有哪些处理的 用到这个组件基本上都是将列表进行排版操作的,竖着,或者横着,横着用HorizontalLayoutGroup 还有一个和这个组件搭配的组件叫ContentSizeFitter 先说我是怎么发现这个组件不好用的 //本地读取…

中标麒麟文件系统损坏修复

中标麒麟v5.0桌面版本文件系统损坏修复 1.用系统安装光盘启动到如下图界面,关闭或最小化“安装到硬盘”窗口 2.右击打开命令提示符,执行su – root 3.执行如下图命令,找到除swap格式分区的其他分区 4.按照上图显示的格式执行相关命令&#…

【数据结构】二叉搜索(查找/排序)树

一、二叉搜索树基本概念 1、定义 二叉搜索树,又称为二叉排序树,二叉查找树,它满足如下四点性质: 1)空树是二叉搜索树; 2)若它的左子树不为空,则左子树上所有结点的值均小于它根结…

第十六章 调用Callout Library函数

文章目录 第十六章 调用Callout Library函数使用 $ZF() 访问 iriszf 标注库 第十六章 调用Callout Library函数 Callout 库是一个共享库(DLL 或 SO 文件),其中包含 $ZF Callout 接口的挂钩,允许各种 Z F 函数在运行时加载它并调…

编程笔记 html5cssjs 025 HTML输入类型(1/2)

编程笔记 html5&css&js 025 HTML输入类型(1/2) 输入类型:text输入类型:password输入类型:submit输入类型: radio输入类型: checkbox输入类型: buttonHTML5 输入类型输入类型:number 本节介绍HTML输…