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

Posted

技术标签:

【中文标题】OpenCV:期望最大化的预测函数的输出【英文标题】:OpenCV: Output of the predict function of Expectation Maximization 【发布时间】:2012-12-23 05:08:51 【问题描述】:

背景: 我有来自图像的 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。但应该

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

第一张图片是ImageCurrent.tif,第二张是ImageFormer.tif,最后一张是mask.tif。

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

【问题讨论】:

【参考方案1】:

据我了解,图像的前景和背景部分有两个单独的 GMM。在前景 GMM 中评估时,测试图像中样本像素“x”的总概率为

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。

【讨论】:

【参考方案2】:

我注意到您正在执行基于图形的图像分割。

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

基本上,我只能说对数概率,不管它是否正确,都不是你要找的。详情请查看以上链接。

【讨论】:

感谢您的链接。但我不想建立一个图形切割。因为我已经知道前景和背景的颜色,所以我尝试将它们聚类并定义属于一个和另一个 GMM 的亲和力。但在那之后,我不使用图形切割。我尝试从本文juew.org/projects/SnapCut/snapcut.htm 实现点2.1(这是页面项目,您可以选择pdf的质量)。我将尝试使用每个集群的权重和概率来计算概率。 其实用每个簇的概率和权重是行不通的。权重之和为 1,概率之和也为 1。例如,如果我的 GMM 中有 2 个权重(0.6 和 0.4)的集群。现在,我有一个像素在颜色空间中离 GMM 很远,但有可能属于(0.5 和 0.5)的每个集群,我的概率为 0.3。但实际上,我应该得到接近 0 的东西,因为它很远。这就是为什么我想获得属于整个 GMM 的概率。 嗨。我提供链接的目的是向您展示基于图形的图像分割代码的作者如何使用 GMM 来计算样本像素属于前景/背景颜色模型的概率。基本上,我所说的是您通过调用 GMM 类的“预测”方法获得的概率不是您想要的。但是 GC 分段代码确实如此,因此请检查一下。希望这会有所帮助。 但是我从他的代码中了解到,他通过将权重乘以每个集群的概率来获取最高概率。for(int g=0;g&lt;num_gaussians;g++) p = max(p,w[g]*(double)(((float*)xprob.data)[g]))。并取概率最高的模型。正如我上面所说,我的像素可能离 GMM 很远,但仍然有很高的概率和互惠性。另外,我不想用标签对所有像素进行分类,我只想找出哪一个肯定是前景,哪一个肯定是背景。 如果我只取概率属于前景(1 GMM)。前景色和背景色相似时会报错。【参考方案3】:

“似然对数”是指概率的对数。因为对于概率 p,我们期望 0 ≤ p ≤ 1,所以我期望值是负数:log(p) ≤ 0。较大的负数意味着较小的概率。

当您处理概率非常小的乘积时,这种形式很有帮助:如果您以正常方式相乘,则很容易出现下溢并失去精度,因为概率变得非常小。但在对数空间中,乘法变成了加法,从而提高了计算的准确性和潜在的速度。

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

【讨论】:

很抱歉打扰您,但您在上面的代码中发现任何问题吗?我仍然不明白预测函数如何返回 0 的似然对数。 看来,例如color[2]/255.0不正确,会导致错误。 为什么要除以 255?这也是你对训练数据所做的吗?另外,您为什么要切换索引-color[2/1/0] 转到sample(0/1/2)?您的代码中似乎发生了很多事情,所以我不确定您具体遇到了什么错误。 predict 函数返回一个二元向量;第一个元素是分类,第二个元素是对数似然。第二个元素永远不应该是正数,但第一个元素可以是。 实际上,我除以 255,因为我有 3 个通道和 8 位彩色图像。所以我想规范化我的数据,但没有必要(训练数据也一样)。由于 Opencv 总是读取 BGR 格式的图像,它只是为了让 RGB 格式与我的代码保持一致,但我改变了它,现在有了color[0/1/2]。从predictdocs.opencv.org/modules/ml/doc/… 的文档中,零元素是日志相似性,我正在寻找的就是这个。我应该编辑我的代码还是打开一个新问题?我还是有这个问题。

以上是关于OpenCV:期望最大化的预测函数的输出的主要内容,如果未能解决你的问题,请参考以下文章

Python中的期望最大化

12. 归纳偏好

12. 归纳偏好

12. 归纳偏好

Mat 类型的 OpenCV 最大可能值

数据库性能测试:sysbench用法详解