OpenCV Grabcut算法
DDsoup 人气:0Grabcut 算法主要运用于计算机视觉中的前背景分割,立体视觉和抠图等。该算法利用了图像中的纹理(颜色)信息和边界(反差)信息,只要少量的用户交互操作即可得到比较好的分割结果.
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<opencv2\highgui\highgui.hpp> #include<opencv2\imgproc\imgproc.hpp> #include<iostream> #include <opencv2\opencv.hpp> #include <math.h> 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; } }
加载全部内容