LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

How to display images directly to canvas controls.

I am trying to display image 1024x768x16 to a canvas, from a buffer read from our camera driver.
 
1) I think the "bits" parameter is my first problem, I couldn't find a real example on how to setup this param
 
2) how do I transfer the image from an unsigned short g_buffer[1024][768] into the bitmapID?
 
void displayImage(void)
{
    int bitmapID, bytesPerRow=2*1024, pixelDepth=16, width=102;
    int height=768, retVal;
    Rect sourceRect, destRect;
    unsigned char bits[16387], mask[128];
    int i,x,y;
   
    for (i=0; i<16387; ++i) bits[i]=i;
   
    retVal = NewBitmap( bytesPerRow, pixelDepth, width, height, NULL,
        bits, NULL, &bitmapID );
       
    // store graph to bitmap
    //@@@ TO DO...
    retVal = CanvasStartBatchDraw (g_panelHandle, PANEL_IMAGE, );
    for (y=0; y<768; ++y)
        for (x=0; x<1024; ++x)
        {
            //@@@ g_buffer[x][y]
        }
    retVal = CanvasEndBatchDraw (g_panelHandle, PANEL_IMAGE);
    //@@@ TO DO...
   
    // display image
    destRect.width  = VAL_KEEP_SAME_SIZE;
    destRect.height = VAL_KEEP_SAME_SIZE;
    retVal = CanvasDrawBitmap( g_panelHandle, PANEL_IMAGE, bitmapID,
        VAL_ENTIRE_OBJECT, destRect );
    retVal = RefreshGraph( g_panelHandle, PANEL_IMAGE );
}
 
0 Kudos
Message 1 of 9
(4,954 Views)
Hello,
 
I totally agree that there are no real good examples of how to create a bitmap.
Something I need to know to help you out: the  unsigned short g_buffer[1024][768] you mentioned, what does it represent? I suppose it is a table of pixel values for a bitmap containing 1024 columns and 768 lines. But what does each pixel value (unsigned short) stand for? Is it just a grey value or are there colors in it?
 
In your example, the parameter is pixelDepthis set to 16. This is not a valid value for the NewBitmap function (check the help file). You can only use the values 1, 4, 8, 24, and 32.  I suppose you choose 16 because of the short int type...
 
Wim 
0 Kudos
Message 2 of 9
(4,944 Views)

The unsigned short g_buffer[1024][76] represents the image coming from the camera.  The 16-bit (unsigned short) represents color per pixel.

Yes, I figured out yesterday that was the error in my NewBitmap() function.  The Function Panel for NewBitmap indicated() the valid values as you stated.  Yes I chose 16 due to my requirements.  It seems like NewBitmap() will not work for my application?

I have since modified the code to use CanvasDrawPoint() and traversed each of the 786,432 points...  As you can tell, it is dog slow, and won't work under 15-30Hz rate.

void displayImage(void)
{
    int bitmapID, bytesPerRow, pixelDepth=32;
    int width=1024, height=768, retVal, byteSize;
    Rect destRect;
    unsigned char *bits=0, mask[128];
    int i,x,y;
   
    // setup bit mapping
    bytesPerRow=width*pixelDepth/8;
    byteSize = width*height*pixelDepth/8;
    bits = malloc(byteSize);
    memset( bits, 0, byteSize );
   
    // create new bitmap buffer
    retVal = NewBitmap( bytesPerRow, pixelDepth, width, height, NULL,
        bits, bits, &bitmapID );
       
    // store graph to bitmap
    //@@@ TO DO...
    retVal = CanvasStartBatchDraw (g_panelHandle, PANEL_CANVAS );
    for (y=0; y<768; ++y)
        for (x=0; x<1024; ++x)
        {
            SetCtrlAttribute (g_panelHandle, PANEL_CANVAS,
                ATTR_PEN_FILL_COLOR, g_image[x][y] );
            SetCtrlAttribute (g_panelHandle, PANEL_CANVAS,
                ATTR_PEN_WIDTH, 1 );
            CanvasDrawPoint (g_panelHandle, PANEL_CANVAS,
                MakePoint (x,y));
        }
    retVal = CanvasEndBatchDraw (g_panelHandle, PANEL_CANVAS);
    //@@@ TO DO...
   
    // display image
    destRect.width  = VAL_KEEP_SAME_SIZE;
    destRect.height = VAL_KEEP_SAME_SIZE;
    destRect.top    = VAL_KEEP_SAME_SIZE;
    destRect.left   = VAL_KEEP_SAME_SIZE;
    retVal = CanvasDrawBitmap( g_panelHandle, PANEL_CANVAS, bitmapID,
        VAL_ENTIRE_OBJECT, destRect );
    ProcessSystemEvents();
} // end displayImage

0 Kudos
Message 3 of 9
(4,930 Views)
How is the color represented by only 16 bits? Don't you need at least 24 bits, 1 byte for red, 1 byte for green and another byte for blue? Or is the 16 bit value an index to some color table?
0 Kudos
Message 4 of 9
(4,921 Views)

Its a color camera output.  I can't answer why its not 24+ bits.  Its just the spec for the camera that I got.  I needed this application to see what it is displaying.

0 Kudos
Message 5 of 9
(4,919 Views)
I'm afraid I can't tell you then which values to put in the bits array... Smiley Sad If you want to use the data returned by your camera, you should know what the returned data represents...
0 Kudos
Message 6 of 9
(4,915 Views)
Okay.  Thanks for trying.  At least I can focus my efforts on that. 
 
And it seems that if that doesn't work, I cannot use bitmaps and canvas for my application.  I can look at other applications to display my images.
0 Kudos
Message 7 of 9
(4,913 Views)
Actually, there's no reason why you still couldn't create a bitmap to display on a canvas. It takes a litte bit of work to convert the 16-bit data to 24-bit, but it's something that you can do in a single pass, as long as you know how the 16-bit per-pixel data you get back from the camera is encoding the RGB values. The most common way to store 16-bit pixel data is the following:

       URRRRRGG GGGBBBBB

where U is an unused bit (the highest-order bit in the 16-bit word) and the other letter represent the bits allocated to R, G, and B, respectively.

I mocked up some code (that assumes the represetantion above) which you can try yourself:

    bitmapDepth = 24;
    cameraDepth = 16;
    cameraData = malloc (1024 * 768 * cameraDepth / 8);
    bitmapData = malloc (1024 * 768 * bitmapDepth / 8);

    for (i = 0; i < 768; i++)
        for (j = 0; j < 1024; j++)
        {
            destPixelIndex = (i * 1024 + j) * bitmapDepth / 8;
            srcPixelIndex = (i * 1024 + j) * cameraDepth / 8;
           
            srcRedValue = (cameraData[srcPixelIndex] & 0x7C) >> 2;
            srcGreenValue = ((cameraData[srcPixelIndex] & 0x03) << 3) |
                ((cameraData[srcPixelIndex+1] & 0xE0) >> 5);
            srcBlueValue = cameraData[srcPixelIndex+1] & 0x1F;
           
            bitmapData[destPixelIndex] = 8 * srcRedValue;
            bitmapData[destPixelIndex+1] = 8 * srcGreenValue;
            bitmapData[destPixelIndex+2] = 8 * srcBlueValue;
        }

    NewBitmap (-1, bitmapDepth, 1024, 768, NULL, bitmapData, NULL, &bitmap);
    CanvasDrawBitmap (panel, canvas, bitmap, VAL_ENTIRE_OBJECT,
        MakeRect (0, 0, VAL_KEEP_SAME_SIZE, VAL_KEEP_SAME_SIZE));
    DiscardBitmap (bitmap);
   
    free (bitmapData);
    free (cameraData);


The idea is to first extract the red, green and blue values from the original array (here designated as 'cameraData') and then store those values in each of the bytes of the new array. In the process, we need to also scale those values by a factor of 8, which represents the difference between a 5-bit quantity (0-31) and an 8-bit quantity (0-255).

Notice also that I'm not using the batch drawing for the canvas. This is only useful when you draw repeatedly into the same canvas. But here I'm only drawing once. You also don't need to (actually, can't) use the RefreshGraph function. That's only used for graph controls for something completely different. And finally, the VAL_KEEP_SAME_SIZE macros should only be used for the width and height of the destination rect. The top and left should be 0.

Hope this helps. Let me know if you have any questions.

Luis



Message 8 of 9
(4,898 Views)
Perfect!  That works great!  Thank you!
0 Kudos
Message 9 of 9
(4,877 Views)