1

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.

Community
  • 1
  • 1
Jan Hackenberg
  • 481
  • 3
  • 14

1 Answers1

1

Proper way to print Mat value is to use operator<<. You already have it.

Your cv::Mat labels has type CV_32SC1. It contain 32 bit signed integer elements. So you can access items by labels.at<int> method.

Better way to access items is to use iterator cv::MatIterator_< _Tp >:

for(cv::MatIterator_<int> it(labels.begin<int>()); it != labels.end<int>(); it++)
{
  std::cout << (*it) << std::endl; // int i = *it
} 
Jan Hackenberg
  • 481
  • 3
  • 14
Nikita
  • 6,270
  • 2
  • 24
  • 37