Hi,
I’m looking for some help with acquiring images using CVB Python from multiple cameras when using a software trigger.
Hardware, 2 USB cameras:
Alvium 1800U-158C-CH-C
There is no hardware trigger, and I’d like to keep it this way. I accept this will lead to mis-matches between the camera acquisition, but would like to still get some initial results to assess this.
System software versions:
Windows 11
Common Vision Blox Image Manager v13.04.005
Python 3.9
CVB python 1.4
When setup in GenICam Browser, the cameras are achieving 250 FPS. I have saved those settings into user sets for each camera, and saved them as configured devices.
I was sent an example that makes use of the software trigger and python threads to acquire from both cameras. The problem with this is that the triggering takes between 1 to 2 seconds, so by the time the images start acquiring I am out of sync with the time I wanted to acquire at.
import datetime
import time
import cvb
import os
import cvb.foundation
import sys
import threading
import numpy
x=200
print("set up start")
start_time = datetime.datetime.now()
device_A = cvb.DeviceFactory.open(os.path.join(cvb.install_path(), "drivers", "GenICam.vin"), port=0)
deviceNodeMap_A = device_A.node_maps["Device"]
deviceStream_A = device_A.stream()
ringBufferCount_A = deviceStream_A.ring_buffer.count
deviceStream_A.ring_buffer.change_count(x, 0)
print("Current RingBuffer amount: " + str(ringBufferCount_A))
device_B = cvb.DeviceFactory.open(os.path.join(cvb.install_path(), "drivers", "GenICam.vin"), port=1)
deviceNodeMap_B = device_B.node_maps["Device"]
deviceStream_B = device_B.stream()
ringBufferCount_B = deviceStream_B.ring_buffer.count
deviceStream_B.ring_buffer.change_count(x, 0)
print("Current RingBuffer amount: " + str(ringBufferCount_B))
ringBufferCount_A = deviceStream_A.ring_buffer.count
print("Changed RingBuffer amount to: " + str(ringBufferCount_A))
ringBufferCount_B = deviceStream_B.ring_buffer.count
print("Changed RingBuffer amount to: " + str(ringBufferCount_B))
triggerMode_A = deviceNodeMap_A["TriggerMode"]
oldTriggerMode_A = deviceNodeMap_A["TriggerMode"]
triggerSource_A = deviceNodeMap_A["TriggerSource"]
oldTriggerSource_A = deviceNodeMap_A["TriggerSource"]
triggerSoftware_A = deviceNodeMap_A["TriggerSoftware"]
triggerMode_A.value = "On"
triggerSource_A.value = "Software"
triggerMode_B = deviceNodeMap_B["TriggerMode"]
oldTriggerMode_B = deviceNodeMap_B["TriggerMode"]
triggerSource_B = deviceNodeMap_B["TriggerSource"]
oldTriggerSource_B = deviceNodeMap_B["TriggerSource"]
triggerSoftware_B = deviceNodeMap_B["TriggerSoftware"]
triggerMode_B.value = "On"
triggerSource_B.value = "Software"
print("Starting stream and trigger camera given amount of times")
print("Set up done: {}".format(datetime.datetime.now() - start_time))
a_images = []
b_images = []
a_times = []
b_times = []
def Stream_A():
global a_times
global a_images
ctr=0
#Start Stream
device_A.stream().start()
print("Triggering A")
start_time = datetime.datetime.now()
# Collect images to fill buffer
while (deviceStream_A.statistics[cvb.StreamInfo.NumBuffersPending] < x):
triggerSoftware_A.execute()
#print("Currently locked buffers: " + str(deviceStream_A.statistics[cvb.StreamInfo.NumBuffersLocked]))
a_count = 0
print("Triggering A done: {}".format(datetime.datetime.now() - start_time))
start_time = datetime.datetime.now()
while (deviceStream_A.statistics[cvb.StreamInfo.NumBuffersPending] > 0):
image_A = device_A.stream().wait()
np_array = cvb.as_array(image_A[0], copy=True)
a_image_time = datetime.datetime.now()
a_images.append(np_array)
a_times.append(a_image_time)
# print("A", np_array[100, 100])
a_count += 1
a_time = (datetime.datetime.now() - start_time).total_seconds()
# Stop Stream
device_A.stream().stop()
print("A: ", a_count, "images", a_time, "seconds")
print("A: last image time: ", a_image_time)
# Reset changed settings of camera
deviceStream_A.ring_buffer.change_count(3, 0)
triggerMode_A = oldTriggerMode_A
triggerSource_A = oldTriggerSource_A
def Stream_B():
global b_times
global b_images
ctr=0
device_B.stream().start()
print("Triggering B")
start_time = datetime.datetime.now()
while (deviceStream_B.statistics[cvb.StreamInfo.NumBuffersPending] < x):
triggerSoftware_B.execute()
# Process through images in buffer
b_count = 0
print("Triggering B done: {}".format(datetime.datetime.now() - start_time))
start_time = datetime.datetime.now()
while (deviceStream_B.statistics[cvb.StreamInfo.NumBuffersPending] > 0):
image_B = device_B.stream().wait()
np_array = cvb.as_array(image_B[0], copy=True)
# print("B", np_array[100, 100])
b_image_time = datetime.datetime.now()
b_images.append(np_array)
b_times.append(b_image_time)
b_count += 1
b_time = (datetime.datetime.now() - start_time).total_seconds()
# Stop Stream
device_B.stream().stop()
print("B:", b_count, "images", b_time, "seconds")
print("B: last image time: ", b_image_time)
# Reset changed settings of camera
deviceStream_B.ring_buffer.change_count(3, 0)
triggerMode_B = oldTriggerMode_B
triggerSource_B = oldTriggerSource_B
thread1 = threading.Thread(target=Stream_A)
thread1.start()
thread2 = threading.Thread(target=Stream_B)
thread2.start()
thread1.join()
thread2.join()
print(len(a_images), len(b_images))
In response to this, I tried moving the trigger within the acquisition loop (as below), but then the achieved FPS is around 90.
import datetime
import time
import cvb
import os
import cvb.foundation
import sys
import threading
import numpy
x=200
print("set up start")
start_time = datetime.datetime.now()
device_A = cvb.DeviceFactory.open(os.path.join(cvb.install_path(), "drivers", "GenICam.vin"), port=0)
deviceNodeMap_A = device_A.node_maps["Device"]
deviceStream_A = device_A.stream()
ringBufferCount_A = deviceStream_A.ring_buffer.count
deviceStream_A.ring_buffer.change_count(x, 0)
print("Current RingBuffer amount: " + str(ringBufferCount_A))
device_B = cvb.DeviceFactory.open(os.path.join(cvb.install_path(), "drivers", "GenICam.vin"), port=1)
deviceNodeMap_B = device_B.node_maps["Device"]
deviceStream_B = device_B.stream()
ringBufferCount_B = deviceStream_B.ring_buffer.count
deviceStream_B.ring_buffer.change_count(x, 0)
print("Current RingBuffer amount: " + str(ringBufferCount_B))
ringBufferCount_A = deviceStream_A.ring_buffer.count
print("Changed RingBuffer amount to: " + str(ringBufferCount_A))
ringBufferCount_B = deviceStream_B.ring_buffer.count
print("Changed RingBuffer amount to: " + str(ringBufferCount_B))
triggerMode_A = deviceNodeMap_A["TriggerMode"]
oldTriggerMode_A = deviceNodeMap_A["TriggerMode"]
triggerSource_A = deviceNodeMap_A["TriggerSource"]
oldTriggerSource_A = deviceNodeMap_A["TriggerSource"]
triggerSoftware_A = deviceNodeMap_A["TriggerSoftware"]
triggerMode_A.value = "On"
triggerSource_A.value = "Software"
triggerMode_B = deviceNodeMap_B["TriggerMode"]
oldTriggerMode_B = deviceNodeMap_B["TriggerMode"]
triggerSource_B = deviceNodeMap_B["TriggerSource"]
oldTriggerSource_B = deviceNodeMap_B["TriggerSource"]
triggerSoftware_B = deviceNodeMap_B["TriggerSoftware"]
triggerMode_B.value = "On"
triggerSource_B.value = "Software"
print("Starting stream and trigger camera given amount of times")
print("Set up done: {}".format(datetime.datetime.now() - start_time))
a_images = []
b_images = []
a_times = []
b_times = []
def Stream_A():
global a_times
global a_images
ctr=0
#Start Stream
device_A.stream().start()
print("Triggering A")
a_count = 0
start_time = datetime.datetime.now()
while a_count < x:
triggerSoftware_A.execute()
image_A = device_A.stream().wait()
np_array = cvb.as_array(image_A[0], copy=True)
a_image_time = datetime.datetime.now()
a_images.append(np_array)
a_times.append(a_image_time)
# print("A", np_array[100, 100])
a_count += 1
a_time = (datetime.datetime.now() - start_time).total_seconds()
# Stop Stream
device_A.stream().stop()
print("A: ", a_count, "images", a_time, "seconds")
print("A: last image time: ", a_image_time)
# Reset changed settings of camera
deviceStream_A.ring_buffer.change_count(3, 0)
triggerMode_A = oldTriggerMode_A
triggerSource_A = oldTriggerSource_A
def Stream_B():
global b_times
global b_images
ctr=0
device_B.stream().start()
print("Triggering B")
b_count = 0
start_time = datetime.datetime.now()
while b_count < x:
triggerSoftware_B.execute()
image_B = device_B.stream().wait()
np_array = cvb.as_array(image_B[0], copy=True)
# print("B", np_array[100, 100])
b_image_time = datetime.datetime.now()
b_images.append(np_array)
b_times.append(b_image_time)
b_count += 1
b_time = (datetime.datetime.now() - start_time).total_seconds()
# Stop Stream
device_B.stream().stop()
print("B:", b_count, "images", b_time, "seconds")
print("B: last image time: ", b_image_time)
# Reset changed settings of camera
deviceStream_B.ring_buffer.change_count(3, 0)
triggerMode_B = oldTriggerMode_B
triggerSource_B = oldTriggerSource_B
thread1 = threading.Thread(target=Stream_A)
thread1.start()
thread2 = threading.Thread(target=Stream_B)
thread2.start()
thread1.join()
thread2.join()
print(len(a_images), len(b_images))
I’d like to increase the achieved FPS as close to 250 as possible. Is there something I’m missing with the software trigger? Or can what I want be achieved another way?
Thanks,
Alex