Search code examples
c#pictureboxemgucvgrayscale16-bit

C# EmguCV PictureBox - How to display unsigned 16 bit grayscale images?


I have a monochrome camera in my project that I read images of at either 8bit/16bit depth. I'm using EmguCV library to create a Mat object out of byte array that I read off the camera and want to display the images on an EmguCV PictureBox control.

When I work in 8bit mode everything looks fine, but when I try to work in 16bit the picture box display turn black. If I save the mat object of the 16bit image to a file, the image looks good, so I'm not sure what the issue may be.

Here is the code I'm using:

//This function run on a separate thread and continuously acquires frames from the camera. 
private int CatureVideoWorker()
{
    while(captureImages) 
    {
    //buffer address is pinned using GCMarshal to variable called pinnedImgBuffer.
    buffer = readFrameFromCamera(); 
    //acquire exclusive lock so GUI thread won't access mat object while it's being written to.
    lock (syncRoot)      {
        lastFrame.Dispose();
        if (8bitMode == true)
            lastFrame = new Mat(_height, _width, Emgu.CV.CvEnum.DepthType.Cv8U, 1, pinnedImgBuffer.AddrOfPinnedObject(), _width);
        else  
            lastFrame = new Mat(_height, _width, Emgu.CV.CvEnum.DepthType.Cv16U, 1, pinnedImgBuffer.AddrOfPinnedObject(), _width * 2);
    }
    }
    return 1;
}

//Timer event that run on the main GUI thread ~33ms to load the lastFrame to the Emgu PictureBox.
private void tmrCaptureFrame_Tick(object sender, EventArgs e)
{
    //make sure to get exclusive lock so the mat object won't get written/disposed while 
    //cloning it to the picture box. 
    lock (syncRoot)
    {
        pbx.Image = lastFrame.Clone();
    }
}

As mentioned, when in 8bit mode, the picture box show a live view from the camera but when switching to 16bit the picture box is all black.

Saving the Mat object to a file in either 8bit/16bit mode works fine and the16bit image looks good when opening the file in msPaint, so not sure what the issue with the picture box.


Solution

  • Few software can display 16 bit images well. Most seem to just take the upper 8 bits, and this only works well if the max value in the image is ushort.MaxValue. If you are saving a 16bit image to a file and it looks good in msPaint, I would double check that it is actually an 16-bit image. Many pieces of software tend to silently convert high dynamic range images to 8-bits. You need to be careful to ensure all components in a processing chain can handle 16-bit images.

    In any case, 16 bit images need to be converted to 8 bits to be displayed. A fairly simple way to do this is to do a linear scaling between the min and max values. EmguCV has this in the normalize function

    normalize(src, dst, NORM_MINMAX, 0, 255)

    More advanced method would be to scale between say the 0.01 and 0.99 percentile pixel values. Or to do some limited form of historgram equalization.