我是OpenCV和C ++的新手,我正在尝试在OpenCV中使用高斯混合模型构建分类器。我弄清楚它是如何工作的并且让它工作......也许吧。我现在有这样的事情:
如果我在训练和保存模型后对训练样本进行分类,我得到了我想要的结果。但是当我使用 read()重新分类我的训练数据时,其中一个群集缺失,意味着我从同一个GMM模型获得了不同的群集结果。我现在不知道,因为我想要的集群已经消失,我再也无法重现分类,直到我使用相同的数据重新训练模型。我在运行时检查了代码,并从 Vec2d 中检查了结果值,其中 predict()从未被分配到1(我设置了3个簇)。
也许有错误或我做错了什么?
P.S。我在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
}
}
}
}
答案 0 :(得分:1)
我想我的答案为时已晚,但由于我遇到同样的问题,我找到的解决方案可能对其他人有用。
通过分析源代码,我注意到在EM :: COV_MAT_DIAGONAL的情况下,在加载保存的数据之后,通过SVD获得协方差矩阵的特征值(源代码中的covsEigenValues)。 但是,SVD计算单数(在我们的例子中为特征)值并将其存储在ASCENDING顺序中。 为了防止这种情况,我简单地直接提取covsEigenValues中加载的协方差矩阵的对角元素以保持良好的顺序。