4
votes

I have an issue parsing the image data from the frame grabber into an OpenCV Mat format. I can get image data from my EDT frame grabber as an unsigned char pointer and pass it to a newly created Mat, but I am losing valuable data in the process and am not sure how to fix it.

My camera is an infrared camera which outputs a 12-bit 320x256 Bayer image. I'm fairly confident that my use of EDT's API's is correct. Using EDT's software, "pdvshow", I can view the image data as expected but when I convert the returned frame from EDT's API to an OpenCV Mat and display it, I lose a significant amount of data. When I have the Mat set to CV16UC1, the frame is near black, when the Mat is set to CV8UC1, the frame displays most data but appears very grainy and some spots are blown out completely. I know that the frame grabber stores each 12-bit pixel in two bytes and the data is MSB justified. GetStride returns 0.

unsigned char *pdvImage;
pdvImage = pdv_image(pdv_p); 

cv::Mat freshFrame;
freshFrame = cv::Mat(GetHeight(), GetWidth(), CV_16UC1, pdvImage, GetStride()); //was CV_16UC1 but 8UC1 shows more data

return freshFrame.clone();
2

2 Answers

2
votes

I have written a code that draws a char* image then convert it to OpenCV Mat:

const int WIDTH = 800, HEIGHT = 600;

uchar *data = new uchar[WIDTH * HEIGHT * 3];

for (int i = 0; i < WIDTH*HEIGHT*3;i+=3)
{
    if (i < WIDTH*HEIGHT*3/2)
    {
        data[i + 0] = (uchar)0;
        data[i + 1] = (uchar)0;
        data[i + 2] = (uchar)255;
    }
    else
    {
        data[i + 0] = (uchar)255;
        data[i + 1] = (uchar)0;
        data[i + 2] = (uchar)0;
    }
}

cout << "May God be pleased with you, amen!\n";

Mat colorfrm = Mat(HEIGHT, WIDTH, CV_8UC3);
colorfrm.data = data;

while (1)
{
    imshow("Original Image", colorfrm);

    /////////

    int c = cvWaitKey(30);
    if (c == ' ')
    {
        break;
    }
    if (c == 'q' || c == 'Q' || c == 27)
    {
        return 0;
    }
}

I hope this will be of help!

1
votes

When you create freshFrame as a CV_16UC1 Mat, the 12 bits of data are in the least significant bits. Scaling the data will fix the problem where the resulting image appears too black. So instead of

return freshFrame.clone();

you need

return freshFrame * 16;

You might also need to check the byte order of the two bytes for each pixel in pdvImage.

With regard to CV_8UC1 this will not work

freshFrame = cv::Mat(GetHeight(), GetWidth(), CV_8UC1, pdvImage, GetStride()); 

because the first two bytes of pdvImage make up the value of the first pixel in the image but become two separate pixels in freshFrame. However, if you create freshFrame as in the above line, the first byte becomes the value for the first pixel in freshFrame and the second byte becomes the value for the second pixel, and so on. Obviously this is wrong. If you really need a CV_8UC1 Mat it would be simplest probably to create a CV_16UC1 Mat and then convert it.