计算机视觉——使用OpenCV GrabCut算法从图像中移除背景

GrabCut算法

GrabCut算法是一种用于图像前景提取的技术,由Carsten Rother、Vladimir Kolmogorov和Andrew Blake三位来自英国剑桥微软研究院的研究人员共同开发。该技术的核心目标是在用户进行最少交互操作的情况下,自动从图像中分割出前景对象。

在GrabCut算法中,用户只需在图像上用矩形框选出包含前景对象的区域,算法随后会迭代地进行分割,直至得到最佳结果。在这个过程中,若算法错误地将某些前景区域标记为背景或反之,用户可通过在图像上绘制笔触进行修正,指导算法在下一次迭代中进行更准确的分割。

GrabCut算法的工作原理可概括为以下几个步骤:

  1. 用户输入:用户在图像上绘制一个矩形框,圈定前景对象。
  2. 初始标记:算法使用高斯混合模型(GMM)对框选区域内的像素进行初始标记,区分前景和背景。
  3. 图割算法:基于像素的颜色分布,构建一个图,并添加源节点和汇聚节点,像素之间的连接权重基于颜色相似性。
  4. 迭代优化:通过迭代方式,利用最小割算法对前景和背景的分割进行优化。
  5. 结果修正:用户可根据分割结果进行手动修正,提高分割的准确性。

GrabCut算法因其用户交互少、操作简单且效果良好而在计算机视觉领域得到广泛应用。

GrabCut算法的工作原理

首先,在图像上绘制一个矩形,包含图像的主题,例如一个人或一只狗。矩形外的区域自动被视为背景。在定义的矩形内,背景中的数据被用作区分前景和背景位置的参考。

基于提供的事实,计算机进行初始标记,识别前景和背景中的像素(或进行硬标记)。

简单来说,这种方法使用高斯混合模型(Gaussian Mixture Model, GMM)定义矩形内的区域作为颜色分布模型,每个像素被标记表示其是否为前景、背景或未知。如果您对图像处理有所了解,您会知道每个像素通过梯度与下一个像素相连,因此该模型将鼓励具有相似颜色分布的像素具有相同的标记。

GMM根据提供的数据学习并创建新的像素分布。换句话说,未知像素根据它们与其他硬标记像素的颜色统计关系被标记为可能的前景或可能的背景(类似于聚类)。

这个像素分布被用来创建一个图。像素是图中的节点。两个新节点被添加:源节点和汇聚节点。每个前景像素都连接到源节点,而每个背景像素都连接到汇聚节点。

像素是前景/背景的可能性决定了连接像素到源节点/汇聚节点的边的权重。边的信息或像素相似性决定了像素之间的权重。如果像素之间存在显著的颜色差异,它们之间的边将具有较低的权重。

创建了带有初始权重的图之后,我们使用最小割算法,以产生两组顶点。

然后我们创建一个具有N个顶点的图(N=像素数),并根据顶点(像素)的颜色相似性用边连接它们。之后,我们将向网络中添加两个顶点(用于前景和背景的标签),每个顶点将根据像素与背景或前景的颜色分布匹配的可能性与N个像素相连。

换句话说,GrabCut方法创建了两个标签,一个用于背景,一个用于前景,并使用每个像素的颜色分布将所有像素与其自身连接。

OpenCV C++实现GrabCut算法

1. 读取图像

cv::Mat src = cv::imread(argv[1]);
assert(!src.empty());

在这里插入图片描述

2. 获取边界框

用户通过绘制矩形来提供输入,这个矩形框圈定了图像中的感兴趣区域。矩形外的所有内容都被视为背景,而矩形内的内容被视为未知。用户可以指定特定的前景和背景区域,这些指定将被视为硬标记,意味着在算法执行过程中不会改变这些标记。

void getBoundingBox(cv::Mat& img, cv::Rect& rect) {cv::Point pt, pt2;int size;for(;;) {cv::Mat temp = img.clone();std::cout << "Insert x1,y1,x2,y2 Point:\n";std::cin >> pt.x >> pt.y >> pt2.x >> pt2.y;cv::rectangle(temp, pt, pt2, cv::Scalar(0,255,0), 3);showImg("boundingBox", temp);char choice;std::cout << "Do You want to change paramters (y/n)";std::cin >> choice;if(choice == 'n'){rect = cv::Rect(pt.x, pt.y, pt2.x, pt2.y);break;}}
}
cv::Rect boundingBox;
getBoundingBox(src, boundingBox);

在这里插入图片描述

3. 创建高斯混合模型(GMM)

在图像分割技术中,识别并区分图像中的前景和背景像素至关重要。为了实现这一目标,我们采用了一种先进的统计工具——高斯混合模型(GMM)——来对前景和背景进行建模。该模型是一种概率模型,它基于一个核心假设:数据可以被视为多个高斯分布的叠加。

  1. 数据预处理与标记:首先,算法会接收到一个感兴趣区域(ROI),并在此区域内识别前景和背景像素。这个过程可能涉及到用户手动提供的硬标记,或者算法自动进行的像素分类。

  2. 高斯分布建模:在GMM中,前景和背景的像素颜色分布被假设为两个独立的高斯分布。每个分布都有其独特的特征,包括均值和协方差,这些参数共同定义了分布的形状和分布。

  3. 参数学习:通过对ROI内的像素颜色数据进行分析,GMM能够学习并确定每个高斯分布的参数。这一学习过程涉及到对数据的统计特性进行估计,以捕捉前景和背景的颜色分布特征。

  4. 概率估计与应用:掌握了这些参数后,对于图像中任意一个像素点,我们都能够计算出它属于前景或背景的概率。这些概率信息是图像分割过程中不可或缺的,它们将在后续的图割(Graph Cut)算法中发挥关键作用,用于构建和优化分割结果。

cv::Mat mask = cv::Mat::zeros(src.rows, src.cols, CV_8UC1);
cv::Mat bgModel, fgModel;

4. GrabCut算法

在C++中,OpenCV库提供的cv::grabCut函数用于实现GrabCut算法,这是一种基于图形的交互式图像分割技术。该算法通过迭代的方式,结合用户提供的前景和背景的初始估计,来细化分割结果。

以下是cv::grabCut函数的基本参数说明和使用方式:

函数原型

void cv::grabCut(InputArray img, InputOutputArray mask,Rect rect, InputOutputArray bgdModel,InputOutputArray fgdModel, int iterCount,int mode = GC_EVAL
);

参数说明

  1. img:输入图像,必须是一个三通道的8位图像(CV_8U)。

  2. mask:输入输出掩码,是一个单通道的8位图像,用于标记前景和背景。掩码的像素值有以下含义:

    • GC_BGD (0):明显背景的像素。
    • GC_FGD (1):明显前景的像素。
    • GC_PR_BGD (2):可能是背景的像素。
    • GC_PR_FGD (3):可能是前景的像素。
  3. rect:定义感兴趣区域(ROI),是一个矩形(Rect对象),表示包含目标对象的区域。这个参数仅在mode参数设置为GC_INIT_WITH_RECT时使用。

  4. bgdModel:背景模型,是一个1行13列的单通道浮点型(CV_32FC1)图像。如果为nullptr,函数将自动初始化它。

  5. fgdModel:前景模型,与背景模型类似,也是1行13列的单通道浮点型图像。

  6. iterCount:算法需要进行的迭代次数。

  7. mode(可选):分割模式标志,可以是以下值之一:

    • GC_INIT_WITH_RECT:使用提供的矩形初始化状态和掩码,然后根据算法进行迭代更新。
    • GC_INIT_WITH_MASK:使用提供的掩码初始化状态,可以与GC_INIT_WITH_RECT组合使用。
    • GC_EVAL:算法应该继续使用上一次的模型进行迭代。

5. 显示图像

cv::Mat dest;
src.copyTo(dest, mask2);
showImg("dest", dest);

在这里插入图片描述

完整代码

#include <iostream>
#include <assert>
#include <opencv2/opencv.hpp>void showImg(const std::string& name, cv::Mat& img) {cv::imshow(name, img);cv::waitKey(0);
}void getBoundingBox(cv::Mat& img, cv::Rect& rect) {cv::Point pt, pt2;int size;for(;;) {cv::Mat temp = img.clone();std::cout << "Insert x1,y1,x2,y2 Point:\n";std::cin >> pt.x >> pt.y >> pt2.x >> pt2.y;cv::rectangle(temp, pt, pt2, cv::Scalar(0,255,0), 3);showImg("boundingBox", temp);char choice;std::cout << "Do You want to change paramters (y/n)";std::cin >> choice;if(choice == 'n'){rect = cv::Rect(pt.x, pt.y, pt2.x - pt.x, pt2.y - pt.y);break;}}
}int main(int argc, char** argv) {cv::Mat src = cv::imread(argv[1]);assert(!src.empty());cv::Rect boundingBox;getBoundingBox(src, boundingBox);cv::Mat mask = cv::Mat::zeros(src.rows, src.cols, CV_8UC1);cv::Mat bgModel, fgModel;unsigned int iteration = 5; //根据需要调整参数cv::grabCut(src, mask, boundingBox, bgModel, fgModel, iteration, cv::GC_INIT_WITH_RECT);cv::Mat mask2 = (mask == 1) + (mask == 3);  // 0 = cv::GC_BGD, 1 = cv::GC_FGD, 2 = cv::PR_BGD, 3 = cv::GC_PR_FGDcv::Mat dest;src.copyTo(dest, mask2);showImg("dest", dest);cv::waitKey(0);return 0;
}

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

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

相关文章

js 制作qq、微信 的表情

这篇csdn缺少的图片资源可以在“我的资源那下载&#xff0c;有一个zip的包” 表情的符号 export const QQFaceList [{name: weixiao,code: [微笑],},{name: piezui,code: [撇嘴],},{name: se,code: [色],},{name: fadai,code: [发呆],},{name: deyi,code: [得意],},{name: li…

机器学习/算法工程师面试题目与答案-数学基础部分

机器学习/算法工程师面试题目--数学基础部分 一、数学基础1、微积分SGD,Momentum,Adagard,Adam原理L1不可导的时候该怎么办sigmoid函数特性 2、统计学&#xff0c;概率论求 Max(a, b) 期望拿更长的玫瑰花的最好策略最大化工作天数的员工数切比雪夫不等式随机截成三段组成三角形…

信号分解 | RLMD(鲁棒性局部均值分解)-Matlab

分解效果 RLMD(鲁棒性局部均值分解) RLMD(鲁棒性局部均值分解)-Matlab 代码实现 % %% 清除所有变量 关闭窗口 clc clear all close all%% 导入数据 % data = xlsread(Data.xlsx);%% 输入信号%% RLMD分解 %参数进行设置 % options.display =

SpringCloud系列(20)--Ribbon的简介及使用

1、Ribbon的简介 Spring Cloud Ribbon是基于Netflix Ribboh实现的一套客户端负载均衡的工具&#xff0c;简单的说&#xff0c;Ribbon是Netflix发布的开源项目&#xff0c;主要功能是提供客户端的软件负载均衡算法和服务调用。Ribbon客户端组件提供一系列完善的配置项如连接超时…

ETL中元数据处理的方式

ETLCloud平台是用于处理从数据抽取、转换、加载到持续数据捕获等一系列数据管理活动。除此之外还支持微服务治理与快速开发&#xff0c;并且具备数据库监听功能&#xff0c;能够以不同的方式监听并同步源数据库表数据到目标系统&#xff0c;比如直接传输、通过ETL流程处理或者传…

交直流充电桩检测的基础知识

交直流充电桩检测是电动汽车充电设施的重要组成部分&#xff0c;其目的是确保充电桩的正常运行&#xff0c;保障电动汽车的安全充电。以下是关于交直流充电桩检测的一些基础知识。 我们需要了解什么是交直流充电桩&#xff0c;简单来说&#xff0c;交直流充电桩是一种为电动汽车…

二维数组打印菱形(C语言)

一、N-S流程图&#xff1b; 二、运行结果&#xff1b; 三、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>int main() {//初始化变量值&#xff1b;char arr[5][5] { { , , *, , }, { , *, *, *, },{*, *, *, *, *}, { , *, *, *, …

使用NGINX做局域网内 浏览器直接访问链接 拓展外网链接访问本地

达成目的功能&#xff1a; 在本地服务的一个文件路径下&#xff0c;局域网内用ip和路径名访问到对应的地址&#xff1b;如 10.5.9.0/v1 即可访问到 某个固定本地地址目录 V1下&#xff0c;名为index.html的文件。前言 NGINX 是一个非常流行的开源 Web 服务器和反向代理服务器…

社交媒体数据恢复:Reddit

Reddit是一個娛樂、社交及新聞網站&#xff0c;註冊使用者可以將文字或連結在網站上發布&#xff0c;使它基本上成為了一個電子佈告欄系統。註冊使用者可以對這些貼文進行投票&#xff0c;結果將被用來進行排名和決定它在首頁或子頁的位置。網站上的內容分類被稱為「subreddit」…

Springboot+Vue项目-基于Java+MySQL的智慧校园管理系统(附源码+演示视频+LW)

大家好&#xff01;我是程序猿老A&#xff0c;感谢您阅读本文&#xff0c;欢迎一键三连哦。 &#x1f49e;当前专栏&#xff1a;Java毕业设计 精彩专栏推荐&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f380; Python毕业设计 &…

计算机网络复习(应用层)

一、概述 1、应用层对应用程序的通信提供服务 2、应用层协议定义了如下内容&#xff1a; 报文类型是请求还是响应各种报文类型语法字段的定义时序 3、应用层功能&#xff1a; 文件传输、访问管理 电子邮件 虚拟终端 查询服务和远程作业登录 二、网络服务模型 1、C/S模…

【研发管理】产品经理知识体系-产品设计与开发工具

导读&#xff1a;产品设计与开发工具的重要性体现在多个方面&#xff0c;它们对于产品的成功开发、质量提升以及市场竞争力都具有至关重要的影响。产品设计工具可以帮助设计师更高效地创建和优化产品原型。开发工具在产品开发过程中发挥着至关重要的作用。产品设计与开发工具还…

PotatoPie 4.0 实验教程(25) —— FPGA实现摄像头图像直方图均衡变换

图像的直方图均衡是什么&#xff1f; 图像的直方图均衡是一种用于增强图像对比度的图像处理技术。在直方图均衡中&#xff0c;图像的像素值被重新分配&#xff0c;以使得图像的直方图变得更均匀&#xff0c;即各个像素值的分布更加平衡。这意味着直方图中每个像素值的频率大致…

AMBA-CHI协议详解(二)

《AMBA 5 CHI Architecture Specification》 文章目录 2.1 Channels综述2.2 Channel域段2.2.1 request fields2.2.2 Response fields2.2.3 Snoop request fields2.2.4 Data fields 2.3 事务结构2.3.1 Read transactions2.3.1.1 Allocating Read2.3.1.2 Non-allocating Read 2.…

Spring Boot 的文件配置

SpringBoot的配置文件,有三种格式 1.properties 2.yaml 3.yml(yaml的简写) 这里主要介绍1和3格式的。 在项目中,同时存在properties和yml配置文件, properties的优先级更高 同时存在时,两个文件都生效 如果两个文件中,都包含同一个配置,以properties为主。 properties的配置…

深入解析AI绘画算法:从GANs到VAEs

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

人工智能底层自行实现篇3——逻辑回归(下)

3. 代码实现 接上一篇文章 3.1 问题背景 应用案例背景 假设我们有一个数据集&#xff0c;包含患者的多种生理指标&#xff08;如年龄、性别、体重指数&#xff08;BMI&#xff09;、血糖水平等&#xff09;以及他们是否被诊断为糖尿病&#xff08;是或否&#xff09;。我们的…

Vue3 el-table 动态高度(element-plus)

先回顾一下vue2element-ui的策略 export default (config) > {const {subtractHeight 250,} config;return {data() {return {subtractHeight,// 列表高度tableHeight: ${document.body.clientHeight - this.subtractHeight}px,};},created() {window.addEventListener(r…

RUST学习过程

一、基础知识&#xff1a; todo!&#xff1a;这个宏用来标记未实现功能。可以不写retuen的写法(if/else不能写分号&#xff0c;break带分号&#xff0c;loop写不写看情况)&#xff1a; fn fib(n: u32) -> u32 {if n < 2 {// The base case.1} else {// The recursive c…

vue-router学习9:过渡动效transition

<transition> 组件 <transition> 是 Vue 提供的一个内置组件&#xff0c;它可以为被包裹的元素或组件添加进入、离开和列表的过渡效果。当包裹的元素或组件的状态改变时&#xff08;例如&#xff0c;v-if 的条件变化或路由切换&#xff09;&#xff0c;<transi…