OpenCV - 带自定义前景/背景模型的GrabCut

时间:2014-05-22 11:52:12

标签: c++ opencv computer-vision image-segmentation

我想使用在OpenCV上实现的GrabCut算法。

documentation所示,这是函数签名:

void grabCut(
    InputArray img, 
    InputOutputArray mask, 
    Rect rect, 
    InputOutputArray bgdModel, // *
    InputOutputArray fgdModel, // *
    int iterCount, 
    int mode=GC_EVAL) 

模式参数,指示如何使用 rect (矩形边框)或蒙版初始化算法(一个矩阵,其值对应于前景/背景区域的用户绘画。

我已经有了FG和BG的颜色模型,所以理想情况下我不需要提供遮罩或矩形,但是使用这些模型作为初始化(我想阻止OpenCV计算新模型和使用我的代替)。我看到 bgdModel fgdModel 参数以某种方式包含此模型信息。不幸的是,文档没有提供关于如何在那里存储模型信息的任何细节

是否可以使用现有数据填充这些模型并使用 mode=GC_EVAL 运行该方法,如果是这样,我该如何编码模型?

2 个答案:

答案 0 :(得分:3)

在opencv / sources / modules / imgproc / src / grabcut.cpp中,您可以查看模型(GMM)的编码方式:

GMM::GMM( Mat& _model )
{
    const int modelSize = 3/*mean*/ + 9/*covariance*/ + 1/*component weight*/;
    if( _model.empty() )
    {
        _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;

    coefs = model.ptr<double>(0);
    mean = coefs + componentsCount;
    cov = mean + 3*componentsCount;

    for( int ci = 0; ci < componentsCount; ci++ )
        if( coefs[ci] > 0 )
             calcInverseCovAndDeterm( ci );
}

因此,您需要为每个模型提供1 x 65双倍的cv :: Mat(componentsCount等于5)。每个组件有3种方法,因为它在RGB色彩空间中计算。使用GC_EVAL确实会使模型完好无损,但我从未尝试使用预先计算的模型。

答案 1 :(得分:1)

即使我有类似的问题。这就是我解决它的方式。 我将抓取源代码中的GC_EVAL条件编辑为 -

if( mode == GC_EVAL )
   { checkMask( img, mask );
    for( int i = 0; i < iterCount; i++ )
{
    GCGraph<double> graph;
    assignGMMsComponents( img, mask, bgdGMM, fgdGMM, compIdxs );

    constructGCGraph(img, mask, bgdGMM, fgdGMM, lambda, leftW, upleftW, upW, uprightW, graph );
    estimateSegmentation( graph, mask );
    return;    
}
}

请注意,此处未调用函数learnGMMs。这样做是因为前景和背景GMM是预先计算的。

您可以使用以下代码段将模型保存在.xml文件中。

 FileStorage fs("mymodels.xml", FileStorage::WRITE);
        fs << "BgdModel" << bgdModel;
        fs << "FgdModel" << fgdModel;
fs.release();

您可以使用以下代码检索模型。

FileStorage fs1("mymodels.xml", FileStorage::READ);

        fs1["BgdModel"] >> bgdModel1;

        fs1["FgdModel"] >> fgdModel1;

这对我有用。