调整OpenCV Mat矢量大小时的意外结果

问题描述 投票:0回答:1

我在Ubuntu 16.04,GCC 5.4,最新的OpenCV。假设我有一个double的向量

  std::vector<std::vector<double>> vecvecdouble;

  vecvecdouble.resize(3, std::vector<double>(3, 0));

  for (int j = 0; j < 3; j++){
    for (int i = 0; i < 3; i++){
      if (i == 0){
        vecvecdouble[i][j] = 1;
        vecvecdouble[i][j] = 1;
      }
      if (i == 1){
        vecvecdouble[i][j] = 2;
        vecvecdouble[i][j] = 2;
      }

      if (i == 1 && j == 0){
        std::cout << vecvecdouble[i - 1][j] << std::endl;
        std::cout << vecvecdouble[i][j] << std::endl;
        std::cout << vecvecdouble[i + 1][j] << std::endl;
      }
    }
  }

它打印

1
2
0

正如所料。但是,如果我用OpenCV cv::mat做同样的事情

  std::vector<std::vector<cv::Mat>> vecvecmat;

  vecvecmat.resize(
      3, std::vector<cv::Mat>(3, cv::Mat(4, 4, CV_64FC1, cv::Scalar(0.0))));

  for (int j = 0; j < 3; j++){
    for (int i = 0; i < 3; i++){
      if (i == 0){
        vecvecmat[i][j].at<double>(0, 0) = 1;
        vecvecmat[i][j].at<double>(0, 1) = 1;
      }
      if (i == 1){
        vecvecmat[i][j].at<double>(0, 0) = 2;
        vecvecmat[i][j].at<double>(0, 1) = 2;
      }

      if (i == 1 && j == 0){
        std::cout << vecvecmat[i - 1][j] << std::endl;
        std::cout << vecvecmat[i][j] << std::endl;
        std::cout << vecvecmat[i + 1][j] << std::endl;
      }
    }
  }

它打印

[2, 2, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0]
[2, 2, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0]
[2, 2, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0]

这是完全出乎意料的,因为我期待它打印

[1, 1, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0]
[2, 2, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0]
[0, 0, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0;
 0, 0, 0, 0]

但是,如果我不尝试在一行中调整向量的大小并经过两个for循环,它实际上会返回预期的结果

  std::vector<std::vector<cv::Mat>> vecvecmat;

  vecvecmat.resize(3);

  for (int i = 0; i < 3; i++){
    for (int j = 0; j < 3; j++){
      cv::Mat mymat = cv::Mat(4, 4, CV_64FC1, cv::Scalar(0.0));

      vecvecmat[i].push_back(mymat);
    }
  }

  for (int j = 0; j < 3; j++){
    for (int i = 0; i < 3; i++){
      if (i == 0){
        vecvecmat[i][j].at<double>(0, 0) = 1;
        vecvecmat[i][j].at<double>(0, 1) = 1;
      }
      if (i == 1){
        vecvecmat[i][j].at<double>(0, 0) = 2;
        vecvecmat[i][j].at<double>(0, 1) = 2;
      }

      if (i == 1 && j == 0){
        std::cout << vecvecmat[i - 1][j] << std::endl;
        std::cout << vecvecmat[i][j] << std::endl;
        std::cout << vecvecmat[i + 1][j] << std::endl;
      }
    }
  }

这条线有什么问题?

vecvecmat.resize(3, std::vector<cv::Mat>(3, cv::Mat(4, 4, CV_64FC1, cv::Scalar(0.0))));
c++ opencv vector
1个回答
2
投票

cv::Mat says(强调我的)复制构造函数的文档:

参数

m将(作为整体或部分)分配给构造矩阵的数组。这些构造函数不会复制任何数据。相反,构造指向m数据或其子数组的标题并将其与之关联。参考计数器(如果有)递增。因此,当您修改使用此类构造函数形成的矩阵时,您还可以修改m的相应元素。如果要拥有子阵列的独立副本,请使用Mat::clone()

您在调用std::vector::resize时构造的初始矩阵将使用此复制构造函数*复制到向量的每个元素中,因此它们都指向相同的数据。修改一个矩阵时,可以修改所有矩阵。

*或者也许与operator=,它做同样的事情(我不确定哪个,但它不影响结果)

我建议像这样初始化你的矢量:

std::vector<std::vector<cv::Mat>> vecvecmat;
vecvecmat.resize(3, std::vector<cv::Mat>());
for(auto& v : vecvecmat)
{
    for(std::size_t i = 0; i < 3; ++i)
    {
        v.emplace_back(4, 4, CV_64FC1, cv::Scalar(0.0));
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.