我想使用在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计算新模型并使用我的模型)。我看到bgdModel和fgdModel参数以某种方式包含此模型信息。不幸的是,文档没有提供关于模型信息如何存储在那里的任何细节。
是否可以用现有数据填充这些模型并使用 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;