I want to write a function that gets an image as parameter and returns another image and bind it into python using pybind11
.
The part on how to receive the image as parameter is nicely solve thanks to this question.
On the other hand, the returning image is a bit tricky.
Here my code (I try flipping the image using a cv
function as an example):
py::array_t<uint8_t> flipcvMat(py::array_t<uint8_t>& img)
{
auto rows = img.shape(0);
auto cols = img.shape(1);
auto channels = img.shape(2);
std::cout << "rows: " << rows << " cols: " << cols << " channels: " << channels << std::endl;
auto type = CV_8UC3;
cv::Mat cvimg2(rows, cols, type, (unsigned char*)img.data());
cv::imwrite("/source/test.png", cvimg2); // OK
cv::Mat cvimg3(rows, cols, type);
cv::flip(cvimg2, cvimg3, 0);
cv::imwrite("/source/testout.png", cvimg3); // OK
py::array_t<uint8_t> output(
py::buffer_info(
cvimg3.data,
sizeof(uint8_t), //itemsize
py::format_descriptor<uint8_t>::format(),
3, // ndim
std::vector<size_t> {rows, cols , 3}, // shape
std::vector<size_t> {cols * sizeof(uint8_t), sizeof(uint8_t), 3} // strides
)
);
return output;
}
And I call it from python as:
img = cv2.imread('/source/whatever/ubuntu-1.png')
img3= opencvtest.flipcvMat(img)
cv::imwrite
are correct (the original is the same as the input and the 2nd is correctly flipped)The Problem is On the python side, the returning image seems to be wrong-aligned (I can distinguish some shapes but the pixels are not in the right place.
My guess is that I have a problem while creating the py::buffer_info
but I cannot find it. What could I be doing wrong?
Yes it indeed is a problem with py::buffer_info
, the strides to be more precise
Instead of:
{ cols * sizeof(uint8_t), sizeof(uint8_t), 3 }
The strides should be:
{ sizeof(uint8_t) * cols * 3, sizeof(uint8_t) * 3, sizeof(uint8_t)}