OpenCV:期望最大化的预测函数的输出

时间:2013-01-09 07:38:49

标签: c++ opencv gaussian image-segmentation expectation-maximization

背景 我有一组来自图像的2组彩色像素,一组对应于背景,另一组对应于前景。接下来,我使用来自OpenCV的EM为每组训练2个高斯混合模型。我的目标是找到随机像素属于前景和背景的概率。因此,我对像素上的每个EM使用“预测”功能。

问题:

  • 我不明白这个函数返回的值。在OpenCV的文档中,写成:
  

该方法返回一个双元素双向量。零元素是样本的似然对数值。第一个元素是给定样本中最可能的混合物成分的指数。

http://docs.opencv.org/modules/ml/doc/expectation_maximization.html?highlight=predict#Vec2d%20EM::predict%28InputArray%20sample,%20OutputArray%20probs%29%20const

我不明白“喜欢对数”是什么意思。在我的结果中,我有时会出现负值和值> 1.使用相同功能的人是否有这种结果或0到1之间的结果?我可以从结果中得出什么结论?

  • 如何获得像素属于整个GMM的概率(不是属于GMM每个群集的概率)?

这是我的代码:

Mat mask = imread("mask.tif", 0);
Mat formerImage = imread("ImageFormer.tif");
Mat currentImage = imread("ImageCurrent.tif");

// number of cluster in the GMM 
int nClusters = 5;

int countB=0, countF=0;

Vec3b color;

Vec2d probFg, probBg; // probabilities to belong to the foreground or background from GMMs

//count the number of pixels for each training data
for(int c=0; c<=40;c++) {
    for(int l=0; l<=40;l++) {
        if(mask.at<BYTE>(l, c)==255) {
            countF++;
        } else if(mask.at<BYTE>(l, c)==0) {
            countB++;
        }
    }
}


printf("countB %d countF %d \n", countB, countF);

Mat samplesForeground = Mat(countF,3, CV_64F);

Mat samplesBackground = Mat(countB,3, CV_64F);


// Expectation-Maximisation able to resolve the GMM and to predict the probability for a pixel to belong to the GMM.
EM em_foreground= EM(nClusters);
EM em_background= EM(nClusters);

countB=0;
countF=0;

// fill the training data from the former image depending of the mask
for(int c=0; c<=40;c++) {
    for(int l=0; l<=40;l++) {
        if(mask.at<BYTE>(l, c)==255) {
            color = formerImage.at<Vec3b>(l, c);
            samplesForeground.at<double>(countF,0)=color[0];
            samplesForeground.at<double>(countF,1)=color[1];
            samplesForeground.at<double>(countF,2)=color[2];
            countF++;
        } else if(mask.at<BYTE>(l, c)==0) {
            color = formerImage.at<Vec3b>(l, c);
            samplesBackground.at<double>(countB, 0)=color[0];
            samplesBackground.at<double>(countB, 1)=color[1];
            samplesBackground.at<double>(countB, 2)=color[2];
            countB++;
        }
    }
}

printf("countB %d countF %d \n", countB, countF);
em_foreground.train(samplesForeground);
em_background.train(samplesBackground);

Mat sample(1, 3, CV_64F);

// try every pixel of the current image and get the log likelihood
for(int c=0; c<=40;c++) {
    for(int l=0; l<=40;l++) {
        color = currentImage.at<Vec3b>(l,c);
        sample.at<double>(0)=color[0];
        sample.at<double>(1)=color[1];
        sample.at<double>(2)=color[2];
        probFg=em_foreground.predict(sample);
        probBg=em_background.predict(sample);
        if(probFg[0]>0 || probBg[0]>0)
            printf("probFg[0] %f probBg[0] %f \n", probFg[0], probBg[0]);
    }
}

修改

在@BrianL解释之后,我现在明白了对数可能性。

我的问题是预测函数的对数概率有时> 0。但它应该是&lt; = 0。有没有人以前遇到过这个问题?

我已编辑上面的代码以显示问题。我尝试过以下图片的程序:

第一个图像是ImageCurrent.tif,第二个是ImageFormer.tif,最后一个是mask.tif。

current image former image mask

这可以被视为OpenCV中的错误吗?我应该在OpenCV错误跟踪器上打开票证吗?

3 个答案:

答案 0 :(得分:4)

“似然对数”表示概率的对数。因为对于概率 p ,我们期望0≤ p ≤1,我希望这些值为负:log( p )≤0。较大的负数意味着较小的概率。

当你处理非常小的概率产品时,这个形式是有用的:如果你乘以正常方式,你很容易得到下溢并失去精度,因为概率变得非常小。但是在对数空间中,乘法变成了一个加法,这提高了准确性,也可能提高了计算的速度。

predict函数用于对数据点进行分类。如果您想为模型中属于任何组件的可能性给出一个分数,您可以使用模型参数(请参阅get文档)自行计算

答案 1 :(得分:1)

我注意到你正在进行基于图形切割的图像分割。

您可能需要查看以下博客文章,其中使用OpenCV及其GMM类的方式与执行基于图形切割的图像分割的方式非常相似。代码在C ++中给出,并附有详细说明。这是链接:link

基本上,我只能说日志概率,无论是否正确,都不是你想要的。请查看以上链接了解详情。

答案 2 :(得分:1)

据我所知,你有两个单独的GMM用于图像的前景和背景部分。样本像素的总概率为&#39; x&#39;在前景GMM中评估的测试图像中

P_fg(x) = sum_over_j_1_to_k ( Wj_fg * Pj_fg( x ))
where 
k = number of clusters in foreground GMM
x = test sample
Pj_fg(x) = probability that sample x is in j-th  cluster according to the foreground GMM
Wj_fg = weight of the j-th cluster in foreground GMM
also, sum of all weights should be 1 for each GMM.

我们可以对背景GMM进行类似的计算。

通过查看opencv中的EM代码,看起来EM返回的2个值的第一部分是对数似然。对于前景GMM,这是

log(P_fg(x_i))

我实现了你的算法,并且对于测试图像中的每个像素,我比较了两个GMM-s中每个像素返回的对数似然,并将像素与具有更高值的GMM分类。我得到了不错的结果。

在这方面,是的,这个值表示像素属于整个GMM。

2) 在我的问题实现中,我总是得到所有测试样本像素的GMMS的对数似然值在0以下。