http://www.cnblogs.com/mikewolf2002/p/3330390.html

OpenCV学习(20) grabcut分割算法

在OpenCV中,实现了grabcut分割算法,该算法可以方便的分割出前景图像,操作简单,而且分割的效果很好。算法的原理参见papaer:“GrabCut” — Interactive Foreground Extraction using Iterated Graph Cuts

比如下面的一副图,我们只要选定一个四边形框,把框中的图像作为grabcut的一个输入参数,表示该框中的像素可能属于前景,但框外的部分一定属于背景。

然后调用grabcut函数,就可以分割出城堡来。具体代码如下:

// 打开另一幅图像
cv::Mat image= cv::imread("../tower.jpg");
if (!image.data)
{
cout<<"不能打开图像!"<<endl;
return 0;
} // 矩形外的像素是背景
cv::Rect rectangle(50,70,image.cols-150,image.rows-180); cv::Mat result;
//两个临时矩阵变量,作为算法的中间变量使用,不用care
cv::Mat bgModel,fgModel;
double tt = cv::getTickCount();
// GrabCut 分段
cv::grabCut(image, //输入图像
result, //分段结果
rectangle,// 包含前景的矩形
bgModel,fgModel, // 前景、背景
1, // 迭代次数
cv::GC_INIT_WITH_RECT); // 用矩形
tt = cv::getTickCount() - tt;
printf("算法执行执行时间:%g ms\n", tt/cv::getTickFrequency()*1000);
// 得到可能是前景的像素
//比较函数保留值为GC_PR_FGD的像素
cv::compare(result,cv::GC_PR_FGD,result,cv::CMP_EQ);
// 产生输出图像
cv::Mat foreground(image.size(),CV_8UC3,cv::Scalar(255,255,255));
//背景值为 GC_BGD=0,作为掩码
image.copyTo(foreground,result);

grabCut函数的第一个参数为我们要处理的图像,本程序中就是image,图像的类型必须为:CV_8UC3

第二个参数是mask图像,它的大小和image一样,但是它的格式为CV_8UC1,只能是单通道的,grabcut算法的结果就保存在该图像中。

前面的代码中,我们并没有对mask图像(result)进行初始化设置,因为第6个参数为cv::GC_INIT_WITH_RECT,它表示算法会根据rectangle的范围,来生成一个初始化的mask图像。

cv::grabCut(image,    //输入图像 
    result,   //分段结果 
    rectangle, // 包含前景的矩形 
    bgModel,fgModel, // 前景、背景 
    1,        // 迭代次数 
    cv::GC_INIT_WITH_RECT); // 用矩形

mask图像的值只能为下面下面4个值(PR,probably表示可能的):

GC_BGD    = 0,  //背景

GC_FGD    = 1,  //前景 
GC_PR_BGD = 2,  //可能背景

GC_PR_FGD = 3   //可能前景

根据rectangle生成的mask图像规则为:四边形外面的部分一定是背景,所以在mask图中对应的像素值为GC_BGD,而四边形内部的的值可能为前景,所以对应的像素值为GC_PR_FGD。所以我们程序中使用mask图像应该如下图所示。

如果第7个参数为GC_INIT_WITH_MASK,这时第三个参数rectangle没有使用,我们必须在调用grabcut函数之前,手工设置mask图像(变量result),如果我们把result设置成上图所示的灰度图。那个调用函数

cv::grabCut(image1,    //输入图像 
    result1,   //分段结果 
    rectangle, // 包含前景的矩形 
    bgModel,fgModel, // 前景、背景 
    1,        // 迭代次数 
    cv::GC_INIT_WITH_MASK); // 用矩形

可以得到同样的结果。 
可以参考下面的代码:

cv::Mat result1= cv::Mat(image1.rows, image1.cols,CV_8UC1, cv::Scalar(cv::GC_BGD));
//注意给子矩阵赋值的方法
cv::Mat roi(result1, cv::Rect(50,70,result1.cols-150,result.rows-180));
roi = cv::Scalar(cv::GC_PR_FGD);
tt = cv::getTickCount();
// GrabCut 分段
cv::grabCut(image1, //输入图像
result1, //分段结果
rectangle,// 包含前景的矩形
bgModel,fgModel, // 前景、背景
1, // 迭代次数
cv::GC_INIT_WITH_MASK); // 用矩形
tt = cv::getTickCount() - tt;
printf("算法执行执行时间:%g ms\n", tt/cv::getTickFrequency()*1000); // 得到可能是前景的像素
//比较函数保留值为GC_PR_FGD的像素
cv::compare(result1,cv::GC_PR_FGD,result,cv::CMP_EQ);
// 产生输出图像
cv::Mat foreground1(image1.size(),CV_8UC3,cv::Scalar(255,255,255));
//背景值为 GC_BGD=0,作为掩码
image.copyTo(foreground1,result1);

第3个参数是rectangle的大小位置,如果第7个参数为GC_INIT_WITH_MASK,则该参数没有作用。

第4,5个参数是两个算法在执行过程中使用临时矩阵变量,不用care它们的内容。

第6个参数是迭代次数,迭代越多,效果越好,但划时间也越长。

第7个参数是操作模式,通常情况下为GC_INIT_WITH_RECT和GC_INIT_WITH_MASK。

从上面的图中,我们可以看到,grabcut算法的效果很好,但是花的时间也很长,上面图像在我的笔记本上需要4.4秒。

程序源代码:工程FirstOpenCV13

OpenCV学习(20) grabcut分割算法的更多相关文章

  1. OpenCV学习(21) Grabcut算法详解

    grab cut算法是graph cut算法的改进.在理解grab cut算之前,应该学习一下graph cut算法的概念及实现方式. 我搜集了一些graph cut资料:http://yunpan. ...

  2. OpenCV学习(23) 使用kmeans算法实现图像分割

          本章我们用kmeans算法实现一个简单图像的分割.如下面的图像,我们知道图像分3个簇,背景.白色的任务,红色的丝带以及帽子.       Mat img = cv::imread(&quo ...

  3. 《opencv学习》 之 OTSU算法实现二值化

    主要讲解OTSU算法实现图像二值化:    1.统计灰度级图像中每个像素值的个数. 2.计算第一步个数占整个图像的比例. 3.计算每个阈值[0-255]条件下,背景和前景所包含像素值总个数和总概率(就 ...

  4. OpenCV 学习笔记 04 深度估计与分割——GrabCut算法与分水岭算法

    1 使用普通摄像头进行深度估计 1.1 深度估计原理 这里会用到几何学中的极几何(Epipolar Geometry),它属于立体视觉(stereo vision)几何学,立体视觉是计算机视觉的一个分 ...

  5. Opencv学习之路—Opencv下基于HOG特征的KNN算法分类训练

    在计算机视觉研究当中,HOG算法和LBP算法算是基础算法,但是却十分重要.后期很多图像特征提取的算法都是基于HOG和LBP,所以了解和掌握HOG,是学习计算机视觉的前提和基础. HOG算法的原理很多资 ...

  6. 基于标记的分水岭分割算法/OpenCV中距离变换

    Opencv分水岭算法——watershed自动图像分割用法 OpenCV距离变换distanceTransform应用 图像分割作为图像识别的基础,在图像处理中占有重要地位,通常需要在进行图像分割算 ...

  7. OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波

    http://blog.csdn.net/chenyusiyuan/article/details/8710462 OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 201 ...

  8. OpenCV 学习笔记03 凸包convexHull、道格拉斯-普克算法Douglas-Peucker algorithm、approxPloyDP 函数

    凸形状内部的任意两点的连线都应该在形状里面. 1 道格拉斯-普克算法 Douglas-Peucker algorithm 这个算法在其他文章中讲述的非常详细,此处就详细撰述. 下图是引用维基百科的.ε ...

  9. OpenCV学习(8) 分水岭算法(2)

        现在我们看看OpenCV中如何使用分水岭算法.     首先我们打开一副图像:    // 打开另一幅图像   cv::Mat    image= cv::imread("../to ...

随机推荐

  1. PHP扩展开发-简单类扩展

    今天来学习简单类扩展开发 实现目标为如下php的类 <?php class classext(){ private $username; CONST URL="http://www.g ...

  2. 为什么要 urlencode()

    1.是因为当字符串数据以url的形式传递给web服务器时,字符串中是不允许出现空格和特殊字符的2. 因为 url 对字符有限制,比如把一个邮箱放入 url,就需要使用 urlencode 函数,因为 ...

  3. mouse的各种事件

    IE测试对象为IE9,不全 mousemove(元素内部移动) 鼠标在元素内部移动时触发,只要鼠标移动,即使只是又移动了一个像素,也会触发,这就意味着短时间内会触发多次事件 支持情况: js onmo ...

  4. 转 [分享一个SQL] 查会话阻塞关系,层次关系.

    with ash as (select /*+ materialize*/* from DBA_HIST_ACTIVE_SESS_HISTORY  where sample_time between ...

  5. GDT、GDTR、LDT、LDTR的理解

    GDT是全局描述附表,主要存放操作系统和各任务公用的描述符,如公用的数据和代码段描述符.各任务的TSS描述符和LDT描述符.(TSS是任务状态段,存放各个任务私有运行状态信息描述符)LDT是局部描述符 ...

  6. HTML day01基础总结

    1.网页的基本元素 文字.图像与超链接. 2.每一个网页元素通常由开始标记.结束标记,以及在这两个标记中的内容所组成. 3.一般结构 <html> <head> <met ...

  7. php 10.2总

    注意事项 获取表单信息 <?php if($_POST["submit"]=="登录"){ echo "您输入的用户名为:".$_PO ...

  8. oracle常用高级sql---1

    Oracle/Sql高级篇   1.TOP 子句 TOP 子句用于规定要返回的记录的数目. 对于拥有数千条记录的大型表来说,TOP 子句是非常有用的. SELECT TOP number|percen ...

  9. 在windows系统用odbc连接

    当连接的数据出现失败时,出现数据库别名仍然存在,但还是要用这个别名重新建立连接 在windows客户端,用输入db2cmd输入c:\Users\yexuxia>db2 list db direc ...

  10. 初探JavaScript魅力(三)

    复选框的全选.反选和不选 <title>无标题文档</title> <style> body{background:#666;} </style> &l ...