OPENCV是否有更好的方法来跨维度访问数据?

时间:2020-03-11 22:25:45

标签: c++ opencv

我有一个3维cv :: Mat,尺寸为(10,行= M,列数= N)。这是MxN像素堆叠在一个立方体中的10张图像。我想在整个图像的维度上按行对多维数据集进行切片,以便最后获得M个(10,N)的切片,并将对其应用其他一些opencv算法。我发现我可以使用cv :: Ranges();但是,我必须使用重塑使其变为2D,因此必须使用clone()使切片连续。下面是我用来执行此操作的代码段,但是执行时间很慢(我认为对每个行切片执行的克隆/复制都执行此操作)。有一个更好的方法吗?我还发现this,这并不令人鼓舞。

const int img_dim[3] = {10, 20, 40};
Mat data = Mat::zeros(3, img_dim, CV_64FC1);
for (int row = 0; row < data.size[1]; row++ {
    std::vector<Range> range;
    range.push_back(Range(0, data.size[0]));
    range.push_back(Range(row, row+1));
    range.push_back(Range(0, data.size[2]));

    // Below slice is still 3D with (10, 1, 40) so I use reshape to make it (10, 40)
    // which requires the clone()
    Mat slice = data(&range[0]).clone();
    const int sz[] {data.size[0], data.size[2]};
    slice = slice.reshape(1, 2, sz);

    // Processing of slice
    // e.g cv::GaussianBlur(slice, dst, Size(0,0), r, r);
}

1 个答案:

答案 0 :(得分:1)

您可以设置step(以字节为单位的步幅),并在不复制数据的情况下构建切片:

假设data在内存中是连续的:

  • 该行从row*N开始偏移double data.data个元素(data.data点矩阵数据)开始。
  • 切片step(行之间的字节跨度)等于M * N *sizeof(double)

[如果data在内存中不连续,则解决方案会更加复杂]。

这是一个代码示例(构建第5行的一部分):

const int M = 20;
const int N = 40;
const int img_dim[3] = { 10, M, N };
Mat data = cv::Mat::zeros(3, img_dim, CV_64FC1);

int row = 5;

data.at<double>(0, row, 0) = 0;
data.at<double>(1, row, 0) = 1;
data.at<double>(2, row, 0) = 2;
data.at<double>(3, row, 0) = 3;

data.at<double>(0, row, 1) = 100;
data.at<double>(1, row, 1) = 101;
data.at<double>(2, row, 1) = 102;
data.at<double>(3, row, 1) = 103;

//Byte stride between M of slice equals M*N*8 bytes
size_t step = M * N *sizeof(double);

//slice begins at data.data + row*N
Mat slice(10, N, CV_64FC1, (uchar*)data.data + row*N*sizeof(double), step);

std::cout << slice.at<double>(0, 0) << std::endl << slice.at<double>(1, 0) << std::endl << slice.at<double>(2, 0) << std::endl << slice.at<double>(3, 0) << std::endl << std::endl;
std::cout << slice.at<double>(0, 1) << std::endl << slice.at<double>(1, 1) << std::endl << slice.at<double>(2, 1) << std::endl << slice.at<double>(3, 1) << std::endl << std::endl;

注意:由于缓存未命中,处理大步幅的数据可能效率不高-复制数据可能更有效(检查数据处理是否变慢)。


输出:

0
1
2
3

100
101
102
103