Difference between Cvb.SharedImg and Cvb.Image.IMG

The way you handle your application looks correct to me. If you dispose the driver IImageVPA you unload the driver, release the camera and free the driver’s ring buffer memory (if nobody else is sharing the ownership :wink:). If you want to acquire again within your app, it would be faster to not unload the driver. As otherwise you would need to reload everything again from scratch.

IRingBuffer for Task-based Processing
Also as @illusive hinted, you can get rid of the costly duplication step. In :cvb: we use the IRingBuffer interface for your use case. This is the companion interface to IGrab2, which you probably used to acquire the images.

For this use case you probably need to increase the number of driver buffers via the driver’s ini-file or programmatically via the RBNumBuffer function with RINGBUFFER_NUMBUFFER_CMD_SET as Action. This will create a new driver IImageVPA with the desired number of buffers if successful. The old IImageVPA object stays intact until you release it. Only all driver interfaces were moved to the new handle. This enables you to e.g. finish processing while switching to a different mode in your app.

After you have your desired number of buffers, you can set the lock mode to RINGBUFFER_LOCKMODE_ON via the RBLockMode function. This is a manual mode in which the acquisition engine only locks the buffers to write-protect it for the engine. You as the user must unlock the buffer via RBUnlock when you don’t need it anymore. Otherwise no buffers are available anymore after the ring buffer is filled and no new images can be acquired.

With RBBufSeq(m_Camera, 0, bufferIndex) you get the buffer index of the last awaited buffer (G2Wait). With RBGetBufferImage and this index you get a view (no copy) on that buffer as a :cvb: image. For more information about RBBufSeq see this post.

Instead of your copy, you can give that ringbuffer image to your processing task(s). After processing is finished you can unlock it (but note, that RBUnlock works on the driver image m_Camera). Whether you release the ringbuffer image every time or cache these and free them after the acquisition is finished is up to you. The ringbuffer images stay valid until released. And as long as you don’t change the number of buffers or their size (IImageRect}), they stay connected to the acquisition engine.

I normally bind together the ringbuffer image, the driver image, the buffer index (the last two for unlocking) and my own ref count initialized to the number of tasks running on the image. Every task decreases the count by one when finished and then unlocks (and maybe releases) the ringbuffer image if that count reaches zero. A Parallel.For for example wouldn’t need the ref count as you have a sync point after the loop finished.

Again a longer post… This is a bit more complicated programming wise, but yields better performance in the short (no copy) and long run (less memory fragmentation). And yes, this scenario including ReleaseObject on the ringbuffer images is thread safe (as long as the driver image stays alive). I hope that helps.

2 Likes