图割grabcut算法
1.绪论
图切割算法是组合图论的经典算法之一。近年来,许多学者将其应用到图像和视频分割中,取得了很好的效果。本文简单介绍了图切算法和交互式图像分割技术,以及图切算法在交互式图像分割中的应用。
图像分割指图像分成各具特性的区域并提取出感兴趣目标的技术和过程,它是由图像处理到图像分析的关键步骤,是一种基本的计算机视觉技术。只有在图像分割的基础上才能对目标进行特征提取和参数测量,使得更高层的图像分析和理解成为可能。因此对图像分割方法的研究具有十分重要的意义。
图像分割技术的研究已有几十年的历史,但至今人们并不能找到通用的方法能够适合于所有类型的图像。常用的图像分割技术可划分为四类:特征阈值或聚类、边缘检测、区域生长或区域提取。虽然这些方法分割灰度图像效果较好,但用于彩色图像的分割往往达不到理想的效果。
交互式图像分割是指,首先由用户以某种交互手段指定图像的部分前景与部分背景,然后算法以用户的输入作为分割的约束条件自动地计算出满足约束条件下的最佳分割。典型的交互手段包括用一把画刷在前景和背景处各画几笔(如[1][4]等)以及在前景的周围画一个方框(如[2])等。
基于图切算法的图像分割技术是近年来国际上图像分割领域的一个新的研究热点。该类方法将图像映射为赋权无向图,把像素视作节点,利用最小切割得到图像的最佳分割。
2.几种改进算法
Graph Cut[1]算法是一种直接基于图切算法的图像分割技术。它仅需要在前景和背景处各画几笔作为输入,算法将建立各个像素点与前景背景相似度的赋权图,并通过求解最小切割区分前景和背景。
Grabcut[2]算法方法的用户交互量很少,仅仅需要指定一个包含前景的矩形,随后用基于图切算法在图像中提取前景。
Lazy Snapping[4]系统则是对[1]的改进。通过预计算和聚类技术,该方法提供了一个即时反馈的平台,方便用户进行交互分割。
示例代码如下:
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/video/background_segm.hpp>
#include <opencv2/opencv.hpp>
#include <stdio.h>
#include <iostream>
#include <sstream>
using namespace cv;
using namespace std;
// 全局变量区域
cv::Point point1, point2;
int drag = 0;
cv::Rect rect;
cv::Mat srcImage, roiImg;
bool select_flag = true;
cv::Mat rectimg;
vector<Point>Pf,Pb;
// 鼠标响应回调
void mouseHandler(int event, int x, int y, int flags, void* param)
{
// 左键按下
if (event == CV_EVENT_LBUTTONDOWN && !drag)
{
point1 = Point(x, y);
drag = 1;
}
// 鼠标移动
else if (event == CV_EVENT_MOUSEMOVE && drag)
{
Mat img1 = srcImage.clone();
point2 = Point(x, y);
rectangle(img1, point1, point2,
CV_RGB(255, 0, 0), 3, 8, 0);
imshow("srcImage", img1);
}
// 左键抬起与拖拽标志
else if (event == CV_EVENT_LBUTTONUP && drag)
{
point2 = Point(x, y);
rect = Rect(point1.x,point1.y,x-point1.x,y-point1.y);
drag = 0;
roiImg = srcImage(rect);
}
// 右键按下
else if (event == CV_EVENT_RBUTTONDOWN)
{
select_flag = false;
drag = 0;
imshow("ROI", roiImg);
}
}
int main()
{
srcImage= imread("..\\images\\sea.jpg");
if (srcImage.empty())
return -1;
// 定义前景与输出图像
cv::Mat srcImage2 = srcImage.clone();
cv::Mat foreground(srcImage.size(),
CV_8UC3,cv::Scalar(255,255,255));
cv::Mat result(srcImage.size(),CV_8UC1);
// grabcut分割前景与背景
cv::Mat fgMat,bgMat;
namedWindow("srcImage",1);
imshow("srcImage", srcImage);
// 迭代次数
int i = 20;
std::cout<<"20 iters"<< std::endl;
// 鼠标响应
setMouseCallback("srcImage", mouseHandler, NULL);
// 选择区域有效,按下esc退出
while((select_flag==true) && (waitKey(0)!=27))
{
// 图割算法熟悉
grabCut(srcImage,result,rect,bgMat,
fgMat,i,GC_INIT_WITH_RECT);
// 图像匹配
cv::compare(result,cv::GC_PR_FGD,
result,cv::CMP_EQ);
// 生成前景图像
srcImage.copyTo(foreground,result);
imshow("foreground",foreground);
}
cv::waitKey(0);
return 0;
}