I'm trying to process images from a Hamamatsu Orca flash 4 camera using Opencv and having some trouble with 12 bit mono images. They are bit packed with 2 pixels in 3 bytes as described:
MONO12 Packed Format
This is output data format of DCAM_PIXELTYPE_MONO12. P is the pixel transmitted by the camera. B is the byte in buffer received data.
Buffer / Pixel Data: B[0] P[0] bits 11 ... 4, B[1] P[1] bits 3 ... 0 | P[0] bits 3 ... 0, B[2] P[1] bits 11 ... 4, ... ... B[m-2] P[n-1] bits 11 ... 4, B[m-1] P[n] bits 3 ... 0 | [n-1] bits 3 ... 0, B[m] P[n] bits 11 ... 4
The following code is supposed to unpack the image but am having trouble following and hope someone might help me understand a few things: first, why would you mix BYTE and WORD with char and ushort, second, why use a LUT to unpack the bits instead of transferring the buffer directly to 2 arrays containing char and ushort, and third, why is this not working as written. ie, isn't pImage a pointer to the unpacked 12 bit image? Maybe that pImage array of chars needs to be transferred to yet another array of ushort 2 bytes at a time first? Is there a more efficient way to do this?
void unpack_mono12_image( void* pSrcTop, int32 srcRowbytes, void* pDstTop, int32 dstRowbytes, int32 width, int32 height )
{
WORD lut1[65536];
WORD lut2[65536];
// make lut to unpack MONO12
int i, j;
for( i=0; i<65536; i++ )
{
WORD w = (WORD)i;
BYTE* p = (BYTE*)&w;
lut1[i] = (p[0] << 4) + (p[1] & 0x0F);
lut2[i] = (p[1] << 4) + ((p[0] & 0xF0) >> 4);
}
// unpack MONO12 and copy
char* src = (char*)pSrcTop;
char* dst = (char*)pDstTop;
for( i=0; i<height; i++ )
{
WORD* pDst = (WORD*)(dst + dstRowbytes * i);
BYTE* pSrc = (BYTE*)(src + srcRowbytes * i);
for( j=0; j<width/2; j++ )
{
*pDst++ = lut1[*(WORD*)pSrc++];
*pDst++ = lut2[*(WORD*)pSrc++];
pSrc++;
}
}
}
...
int32 rowbytes = bufframe.width * 2;
int32 framebytes = rowbytes * bufframe.height;
char* pImage = new char[ framebytes ];
memset( pImage, 0, framebytes );
unpack_mono12_image( bufframe.buf, bufframe.rowbytes, pImage, rowbytes, bufframe.width, bufframe.height );
cv::Mat img(bufframe.width, bufframe.height, CV_16U, pImage);
ushort* pointer_to_data_start = img.ptr<ushort>();
memcpy(pointer_to_data_start, pImage, bufframe.height * rowbytes);
cv::imshow("image", img);
cv::waitKey(30);
delete pImage;