LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

Issues using IMAQdx Get Image Data.vi, with 8-bit, 12-bit and packed 12-bit pixel formats

Hi!

 

I'm using a Basler acA1920-155um USB camera with LabVIEW.

 

Some potentially useful resources, in case they're useful:

Programmer's manual: http://mlab.no/blog/wp-content/uploads/2009/06/basler_pylon_prog_guide_and_api_ref.pdf

User's manual: https://graftek.biz/system/files/2576/original/Basler_Ace_USB_3.0_Manual.pdf?1479057814

 

 

This monochrome camera has the option of supplying images in a "Mono 8", "Mono 12", or "Mono 12p" format, meaning 8-bit, 12-bit, or 12-bit packed. I think when using Mono 12, the camera should return a 16-bit number for each pixel (with four zeros as the most significant bits), and when using Mono 12p, the camera should return a 12-bit number for each pixel, though I have to check more carefully.

 

 

So far I've had good success using Mono 8, using the VI "IMAQdx Get Image Data.vi" to grab the image data for each frame. However, this VI returns the image data array as an 8-bit U8 array, which is causing some unusual images if I set the camera to Mono 12 or Mono 12p.

 

Furthermore: When using Mono 12, IMAQdx Get Image Data.vi returns an image array with length 2x longer than with Mono 8. Similarly, when using Mono 12p, IMAQdx Get Image Data.vi returns an image array with length 1.5x longer than with Mono 8. Everything works properly when testing the camera with NI MAX, but it misbehaves when I use my own code with Mono 12 and Mono 12p.

 

IMAQdx set camera pixel format.PNG

 

 

IMAQdx Get Image Data.PNG

 

 

I have some suspicions for what's going wrong, and some potential hacks to fix it, but I want to ask: Do you have some recommendations for how I might be able to properly acquire camera image data with the Mono 12 and Mono 12p pixel formats?

 

 

 

Thanks in advance!

0 Kudos
Message 1 of 11
(4,952 Views)

A quick update: I've been able to post-process and correct the U8 image array data, with some partial success (some bugs remain though). The problem is that this unnecessarily slows down the camera frame acquisition. For high frame rate and many pixels per frame, this performance reduction is unacceptable.

 

A more rigorous solution (that's less of a hack) would be greatly appreciated!

0 Kudos
Message 2 of 11
(4,882 Views)

What image format are you using when creating the IMAQ image? Typically that has to match with what you later try to copy into the image,

so try to select a i16 or whatever it is called format when creating the IMAQ reference.

 

I just see that you do direct grab into a memory buffer not an IMAQ reference. In that case the Unflatten from String function might work a lot better than what you can do. Run the byte array through a Byte Array to String function and then to a Unflatten from String. Connect an empty I16 byte array constant to the input, a false to the “contains length” input. Now you can play with the Endian input. It either needs to be big endian or little endian. Also depending on the data format of the camera it may work better with an u16 array constant.

This definitely won’t work for packed formats. There you need to do the unpacking somehow and there are way to many possible variables to expect IMAQ to provide ready made functions that would support them all.

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 3 of 11
(4,868 Views)

Thanks for your suggestions - here are some updates:

 

1. I made a version of IMAQdx Get Image Data.vi, which passes an empty U16 array to the DLL call and outputs a U16 array (instead of U8 for both, as in the screenshots above). I also pass it a U16 IMAQ image object to "IMAQdx Grab2.vi" instead of a U8 IMAQ image object. It seems to work slightly better, though there are still some issues:

 

- It still returns an array that's still 2x longer than it should be (4608000 pixels instead of 2304000).

- What used to be a ~100 pixel brightness with Mono 8 is now a ~1600 pixel brightness with Mono 12, which is good.

- For some reason, elements 2304000 to 2326519 are all zeros, and many array elements beyond 2326519 are greater than 4095 (what should be the maximum for 12-bit data). The actual array should have an index from 0 to 2303999, so I'm not sure what this indicates. 

- This test also crashes quite often, so it's difficult to troubleshoot.

 

 

2. In case it's useful, I figured out more details for how the Mono 12p spreads the data for two pixels across three bytes:

 

First byte: eight most-significant-bits for Pixel 0

Second byte: four least-significant-bits for Pixel 0, and four most-significant-bits for Pixel 1

Third byte: eight least-significant-bits for Pixel 1

...

 

3. My main goal is to use the Mono 12p output. This is because the Mono 12 version has a slower frame rate than Mono 12. I'm also testing to see if Mono 12 will work though, since it's a bit more intuitive.

 

4. I tried your suggestion for using Unflatten From String, but unfortunately I can't make it work. Can you add a screenshot of what this should look like?

 

5. Is there another method I can use besides IMAQdx Get Image Data.vi that can give me the pixel data? 

 

 

Thanks again!

0 Kudos
Message 4 of 11
(4,827 Views)

@pmk01 wrote:

Thanks for your suggestions - here are some updates:

 

1. I made a version of IMAQdx Get Image Data.vi, which passes an empty U16 array to the DLL call and outputs a U16 array (instead of U8 for both, as in the screenshots above). I also pass it a U16 IMAQ image object to "IMAQdx Grab2.vi" instead of a U8 IMAQ image object. It seems to work slightly better, though there are still some issues:


You can't do that! The function in the DLL does not magically know that you have wired a I16 array to the terminal. So it goes and allocates a byte array with the necessary size (width + padding) * (height ) * 2 (for the I16 values). Then it fills in the data and in the 32-bit length value for the handle this number. Now this array is returned to LabVIEW and you told it that it is an I16 array. So LabVIEW interpretes the length parameter as the number of I16 values and Booooom, it accesses a memory buffer that is double as large as it really is. No surprise you see strange values after the half of your buffer, those values were not only never initialized by the function, but don't belong to the actual array (and image) but are instead just some other data in memory (and can even reach into address space that is not currently mapped to your process, which is what causes the crashes).

 

And no you can't place a Resize Array after the function call to resize it to the real number of elements. Resize array MAY simply update the length value but it MAY just as well decide to resize the handle for real and Booom again as the memory manager is told to resize that handle that doesn't really have the number of bytes it assumes to have.

 

Even updating the 32-bit length value through direct memory access (for instance calling MoveBlock function) wouldn't be safe as there is a small time window between when the Call Library Node for your function returns to when you call the Call Library Node for the MoveBlock call to correct the length value, where the array contains inconsistent data and might crash under some conditions (for instance if someone debugs the code and places a probe on that wire).

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 5 of 11
(4,813 Views)

Thanks for the info - that makes sense. I assumed this would work from looking at the back panel of IMAQdx Get Image Data.vi

 

IMAQdx Get Image Data.PNG

 

pmk01_0-1597165161250.png

 

 

Can you tell me what DLL call I should use instead to do this properly?

 

 

Thanks again!

0 Kudos
Message 6 of 11
(4,786 Views)

You know what the first three letters of "assume" are. That's where it bites you! 🙂

 


@pmk01 wrote:

 

Can you tell me what DLL call I should use instead to do this properly?


No I can't. Most likely this function does not exist in the DLL. The problem about data types and C programming is that one needs to write one function for every datatype. And most of each function is the same with a few minor differences. Not something that gets done just because it is fun.

 

Every graphic library written in C has to fight with this unless you use variant data types, but they have other problems such as being less easy to handle and you loose some performance as you have to check all kinds of things every time you want to access the data in the variant.

Rolf Kalbermatter  My Blog
DEMO, Electronic and Mechanical Support department, room 36.LB00.390
0 Kudos
Message 7 of 11
(4,775 Views)

You should have started by looking at the manufacturer's website to see if there are any drivers or software downloads that would help you. After some quick Googling, I discovered a software suite called pylon which includes an SDK and some examples to get you started...

 

https://www.baslerweb.com/en/products/software/basler-pylon-camera-software-suite/

 

update: after installing that software, the DLLs are registered and can immediately be used in LabVIEW.

FireFist-Redhawk_0-1597174571848.png

 

Redhawk
Test Engineer at Moog Inc.

Saying "Thanks that fixed it" or "Thanks that answers my question" and not giving a Kudo or Marked Solution, is like telling your waiter they did a great job and not leaving a tip. Please, tip your waiters.

0 Kudos
Message 8 of 11
(4,760 Views)

Thanks for the suggestion!

 

I have Pylon installed, and I can do some primitive things with .NET Property Nodes and Invoke Nodes.

 

The problem is: I'm not sure if using DLL calls is compatible with the other IMAQdx code I'm currently using. In NI-MAX I have the option of selecting one of two drivers for the camera:

 

1. Basler ace USB3 Vision Camera (works with Pylon SDK)

2. NI-IMAQdx USB3 Vision Device (works with IMAQdx)

 

It seems like I can only use one or the other. Unfortunately if I'm forced to use the Pylon DLL calls, that means I have to rewrite and troubleshoot everything else (camera initialize, getters & setters, and so on). A solution using IMAQdx would be preferable.

 

 

Let me know what you think!

0 Kudos
Message 9 of 11
(4,667 Views)

I ran into the same kind of thing a while back. Still running into it actually, just the project has taken a low priority lately. In my situation I was using a Dino-Lite camera and doing edge detection. The only things I do with my associated .NET property nodes is initialize, get frames, and close. All of the image processing and edge detection is still done using IMAQdx.

Redhawk
Test Engineer at Moog Inc.

Saying "Thanks that fixed it" or "Thanks that answers my question" and not giving a Kudo or Marked Solution, is like telling your waiter they did a great job and not leaving a tip. Please, tip your waiters.

0 Kudos
Message 10 of 11
(4,661 Views)