了解NAryMatIterator中的平面

时间:2016-07-17 10:46:00

标签: c++ opencv opencv3.0

我有三维矩阵:

const int n_mat_size = 5;
const int n_mat_sz[] = { n_mat_size , n_mat_size, n_mat_size };
cv::Mat m1(3, n_mat_sz, CV_32FC1);

现在我想迭代它的平面并期望它应该是三个二维矩阵:

const cv::Mat* arrays[] = { &m1, 0 };
cv::Mat planes[3];
cv::NAryMatIterator it(arrays, planes);
std::cout << it.nplanes << ", " << it.planes[0].rows << ", " << it.planes[0].cols;

我希望输出“3,5,5”,但我得到“1,1,125”。矩阵的切片在哪里?

1 个答案:

答案 0 :(得分:0)

因为矩阵m1是连续的,所以只有一个平面(或切片)。

请参阅NAryMatIterator的文档:

  

迭代切片(或平面),而不是元素,其中“切片”是数组的连续部分。

例如,以下代码中的矩阵m2不是连续的:

const int n_mat_size = 5;
const int n_mat_sz[] = { n_mat_size , n_mat_size, n_mat_size };
cv::Mat m1(3, n_mat_sz, CV_32FC1);

// Get plane 2 and 3 of m1
// and row 2, row 3 and row 4 of every selected plane
// m2 is not continuous
cv::Mat m2 = m1(cv::Range(2,4), cv::Range(2,5));

const cv::Mat* arrays[] = { &m2, 0 };
cv::Mat planes[3];
cv::NAryMatIterator it(arrays, planes);
std::cout << it.nplanes << ", " << it.planes[0].rows << ", " << it.planes[0].cols << std::end;

上述代码的输出为:2, 1, 15

请注意,每个平面的行数始终为1,列数是平面中包含的元素数。

有声明:

planes[i] = Mat(1, (int)size, A.type(), A.data);

在函数void NAryMatIterator::init中,可以在https://github.com/opencv/opencv/blob/master/modules/core/src/matrix.cpp#L4596找到。

上述声明设定了飞机的大小。

要将您提供的矩阵分隔为平面,可以使用cv::InputArray::getMatVector

以下代码显示了它的用法。

int main()
{
  const int n_mat_size = 3;
  const int n_mat_sz[] = { n_mat_size , n_mat_size, n_mat_size };
  cv::Mat m1(3, n_mat_sz, CV_8U);

  cv::MatIterator_<uchar> it = m1.begin<uchar>();
  cv::MatIterator_<uchar> end = m1.end<uchar>();
  for (uchar i = 0; it != end; ++it, ++i)
  {
         *it = i;
  }

  cv::InputArray arr(m1);
  std::vector<cv::Mat> planes;
  arr.getMatVector(planes);
  for (size_t i = 0; i < planes.size(); ++i)
  {
    std::cout << "-------" << std::endl
    << planes[i] << std::endl << "******" << std::endl;
  }
}

其输出如下:

-------
[  0,   1,   2;
   3,   4,   5;
   6,   7,   8]
******
-------
[  9,  10,  11;
  12,  13,  14;
  15,  16,  17]
******
-------
[ 18,  19,  20;
  21,  22,  23;
  24,  25,  26]

******

也许最简单的方法是使用方法cv::Mat::row(int)。相应的代码是:

int main()
{
  const int n_mat_size = 3;
  const int n_mat_sz[] = { n_mat_size , n_mat_size, n_mat_size };
  cv::Mat m1(3, n_mat_sz, CV_8U);

  cv::MatIterator_<uchar> it = m1.begin<uchar>();
  cv::MatIterator_<uchar> end = m1.end<uchar>();
  for (uchar i = 0; it != end; ++it, ++i)
  {
         *it = i;
  }

  int n = m1.size[0];
  for (int i = 0; i < n; ++i)
  {
     cv::Mat three_d_plane = m1.row(i);
     // three_d_plane has a size 1x3x3
     // std::cout supports only 2-d matrix. Therefore, we change it to 2-d here
     cv::Mat two_d_plane(three_d_plane.size[1], three_d_plane.size[2], three_d_plane.type(), three_d_plane.data);
     std::cout << two_d_plane << std::endl << "----" << std::endl;
  }
}

输出

[  0,   1,   2;
   3,   4,   5;
   6,   7,   8]
----
[  9,  10,  11;
  12,  13,  14;
  15,  16,  17]
----
[ 18,  19,  20;
  21,  22,  23;
  24,  25,  26]
----