繁体   English   中英

调整OpenCV Mat的Vector的大小时出现意外结果

[英]Unexpected result when resizing Vector of Vector of OpenCV Mat

我使用的是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))));

cv::Mat的副本构造函数的文档 (强调我的意思):

参量

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM