如何在C++(OpenCV)中堆叠2D Mat生成可遍历的3D数组?
cv::Mat into a 3D Structure in OpenCV (C++) Great question! Coming from NumPy's handy vstack/stack functions, it’s totally reasonable to want a similar workflow in OpenCV for C++. Luckily, OpenCV’s cv::Mat natively supports multi-dimensional arrays, so we can achieve exactly what you need—stacking a 2D grayscale image into a 3D matrix with N copies, and easily traversing each element to modify values.
Let’s walk through two straightforward approaches:
1. Quick & Clean: Use cv::repeat + cv::reshape
This method is perfect if you just need to duplicate your image N times and reshape the result into a 3D array in one go. It’s concise and requires minimal code.
Example Code
#include <opencv2/opencv.hpp> #include <iostream> int main() { // Load your grayscale image cv::Mat im = cv::imread("image.png", 0); if (im.empty()) { std::cerr << "Failed to load image!" << std::endl; return -1; } const int N = 5; // Number of layers you want to stack // Step 1: Repeat the image N times vertically (result is H*N x W, single channel) cv::Mat repeated = cv::repeat(im, N, 1); // Step 2: Reshape into a 3D Mat with dimensions (N, image_height, image_width) // reshape params: 1st = number of channels (keep 1), 2nd = new 3D size vector cv::Mat stacked_3d = repeated.reshape(1, cv::Size({N, im.rows, im.cols})); // Now you have your 3D matrix ready for use! return 0; }
2. Manual Control: Create 3D Mat & Fill Layers
If you need more flexibility (e.g., modifying layers as you stack them), manually creating the 3D matrix and copying each layer gives you full control over the process.
Example Code
#include <opencv2/opencv.hpp> #include <iostream> int main() { cv::Mat im = cv::imread("image.png", 0); if (im.empty()) { std::cerr << "Failed to load image!" << std::endl; return -1; } const int N = 5; // Define 3D dimensions: (number of layers, image height, image width) int dims[] = {N, im.rows, im.cols}; // Create an empty 3D Mat with the same data type as your input image cv::Mat stacked_3d(3, dims, im.type()); // Copy the original image into each layer for (int layer_idx = 0; layer_idx < N; ++layer_idx) { // Extract the current layer as a sub-matrix cv::Mat layer = stacked_3d(cv::Range(layer_idx, layer_idx + 1), cv::Range::all(), cv::Range::all()); // Reshape the layer to match the original image's 2D size, then copy im.copyTo(layer.reshape(1, im.rows)); } return 0; }
Traversing the 3D Mat
Once you have your 3D matrix, accessing and modifying elements is straightforward using cv::Mat::at<>(). For a grayscale image (uchar type), you can iterate through all layers, rows, and columns like this:
// Iterate through every element in the 3D matrix for (int i = 0; i < stacked_3d.size[0]; ++i) { // i = layer index for (int y = 0; y < stacked_3d.size[1]; ++y) { // y = row for (int x = 0; x < stacked_3d.size[2]; ++x) { // x = column // Add 1 to each element (example operation) stacked_3d.at<uchar>(i, y, x) += 1; } } }
Quick Notes
- If you prefer a multi-channel 2D Mat instead of a strict 3D array (e.g., treating layers as channels), you could use
cv::mergewith a vector of repeated images—but this is a different structure than a true 3D matrix. - For better performance with large images, consider using pointer-based access instead of
at<>(), butat<>()is perfectly fine for most use cases and much more readable.
内容的提问来源于stack exchange,提问作者daniglezad

