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

news2024/10/7 18:22:20

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_FGD
    cv::Mat dest;
    src.copyTo(dest, mask2);
    showImg("dest", dest);
    cv::waitKey(0);
    return 0;
}

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

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

相关文章

每日一题:视频拼接

你将会获得一系列视频片段&#xff0c;这些片段来自于一项持续时长为 time 秒的体育赛事。这些片段可能有所重叠&#xff0c;也可能长度不一。 使用数组 clips 描述所有的视频片段&#xff0c;其中 clips[i] [starti, endi] 表示&#xff1a;某个视频片段开始于 starti 并于 …

LeetCode39题: 组合总和(原创)

【题目描述】 给你一个 无重复元素 的整数数组 candidates 和一个目标整数 target &#xff0c;找出 candidates 中可以使数字和为目标数 target 的 所有 不同组合 &#xff0c;并以列表形式返回。你可以按 任意顺序 返回这些组合。candidates 中的 同一个 数字可以 无限制重复…

技术速递|利用 Redis 使 AI 驱动的 .NET 应用程序更加一致和智能

作者&#xff1a;Catherine Wang 排版&#xff1a;Alan Wang Redis 是一种流行的内存数据存储&#xff0c;可用于解决构建和扩展智能应用程序的关键挑战。在本文中&#xff0c;你将了解如何使用 Redis 的 Azure 缓存来提高使用 Azure OpenAI 的应用程序的效率。 Redis 的 Azur…

聚观早报 | 生数科技推出Vidu;2024款欧拉好猫正式上市

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 4月28日消息 生数科技推出Vidu 2024款欧拉好猫正式上市 雷诺与小米汽车洽谈技术合作 微软张祺谈未来AI如何发展 …

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

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

基于MSP430F249的电子钟仿真(源码+仿真)

目录 1、前言 2、仿真 3、程序 资料下载地址&#xff1a;基于MSP430F249的电子钟仿真(源码仿真&#xff09; 1、前言 基于MSP430F249的电子钟仿真&#xff0c;数码管显示时分秒&#xff0c;并可以通过按键调节时间。 2、仿真 3、程序 #include <MSP430x24x.h> #def…

Jenkins集成Terraform实现阿里云CDN自动刷新

在互联网业务中&#xff0c;CDN的应用已经成了普遍&#xff0c;SRE的日常需求中&#xff0c;CDN的刷新在前端需求逐渐中占了很大比例&#xff0c;并且比较琐碎。做为合格的SRE&#xff0c;把一切自动化是终极使命&#xff0c;而今天就分享通过JenkinsTerraform实现阿里云的CDN自…

java-动态代理

为什么需要代理&#xff1f; 如何创建代理 注意&#xff1a;实现类和代理需要实现同一个接口 接口 public interface Star {String sing(String song);void dance(); }实现类 public class BigStar implements Star {private String name;public BigStar(String name) {this.…

2024Mac系统热门游戏排行榜 Mac支持的网络游戏有哪些?mac能玩哪些大型网游 苹果电脑Mac游戏资源推荐 Mac玩Windows游戏

“游戏是这个世界上唯一能和女性争夺男朋友的东西&#xff08;/滑稽&#xff0c;有不少女生也喜欢玩游戏&#xff09;。” 虽然只是一句玩笑话&#xff0c;不过也可以看出游戏对大多数男生来说是必不可少的一项娱乐活动了。而网络游戏是游戏中的一大分支&#xff0c;能让玩家们…

uniapp问题归类

最近使用uniapp中&#xff0c;遇到了一些问题&#xff0c;这边mark下。 1. 启动页变形 设置启动页的时候发现在部分android手机上启动页被拉伸了&#xff0c;最后看了下官方建议使用9.png图 生成9.png地址&#xff0c;推荐图片大小为1080x2340 uniapp推荐官方地址传送门 我…

Thread类的基本用法

1.线程创建 这里介绍线程创建常用的五种方法 1.继承Thread&#xff0c;重写run class MyThread extends Thread{public void run(){//这里写的代码就是线程要完成的任务while (true){System.out.println("hello thread");try {Thread.sleep(1000);//线程会休眠一秒…

Springboot+Vue项目-基于Java+MySQL的家政服务平台系统(附源码+演示视频+LW)

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

FreeRTOS:3.信号量

FreeRTOS信号量 参考链接&#xff1a;FreeRTOS-信号量详解_freertos信号量-CSDN博客 目录 FreeRTOS信号量一、信号量是什么二、 FreeRTOS信号量1、二值信号量1、获取信号量2、释放信号量 2、计数信号量3、互斥信号量1、优先级反转2、优先级继承3、源码解析1、互斥量创建2、获取…

[蓝桥杯2024]-PWN:fd解析(命令符转义,标准输出重定向)

查看保护 查看ida 这里有一次栈溢出&#xff0c;并且题目给了我们system函数。 这里的知识点没有那么复杂 完整exp&#xff1a; from pwn import* pprocess(./pwn) pop_rdi0x400933 info0x601090 system0x400778payloadb"ca\\t flag 1>&2" print(len(paylo…

2024.04.28 Typecho管理视频文件,出现预览功能

需求原因原版的Typecho不支持在线视频预览,只有一个图片预览功能, 所以为了实现可以在线预览视频功能, 修改 typecho/admin/media.php 在大概19行的时候,追加如下内容 <?php if ($attachment->attachment->isImage): ?><p><img src"<?php $att…

装饰器模式【结构型模式C++】

1.概述 装饰器模式是一种结构型设计模式&#xff0c; 允许你通过将对象放入包含行为的特殊封装对象中来为原对象绑定新的行为。 2.结构 抽象构件&#xff08;Component&#xff09;角色&#xff1a;定义一个抽象接口以规范准备接收附加责任的对象。具体构件&#xff08;Concre…

关于文档中心的英文快捷替换方案

背景&#xff1a;文档中心需要接入国际化&#xff0c;想节省时间做统一英文方案处理&#xff1b; 文档中心是基于vuepress框架编写的&#xff1b; 1、利用百度翻译 API 的接口去做底层翻译处理&#xff0c;https://api.fanyi.baidu.com/需要在该平台上注册账号&#xff0c;个人…

决策树学习笔记

一、衡量标准——熵 随机变量不确定性的度量 信息增益&#xff1a;表示特征X使得类Y的不确定性减少的程度。 二、数据集 14天的打球情况 特征&#xff1a;4种环境变化&#xff08;天气、温度等等&#xff09; 在上述数据种&#xff0c;14天中打球的天数为9天&#xff1b;不…

docker部署的nacos2.2x开启鉴权功能

注意在2.2.0版本之后如果不开启鉴权&#xff0c;那么默认不需要登录就可以访问 所以我们需要手动开启鉴权&#xff0c;nacos启动好以后来到容器内部修改 docker exec -it nacos /bin/shvim conf/application.properties在第34行下面添加 nacos.core.auth.enabledtrue nacos.cor…

编译GTSAM库时报错undefined reference to `_dl_vsym@GLIBC_PRIVATE‘

/home/alex/miniforge3/envs/ros_py39_env/bin/ld: /home/alex/miniforge3/envs/ros_py39_env/bin/../x86_64-conda-linux-gnu/sysroot/lib64/libdl.so.2: undefined reference to _dl_vsymGLIBC_PRIVATE SOLUTION&#xff1a;在CMakeLists.txt里加入&#xff1a; set (CMAKE…