OpenCV reads an image in NCHW format (Number of samples x Channels x Height x Width), I need to convert it to NHWC format (move 2nd dimension of array to last). Is there an efficient way to convert from NCHW to NHWC in C++? I can do this with a 3 for loops, but obviously this is not efficient at all.
Asked
Active
Viewed 1,257 times
0
-
Do you want to separate channels? You can either use cv::split followed by concatenation or use cv::blobFromImage. Maybe there are other ways with cvtColor or more specialized functions. – Micka Sep 05 '21 at 14:04
-
@Micka no, blobFromImage creates blob in NCHW format. at this point, I can't find an efficient way to convert it to NHWC. what I wanted to do was just read the image with cv::imread and convert it to 4d Mat myself instead of using blobFromImage. I don't know this is going to solve the issue or not but I'll try. anyway thank you so much for your response. – Moghaddam Sep 05 '21 at 14:37
-
Then NCHW is just concatenation of N images. Maybe you can embed it to Mat4d as a data-pointer – Micka Sep 05 '21 at 15:31
-
Dimension ordering as specified here is ambiguous. Is the last dimension the one where samples are contiguous in memory? Because OpenCV typically does read in images with the samples for one pixel contiguous in memory. You will need to be more clear about how you need to reorganize the memory layout of your data. – Cris Luengo Sep 05 '21 at 15:35
-
Also, why do you say loops are not efficient? You cannot copy data other than by looping over it. Even system calls like `memcpy` loop over the data. – Cris Luengo Sep 05 '21 at 15:37
-
@CrisLuengo Thank you very much for your response and yeah using for loops is not that terrible but I'm trying to do it without using loops. I'm sure there must be a way to achieve this – Moghaddam Sep 05 '21 at 18:51
-
Same question, but has no good answers: https://stackoverflow.com/questions/46017418/how-can-i-permute-dimensions-in-cvmat-from-cxwxh-to-wxhxc – Cris Luengo Sep 05 '21 at 19:21
-
“Using for loops is not that terrible” — it’s unavoidable. You can call a function to do something on an array, but that function will be implemented with a loop. Your processor does not have instructions to do something with a large block of data, it only has instructions to do something with single values or (in case of SIMD instructions) with a small set of values. All array operations are always implemented with a loop. Sure, if you can call a function, do that, it’s better than re-implementing existing functionality. But don’t think of loops as inherently flawed things. C++ is not Python. – Cris Luengo Sep 05 '21 at 19:26
-
That is to say, your loop is probably the best solution you’ll find. It might be possible to speed up the loop if you traverse the data in the right order, and use the right functionality to read and write values. I suggest you post your (working!) code on [Code Review](https://codereview.stackexchange.com/) to get tips like that. – Cris Luengo Sep 05 '21 at 19:29
2 Answers
0
This straightforward solution worked for me with OpenCV C++:
static void hwc_to_chw(cv::InputArray src, cv::OutputArray dst) {
std::vector<cv::Mat> channels;
cv::split(src, channels);
// Stretch one-channel images to vector
for (auto &img : channels) {
img = img.reshape(1, 1);
}
// Concatenate three vectors to one
cv::hconcat( channels, dst );
}

Roy Shilkrot
- 3,079
- 29
- 25
0
With OpenCV >= 4.6, you can use transposeND
(from opencv2/core.hpp
) for such kind of convertion:
std::vector<int> order = {0, 2, 3, 1};
Mat inp, out; // inp: NCHW, out: NHWC
transposeND(inp, order, out);

fytao
- 181
- 3
- 14