Machine Vision

cancel
Showing results for 
Search instead for 
Did you mean: 

How do I set CWIMAQImage from a bmp fast?

Hello,


I'm using a 3rd party camera and driver and it gives me each frame as a new bitmap (bmp) image.  I need to get this bitmap into the CWIMAQImage format to display it in the viewer.

 

I'm having trouble making it go fast enough.  The simplest (and fastest) code I've found so far is:

 

System.Windows.Forms.Clipboard.SetImage(bmp);

axCWIMAQVision1.ReadImageFromClipboard(axCWIMAQViewer1.Image, ref HasImg, axCWIMAQViewer1.Palette); 

 

The first line takes 74ms and the second takes 36ms.  Since I'm running at 30 frames per second, I need it to be much faster.

 

Is there a workaround, perhaps with unsafe code? Can a method be added to the new VDM 2009 native .NET to attach a viewer directly to a bmp or other standard image format?

 

Thanks in advance for any help you can offer!

Neville 

0 Kudos
Message 1 of 6
(4,568 Views)

Do not use Clipboard for transferring images from bitmap to the IMAQ Image. First, its slow, and second - if someone else will put another image into clipboard, you will be surprised (try to press PrintScreen).

 

You should transfer your image directly to IMAQImage (with ArrayToImage function, for example). Somewhere on msdn.com you will found, how windows bitmap organized in memory (unfortunately I'm not expert in this area). All what you need is pointer to the memory area where pixels located.

 

Andrey.

Message 2 of 6
(4,561 Views)

Hello Andrey,


Thanks for your help.  You make some excellent points and I agree with you that I should use a faster and more robust method.

 

I tried for 5 hours yesterday to convert the bmp to a byte array and then use the ArrayToImage function to read it in, but I could not do it.  I'm not very good with unsafe code, but I realize it's probably necessary until there is native support in VDM for reading in non-NI images.

 

If you (or anyone) would be so kind as to send me a C# snippet that converts a bmp to a byte array and reads it in via the ArrayToImage function, it would be *much* appreciated, as I'm totally stuck.  I'm using a black and white camera that uses the 'Y800' format, which is an 8-bit gray image format going from the top down.  See:

http://74.125.155.132/search?q=cache:AgSnvSkUKX4J:www.fourcc.org/yuv.php+y800&cd=1&hl=en&ct=clnk&gl=...

 

 

Once the camera gets the image it has a function that outputs the data as a .NET Bitmap object, which I can manipulate or save to disk, etc.  I just need a way to get it from the bmp to a byte array and then have ArrayToImage read it in without complaining. A sample image that is ready for conversion to a byte array is attached.  My sample code (which doesn't work properly) is below.

 

 

Thanks,

Neville 

 

-----------------------

NOTE: THIS CODE DOES NOT WORK PROPERLY

 

//Bitmap bmp = camControl1.ImageBuffers[e.bufferIndex].Bitmap;  // Returns the active Image Buffer as a Bitmap object

 

// This section usese the Image Buffer directly (without first going to a Bitmap) 

TIS.Imaging.ImageBuffer CurrentBuffer = default(TIS.Imaging.ImageBuffer);

int x = 0;

int y = 0;

int BytesPerLine = 0;

byte[] img_buff = null;

 

TIS.Imaging.ImageBuffer CurrentBuffer = camControl1.ImageBuffers[e.bufferIndex];

 

BytesPerLine = CurrentBuffer.BitsPerPixel / 8 * CurrentBuffer.PixelPerLine;

int img_size = CurrentBuffer.Lines * BytesPerLine;

 

img_buff = new byte[img_size];

 

// Calculate the count of bytes ber line using the color format and the pixels per line of the image buffer.

BytesPerLine = CurrentBuffer.BitsPerPixel / 8 * CurrentBuffer.PixelPerLine - 1;

for (y = 0; y <= CurrentBuffer.Lines - 1; y++)

{

for (x = 0; x <= BytesPerLine; x++)

{

img_buff[(CurrentBuffer.Lines - 1 - y) * BytesPerLine + x] = CurrentBuffer[x, y];

}

}

 

MainBufferImage.Type = NationalInstruments.CWIMAQControls.CWIMAQImageTypes.cwimaqImageTypeU8;

MainBufferImage.ArrayToImage(img_buff); 

 

 

Also, there is this method: (I don't know why it says the images are stored bottum up when my format Y800 says it is stored top down - one of the pieces of documentation must be incorrect)

ImageBuffer.GetImageData Method

Returns a pointer to the image data.
Syntax: 
[C#]
unsafe public byte* GetImageData();
Remarks: 

This method is declared unsafe, and therefore not accessible from VB.NET.

Please note that the images are stored bottom up, therefore the byte at the address returned by this method is the first byte of the first pixel of the last line of the image.

See also: ImageBuffer, ImageBuffer.Lines, ImageBuffer.PixelPerLine, ImageBuffer.BitsPerPixel

<< ImageAvailableEventArgs.ImageBuffer 

0 Kudos
Message 3 of 6
(4,559 Views)

Hello,

 

Well, I finally figured out how to do what I need to do.  The total time is now 30-50ms instead of 110ms.  With Viewer.NonTearingDisplay = false, the time is about 12ms.

 

The code is below for anyone who is interested.

 

All (~98%) of the time is spent in the ArrayToImage function.  I'll start a separate post to see what can be done in future releases to speed it up.

 

Thanks,
Neville 

 

-------------------

TIS.Imaging.ImageBuffer CurrentBuffer = null;

int ImageSize = 0;

byte[] ImageBuffer1D = null;

byte[,] ImageBuffer2D = null; 

 

//---------------------------------------------------------------

private void camControl1_ImageAvailable(object sender, TIS.Imaging.ICImagingControl.ImageAvailableEventArgs e)

{

try

{

CurrentBuffer = camControl1.ImageBuffers[e.bufferIndex];

 

unsafe

{

IntPtr ptrToFrameData = (IntPtr)CurrentBuffer.GetImageData();

System.Runtime.InteropServices.Marshal.Copy(ptrToFrameData, ImageBuffer1D, 0, ImageSize);

}

 

Buffer.BlockCopy(ImageBuffer1D, 0, ImageBuffer2D, 0, ImageBuffer1D.Length * sizeof(byte));

MainBufferImage.ArrayToImage(ImageBuffer2D);

}

catch (Exception ex)

{

Console.WriteLine(ex.Message);

}

}

 

//---------------------------------------------------------------

private void CalcParams(TIS.Imaging.ImageBuffer curBuf)

{

int BytesPerLine = curBuf.BitsPerPixel / 8 * curBuf.PixelPerLine;

 

ImageSize = curBuf.Lines * BytesPerLine;

ImageBuffer1D = new byte[ImageSize];

ImageBuffer2D = new byte[curBuf.Lines, BytesPerLine];

0 Kudos
Message 4 of 6
(4,549 Views)

I know it is painful. In my humble opinion with a limited experience as I think of myself this method will result a memory leak by time since unmanaged code doesn't give the CLR garbage collection the freedom of memory management.

 

The good news is starting from Vision Acquision 2009 which will be realeased with VDM 2009, DirectShow will be supported for .NET which means we will be able to stream our images directly from any camera that supports DirectShow (e.g. USB cameras).

 

Does it give you a hope  :smileywink:

 

NI Vision Team paid attention lately to the fast growing developers with VDM and .NET. So cheerup, this is going to be tackled soon.

 

Have a lovely.

Waleed El-Badry MSc.,MCPD, ISTQB Certified Tester
Assistant Lecturer
Mechatronics Department
Faculty of Engineering
Misr University for Science & Technology



View Waleed El-Badry's profile on LinkedIn

Message 5 of 6
(4,532 Views)

Hello Waleed,

 

That is great news!  Hopefully VDM 2009 is released soon.


Neville 

0 Kudos
Message 6 of 6
(4,511 Views)