OpenCV使用GrabCut实现抠图功能

 更新时间:2023年02月19日 11:08:42   作者:音视频开发老舅  
Grabcut是基于图割(graph cut)实现的图像分割算法,它需要用户输入一个bounding box作为分割目标位置,实现对目标与背景的分离/分割。本文将使用GrabCut实现抠图功能,需要的可以参考一下

1、概述

案例:使用OpenCV的GrapCut实现有用户交互的抠图

grabCut( InputArray img, InputOutputArray mask, Rect rect,
                           InputOutputArray bgdModel, InputOutputArray fgdModel,
                           int iterCount, int mode = GC_EVAL );
  • img --> 输入的三通道图像;
  • mask --> 输入的单通道图像,初始化方式为GC_INIT_WITH_RECT表示ROI区域可以被初始化为:
  • GC_BGD --> 定义为明显的背景像素 0
  • GC_FGD --> 定义为明显的前景像素 1
  • GC_PR_BGD --> 定义为可能的背景像素 2
  • GC_PR_FGD --> 定义为可能的前景像素 3
  • rect --> 表示roi区域;
  • bgdModel --> 表示临时背景模型数组;
  • fgdModel --> 表示临时前景模型数组;
  • iterCount --> 表示图割算法迭代次数, 次数越多,效果越好;
  • mode --> 当使用用户提供的roi时候使用GC_INIT_WITH_RECT

实现算法的步骤:

1.创建一个遮罩,并初始化为背景GC_BGD

2.用户选定一个ROI区域初始化为前景GC_FGD

3.调用grabCut函数实现算法

4.输入mask即为目标抠图

2、代码示例

(这个例子不完善,图像的颜色输出有问题,先记录一下,后面改正。但是不影响整个算法的流程及效果,仅仅是RGB和BGR像素通道的问题)

CrabCut_Matting::CrabCut_Matting(QWidget *parent)
    : MyGraphicsView{parent}
{
    this->setWindowTitle("crabCut抠图");
    this->setMouseTracking(true);//设置鼠标事件可用
    init = false;
    numRun = false;
}
 
 
void CrabCut_Matting::dropEvent(QDropEvent*event){
    QString filePath = event->mimeData()->urls().at(0).toLocalFile();
    showCrabCutMatting(filePath.toStdString().c_str());
}
 
void CrabCut_Matting::showCrabCutMatting(const char* filePath){
    src = imread(filePath);
    if(src.empty()){
        qDebug()<<"输入图像为空";
        return;
    }
 
    //创建一个背景遮罩
    mMask = Mat::zeros(src.size(),CV_8UC1);
    mMask.setTo(Scalar::all(GC_BGD));
 
 
    convert2Sence(src);
}
void CrabCut_Matting::mouseMoveEvent(QMouseEvent *event){
    //    if(event->button()==Qt::LeftButton){//鼠标左键
    rect = Rect(Point(rect.x, rect.y), Point(event->pos().x(), event->pos().y()));
    qDebug()<<"mouseMoveEvent:"<<rect.width<<"|"<<rect.height;
    showImage();
    //    }
}
 
void CrabCut_Matting::mousePressEvent(QMouseEvent *event){
    grabMouse();
    if(event->button()==Qt::LeftButton){//鼠标左键
        rect.x = event->pos().x();
        rect.y = event->pos().y();
        rect.width = 1;
        rect.height = 1;
        init = false;
        numRun = 0;
        qDebug()<<"mousePressEvent:"<<event->pos().x()<<"|"<<event->pos().y();
    }
 
}
 
void CrabCut_Matting::mouseReleaseEvent(QMouseEvent *event){
    releaseMouse();
    if(event->button()==Qt::LeftButton){//鼠标左键
        if (rect.width > 1 && rect.height > 1) {
            setROIMask();
            qDebug()<<"mouseReleaseEvent:"<<rect.width<<"|"<<rect.height;
            //执行grabcut的代码
            runGrabCut();
            numRun++;
            showImage();
        }
 
    }
}
/**
 * 将选中的区域设置为前景
 * @brief CrabCut_Matting::setROIMask
 */
void CrabCut_Matting::setROIMask(){
    // GC_FGD = 1
    // GC_BGD =0;
    // GC_PR_FGD = 3
    // GC_PR_BGD = 2
    mMask.setTo(GC_BGD);
    rect.x = max(0, rect.x);
    rect.y = max(0, rect.y);
    rect.width = min(rect.width, src.cols - rect.x);
    rect.height = min(rect.height, src.rows - rect.y);
    mMask(rect).setTo(Scalar(GC_PR_FGD));//将选中的区域设置为
}
 
void CrabCut_Matting::showImage(){
    Mat result, binMask;
    binMask.create(mMask.size(), CV_8UC1);
    binMask = mMask & 1;
    if (init) {
        src.copyTo(result, binMask);
    } else {
        src.copyTo(result);
    }
    rectangle(result, rect, Scalar(0, 0, 255), 2, 8);
    convert2Sence(result);
 
}
 
 
void CrabCut_Matting::runGrabCut(){
    if (rect.width < 2 || rect.height < 2) {
        return;
    }
 
    if (init) {
        grabCut(src, mMask, rect, bgModel, fgModel, 1);
    } {
        grabCut(src, mMask, rect, bgModel, fgModel, 1, GC_INIT_WITH_RECT);
        init = true;
    }
}
 
 
void CrabCut_Matting::convert2Sence(Mat target){
    scene.clear();
    QImage image = ImageUtils::matToQImage(target);
    QPixmap pixmap = QPixmap::fromImage(image);
    QGraphicsPixmapItem *item = new QGraphicsPixmapItem(pixmap.scaled(this->size(),Qt::KeepAspectRatio,Qt::SmoothTransformation));
    scene.addItem(item);
}

3、示例图片

以上就是OpenCV使用GrabCut实现抠图功能的详细内容,更多关于OpenCV GrabCut抠图的资料请关注脚本之家其它相关文章!

相关文章

  • C++中的数据对齐示例详解

    C++中的数据对齐示例详解

    这篇文章主要介绍了C++中数据对齐的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-03-03
  • C++实现四则运算器(带括号)

    C++实现四则运算器(带括号)

    这篇文章主要为大家详细介绍了C++实现四则运算器,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • Qt出现假死冻结现象的原因及解决方法

    Qt出现假死冻结现象的原因及解决方法

    应用程序出现假死或冻结现象通常是由于一些常见问题所导致的,本文主要介绍了Qt出现假死冻结现象的原因及解决方法,具有一定的参考价值,感兴趣的可以了解一下
    2023-10-10
  • 浅谈C#互操作的内存溢出问题

    浅谈C#互操作的内存溢出问题

    以前了解过c++的栈内存溢出,没想到在c#里被我遇到了,问题看似不大,如何被恰好相邻的四个字节是返回地址,说不定危害不小啊!看来c#的互操作还是得小心为好
    2013-10-10
  • C语言实现enum枚举

    C语言实现enum枚举

    在实际编程中,有些数据的取值往往是有限的,只能是非常少量的整数,并且最好为每个值都取一个名字,以方便在后续代码中使用,比如一个星期只有七天,一年只有十二个月,一个班每周有六门课程等。 以每周七天为例,我们可以使用#define命令来给每天指定一个名字
    2021-06-06
  • C++的对象特性和友元你真的了解吗

    C++的对象特性和友元你真的了解吗

    这篇文章主要为大家详细介绍了C++的对象特性和友元,使用数据库,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • 你真的知道C++对象大小吗?

    你真的知道C++对象大小吗?

    这篇文章主要给大家介绍了关于C++对象大小的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • C语言 如何用堆解决Topk问题

    C语言 如何用堆解决Topk问题

    TopK问题即在N个数中找出最大的前K个,这篇文章将详细讲解如何利用小根堆的方法解决TopK问题,文中代码具有一定参考价值,快跟随小编一起学习一下吧
    2021-12-12
  • c++ 写注册表方式让程序开机自启动

    c++ 写注册表方式让程序开机自启动

    这篇文章主要介绍了c++ 写注册表方式让程序开机自启动,需要的朋友可以参考下
    2017-09-09
  • opencv实现机器视觉检测和计数的方法

    opencv实现机器视觉检测和计数的方法

    在机器视觉中,有时需要对产品进行检测和计数。其难点无非是对于产品的图像分割。本文就来介绍一下机器视觉检测和计数的实现,感兴趣的可以参考一下
    2021-05-05

最新评论