Ask Your Question
1

OpenCV padded Mat, use with VideoWriter

asked 2016-04-28 02:54:23 -0600

tmlen gravatar image

I have an image represented using a 2D array of 3 byte color values (OpenCV type CV_8UC3). The array is not densely packed, but instead elements are aligned on a 4 byte boundary, i.e. there is 1 byte of padding.

So the array is of the format

RGB_RGB_RGB_RGB_RGB_RGB_RGB_RGB_RGB_RGB_RGB_RGB_RGB_RGB_RGB_...

I want to access this data using OpenCV, without making a new copy of it. But OpenCV Mat of type CV_8UC3 is packed by default, so I create the Mat with explicit strides/steps, using

cv::Mat mat(
    2,
    sizes, // = (1080, 1920)
    CV_8UC3,
    reinterpret_cast<void*>(data),
    steps // = (7680, 4)
);

data is a pointer to a rgb_color array, defined by

struct alignas(4) rgb_color { std::uint8_t r, g, b; };

However using this mat with cv::VideoWriter still produces incorrect results, and it seems that VideoWriter ignores the strides of the Mat.

Is it possible to use VideoWriter and other OpenCV functionality with matrices of this type?

edit retag flag offensive close merge delete

1 answer

Sort by ยป oldest newest most voted
1

answered 2016-04-28 05:14:25 -0600

pklab gravatar image

updated 2016-04-28 05:22:03 -0600

1st of all I think your struct is wrong because r,g,b should be uchar...

Now, suppose you have this data:

const int width = 1920, height = 1080;
struct srcPixelType { uchar r, g, b, pad; };
srcPixelType data[width *height];

you could use CV_8UC4 such as for BGR+Alpha images and ignoring Alpha channel...

Size sz(width, height);
cv::Mat mat(sz, CV_8UC4, data);

You can access this data using cv::Vec4b data type

Vec4b pxFromOCV;
pxFromBGRA = mat.at<Vec4b>(row, col);
uchar red = pxFromBGRA[0];

Even if you can ignore the 4th channel, OpenCV functions will not. Channels are processed independently wasting time for the useless 4th chan.

In addiction OpenCV functions like imshow, imwrite or VideoWriter expect a BGR image and not RGBx image, than you have to swap B<->R channels before to use these functions.

//colors are wrong because mat is RGBx but BGRx is expected
imshow("the data", mat);
// convert the mat before to show it
Mat img;
cvtColor(mat, img, CV_RGBA2BGR);
imshow("the image from data", img);

because you have to convert your Mat at the end I would suggest to convert it immediately so you will work on less memory:

Size sz(width, height);
cv::Mat mat(sz, CV_8UC4, data);
Mat img;
cvtColor(mat, img, CV_RGBA2BGR);
Vec3b pxFromBGR;
pxFromBGR = img.at<Vec3b>(row, col);
uchar red = pxFromBGRA[2];
edit flag offensive delete link more

Comments

The goal was to integrate OpenCV with an existing framework, and there are also cases where the padding would take a larger value (for example to access color information from a point_xyzrgb POD type). I think std::uint8_t and uchar are guaranteed to be the same assuming CHAR_BIT == 8. But do the other functions in OpenCV (e.g. those in imgproc) respect the strides of the matrix?

tmlen gravatar imagetmlen ( 2016-04-28 05:25:36 -0600 )edit

if you like std::uint8_t use it but OpenCV uses uchar... btw Using cv::Mat_ you can build Mat around your own data type:

//define your own data type
struct srcPixelType { std::_Uint8_t r, g, b, pad; };
srcPixelType data[width *height];

//build a Mat around your data and datatype
Mat m = Mat_<srcPixelType>(sz.height, sz.width,(srcPixelType*)data);
//and read the pixel value as 
srcPixelType pixel;
pixel = m.at<srcPixelType>(row, col);
std::_Uint8_t red = pixel[0];
pklab gravatar imagepklab ( 2016-04-28 06:39:20 -0600 )edit

Question Tools

1 follower

Stats

Asked: 2016-04-28 02:54:23 -0600

Seen: 905 times

Last updated: Apr 28 '16