访问CV_32SC1 nx1的opencv矩阵

Access to CV_32SC1 nx1 opencv matrix

本文关键字:opencv 矩阵 nx1 32SC1 CV 访问      更新时间:2023-10-16

我有一个人工矩阵,我把它传递给OpenCV - 3.0.0版本的EM高斯混合模型算法:

[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)

文档说明了我感兴趣的矩阵标签:

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

我对'labels'的非工作访问打印(0,0,0,0,0)而不是预期的(0,0,1,1,2),这是通过

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

。我需要使用整数索引来处理我想通过点云功能聚类的原始PCL点云:

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主题说明,如果我知道矩阵元素类型,我可以使用模板化的at()函数。api声明标签矩阵的类型为$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的qdebug()用法,而不是std::cout。如果仍然认为有价值,可以改进我提供的最小示例中的构造函数,并删除这句话和以下内容。我仍然希望有一个一行的解决方案,但我还没有执行。

正确的打印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
}