Get_snapshot stops working after first acquisition

I am trying to acquire images from 2 GigE cameras with the get_snapshot() Python function. The first round of acquisition works (I get one image from each camera), but at the second round get_snapshot doesn’t return anything, I get a timeout error.

I use the following code:

device = cvb.DeviceFactory.open(self.access_token, port=0)
stream = device.stream() 

for i in range(10): 
    image, status = stream.get_snapshot()
    if status == cvb.WaitStatus.Ok:
        # Convert image into numpy array
        self.images[cam_idx] = cvb.as_array(image, copy=True) 

Why can’t I get images from the cameras the second time? What goes wrong after the first acquisition? Do the cameras get blocked somehow?

Are the cameras running in freerun mode or are they triggered externally?

Not sure if this is related. Can you use stream().get_snapshot()? https://forum.commonvisionblox.com/t/impossible-to-get-stream-methods-to-work-in-recent-installation-of-cvbpy/1535

There is no external trigger. They are directly connected via a switch with an Ubuntu machine.

stream().get_snapshot() throws an error when I try to get the numpy array of the cvb image object.

For me it looks like get_snapshot() is either not freeing up the resources (timeout during the second approach/endless execution) or it deletes them prematurely before I can get the image data (“RuntimeError: failed to extract type - resource might be gone”).

Hi @Oguz

just out of curiostity, why are you using the get_snapshot() rather than having the cameras software triggered?
I cant see any timeout exception in your output, to me it looks more like you are trying to access data, that is already gone due to some other process manipulating it.

Have you tried not to store the images into your array? So simply make the image an array and forget about it…
Also images[imageIndex] should be an image array. I dont know how Python handles ref and value types but lets assume this object is currently being manipulated somewhere else, assigning a new value to it might fail as the storage is already freed.

Also, why exactly are you storing the images in this array? Maybe you just want to increase your ringbuffer?

Let us know a little more about what you want to do, so we dont work on fixing the symptoms if we would be better off having a different approach.

Cheers
Chris

The error message above is related to the version with () right after stream object. In my code as shown above, the stream.get_snapshot() doesn’t return after the first time. It runs endlessly.

In our setup we have 6 rolling shutter cameras. Later we will potentially buy 6 more. The example above is just for 2 cameras.

We want to get an image from the camera only when we need it and avoid getting flooded with data by the cameras, because otherwise the images have have black horizontal bars when we use a “weak” ethernet connection, presumably due to network capacity issues. These bars sometimes appear even when we use a 10Gig ethernet connection, but with a smaller connection they almost always appear.

I have already tried not storing them into an array. The “resource might be gone” error doesn’t appear but get_snapshot still doesn’t stop running after the first time. To process the image data, I need them as a numpy array. Is there another way to get the images as numpy arrays? Storing them like that as numpy arrays works continuously when I use the wait_for function and it also works with get_snapshot the first time.

Could you provide a minimal image acquisition example with the get_snapshot function please? There is one for the other functions, e.g. wait_for, which was very helpful.

How do I change the ringbuffer in Python? How can I ensure that an image is provided to me only after the complete data of that image has arrived so that I don’t have only half of the image and the rest is just a black bar? The images all look good when I get the data with the Common Vision Block Genicam Browser tool, but with the Python wrapper we still have problems.

I think we need to start from scratch here.

First of all… have you optimized your network settings?

https://help.commonvisionblox.com/NextGen/14.0/md_theory_of_operation_hardware__gen_i_cam__c_v_b__user_guide.html#gcug_chmtopic26

Second:
The get_snapshot method being stuck is something we have not experienced and I assume, the problem is not in the method itself but somewhere along the acquisiton itself. The get_snapshot usually does nothing else but:

stream.start
stream.wait
stream.stop

This is something you usually dont want to do for every image on n cameras.
The better approach would be to trigger the cameras via software.

Storing the images as arrays in a queue is just fine, without that further explanation you provided me it sounded like you just did not know, that there is such a thing as the ringbuffer and with this way wanted to avoid loosing images.

My suggestion would be to load all cameras, configure all of them to being triggered via Software.

Example of software triggered acq

import os 
import cvb    

# Configure the TriggerMode of a camera and execute a SoftwareTrigger using GenApi   
#Tested With Dalsa Genie Nano, names of Nodes may be different on other devices  
# Load driver  

device = cvb.DeviceFactory.open(os.path.join(cvb.install_path(), "drivers", "GenICam.vin"), port=0)   

#Load NodeMap for the device  
dev_node_map = device.node_maps["Device"]     

#First set the TriggerMode  
triggerModeNode = dev_node_map["TriggerMode"]  
triggerModeNode.value = "On"    

#Then choose TriggerSource (not available if TriggerMode not set)  
triggerSourceNode = dev_node_map["TriggerSource"]  
triggerSourceNode.value = "Software"     

# Start stream to be able to get an image 
device.stream.start()   

#Then execute a SoftwareTrigger  
softwareTrigger = dev_node_map["TriggerSoftware"]  
softwareTrigger.execute()     

#Now wait for the image and process it... 
image = device.stream.wait(). 
```py

Now, start the stream on all cameras, no load will be put on the network, as no triggers and thus no images are sent.

When you want to get an images just execute the software trigger and wait for the image.

When you are done, stop the stream and thats it…

Cheers
Chris

Hi @Chris, I have tried your code but it doesn’t work. I needed to change a few little things to make it run through (stream → stream(); etc.), but in the end it still doesn’t work. I always get RuntimeError: failed to extract type - resource might be gone error.

Here is my code:

       # get resources for all cameras
        for d in range(self.num_cams):
            # get device
            device = cvb.DeviceFactory.open(self.access_token_lst[d], port=0) 

            #asuming that the vin driver configures 3 buffers by default.
            # device.stream().ring_buffer.change_count(5, cvb.DeviceUpdateMode.UpdateDeviceImage)

            #Load NodeMap for the device  
            dev_node_map = device.node_maps["Device"]     

            #First set the TriggerMode  
            triggerModeNode = dev_node_map["TriggerMode"]  
            triggerModeNode.value = "On"    

            #Then choose TriggerSource (not available if TriggerMode not set)  
            triggerSourceNode = dev_node_map["TriggerSource"]  
            triggerSourceNode.value = "Software"     

            # Start stream to be able to get an image 
            device.stream().start()   

            #Then execute a SoftwareTrigger  
            softwareTrigger = dev_node_map["TriggerSoftware"]  

            softwareTrigger.execute()     

            #Now wait for the image and process it... 
            image, status = device.stream().wait()
            if status == cvb.WaitStatus.Ok:
                image.save("cam_"+str(d)+".png") 

It runs without any errors until inside the if-statement at the end. But when I try to do anything with the image object at the end (e.g. image.save(...)), I get an error. The if status == cvb.WaitStatus.Ok: returns True, but the image doesn’t seem to have the actual data. The content of the cvb.RingBufferImage object is below.


If I try to change the ring buffer size with device = cvb.DeviceFactory.open(self.access_token_lst[d], port=0) I get again the RuntimeError: failed to extract type - resource might be gone.

I was facing a similar issue just yesterday when I tried to access the nodemap of the device using device.stream().ring_buffer.
The fix for me was to store the device.stream() in a seperate variable.
The reason is that in python you can not be sure about the lifetime of the stream object.
As soon as you store the stream in a variable this problem should be gone.

This might also apply to the open method… maybe device is already disposed or one of the arguments you use for the open method, not sure on this one.

1 Like

Thank you @Chris! That solved the problem. Now it works :slight_smile:
Here is my working code:

# get resources for all cameras
        for d in range(self.num_cams):
            # get device
            device = cvb.DeviceFactory.open(self.access_token_lst[d], port=0) 

            #asuming that the vin driver configures 3 buffers by default.
            # device.stream().ring_buffer.change_count(5, cvb.DeviceUpdateMode.UpdateDeviceImage)

            #Load NodeMap for the device  
            dev_node_map = device.node_maps["Device"]     

            #First set the TriggerMode  
            triggerModeNode = dev_node_map["TriggerMode"]  
            triggerModeNode.value = "On"    

            #Then choose TriggerSource (not available if TriggerMode not set)  
            triggerSourceNode = dev_node_map["TriggerSource"]  
            triggerSourceNode.value = "Software"     

            # save stream in a variable, otherwise it will be removed 
            stream = device.stream()  

            # Start stream to be able to get an image 
            stream.start()   

            #Then execute a SoftwareTrigger  
            softwareTrigger = dev_node_map["TriggerSoftware"]  

            softwareTrigger.execute()     

            #Now wait for the image and process it... 
            image, status = stream.wait()
            if status == cvb.WaitStatus.Ok:
                image.save("/home/raptor/Downloads/test/cam_"+str(d)+".png") 
2 Likes

Hi @Oguz ,

glad to hear that, I would have been out of ideas anyway. :sweat_smile:

Happy coding!

1 Like