LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

IMAQdx Acquisition - grabbing not fast enough

Solved!
Go to solution
Highlighted

Hello,

I'm triying to capture images as fast as possible.

The USB3 camera should allow 200 fps, NI MAX gives an attribute of 222 fps.

However trying to capture every single frame and saving it afterwards only reaches 140 up to 170 fps.

max_fps.pngI'm not sure what slows it down.

I create the time array to get to know the exact capture time.


Does anyone know how to accelerate it?

 

Thanks a lot

Stefan

0 Kudos
Message 1 of 17
(2,632 Views)

@stefan123 wrote:

Hello,

I'm triying to capture images as fast as possible.

Does anyone know how to accelerate it?

 


Yes (that is, I think I know how to accelerate it ...).  IMAQdx has a lot of "hidden abilities" that are described in the well-written Documentation largely "hidden" unless you dig through the Help, some Examples (I haven't looked at what is shipping now, but this was the case 4-5 years ago when I was faced with a similar problem), and a bit of "experimentation" to see how this really works.

 

The key is in the IMAQdx Driver.  Take a look at the IMAQdx Configure Acquisition function.  You used the Default values, One-Shot operation with a single Buffer.  This means that for each Frame, you need to (a) allocate an Image (buffer), (b) do the Grab (which transfers the data from within the Driver's Buffer to your Image, an Array Copy), then (c) build an Array of Images.  That's a lot of pixel-moving.

 

What we do is the following:

  • Configure the Camera for Continuous Imaging, and a lot of buffers (how many is a function of a number of factors, including the Frame Rate and how long you are recording).
  • Have a loop that, once a Frame, puts the Buffer Index on a Queue.  This takes essentially 0 time, so this loop should run as fast as the Camera, and should, itself, consume few cycles as it is basically "waiting" for the Camera to take the frame.  This is your first Producer loop.
  • Your Consumer loop gets the Buffer Index, goes to the Driver, and extracts the Image from it.  Depending on what you want to do with the Image (if you are just displaying it, which is fast, or want to spool it to disk, which can be slower), you can do the processing here or place the Image (a single Array of Pixels) on a second Queue (now you are functioning as a second Producer).  In our case, we write AVIs, so we put the individual Frames on such a second Queue.
  • If you need a second Consumer (such as to write the AVIs), that's yet another parallel loop.

You've now sub-divided your problem into multiple asynchronous loops, with data being buffered in Queues.  When you create the Queues (which you do before things start running), you can create them with a fixed size (so they won't "grow" during processing, saving some time), but you'll need to experiment to see what an appropriate size would be (there should be no worry for the Buffer Index Queue, as this allocation will be trivial).

 

This technique worked very well for us 5 years ago.  We weren't sampling at 200fps, but instead were sampling at 30fps from 24 cameras simultaneously (effectively 720fps).

 

I haven't revisited this code recently, but am about to "resurrect" it (and totally rewrite it for LabVIEW 2016), so there may be some details I've forgotten to mention (one that I'll have to re-learn is how the Camera Buffer Timing is done -- where's the "Clock" in the first loop, is it automatic?), but as I said, writing little routines that have only a few functions inside them and seeing how they perform Reveals All Most Stuff.

 

Bob Schor

Message 2 of 17
(2,600 Views)

Hello Bob,

thanks a lot for this very detailed description, thats a great help!

I tried to follow your advice, which now looks like this:

max_fps_queue.png

Now the Buffer has the main influence. If it's not continuous or if the buffer is < 3000, the captured fps value is around 169 fps all the time.

If it's > or = 3000 the captured fps starts very high like 5000 and decreases afterwords with like 100 fps/s.

Eventually it even goes beneath 0. The queue is not growing.

If I put a timing in the loops, like 5 ms, it starts working with 200 fps very well but suddenly it goes beneath 0 as well.

There is no change in Computer RAM usage.

 

What else could I do to make it stable?

Best regards

Stefan

0 Kudos
Message 3 of 17
(2,567 Views)

Building those array of images and timestamps for every element in the queue in the consumer loop is most likely the source of the slowdown.  And, there is really no reason to iterate that consumer loop for each image!  

 

That's right, instead of dequeue element and trying to keep up with the acquisition (hogging resources of the more important loops) throw a longish wait (like 1 second) and flush the queue adding the images and timestamps to a single array in batches of @200.  That should reduce the overhead of consumer loop by @16dB.  Unbundle the queue data in the post acquisition for loop.

0 Kudos
Message 4 of 17
(2,561 Views)

I cannot "run" (or otherwise test) your "picture".  Please, attach the code (*.vi) or, if you know how to make them, put a VI Snippet in your post (as these will transform into LabVIEW code when dropped into a Block Diagram).

 

Bob Schor

0 Kudos
Message 5 of 17
(2,557 Views)

Thanks to both of you,

 

"Building those array of images and timestamps for every element in the queue in the consumer loop is most likely the source of the slowdown"

I would like to name the saved image after the exact time of capturing, e.g. 08h_55m_23,566s.jpg

I tried building two queues instead of a cluser in one, doesn't make a difference.

How else could i ensure that?

 

"throw a longish wait (like 1 second) and flush the queue adding the images and timestamps to a single array in batches of @200"

I did that and that made me able to delete the shift registers. The effect is, that it works longer with 200 fps now, but after a minute or so it drops to 130 fps and less.

max_fps_queue_2.png

 

I attached the VI.

Best regards

Stefan

 

 

 

0 Kudos
Message 6 of 17
(2,542 Views)

In your last code you only throw the last images, you'll need the Delete image inside the consumer. (You also don't need the Array size to the delete loop)

/Y

G# - Award winning reference based OOP for LV, for free! ADDQ VIPM Now on GitHub
"Only dead fish swim downstream" - "My life for Kudos!" - "Dumb people repeat old mistakes - smart ones create new ones."
Certified-LabVIEW-Developer
Message 7 of 17
(2,528 Views)

Thanks, now the fps stays around 200 fps all the time.

When I create an Indicater for the Image references, which come out of a queue, it only gives me the references, e.g. "imange299".

How can I transform it to the visible image now? (Stupid question perhaps)

regards

0 Kudos
Message 8 of 17
(2,525 Views)

For this you need to use the "IMAQ Write File 2 VI". Here is a very good example:

 

http://forums.ni.com/t5/Example-Program-Drafts/IMAQdx-Grab-and-Save-Individual-Files/ta-p/3516946

0 Kudos
Message 9 of 17
(2,496 Views)

Hello again.

 

First, it was a configuration problem that I couldn't get the full 200 fps. There is an option in NI MAX to set it to fast mode.

 

2nd: Now I tried to make it a proper queued state machine, which caused me a lot of trouble and is of cource not perfectly done. So far I realized 2 modes, "auto jpg" which captures a number of pictures and works well. But "auto avi" is causing problems.

The "IMAQ Avi write frame" creates an error "not an image".

I don't understand, because in an seperate VI without queue the sequence would work.

Could anybody help me with that new problem?

Thanks a lot

Message 10 of 17
(2,482 Views)