I have an artificial matrix which I pass to the EM Gaussian Mixture Model algorithm in OpenCV - version 3.0.0 of the form :
[1.1, 3.2;
1.15, 3.1500001;
3.0999999, 4.1999998;
3.2, 4.3000002;
5, 5]
I call the GMM prediction via:
cv::Ptr<cv::ml::EM> source_model = cv::ml::EM::create();
source_model->setClustersNumber(3);
cv::Mat logs;
cv::Mat labels;
cv::Mat probs;
source_model->trainEM( openCVPointCloud,logs,labels,probs)
The documentation states about the matrix labels which I am interested in:
labels – The optional output 'class label' for each sample: labels_i = {arg max}k(p{i,k}), i=1..N (indices of the most probable mixture component for each sample). It has nsamples x 1 size and 'CV_32SC1' type.
My non working access to 'labels' prints (0,0,0,0,0) instead of expected (0,0,1,1,2) which is plotted via
std::cout << labels <<std::endl;
. I need though working with the integer indices to work with my original PCL point cloud which I want to cluster via poitn cloud features:
std::cout << labels.data[0] << std::endl;
std::cout << labels.data[1] << std::endl;
std::cout << labels.data[2] << std::endl;
std::cout << labels.data[3] << std::endl;
std::cout << labels.data[4] << std::endl;
The code fragments wrapped together in an untested minimal example (I have problems with qmake without using my frame work):
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/ml.hpp>
int main()
{
cv::Mat openCVPointCloud(5, 2, CV_32FC(1));
{
cv::Vec<float,1> & values1 = openCVPointCloud.at<cv::Vec<float,1> >(0,0);
values1.val[0] = 1.1;
cv::Vec<float,1> & values2 = openCVPointCloud.at<cv::Vec<float,1> >(0,1);
values2.val[0] = 3.2;
}
{
cv::Vec<float,1> & values1 = openCVPointCloud.at<cv::Vec<float,1> >(1,0);
values1.val[0] = 1.15;
cv::Vec<float,1> & values2 = openCVPointCloud.at<cv::Vec<float,1> >(1,1);
values2.val[0] = 3.15;
}
{
cv::Vec<float,1> & values1 = openCVPointCloud.at<cv::Vec<float,1> >(2,0);
values1.val[0] = 3.1;
cv::Vec<float,1> & values2 = openCVPointCloud.at<cv::Vec<float,1> >(2,1);
values2.val[0] = 4.2;
}
{
cv::Vec<float,1> & values1 = openCVPointCloud.at<cv::Vec<float,1> >(3,0);
values1.val[0] = 3.2;
cv::Vec<float,1> & values2 = openCVPointCloud.at<cv::Vec<float,1> >(3,1);
values2.val[0] = 4.3;
}
{
cv::Vec<float,1> & values1 = openCVPointCloud.at<cv::Vec<float,1> >(4,0);
values1.val[0] = 5;
cv::Vec<float,1> & values2 = openCVPointCloud.at<cv::Vec<float,1> >(4,1);
values2.val[0] = 5;
}
std::cout << openCVPointCloud << std::endl;
cv::Ptr<cv::ml::EM> source_model = cv::ml::EM::create();
source_model->setClustersNumber(3);
cv::Mat logs;
cv::Mat labels;
cv::Mat probs;
if(source_model->trainEM( openCVPointCloud,logs,labels,probs))
{
std::cout << "true train em";
std::cout << labels.data[0] << std::endl;
std::cout << labels.data[1] << std::endl;
std::cout << labels.data[2] << std::endl;
std::cout << labels.data[3] << std::endl;
std::cout << labels.data[4] << std::endl;
} else {
std::cout <<"false train em" << std::endl;
}
}
What can I do to get access to the integer numbers stored in labels?
This stackexchange topic states, that if I know the matrix element type I can use the templated at() function. The api states that the label Matrix is of type $CV_32SC1$. Accessing now via:
std::cout << labels.at<CV_32SC1>(2,0) << std::endl;
Results in the following error:
invalid template argument for '_Tp', type expected
At the time of creation of this question I was also 100% sure I tested
std::cout << labels.at<int>(2,0) << std::endl;
also which plotted 0 (and should have been 1). Code in front of me after accepted answer adaptian though prooves me wrong. Might be a duplicate because of a typo I did not see for some hours and the "typo" might have been QT's qdebug() usage instead of std::cout. If still considered valuable someone might improve the constructor in the minimal example I provided and remove this sentence and the following. I still hope for a one line solution which I yet failed to perform.