I’m trying out the new 3rd Generation Acquisition stack for the first time in C# .Net. So far I’ve been able discover and open the camera, and stream images from it. What I’d like to be able to do, is acquire a number of frames, then be able to replay them in a display, or display a specific frame. Previously I would have done this by accessing the RingBuffer. I understand that now I should be using FlowSetPools. My understanding of FlowSetPools is as such:
- A Stream has a FlowSetPool.
- The FlowSetPool has a list of Flow Sets.
- Each FlowSet has a list of Flows.
- Each flow is basically a buffer for an image.
My issue is that I don’t see any way to access the information in the FlowSetPool. I can assign it a number of buffers using the RegisterManagedFlowSetPool method, but the stream itself doesn’t have a FlowSetPool property. How do I retrieve the images I have stored in memory?
Edit: I should mention I’m using 13.04 and a regular image stream.
The idea behind the flow sets and the flow set pools is slightly different from what you seem to expect. Flow sets and flow set pools are a mechanism to provide buffer space to the driver - nothing else. The driver then acquires the pixel data (and potentially additional information like chunk data) into these buffers, but the images (which consist of the pixel data plus a description of the properties of the image) and handed back to the user as the result of the
Stream::WaitFor calls. It will not easily be possible to make sense of the data in the flow sets directly.
Thanks for the response. So, if I want to index through my buffered images, everytime I receive an image via the WaitFor method, I should add them to a list or similar collection? That’s fine, I just want to confirm I’m not duplicating memory.
Edit: Additionally, will the images be automatically disposed by the Garbage Collector when there are no more references to them, or will I have to manullly dispose them? In a similar vein, when is an image locked or unlocked in this new system? There doesn’t seem to be an option for enabling the lock mode.
One thing you should be aware of is that with the Gen. 3 acquisition stack we are basically operating as we did with the Lock mode on on the Gen. 2 acquisition stack’s
IRingBuffer interface. There is no switchable lock mode any more - and it is not needed!
- If I receive an image as a result of a
WaitFor call, then the buffer (part of the flow set pool) in which that image was stored will remain locked (i. e. unavailable for the next incoming images) as long as that image continues to live.
- To make these buffers available to the acquisition engine again it’ll therefore be necessary to make sure the image ceases to exist as soon as it is no longer needed (in C# this happens e. g. if the
using scope ends, likewise for Python and the
with statemen and C++ and the scoped smart or unique pointer).
Note: I would strongly advise against relying on any garbage collector to do this properly! The garbage collector at best only has a vague idea of how much memory is associated with an image handle and without that knowledge it is prone to misjudging how urgent the cleanup of an image really is. You are much better off doing this deterministically - either with the
using keyword or by calling the
.Dispose() method (I am assuming you are using C#…).
- Implicitly this means: If you want to “keep” images in a sequence that you acquired all you need to do is not yield the memory back to the acquisition engine (e. g. by storing their handle in a collection) as you said. And duplication of memory is not needed for this (luckily…).
Great thanks for this info. That’s all fairly straight forward then, especially with regards to the locking. I think that’s all the questions I have for now!
Sorry, one last question if you don’t mind!
When I deregister the flow set pool, what happens to the images that have pixel data in that pool. Are they automatically disposed, or do they becomes corrupted?
Regardless, I imagine the most sensible way to change buffer size would be to do the following:
- Manually dispose all the images in my collection.
- Remove all the elements of the collection.
- Deregister the flow set pool.
- Register a new flow set pool of a different size.
- Continue adding images as before.
This process seems like it’d avoid memory issues, although I do have some concerns over speed. Previously, assigning memory for the RingBuffer was pretty slow, so I assume that registering a flow set pool also takes a fair amount of time. If I were to go from a FlowSetPool size of 100 to a FlowSetPool size of 50, is there a more performant way to do that than the method posted prior?
Stick to the process you outline. If I recall correctly, deregistering shouldn’t even be possible while there are images around that rely on the memory that has been registered. And if Deregistering is not blocked then this is a guaranteed way of generating undefined behavior (a.k.a. random crashes).
Performance should not be as much of an issue as it used to be with the
IRingBuffer interface because all that happens is that a list of pointers to buffers gets stored - after all the allocation has already been done by you, whereas
IRingBuffer always used to do the allocation for you. And: At the end of the day the safe method is the preferable one anyway…