OpenCV学习(20) grabcut分割算法
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分割算法的更多相关文章
- OpenCV学习(21) Grabcut算法详解
grab cut算法是graph cut算法的改进.在理解grab cut算之前,应该学习一下graph cut算法的概念及实现方式. 我搜集了一些graph cut资料:http://yunpan. ...
- OpenCV学习(23) 使用kmeans算法实现图像分割
本章我们用kmeans算法实现一个简单图像的分割.如下面的图像,我们知道图像分3个簇,背景.白色的任务,红色的丝带以及帽子. Mat img = cv::imread(&quo ...
- 《opencv学习》 之 OTSU算法实现二值化
主要讲解OTSU算法实现图像二值化: 1.统计灰度级图像中每个像素值的个数. 2.计算第一步个数占整个图像的比例. 3.计算每个阈值[0-255]条件下,背景和前景所包含像素值总个数和总概率(就 ...
- OpenCV 学习笔记 04 深度估计与分割——GrabCut算法与分水岭算法
1 使用普通摄像头进行深度估计 1.1 深度估计原理 这里会用到几何学中的极几何(Epipolar Geometry),它属于立体视觉(stereo vision)几何学,立体视觉是计算机视觉的一个分 ...
- Opencv学习之路—Opencv下基于HOG特征的KNN算法分类训练
在计算机视觉研究当中,HOG算法和LBP算法算是基础算法,但是却十分重要.后期很多图像特征提取的算法都是基于HOG和LBP,所以了解和掌握HOG,是学习计算机视觉的前提和基础. HOG算法的原理很多资 ...
- 基于标记的分水岭分割算法/OpenCV中距离变换
Opencv分水岭算法——watershed自动图像分割用法 OpenCV距离变换distanceTransform应用 图像分割作为图像识别的基础,在图像处理中占有重要地位,通常需要在进行图像分割算 ...
- OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波
http://blog.csdn.net/chenyusiyuan/article/details/8710462 OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 201 ...
- OpenCV 学习笔记03 凸包convexHull、道格拉斯-普克算法Douglas-Peucker algorithm、approxPloyDP 函数
凸形状内部的任意两点的连线都应该在形状里面. 1 道格拉斯-普克算法 Douglas-Peucker algorithm 这个算法在其他文章中讲述的非常详细,此处就详细撰述. 下图是引用维基百科的.ε ...
- OpenCV学习(8) 分水岭算法(2)
现在我们看看OpenCV中如何使用分水岭算法. 首先我们打开一副图像: // 打开另一幅图像 cv::Mat image= cv::imread("../to ...
随机推荐
- 获取IP地址bash[转载]
ipaddr=`/sbin/ifconfig | grep 'inet addr:' | grep -v '127.0.0.1' | cut -d : -f2 | awk '{print $1}'`
- linux 进程监控和自动重启的简单实现(转)
目的:linux 下服务器程序会因为各种原因dump掉,就会影响用户使用,这里提供一个简单的进程监控和重启功能. 实现原理:由定时任务crontab调用脚本,脚本用ps检查进程是否存在,如果不存在则重 ...
- get 和 post请求的区别
(1)GET请求用于获取信息,从Client的角度看,不会改变资源状态,并且多次对同一URL的多个请求应该返回相同的结果. GET请求的参数会显示在URL中,即放置在HTTP协议头中(所 ...
- 50条规则提高PHP开发提高效率技巧
0.用单引号代替双引号来包含字符串,这样做会更快一些.因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会,注意:只有echo能这么做,它是一种可以把多个字符串当作 参数的“函数”(译注:PHP手 ...
- Mybatis学习(5)高级映射
需求: 一.一对一查询 查询订单信息,关联查询创建订单的用户信息: orders--->user:一个订单只由一个用户创建,一对一 orders表 和 user表: 1)使用resultType ...
- select 通过表单提交获取select中的值
<select class="txt" name="choice"> <option value="name" ...
- hadoop的安全模式
在安全模式下:不能增.删.改操作:但可以查看. 查看hadoop是否i处于安全模式下: 执行命令:hadoop dfsadmin -safemode get 进入hadoop的安全模式下: 执行命令: ...
- Web跨浏览器进程通信(Web跨域)
Web跨域已是老生常谈的话题,这次来尝试下跨域浏览器进程之间的通信 —— 这在过去基本依靠网络中转实现 在之前一篇文章里尝试了跨浏览器的数据共享,最后提到使用LocalConnection还可以实 ...
- Entity Framework 学习初级篇6--EntityClient
System.Data.EntityClient 命名空间是 实体框架的 .NET Framework 数据提供程序.EntityClient 提供程序使用存储特定的 ADO.NET 数据提供程序类和 ...
- 【转载】区间DP
http://www.cnblogs.com/zsboy/archive/2013/03/08/2950261.html 博客园 首页 新随笔 联系 订阅 管理 定义区间DP 区间动态规划问题一般 ...