opencv grabcut
demo: http://download.csdn.net/detail/keen_zuxwang/9852585
高斯混合模型GMM和EM算法
http://blog.csdn.net/u011574296/article/details/52986943
图像分割之(四)OpenCV的GrabCut函数使用和源码解读
http://blog.sina.com.cn/s/blog_6272500201018cc7.html
opencv中的高斯混合模型源码详解
http://blog.csdn.net/u011574296/article/details/52994054
从GraphCut到GrabCut的OpenCV实现:图像分割
http://blog.sina.com.cn/s/blog_1584387c90102x5fu.html
基于图割理论
利用图像的纹理,颜色,位置信息,得到的分割结果具有交大的边界反差。这个算法要求手动设置(可能的)前景和背景的种子点。当背景和前景的差别比较大时,分割结果比较好, 反之分割结果比较差。
图像分割算法:
全自动图像分割:采用聚类算法来最大化前景与背景的差。
互动式图像分割: 根据提供的前景和背景种子,对前景背景建立概率分布模型。
GrabCut
就是属于第二类图像分割算法,主要应用高斯混合模型GMM算法、期望最大化EM算法(EM去计算GMM参数,当GMM模型参数趋于稳定即认为完成了图下像的分割)
GrabCut具体步骤如下(根据框选矩形):
1、长方形外的像素作为背景像素,长方形内的像素作为前景像素,用这两组像素去Train背景GMM和前景GMM。
2、用训练好的两个GMM来计算每一个像素属于背景和属于前景的概率,
进而计算出能量函数E中的Data项,能量函数中的Smoothness项的计算方法大致与GraphCut相同。
3、通过最优化能量函数得到图像的一个分割。
4、用3中的分割结果中的前景像素和背景像素去训练前景GMM和背景GMM.
5、重复2,3,4,直到分割结果收敛(两次迭代的结果变化小于一定程度)。
GrabCut是一个循环执行的算法,其循环的目的是为了EM(Expectation Maximization)。
长方形内也有部分背景像素,这样的种子是不完全正确的。但GMM模型并不要求所有的训练数据正确,即使有一部分分类不正确,也可以通过EM步骤使得最终结果正确。而GrabCut正是利用了GMM的这一特性。
//! class of the pixel in GrabCut algorithm
enum
{
GC_BGD = 0, //!< background
GC_FGD = 1, //!< foreground
GC_PR_BGD = 2, //!< most probably background
GC_PR_FGD = 3 //!< most probably foreground
};
//! GrabCut algorithm flags
enum
{
GC_INIT_WITH_RECT = 0,
GC_INIT_WITH_MASK = 1,
GC_EVAL = 2
};
首先用户在图片上画一个方框,grabCut默认方框内部为前景,设置掩码为2,方框外部都是背景,设置掩码为0。然后根据算法,将方框内部检查出来是背景的位置,掩码由2改为0。经算法处理,方框中掩码依然为2的,就是检查出来的前景,其他为背景
//! segments the image using GrabCut algorithm
CV_EXPORTS_W void grabCut( InputArray img, InputOutputArray mask, Rect rect,
InputOutputArray bgdModel, InputOutputArray fgdModel,
int iterCount, int mode = GC_EVAL );
功能:图像前景与背景的分离
img:
待分割的源图像,必须是8位3通道(CV_8UC3)图像
mask:
掩码图像,大小和原图像一致。可以有如下几种取值
GC_BGD(=0),背景
GC_FGD(=1),前景
GC_PR_BGD(=2),可能的背景
GC_PR_FGD(=3),可能的前景
rect:
用于限定需要进行分割的图像范围,只有该矩形窗口内的图像部分才被处理
bgdModel:
背景模型,如果为null,函数内部会自动创建一个bgdModel
fgdModel:
前景模型,如果为null,函数内部会自动创建一个fgdModel
iterCount:
迭代次数,必须大于0
mode:
用于指示grabCut函数进行什么操作。可以有如下几种选择:
GC_INIT_WITH_RECT(=0),用矩形窗初始化GrabCut
GC_INIT_WITH_MASK(=1),用掩码图像初始化GrabCut
GC_EVAL(=2),执行分割
JNI代码:
JNIEXPORT jlong JNICALL Java_com_example_grabcut_MainActivity_doGrabCut(JNIEnv *env, jclass clz, jlong imageGray)
{
Mat img = Mat(*(Mat*)imageGray);
Mat img0(img.size(),CV_8UC3); //输入图像须为CV_8UC3类型
cvtColor(img, img0, CV_BGRA2BGR);
Mat result; //4种可能结果
Mat bgModel;//背景
Mat fgModel;//前景
Rect selection = Rect(img.cols/4, 0, img.cols/2, img.rows*3/4); //须框选矩形,为grabCut前景、背景
grabCut(img0, result, selection, bgModel, fgModel, 5, GC_INIT_WITH_RECT); //迭代5次,GC_INIT_WITH_RECT矩形窗初始化GrabCut
compare(result, GC_PR_FGD, result, CMP_EQ); //得到前景mask
Mat foreground(img.size(),CV_8UC3, Scalar::all(255));
img0.copyTo(foreground,result); // img
Mat *hist = new Mat(foreground);
return (jlong) hist;
}