使用自定义前景/背景模型的GrabCut

OpenCV - GrabCut with custom foreground/background models

本文关键字:背景 模型 GrabCut 自定义      更新时间:2023-10-16

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

如文档中所示,这是函数签名:
void grabCut(
    InputArray img, 
    InputOutputArray mask, 
    Rect rect, 
    InputOutputArray bgdModel, // *
    InputOutputArray fgdModel, // *
    int iterCount, 
    int mode=GC_EVAL) 
mode参数表示如何初始化算法,可以使用rect(一个矩形边界框)或mask(一个矩阵,其值对应于前景/背景区域的用户绘制)。

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

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

在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 );
}

所以你需要每个模型的cv::Mat为1 x 65双精度(componentsCount等于5)。每个组件有3个平均值,因为它是在RGB色彩空间中计算的。使用GC_EVAL确实会使模型保持完整,但我从未尝试过使用预先计算的模型。

我也遇到过类似的问题。这就是我解决它的方法。我在grabcut源代码中编辑了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;