迭代图像切割技术的交互式前景提取

----- -----《“GrabCut” — Interactive Foreground Extraction using Iterated Graph Cuts》

以下是我对grabcut的简单认识

grabcut是在graphcut基础上演变来的,grabcut算法利用了图像中的纹理(颜色)信息和边界(反差)信息,只要少量的用户交互操作即可得到比较好的分割结果。


一、Graph cut的介绍

 

图1

首先,介绍一种图,如图1所示,这是一个特殊的图(graph),它的特殊之处在于除了中间的像素点之间(网格部分)构成图之外,他还有两个特殊顶点T(汇点)和S(源点),分别表示背景(Background)和前景(Object),以及各个像素和这两个点之间的连线,这两个特殊点是种子点,是用户在进行图像分割过程中标注出来的点(用户交互过程中指明哪里是背景,哪里是前景),如图2所示。

 

图2

 

这种图的顶点确定了,那它各个点之间的边值又是怎么确定的呢?

这里我们就要引入最重要的公式了,利用这个公式不仅能解决上面的这个问题,还能帮我们进行图像分割,神奇,图像能量表示公式:

公式1

 

首先看公式(1)E(A)=lamda*R(A)+B(A),其中R(A)是区域项,表示像素A属于背景或者前景的概率,在图1中表示所有像素点与顶点T和顶点S的连线的边的权值,那我们怎么知道R(A) 为多少呢?这里要用到这个公式2,它等于该像素点属于前景或是背景的概率的负对数。

公式2

 

B(A)代表边界项,它对应图1中相邻像素点之间的边的权值,表示为两个像素点接近程度,这里用公式3来表示,两个像素点的像素值大小越相近,B(A)的值就越大,两个像素值大小越不相近,B(A)的值越小。

公式3

 lamda表示R(A)和B(A)的比重,若lamda为0,代表只考虑B(A),这里的lamda也是通过计算得出来的,具体详见第二部分。

这样我们不难发现,若是R(A)越小,代表像素属于前景或是背景的概率也就越大,B(A)越小,代表两个像素点不相近,不属于一类像素,应该分开,所以当E(A)能量越小,代表分割越准确。

 

那么我们如何进行分割呢?这里根据《Interactive Graph Cuts for Optimal Boundary & Region Segmentation of Objects in N-D Images》这篇论文,提出了最小割方法。最小割算法原理可以参考https://blog.youkuaiyun.com/chinacoy/article/details/45040897。通俗易懂。

二、grabcut 介绍

与graph cut相比,grabcut具有以下优点:

1、只需一个长方形的目标框

2、增加少量的用户交互,分割更完美

3border matting技术使目标分割边界更加自然

与graph cut 的不同之处在于:

1Graph Cut 目标、背景是灰度直方图,Grab CutRGB三通道的混合高斯模型(GMM

2Graph Cut 分割一次完成,Grab Cut是不断进行分割估计和模型参数学习的迭代过程

3Graph Cut 需要指定目标和背景种子点,Grab Cut 只需框选目标,允许不完全标注

上算法流程图,配合下面代码更容易看懂一些:

初始化部分                                                                                               模型迭代部分:

 

grabcut()函数内部代码: 


/*M///////////////////////////////////////////////////////////////////////////////////////

//

//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.

//

//  By downloading, copying, installing or using the software you agree to this license.

//  If you do not agree to this license, do not download, install,

//  copy or use the software.

//

//

//                        Intel License Agreement

//                For Open Source Computer Vision Library

//

// Copyright (C) 2000, Intel Corporation, all rights reserved.

// Third party copyrights are property of their respective owners.

//

// Redistribution and use in source and binary forms, with or without modification,

// are permitted provided that the following conditions are met:

//

//   * Redistribution's of source code must retain the above copyright notice,

//     this list of conditions and the following disclaimer.

//

//   * Redistribution's in binary form must reproduce the above copyright notice,

//     this list of conditions and the following disclaimer in the documentation

//     and/or other materials provided with the distribution.

//

//   * The name of Intel Corporation may not be used to endorse or promote products

//     derived from this software without specific prior written permission.

//

// This software is provided by the copyright holders and contributors "as is" and

// any express or implied warranties, including, but not limited to, the implied

// warranties of merchantability and fitness for a particular purpose are disclaimed.

// In no event shall the Intel Corporation or contributors be liable for any direct,

// indirect, incidental, special, exemplary, or consequential damages

// (including, but not limited to, procurement of substitute goods or services;

// loss of use, data, or profits; or business interruption) however caused

// and on any theory of liability, whether in contract, strict liability,

// or tort (including negligence or otherwise) arising in any way out of

// the use of this software, even if advised of the possibility of such damage.

//

//M*/

 

#include "precomp.hpp"

#include "gcgraph.hpp"

#include <limits>

 

using namespace cv;

 

/*

This is implementation of image segmentation algorithm GrabCut described in

"GrabCut — Interactive Foreground Extraction using Iterated Graph Cuts".

Carsten Rother, Vladimir Kolmogorov, Andrew Blake.

 */

 

/*

 GMM - Gaussian Mixture Model

*/

class GMM

{

public:

    static const int componentsCount = 5;

 

    GMM( Mat& _model );

    double operator()( const Vec3d color ) const;

    double operator()( int ci, const Vec3d color ) const;

    int whichComponent( const Vec3d color ) const;

 

    void initLearning();

    void addSample( int ci, const Vec3d color );

    void endLearning();

 

private:

    void calcInverseCovAndDeterm( int ci );

    Mat model;

    double* coefs;

    double* mean;

    double* cov;

 

    double inverseCovs[componentsCount][3][3]; //协方差的逆矩阵

    double covDeterms[componentsCount];  //协方差的行列式

 

    double sums[componentsCount][3];

    double prods[componentsCount][3][3];

    int sampleCounts[componentsCount];

    int totalSampleCount;

};

 

//背景和前景各有一个对应的GMM(混合高斯模型)

GMM::GMM( Mat& _model )

{

	//一个像素的(唯一对应)高斯模型的参数个数或者说一个高斯模型的参数个数

	//一个像素RGB三个通道值,故3个均值,3*3个协方差,共用一个权值

    const int modelSize = 3/*mean*/ + 9/*covariance*/ + 1/*component weight*/;

    if( _model.empty() )

    {

		//一个GMM共有componentsCount个高斯模型,一个高斯模型有modelSize个模型参数

        _model.create( 1, modelSize*componentsCount, CV_64FC1 );

        _model.setTo(Scalar(0));

    }

    else if( (_model.type() != CV_64FC1) || (_model.rows != 1) || (_model.cols != modelSize*componentsCount) )

        CV_Error( CV_StsBadArg, "_model must have CV_64FC1 type, rows == 1 and cols == 13*componentsCount" );

 

    model = _model;

 

	//注意这些模型参数的存储方式:先排完componentsCount个coefs,再3*componentsCount个mean。

	//再3*3*componentsCount个cov。

    coefs = model.ptr<double>(0);  //GMM的每个像素的高斯模型的权值变量起始存储指针

    mean = coefs + componentsCount; //均值变量起始存储指针

    cov = mean + 3*componentsCount;  //协方差变量起始存储指针

 

    for( int ci = 0; ci < componentsCount; ci++ )

        if( coefs[ci] > 0 )

			 //计算GMM中第ci个高斯模型的协方差的逆Inverse和行列式Determinant

			 //为了后面计算每个像素属于该高斯模型的概率(也就是数据能量项)

             calcInverseCovAndDeterm( ci ); 

}

 

//计算一个像素(由color=(B,G,R)三维double型向量来表示)属于这个GMM混合高斯模型的概率。

//也就是把这个像素像素属于componentsCount个高斯模型的概率与对应的权值相乘再相加,

//具体见论文的公式(10)。结果从res返回。

//这个相当于计算Gibbs能量的第一个能量项(取负后)。

double GMM::operator()( const Vec3d color ) const

{

    double res = 0;

    for( int ci = 0; ci < componentsCount; ci++ )

        res += coefs[ci] * (*this)(ci, color );

    return res;

}

 

//计算一个像素(由color=(B,G,R)三维double型向量来表示)属于第ci个高斯模型的概率。

//具体过程,即高阶的高斯密度模型计算式,具体见论文的公式(10)。结果从res返回

double GMM::operator()( int ci, const Vec3d color ) const

{

    double res = 0;

    if( coefs[ci] > 0 )

    {

        CV_Assert( covDeterms[ci] > std::numeric_limits<double>::epsilon() );

        Vec3d diff = color;

        double* m = mean + 3*ci;

        diff[0] -= m[0]; diff[1] -= m[1]; diff[2] -= m[2];

        double mult = diff[0]*(diff[0]*inverseCovs[ci][0][0] + diff[1]*inverseCovs[ci][1][0] + diff[2]*inverseCovs[
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值