# coding=utf-8
# =============================================================================
# Copyright (c) 2026 FLIR Integrated Imaging Solutions, Inc. All Rights Reserved.
#
# This software is the confidential and proprietary information of FLIR
# Integrated Imaging Solutions, Inc. ("Confidential Information"). You
# shall not disclose such Confidential Information and shall use it only in
# accordance with the terms of the license agreement you entered into
# with FLIR Integrated Imaging Solutions, Inc. (FLIR).
#
# FLIR MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
# SOFTWARE, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
# PURPOSE, OR NON-INFRINGEMENT. FLIR SHALL NOT BE LIABLE FOR ANY DAMAGES
# SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
# THIS SOFTWARE OR ITS DERIVATIVES.
# =============================================================================
#
# StereoGPIO.py shows how to set the GPIO of the stereo camera.
#
# This example demonstrates how to set the GPIO of the camera.
# After setting the GPIO controls, images are grabbed pending on a signal
# in the GPIO line.
#
# Please leave us feedback at: https://www.surveymonkey.com/r/TDYMVAPI
# More source code examples at: https://github.com/Teledyne-MV/Spinnaker-Examples
# Need help? Check out our forum at: https://teledynevisionsolutions.zendesk.com/hc/en-us/community/topics
import os
import PySpin
import sys
import platform
def validate_image_list(stream_transmit_flags, image_list):
"""
This function validates the image list.
:param stream_transmit_flags: list of boolean flags refering to the various streams indicating if to trasmit the stream.
:param image_list: list of aquired streams.
:type stream_transmit_flags: dict
:type image_list: ImageList
:return: True if successful, False otherwise.
:rtype: bool
"""
is_image_list_incomplete = False;
if stream_transmit_flags['rawSensor1TransmitEnabled']:
image = image_list.GetByPayloadType(PySpin.SPINNAKER_IMAGE_PAYLOAD_TYPE_RAW_SENSOR1);
is_image_list_incomplete |= ((image is None) or image.IsIncomplete())
if stream_transmit_flags['rawSensor2TransmitEnabled']:
image = image_list.GetByPayloadType(PySpin.SPINNAKER_IMAGE_PAYLOAD_TYPE_RAW_SENSOR2);
is_image_list_incomplete |= ((image is None) or image.IsIncomplete())
if stream_transmit_flags['rectSensor1TransmitEnabled']:
image = image_list.GetByPayloadType(PySpin.SPINNAKER_IMAGE_PAYLOAD_TYPE_RECTIFIED_SENSOR1);
is_image_list_incomplete |= ((image is None) or image.IsIncomplete())
if stream_transmit_flags['rectSensor2TransmitEnabled']:
image = image_list.GetByPayloadType(PySpin.SPINNAKER_IMAGE_PAYLOAD_TYPE_RECTIFIED_SENSOR2);
is_image_list_incomplete |= ((image is None) or image.IsIncomplete())
if stream_transmit_flags['disparityTransmitEnabled']:
image = image_list.GetByPayloadType(PySpin.SPINNAKER_IMAGE_PAYLOAD_TYPE_DISPARITY_SENSOR1);
is_image_list_incomplete |= ((image is None) or image.IsIncomplete())
if is_image_list_incomplete:
print('Image List is incomplete.')
return not is_image_list_incomplete
def configure_gpio(cam):
"""
This function configures the camera to use a hardware trigger via the GPIO.
First, trigger mode is set to off in order to select the trigger source.
Then input line 0 is selected to trigger frame start.
Also, output line 1 is set to to trigger on exposure active.
Once the trigger source has been selected, trigger mode is then enabled, which has the camera
capture only a single image upon the execution of the chosen trigger.
:param cam: Camera to configure trigger for.
:type cam: CameraPtr
:return: True if successful, False otherwise.
:rtype: bool
"""
result = True
print('*** CONFIGURING TRIGGER ***\n')
try:
nodemap = cam.GetNodeMap()
# Set triggerMode to Off
# Trigger mode must be off when setting the trigger source.
if not set_trigger(nodemap, False):
print('Unable to disable the trigger mode. Aborting...')
return False
# Set trigger source to line 0
node_trigger_source = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerSource'))
if not PySpin.IsReadable(node_trigger_source) or not PySpin.IsWritable(node_trigger_source):
print('Unable to get or set the trigger source (node retrieval). Aborting...')
return False
node_trigger_source_hardware = node_trigger_source.GetEntryByName('Line0')
if not PySpin.IsReadable(node_trigger_source_hardware):
print('Unable to get trigger source (Line0 enum entry retrieval). Aborting...')
return False
node_trigger_source.SetIntValue(node_trigger_source_hardware.GetValue())
print('Trigger source set to hardware, line 0.')
# Set trigger selector to frame start
# For this example, the trigger selector should be set to frame start.
# This is the default for most cameras.
node_trigger_selector = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerSelector'))
if not PySpin.IsReadable(node_trigger_selector) or not PySpin.IsWritable(node_trigger_selector):
print('Unable to get or set the trigger selector (node retrieval). Aborting...')
return False
node_trigger_selector_framestart = node_trigger_selector.GetEntryByName('FrameStart')
if not PySpin.IsReadable(node_trigger_selector_framestart):
print('Unable to get the trigger selector (enum entry retrieval). Aborting...')
return False
node_trigger_selector.SetIntValue(node_trigger_selector_framestart.GetValue())
print('Trigger selector set to frame start.')
# Set line selector to line 1
node_line_selector = PySpin.CEnumerationPtr(nodemap.GetNode('LineSelector'))
if not PySpin.IsReadable(node_line_selector) or not PySpin.IsWritable(node_line_selector):
print('Unable to get or set the trigger selector (node retrieval). Aborting...')
return False
node_line_selector_line1 = node_line_selector.GetEntryByName('Line1')
if not PySpin.IsReadable(node_line_selector_line1):
print('Unable to get the trigger selector (enum entry retrieval). Aborting...')
return False
node_line_selector.SetIntValue(node_line_selector_line1.GetValue())
print('Line selector set line 1.')
# Set line source to exposure active
node_line_source = PySpin.CEnumerationPtr(nodemap.GetNode('LineSource'))
if not PySpin.IsReadable(node_line_source) or not PySpin.IsWritable(node_line_source):
print('Unable to get or set the line source (node retrieval). Aborting...')
return False
node_line_source_exposure_active = node_line_source.GetEntryByName('ExposureActive')
if not PySpin.IsReadable(node_line_source_exposure_active):
print('Unable to get the line source (enum entry retrieval). Aborting...')
return False
node_line_source.SetIntValue(node_line_source_exposure_active.GetValue())
print('Line source set to exposure active.')
# Set triggerMode to On
if not set_trigger(nodemap, True):
print('Unable to enable the trigger mode. Aborting...')
return False
except PySpin.SpinnakerException as ex:
print('Error: %s' % ex)
return False
return result
def set_trigger(nodemap, is_on):
"""
This function sets the trigger mode to on/off.
:param nodemap: Transport layer device nodemap.
:param is_on: the state to put the trigger mode to.
:type nodemap: INodeMap
:type is_on: bool
:returns: True if successful, False otherwise.
:rtype: bool
"""
stateStr = "On" if is_on else "Off"
try:
result = True
node_trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerMode'))
if not PySpin.IsReadable(node_trigger_mode) or not PySpin.IsWritable(node_trigger_mode):
print(f"Unable to update trigger mode (node retrieval). Aborting...")
return False
node_trigger_mode_state = node_trigger_mode.GetEntryByName(stateStr)
if not PySpin.IsReadable(node_trigger_mode_state):
print(f"Unable to update trigger mode (enum entry retrieval). Aborting...")
return False
node_trigger_mode.SetIntValue(node_trigger_mode_state.GetValue())
if is_on:
print(f"Trigger mode enabled...")
else:
print(f"Trigger mode disabled...")
except PySpin.SpinnakerException as ex:
print('Error: %s' % ex)
result = False
return result
def acquire_images(cam, nodemap, nodemap_tldevice):
"""
This function acquires and saves multiple image sets from a device.
:param cam: Camera to acquire images from.
:param nodemap: Device nodemap.
:param nodemap_tldevice: Transport layer device nodemap.
:type cam: CameraPtr
:type nodemap: INodeMap
:type nodemap_tldevice: INodeMap
:return: True if successful, False otherwise.
:rtype: bool
"""
print('*** IMAGE ACQUISITION ***\n')
try:
result = True
# Set acquisition mode to continuous
# In order to access the node entries, they have to be casted to a pointer type (CEnumerationPtr here)
node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode'))
if not PySpin.IsReadable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode):
print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...')
return False
# Retrieve entry node from enumeration node
node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous')
if not PySpin.IsReadable(node_acquisition_mode_continuous):
print('Unable to set acquisition mode to continuous (entry retrieval). Aborting...')
return False
# Retrieve integer value from entry node
acquisition_mode_continuous = node_acquisition_mode_continuous.GetValue()
# Set integer value from entry node as new value of enumeration node
node_acquisition_mode.SetIntValue(acquisition_mode_continuous)
print('Acquisition mode set to continuous...')
cam.BeginAcquisition()
stream_transmit_flags = {}
stream_transmit_flags['rawSensor1TransmitEnabled'] = False
stream_transmit_flags['rawSensor2TransmitEnabled'] = False
stream_transmit_flags['rectSensor1TransmitEnabled'] = True
stream_transmit_flags['rectSensor2TransmitEnabled'] = False
stream_transmit_flags['disparityTransmitEnabled'] = True
timeoutInMilliSecs = 5000
num_images_sets = 3
if timeoutInMilliSecs == PySpin.EVENT_TIMEOUT_INFINITE:
print ('\nAcquiring %d image sets pending on GPIO signal, within an infinite time limit.' % num_images_sets)
else:
print ('\nAcquiring %d image sets pending on GPIO signal, within a time limit of %f secs.' % (num_images_sets, timeoutInMilliSecs / 1000))
# Retrieve, process the images
for i in range(num_images_sets):
try:
print('Acquiring stereo image set: %d' % i)
image_list = cam.GetNextImageSync(timeoutInMilliSecs)
if not validate_image_list(stream_transmit_flags, image_list):
print('Failed to get next image set.')
continue;
except PySpin.SpinnakerException as ex:
print('Error: %s' % ex)
result = False
cam.EndAcquisition()
except PySpin.SpinnakerException as ex:
print('Error: %s' % ex)
result = False
return result
def print_device_info(nodemap):
"""
This function prints the device information of the camera from the transport
layer; please see NodeMapInfo example for more in-depth comments on printing
device information from the nodemap.
:param nodemap: Transport layer device nodemap.
:type nodemap: INodeMap
:returns: True if successful, False otherwise.
:rtype: bool
"""
print('*** DEVICE INFORMATION ***\n')
try:
result = True
node_device_information = PySpin.CCategoryPtr(nodemap.GetNode('DeviceInformation'))
if PySpin.IsReadable(node_device_information):
features = node_device_information.GetFeatures()
for feature in features:
node_feature = PySpin.CValuePtr(feature)
print('%s: %s' % (node_feature.GetName(),
node_feature.ToString() if PySpin.IsReadable(node_feature) else 'Node not readable'))
else:
print('Device control information not readable.')
except PySpin.SpinnakerException as ex:
print('Error: %s' % ex)
return False
return result
def run_single_camera(cam):
"""
This function acts as the body of the example; please see NodeMapInfo example
for more in-depth comments on setting up cameras.
:param cam: Camera to run on.
:type cam: CameraPtr
:return: True if successful, False otherwise.
:rtype: bool
"""
try:
result = True
# Retrieve TL device nodemap and print device information
nodemap_tldevice = cam.GetTLDeviceNodeMap()
result &= print_device_info(nodemap_tldevice)
# Initialize camera
cam.Init()
# Retrieve GenICam nodemap
nodemap = cam.GetNodeMap()
device_serial_number = ''
node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber'))
if PySpin.IsReadable(node_device_serial_number):
device_serial_number = node_device_serial_number.GetValue()
print('Device serial number retrieved as %s...' % device_serial_number)
is_stereo_camera = PySpin.ImageUtilityStereo.IsStereoCamera(cam)
if is_stereo_camera:
print('Camera %s is a stereo camera' % device_serial_number)
else:
print('Camera %s is not a valid BX camera. Skipping...' % device_serial_number)
return True
print('Configuring GPIO...')
if not configure_gpio(cam):
print('Failed to configure the GPIO. Aborting...')
return False
# Acquire images
print('Acquiring images...')
result &= acquire_images(cam, nodemap, nodemap_tldevice)
# Set trigger to Off
result |= set_trigger(nodemap, False)
# Deinitialize camera
cam.DeInit()
except PySpin.SpinnakerException as ex:
print('Error: %s' % ex)
result = False
return result
def main():
"""
Example entry point; please see Enumeration example for more in-depth
comments on preparing and cleaning up the system.
:return: True if successful, False otherwise.
:rtype: bool
"""
result = True
# Retrieve singleton reference to system object
system = PySpin.System.GetInstance()
# Get current library version
version = system.GetLibraryVersion()
print('Library version: %d.%d.%d.%d' % (version.major, version.minor, version.type, version.build))
# Retrieve list of cameras from the system
cam_list = system.GetCameras()
num_cameras = cam_list.GetSize()
print('Number of cameras detected: %d' % num_cameras)
# Finish if there are no cameras
if num_cameras == 0:
# Clear camera list before releasing system
cam_list.Clear()
# Release system instance
system.ReleaseInstance()
print('Not enough cameras!')
input('Done! Press Enter to exit...')
return False
# Run example on each camera
for i, cam in enumerate(cam_list):
print('Running example for camera %d...' % i)
result &= run_single_camera(cam)
print('Camera %d example complete... \n' % i)
# Release reference to camera
# NOTE: Unlike the C++ examples, we cannot rely on pointer objects being automatically
# cleaned up when going out of scope.
# The usage of del is preferred to assigning the variable to None.
del cam
# Clear camera list before releasing system
cam_list.Clear()
# Release system instance
system.ReleaseInstance()
input('Done! Press Enter to exit...')
return result
if __name__ == '__main__':
if main():
sys.exit(0)
else:
sys.exit(1)