C ++:从堆叠2D数组中创建3D数组

时间:2018-03-21 16:40:20

标签: c++ opencv 3d stack 2d

在Python中,我通常使用 vstack stack 等函数,通过将2D数组堆叠到另一个上来轻松创建3D数组。

有没有办法在C ++中做到这一点?

特别是,我已经使用OpenCV将图像加载到Mat变量中,如:

cv::Mat im = cv::imread("image.png", 0);

我想通过堆叠该Mat变量的副本来制作N层的3D阵列/ Mat。

编辑:这个新的3D矩阵必须是"可旅行的"通过向其任何组件添加一个整数,这样如果我在位置(x1,y1,1)并且我向最后一个组件添加+1,则到达(x1,y1,2)。类似地,对于3D矩阵的任何坐标/分量。

已解决: @Aram和@Nejc的答案都符合预期。我将@Nejc的答案设置为他的短代码的正确答案。

4 个答案:

答案 0 :(得分:2)

这个回答是针对上述问题的回答:

  

在Python中,我通常使用vstack,stack等函数,通过将2D数组一个堆叠到另一个上来轻松创建3D数组。

这当然是可行的,你可以将矩阵添加到一个矢量中,这个矢量就是你的“堆栈”

例如,您可以使用

std::vector<cv::Mat>>

这会给你一个垫子的矢量,这将是一个切片,然后你可以通过添加更多切片矢量“分层”那些

如果您想要多个堆栈,可以将该向量添加到另一个向量中:

std::vector<std::vector<cv::Mat>>

要将矩阵添加到数组中,请执行以下操作:

myVector.push_back(matrix);

编辑以下问题

  

在这种情况下,我可以从一个位置(x1,y1,z1)行进到紧靠上方位置(x1,y1,z1 + 1),这样我在矩阵中的新位置就是(x1,y1) ,Z2)?

你最终会得到一些看起来很像这样的东西。如果向量中的元素1有一个矩阵,它与元素[2]实际上没有任何关系,除非你已将它添加到该点。如果你想建立关系,那么你需要自己编写代码。 enter image description here

答案 1 :(得分:2)

您实际上可以使用opencv创建3D或ND垫,您需要使用以dimensions作为输入的构造函数。然后将每个矩阵复制到(本例中)3D阵列

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

int main() {
    // Dimensions for the constructor... set dims[0..2] to what you want
    int dims[] = {5, 5, 5}; // 5x5x5 3d mat

    Mat m = Mat::zeros(5, 5, CV_8UC1);

    for (size_t i = 0; i < 5; i++) {
        for (size_t k = 0; k < 5; k++) {
            m.at<uchar>(i, k) = i + k;
        }
    }

    // Mat with constructor specifying 3 dimensions with dimensions sizes in dims.
    Mat 3DMat = Mat(3, dims, CV_8UC1);

    // We fill our 3d mat.
    for (size_t i = 0; i < m2.size[0]; i++) {
        for (size_t k = 0; k < m2.size[1]; k++) {
            for (size_t j = 0; j < m2.size[2]; j++) {
                3DMat.at<uchar>(i, k, j) = m.at<uchar>(k, j);
            }
        }
    }

    // We print it to show the 5x5x5 array.
    for (size_t i = 0; i < m2.size[0]; i++) {
        for (size_t k = 0; k < m2.size[1]; k++) {
            for (size_t j = 0; j < m2.size[2]; j++) {
                std::cout << (int) 3DMat.at<uchar>(i, k, j) << " ";
            }
            std::cout << endl;
        }
        std::cout << endl;
    }

    return 0;
}

答案 2 :(得分:1)

Numpy函数vstack返回一个连续的数组。生成cv::Mat个对象的向量或数组的任何C ++解决方案都不会反映vstack在这方面的行为,因为单独的&#34;层&#34;属于单个cv :: Mat对象的属性不会存储在连续的缓冲区中(除非在事先提前仔细分配底层缓冲区)。

我提出了将所有数组复制到具有连续缓冲区的三维cv::Mat对象的解决方案。就这个想法而言,这个答案类似于Aram's answer。但是,我没有逐个分配像素值,而是利用了OpenCV功能。在开始时,我分配了一个大小为N X ROWS X COLS的矩阵,其中N是我想要的二维图像的数量&#34; stack&#34;并且ROWS x COLS是每个图像的尺寸。

然后我做了N步骤。在每一步,我获得指向第一个元素沿&#34;外部&#34;的位置的指针。尺寸。我将该指针传递给临时Mat对象的构造函数,该对象充当大小为ROWS x COLS的内存块的一种包装器(但没有复制),它从指针指向的地址开始。然后我使用copyTo方法将i - 图像复制到该内存块中。 N = 2的代码:

cv::Mat img0 = cv::imread("image0.png", CV_IMREAD_GRAYSCALE);
cv::Mat img1 = cv::imread("image1.png", CV_IMREAD_GRAYSCALE);

cv::Mat images[2] = {img0, img1};  // you can also use vector or some other container

int dims[3] = { 2, img0.rows, img0.cols }; // dimensions of new image  

cv::Mat joined(3, dims, CV_8U); // same element type (CV_8U) as input images

for(int i = 0; i < 2; ++i)
{
  uint8_t* ptr = &joined.at<uint8_t>(i, 0, 0); // pointer to first element of slice i

  cv::Mat destination(img0.rows, img0.cols, CV_8U, (void*)ptr); // no data copy, see documentation

  images[i].copyTo(destination);
}

答案 3 :(得分:0)

根据问题和评论,我认为你正在寻找这样的事情:

std::vector<cv::Mat> vec_im;
//In side for loop:
vec_im.push_back(im);

然后,您可以通过以下方式访问它:

Scalar intensity_1 = vec_im[z1].at<uchar>(y, x);
Scalar intensity_2 = vec_im[z2].at<uchar>(y, x);

这假设图像是单通道。