# Async Saving of Images

**URL:** <https://forum.commonvisionblox.com/t/async-saving-of-images/573>\
**Category:** Programming Questions\
**Created:** [October 22, 2018, 11:23am UTC](https://forum.commonvisionblox.com/t/async-saving-of-images/573 "2018-10-22T11:23:12Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![johmarjac](https://avatars.discourse-cdn.com/v4/letter/j/9fc348/32.png) [@johmarjac](https://forum.commonvisionblox.com/u/johmarjac)\
**Post date:** [October 22, 2018, 11:23am UTC](https://forum.commonvisionblox.com/t/async-saving-of-images/573/1 "2018-10-22T11:23:12Z")

</div>

Hi,

I am currently using CVB 13.06 with the .NET WPF Bindings. My application connects to a TwinCat2 Ads Server and listens for a trigger. Once Trigger is received, 2 images should be captured and saved to disk ASAP.

I ´ve created a DeviceDependency class inheriting from DependencyObject. In there is a DependencyProperty for the Device just like in the samples you provide.

In my ViewModel I create an instance of that DeviceDependency class in the constructor and the Display on my View binds to the DeviceImage of that Device in the DeviceDependency-object.

Now what is great is, there are functions like GetSnapshotAsync(), but unfortunately, my trigger event gets fired from another thread so I have to actually invoke it on ViewModel thread right? That’s why I am currently holding an instance of my Window in my ViewModel which is, not MVVM friendly. So in my trigger I actually call Window.Dispatcher.InvokeAsync and do all my capturing and saving in there. However, the whole window freezes whenever a trigger occurs and unfreezes when saving is done. I am not sure whether it is the Saving, or the Capturing that blocks the GUI (at the time of writing this). For saving images there are no async methods unfortunately, do you have a work around for that? Like, is it safe to await a Task.Factory.StartNew() Task in which I call the Save method? Will that even work? How would you achieve that properly?

Thanks in advance

---

<div class="post-metadata">

**Author:** ![parsd](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/parsd/32/7_2.png) [@parsd](https://forum.commonvisionblox.com/u/parsd)\
**Post date:** [October 22, 2018, 8:05pm UTC](https://forum.commonvisionblox.com/t/async-saving-of-images/573/2 "2018-10-22T20:05:28Z")

</div>

I think the answer is easier shown with a project: [AcqSave.zip](https://forum.commonvisionblox.com/uploads/commonvisionblox/original/1X/0b6930603c92f574c5279fbbe4b771e9264f2611.zip) (11.9 KB). The _Stemmer.Cvb_ and _Stemmer.Cvb.Wpf_ assemblies need to be installed also (see the [downloads](https://forum.commonvisionblox.com/t/common-vision-blox-add-ons/570)). The app expects the camera to be in software trigger mode. If it is not it will save a lot of images 🙂.

In the project I implemented the _ISoftwareTrigger_ via a `Button`. The `MainWindow` also shows a live image. The `MainViewModel` provides the live `Image` and commands for triggering and app-closing. The whole program logic is in the `TriggerSaver` model class.

The `MainWindow` creates the `MainViewModel` which in turn creates the `TriggerSaver` which opens the first GenICam device it finds. Then the app is run async via WPF’s `Dispatcher`. Thus the main logic runs on the UI thread. That is not a bad thing as all the code is written async. The `Image.Save` is executed via .Net’s task pool (`Task.Run`).

The :cvb: `Device` is encapsulated in the model class `TriggerSaver`. Only the live `Image` is publicly available plus the use cases of running the app and sending (double) software triggers. Depending on the camera used you probably want to modify the `TriggerSaver.SendSoftwareTrigger` method.

The app logic is written in a way that we wait for two images and save them as soon as they arrive. We utilize :cvb:'s _IRingBuffer_ interface to keep the acquisition code simple without loosing images. We use `RingBufferLockMode.On` and manually unlock acquired `Image`s via the `using`-block in `SaveAndUnlockImageAsync`. Depending on your acquisition rate and hard disk/ssd used you might need to increase the buffer count on the ring buffer to handle processing peaks (see `TriggerSaver.SetupDevice`).

Here is the core logic:

```auto
public async Task RunAsync(CancellationToken cancellationToken)
{
  var stream = _device.Stream;
  stream.RingBuffer.LockMode = RingBufferLockMode.On;

  stream.Start();
      
  try
  {
    long counter = 0;
    while (!cancellationToken.IsCancellationRequested)
    {
      try
      {
        var savesFinished = new Task[2];
        for (int i = 0; i < 2; i++)
        {
          var imageTask = stream.WaitForAsync(AcquisitionTimeout);
          savesFinished[i] = SaveAndUnlockImageAsync(imageTask, counter++);
        }

        await Task.WhenAll(savesFinished);            
      }
      catch (TimeoutException)
      {
        // swallow timeouts, but we need to check for cancellation
      }
    }
  }
  finally
  {
    stream.Abort();
  }
}

private async Task SaveAndUnlockImageAsync(Task<StreamImage> imageTask, long imageNumber)
{
  Debug.Assert(imageTask != null);

  using (var image = await imageTask)
  {
    await SaveImageAsync(image, imageNumber);
  }
}

private static Task SaveImageAsync(Image image, long imageNumber)
{
  Debug.Assert(image != null);

  return Task.Run(() =>
    image.Save(Path.Combine(StorageDirectory, $"{imageNumber}.bmp"))
  );
}

```

---

<div class="post-metadata">

**Author:** ![johmarjac](https://avatars.discourse-cdn.com/v4/letter/j/9fc348/32.png) [@johmarjac](https://forum.commonvisionblox.com/u/johmarjac)\
**Post date:** [October 23, 2018, 7:25am UTC](https://forum.commonvisionblox.com/t/async-saving-of-images/573/3 "2018-10-23T07:25:37Z")

</div>

Hi, that is interesting, I will have a look into the project. Thank your for the example and the great explanation how it is being setup/made.

But I have another small question. I was using GetSnapshotAsync for now because when I started a stream, I took an image, changed the ExposureTime Node, took another image, it didnt change the exposureTime in the next image. It first appeared some frames after the two frames I grabbed. Is there a way to wait for the camera to apply the exposure time and then react with a camera shot? For now I had to do it via GetSnapshotAsync but I can imagine it is way slower than taking single frames from a running stream.

---

<div class="post-metadata">

**Author:** ![parsd](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/parsd/32/7_2.png) [@parsd](https://forum.commonvisionblox.com/u/parsd)\
**Post date:** [October 23, 2018, 8:12am UTC](https://forum.commonvisionblox.com/t/async-saving-of-images/573/4 "2018-10-23T08:12:39Z")

</div>

We seldom use `.GetSnapshot` as it is systematically slow:

1. it starts the acquisition engine
2. setups the camera to single frame mode if possible
3. starts the camera acquisition
4. waits for one frame
5. stops the acquisition engine
6. restores the former acquisition mode in the camera

If you have non-moving objects and enough time available this is still a viable way to go.

Regarding the application of settings in the camera I can imagine two things:

1. The intended contract for a GenApi device is that the setting is applied when the value write was acknowledged. Some cameras try to improve UI responsiveness by immediately acknowledging the write and then applying the value later.
2. Acquisition is configured free running and was active and the camera is delivering frames relatively fast. Thus you will have a new frame in the `Device`'s ring buffer while you set the new exposure time. The current frame in the camera will still be exposed with the old exposure time and then the next one will use your newly set one.

In both cases you end up with frames with the old exposure time. The only way you can get around that if your software wants to control everything is to use triggered acquisition or the `.GetSnapshot` method. Setting up the camera in software trigger mode and sending software triggers is much more efficient and helps to nicely separate the concerns in your application: Trigger logic is then independent of acquisition.

---

<div class="post-metadata">

**Author:** ![johmarjac](https://avatars.discourse-cdn.com/v4/letter/j/9fc348/32.png) [@johmarjac](https://forum.commonvisionblox.com/u/johmarjac)\
**Post date:** [November 19, 2018, 1:05pm UTC](https://forum.commonvisionblox.com/t/async-saving-of-images/573/5 "2018-11-19T13:05:28Z")

</div>

@parsd The provided example solution AcqSave.zip shows, how software triggering works. Am I correct with the thought, that on Button Click it will trigger 2 times and the whole process has a 100ms timeout for both the images?

So basically if I wanted to set the exposure time in between of those two, I will first set the exposure time, then send a software trigger, set the exposure time again to another value, send a second software trigger. Wont this end up also in not applied exposure times because of the ring buffer, or is a software trigger real time acquisition?

---

<div class="post-metadata">

**Author:** ![parsd](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.commonvisionblox.com/parsd/32/7_2.png) [@parsd](https://forum.commonvisionblox.com/u/parsd)\
**Post date:** [November 20, 2018, 8:30am UTC](https://forum.commonvisionblox.com/t/async-saving-of-images/573/6 "2018-11-20T08:30:51Z")

</div>

Hi @johmarjac,

regarding the example: yes in this simple example there will be two software triggers sent. Depending on your application requirements and camera used you need to adapt that trigger code. Also we use a timeout of 100ms, but not for the whole process. We try to acquire two images with a 100ms timeout each. So if there are not two images arriving within 200ms we won’t save anything. This timeout also enable us to cancel our acquisition app even when no images are arriving (see the outer loop with `!cancellationToken.IsCancellationRequested`).

Regarding the triggering and exposure time:

1. Triggering  
The example here is quite silly and will only work for very short exposure times. If you trigger too quickly you will “overtrigger” the camera and probably loose a frame. Thus you should wait inbetween two triggers (at least for the exposure time).

2. Exposure Time  
If you want to control the acquisition sequence as you described you can do it like this:

3. The RingBuffer  
The _RingBuffer_ and the camera are two different entities. They both run in parallel completely independent of each other (they are in two different devices: the camera and your PC). If you send a software trigger you simply tell the camera to take a picture and send it to you. If the acquisition engine is active and the _RingBuffer_ has space left it will store that picture until you collect it via the `.Wait` function. The `.Wait` won’t collect the data; it just syncs to the next acquired image. The acquisition handling collects the incoming images in parallel to your application code.

To sum up: in 2. I only described camera setup/communication. I also would rename the `.SendSoftwareTrigger` method to something along `.SendAcquisitionSequence`. Perhaps you even find a better name 🙂. The acquisition handling on the receiving end doesn’t change at all. We simply get two images. You need to change your timeout settings, though, if you use differing exposure times. I would suggest using the short exposure time first as this makes cancelling your acquisition code faster.

I hope that makes whats happening between the camera and your software clearer.
