热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

OpenCV中Grabcut算法的具体使用

本文主要介绍了OpenCV中Grabcut算法的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

Grabcut 算法主要运用于计算机视觉中的前背景分割,立体视觉和抠图等。该算法利用了图像中的纹理(颜色)信息和边界(反差)信息,只要少量的用户交互操作即可得到比较好的分割结果.

1. Grabcut 的目标和背景的模型是RGB三通道的混合高斯模型GMM;

2. Grab Cut为一个不断进行分割估计和模型参数学习的交互迭代过程

3. Grab Cut只需要提供背景区域的像素集就可以了。也就是说你只需要框选目标,那么在方框外的像素全部当成背景,这时候就可以对GMM进行建模和完成良好的分割了。即Grab Cut允许不完全的标注.

Grabcut 算法的基本步骤:

Grabcut的相关API:

void grabCut( InputArray img,           //输入图像,必须是8位3通道图像,在处理过程中不会被修改
              InputOutputArray mask,    //掩码图像,用来确定哪些区域是背景,前景,可能是背景, 
                                          可能是前景等
                                        //mask既可以作为输入也可以作为输出。作为输入时,mode要                                                    
                                          选择GC_INIT_WITH_MASK (=1);
GCD_BGD (=0), 背景;GCD_FGD (=1),前景;GCD_PR_BGD (=2),可能是背景;GCD_PR_FGD(=3),可能是前景
                   
              Rect rect,                //包含前景的矩形,格式为(x, y, w, h)
              InputOutputArray bgdModel,//算法内部使用的数组,只需要创建大小为(1,65), 
                                          数据类型为np.float64的数组
              InputOutputArray fgdModel,//同上
              int iterCount,            //算法迭代的次数
              int mode = GC_EVAL        //用来指示grabCut函数进行什么操作
              // GC_INIT_WITH_RECT (=0),用矩形窗初始化GrabCut;
              // GC_INIT_WITH_MASK (=1),用掩码图像初始化GrabCut
            );

有关鼠标操作的两个函数:

void setMouseCallback( const string& winname,     //图像视窗名称
                       MouseCallback onMouse,     //鼠标响应函数,监视到鼠标操作后调用并处理相 
                                                    应动作
                       void* userdata = 0         //鼠标响应处理函数的ID,识别号
                     );
void OnMouseAction( int event,  // 代表了鼠标的各种操作
                    int x,      // 代表鼠标位于窗口的(x,y)坐标位置,即Point(x,y)
                    int y,      
                    int flags,  // 代表鼠标的拖拽事件,以及键盘鼠标联合事件
                    void *ustc  // 标识了所响应的事件函数
                  );
int event:
 
#define CV_EVENT_MOUSEMOVE 0             //滑动
#define CV_EVENT_LBUTTONDOWN 1           //左键点击
#define CV_EVENT_RBUTTONDOWN 2           //右键点击
#define CV_EVENT_MBUTTONDOWN 3           //中键点击
#define CV_EVENT_LBUTTONUP 4             //左键放开
#define CV_EVENT_RBUTTONUP 5             //右键放开
#define CV_EVENT_MBUTTONUP 6             //中键放开
#define CV_EVENT_LBUTTONDBLCLK 7         //左键双击
#define CV_EVENT_RBUTTONDBLCLK 8         //右键双击
#define CV_EVENT_MBUTTONDBLCLK 9         //中键双击
int flags:
 
#define CV_EVENT_FLAG_LBUTTON 1       //左鍵拖曳
#define CV_EVENT_FLAG_RBUTTON 2       //右鍵拖曳
#define CV_EVENT_FLAG_MBUTTON 4       //中鍵拖曳
#define CV_EVENT_FLAG_CTRLKEY 8       //(8~15)按Ctrl不放事件
#define CV_EVENT_FLAG_SHIFTKEY 16     //(16~31)按Shift不放事件
#define CV_EVENT_FLAG_ALTKEY 32       //(32~39)按Alt不放事件

Grabcut 算法的代码示例:

#include
#include
#include
#include 
#include 
using namespace cv;
using namespace std;
 
 //grabcut算法
bool setMouse = false;    //判断鼠标左键的状态(up / down)
bool init;
Point pt;
Rect rect;
Mat srcImg, mask, bgModel, fgModel;
int numRun = 0;
void onMouse(int, int, int, int, void*);
void runGrabCut();
void showImage();
int main()
{
	srcImg = imread("tahiti.jpg");
	if (srcImg.empty())
	{
		printf("could not load image...\n");
		return -1;
	}
 
	imshow("源图像", srcImg);
 
	mask.create(srcImg.size(), CV_8U);
	setMouseCallback("源图像", onMouse, 0);
 
	while (1)
	{
		char c = (char)waitKey(0);
		if (c == ' ') {//选中矩形框后,按空格键执行grabcut分割
			runGrabCut();
			numRun++;
			showImage();
			printf("current iteative times : %d\n", numRun);
		}
		if ((int)c == 27) {
			break;
		}
 
	}
	return 0;
}
 
void showImage()
{
	Mat result, binmask;
	binmask = mask & 1;				//进一步掩膜
	if (init)						//进一步抠出无效区域。鼠标按下,init变为false
	{
		srcImg.copyTo(result, binmask);
	}
	else
	{
		result = srcImg.clone();
	}
	rectangle(result, rect, Scalar(0, 0, 255), 2, 8);
	imshow("源图像", result);
}
 
void onMouse(int events, int x, int y, int flag, void *)
{
	if (x <0 || y <0 || x > srcImg.cols || y > srcImg.rows)	//无效区域
		return;
 
 
	if (events == EVENT_LBUTTONDOWN)
	{
		setMouse = true;
		pt.x = x;
		pt.y = y;
		init = false;
	}
	else if (events == EVENT_MOUSEMOVE)//鼠标只要动,就执行一次
	{
		if (setMouse == true)			//鼠标左键按住,滑动
		{
			Point pt1;
			pt1.x = x;
			pt1.y = y;
			rect = Rect(pt, pt1);//定义矩形区域
			showImage();
			mask.setTo(Scalar::all(GC_BGD));//背景
			mask(rect).setTo(Scalar(GC_PR_FGD));//前景			    //对rect内部设置为可能的前景,外部设置为背景
		}
	}
	else if (events == EVENT_LBUTTONUP)
		setMouse = false;	        	//鼠标左键抬起
}
 
void runGrabCut()
{
	if (init)//鼠标按下,init变为false
		grabCut(srcImg, mask, rect, bgModel, fgModel, 1);//第二次迭代,用mask初始化grabcut
	else
	{
		grabCut(srcImg, mask, rect, bgModel, fgModel, 1, GC_INIT_WITH_RECT);//用矩形窗初始化GrabCut
		init = true;
	}
}

到此这篇关于OpenCV中Grabcut算法的具体使用的文章就介绍到这了,更多相关OpenCV Grabcut算法内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!


推荐阅读
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 使用nodejs爬取b站番剧数据,计算最佳追番推荐
    本文介绍了如何使用nodejs爬取b站番剧数据,并通过计算得出最佳追番推荐。通过调用相关接口获取番剧数据和评分数据,以及使用相应的算法进行计算。该方法可以帮助用户找到适合自己的番剧进行观看。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • 本文介绍了P1651题目的描述和要求,以及计算能搭建的塔的最大高度的方法。通过动态规划和状压技术,将问题转化为求解差值的问题,并定义了相应的状态。最终得出了计算最大高度的解法。 ... [详细]
  • 本文介绍了一个程序,可以输出1000内能被3整除且个位数为6的所有整数。程序使用了循环和条件判断语句来筛选符合条件的整数,并将其输出。 ... [详细]
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • 本文详细介绍了Java中vector的使用方法和相关知识,包括vector类的功能、构造方法和使用注意事项。通过使用vector类,可以方便地实现动态数组的功能,并且可以随意插入不同类型的对象,进行查找、插入和删除操作。这篇文章对于需要频繁进行查找、插入和删除操作的情况下,使用vector类是一个很好的选择。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
author-avatar
聪头丶_505
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有