簡體   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