访问CV_32SC1 nx1 opencv矩阵

时间:2016-10-12 14:19:26

标签: c++ qt opencv

我有一个人工矩阵,我将其传递给EM Gaussian Mixture Model格式的OpenCV - version 3.0.0算法:

[1.1, 3.2;
 1.15, 3.1500001;
 3.0999999, 4.1999998;
 3.2, 4.3000002;
 5, 5]

我通过以下方式调用GMM预测:

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)

关于我感兴趣的矩阵标签documentation州:

  

标签 - 每个样本的可选输出“类标签”:   labels_i = {arg max} k(p {i,k}),i = 1..N(每个样本的最可能混合成分的指数)。它具有nsamples x 1大小和'CV_32SC1'类型。

我对“标签”的非工作性访问打印(0,0,0,0,0)而非预期(0,0,1,1,2),这是通过

绘制的
std::cout << labels <<std::endl;

。我需要使用整数索引来处理原始PCL point cloud,我希望通过poitn云功能进行聚类:

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;

代码碎片在一个未经测试的最小例子中包装在一起(我在没有使用框架工作时遇到qmake问题):

#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;
    }

}

如何访问标签中存储的整数?

stackexchange topic个状态,如果我知道矩阵元素类型,我可以使用模板化的at()函数。 api表示标签Matrix的类型为$ CV_32SC1 $。现在通过:

访问
  std::cout << labels.at<CV_32SC1>(2,0) << std::endl;

导致以下错误:

  invalid template argument for '_Tp', type expected

在创建这个问题时,我也100%确定我已经测试了

  std::cout << labels.at<int>(2,0) << std::endl;

也绘制了0(应该是1)。在接受了答案后,代码在我面前虽然证明我错了。可能是重复的,因为我在几个小时内没有看到错字,而“错字”可能是QT's qdebug()使用而不是std::cout。如果仍然被认为有价值,有人可能会在我提供的最小示例中改进构造函数并删除此句子和以下内容。我仍然希望有一个单线解决方案,但我还没有完成。

1 个答案:

答案 0 :(得分:1)

打印Mat值的正确方法是使用operator<<。你已经拥有它了。

您的cv::Mat labels类型为CV_32SC1。它包含32位有符号整数元素。因此,您可以通过labels.at<int>方法访问项目。

访问项目的更好方法是使用迭代器cv::MatIterator_< _Tp >

for(cv::MatIterator_<int> it(labels.begin<int>()); it != labels.end<int>(); it++)
{
  std::cout << (*it) << std::endl; // int i = *it
}