在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的答案设置为他的短代码的正确答案。
答案 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]实际上没有任何关系,除非你已将它添加到该点。如果你想建立关系,那么你需要自己编写代码。
答案 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);
这假设图像是单通道。