2
votes

I have an array of pixel data in RGBA format. Although I have already converted this data to grayscale using the GPU (thus all 4 channels are identical).

I now want to use this grayscale data in OpenCV, and I don't want to store 4 copies of the same data. Is it possible to create a cv::Mat structure from this pixel array by specifying a stride. (i.e. only read out every 4th byte)

I am currently using

GLubyte* Img = stuff from GPU;
cv::Mat tmp(height, width, CV_8UC4, Img);

But this copies all the data, or does it wrap the existing pointer into a cv::Mat without copying it? If it wraps without copy then I will be happy to use standard c++ routines to copy only the data I want from Img into a new section of memory and then wrap this as cv::Mat.

Otherwise how would you suggest doing this to reduce the amount of data being copied.

Thanks

1
so, this copies all 4 channels, but you only need/want one ? (and so far, it copies the pointer only, not the data) - berak
Yes this will copy all 4 channels, and I only want 1. I am not sure if this is copying the pointer or the data. - System123
the pointer only. it's a borrowed pointer, so it does not alloc memory or copy anything. maybe do a cvtColor to grayscale on that ? - berak
oh, and please reverse width, height above. - berak
Aaaah, fixed that. Thanks for pointing it out. I already have a grayscale image so it seems pointless wasting CPU cycles to convert grayscale to grayscale. I will just copy the values I want over to a new buffer and convert that to cvMat. Thanks - System123

1 Answers

5
votes

The code that you are using

cv::Mat tmp(rows, cols, CV_8UC4, dataPointer);

does not perform any copy but only assign the data field of the Mat instance.

If it's ok for you to work with a matrix of 4 channels, then just go on. Otherwise, if you prefer working with a 1-channel matrix, then just use the function cv::cvtColor() to create a new image with a single channel (but then you will get one additional image in memory and pay the CPU cycles for the conversion):

cv::Mat grey;
cv::cvtColor(tmp, grey, CV_BGR2GRAY);

Finally, one last thing: if you can deinterlace the colorplanes beforehand (for example on the GPU) and get some image with [blue plane, green plane, red plane], then you can pass CV_8UC1 as image type in the construction of tmp and you get a single channel grey image without any data copy.