我是OpenCV和c++的新手,我试图在OpenCV中使用高斯混合模型构建一个分类器。我弄清楚了它是如何工作的,并让它工作了……也许吧。我现在得到了这样的东西:
如果我在模型刚刚训练完成并保存之后对训练样本进行分类,我就得到了我想要的结果。但是,当我使用read()对训练数据进行重新分类时,其中一个聚类缺失,这意味着我从相同的GMM模型中得到了不同的聚类结果。我现在没有得到它,因为我想要的集群已经消失了,我无法再次复制分类,直到我使用相同的数据重新训练模型。我在运行时检查了代码,Vec2d中的结果值来自,其中predict()返回从未分配给1(我设置了3个集群)。
可能有bug或者我做错了什么?
注。我在VS2013中使用2.4.8
我的程序是这样的:
培训部分
void GaussianMixtureModel::buildGMM(InputArray _src){
//use source to train GMM and save the model
Mat samples, input = _src.getMat();
createSamples(input, samples);
bool status = em_model.train(samples);
saveModel();
}
保存/加载模型
FileStorage fs(filename, FileStorage::READ);
if (fs.isOpened()) // if we have file with parameters, read them
{
const FileNode& fn = fs["StatModel.EM"];
em_model.read(fn);
fs.release();
}
FileStorage fs_save(filename, FileStorage::WRITE);
if (fs_save.isOpened()) // if we have file with parameters, read them
{
em_model.write(fs_save);
fs_save.release();
}
预测部分vector<Mat> GaussianMixtureModel::classify(Mat input){
/// samples is a matrix of channels x N elements, each row is a set of feature
Mat samples;
createSamples(input, samples);
for (int k = 0; k < clusterN; k++){
masks[k] = Mat::zeros(input.size(), CV_8UC1);
}
int idx = 0;
for (int i = 0; i < input.rows; i++){
for (int j = 0; j < input.cols; j++){
//process the predicted probability
Mat probs(1, clusterN, CV_64FC1);
Vec2d response = em_model.predict(samples.row(idx++), probs);
int result = cvRound(response[1]);
for (int k = 0; k < clusterN; k++){
if (result == k){
// change to the k-th class's picture
masks[k].at<uchar>(i, j) = 255;
}
...
// something else
}
}
}
}
我想我的答案将是太迟了,但由于我遇到了同样的问题,我发现的解决方案可能对其他人有用。
通过分析源代码,我注意到在EM::COV_MAT_DIAGONAL的情况下,协方差矩阵的特征值(源代码中的covsEigenValues)是在加载保存的数据后通过SVD获得的。然而,SVD计算奇异值(在我们的例子中是特征值)并按ASCENDING顺序存储它。为了防止这种情况,我只是直接提取covsEigenValues中加载的协方差矩阵的对角元素,以保持良好的顺序。