# 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.
# =============================================================================
#
# Sequencer.py shows how to use the sequencer to grab images with
# various settings. It relies on information provided in the Enumeration,
# Acquisition, and NodeMapInfo examples.
#
# It can also be helpful to familiarize yourself with the ImageFormatControl
# and Exposure examples as these examples provide a strong introduction to
# camera customization.
#
# The sequencer is another very powerful tool, which can be used to create
# and store multiple states of customized image settings. A very useful
# application of the sequencer is creating high dynamic range images.
#
# This example is probably the most complex and definitely the longest. As
# such, the configuration has been split between three functions. The first
# prepares the camera to set the sequences, the second sets the settings for
# a single state (it is run five times), and the third configures the
# camera to use the sequencer when it acquires images.
#
# 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
NUM_IMAGES = 10 # number of images to grab
def print_retrieve_node_failure(node, name):
""""
This function handles the error prints when a node or entry is unavailable or
not readable on the connected camera.
:param node: Node type. "Node' or 'Entry'
:param name: Node name.
:type node: String
:type name: String
:rtype: None
"""
print('Unable to get {} ({} {} retrieval failed.)'.format(node, name, node))
print('The {} may not be available on all camera models...'.format(node))
print('Please try a Blackfly S camera.')
def configure_sequencer_part_one(nodemap):
""""
This function prepares the sequencer to accept custom configurations by
ensuring sequencer mode is off (this is a requirement to the enabling of
sequencer configuration mode), disabling automatic gain and exposure, and
turning sequencer configuration mode on.
:param nodemap: Device nodemap.
:type nodemap: INodeMap
:return: True if successful, False otherwise.
:rtype: bool
"""
print('*** CONFIGURING SEQUENCER ***\n')
try:
result = True
# Ensure sequencer is off for configuration
#
# *** NOTES ***
# In order to configure a new sequence, sequencer configuration mode
# needs to be turned on. To do this, sequencer mode must be disabled.
# However, simply disabling sequencer mode might throw an exception if
# the current sequence is an invalid configuration.
#
# Thus, in order to ensure that sequencer mode is disabled, we first
# check whether the current sequence is valid. If it
# isn't, then we know that sequencer mode is off and we can move on;
# if it is, then we can manually disable sequencer mode.
#
# Also note that sequencer configuration mode needs to be off in order
# to manually disable sequencer mode. It should be off by default, so
# the example skips checking this.
#
# Validate sequencer configuration
node_sequencer_configuration_valid = PySpin.CEnumerationPtr(nodemap.GetNode('SequencerConfigurationValid'))
if not PySpin.IsReadable(node_sequencer_configuration_valid):
print_retrieve_node_failure('node', 'SequencerConfigurationValid')
return False
sequencer_configuration_valid_yes = node_sequencer_configuration_valid.GetEntryByName('Yes')
if not PySpin.IsReadable(sequencer_configuration_valid_yes):
print_retrieve_node_failure('entry', 'SequencerConfigurationValid Yes')
return False
# If valid, disable sequencer mode; otherwise, do nothing
node_sequencer_mode = PySpin.CEnumerationPtr(nodemap.GetNode('SequencerMode'))
if node_sequencer_configuration_valid.GetCurrentEntry().GetValue() == \
sequencer_configuration_valid_yes.GetValue():
if not PySpin.IsReadable(node_sequencer_mode) or not PySpin.IsWritable(node_sequencer_mode):
print_retrieve_node_failure('node', 'SequencerMode')
return False
sequencer_mode_off = node_sequencer_mode.GetEntryByName('Off')
if not PySpin.IsReadable(sequencer_mode_off):
print_retrieve_node_failure('entry', 'SequencerMode Off')
return False
node_sequencer_mode.SetIntValue(sequencer_mode_off.GetValue())
print('Sequencer mode disabled...')
# Turn off automatic exposure
#
# *** NOTES ***
# Automatic exposure prevents the manual configuration of exposure
# times and needs to be turned off for this example.
#
# *** LATER ***
# Automatic exposure is turned back on at the end of the example in
# order to restore the camera to its default state.
node_exposure_auto = PySpin.CEnumerationPtr(nodemap.GetNode('ExposureAuto'))
if not PySpin.IsReadable(node_exposure_auto) or not PySpin.IsWritable(node_exposure_auto):
print_retrieve_node_failure('node', 'ExposureAuto')
return False
exposure_auto_off = node_exposure_auto.GetEntryByName('Off')
if not PySpin.IsReadable(exposure_auto_off):
print_retrieve_node_failure('entry', 'ExposureAuto Off')
return False
node_exposure_auto.SetIntValue(exposure_auto_off.GetValue())
print('Automatic exposure disabled...')
# Turn off automatic gain
#
# *** NOTES ***
# Automatic gain prevents the manual configuration of gain and needs
# to be turned off for this example.
#
# *** LATER ***
# Automatic gain is turned back on at the end of the example in
# order to restore the camera to its default state.
node_gain_auto = PySpin.CEnumerationPtr(nodemap.GetNode('GainAuto'))
if not PySpin.IsReadable(node_gain_auto) or not PySpin.IsWritable(node_gain_auto):
print_retrieve_node_failure('node', 'GainAuto')
return False
gain_auto_off = node_gain_auto.GetEntryByName('Off')
if not PySpin.IsReadable(gain_auto_off):
print_retrieve_node_failure('entry', 'GainAuto Off')
return False
node_gain_auto.SetIntValue(gain_auto_off.GetValue())
print('Automatic gain disabled...')
# Turn configuration mode on
#
# *** NOTES ***
# Once sequencer mode is off, enabling sequencer configuration mode
# allows for the setting of each state.
#
# *** LATER ***
# Before sequencer mode is turned back on, sequencer configuration
# mode must be turned back off.
node_sequencer_configuration_mode = PySpin.CEnumerationPtr(nodemap.GetNode('SequencerConfigurationMode'))
if not PySpin.IsReadable(node_sequencer_configuration_mode) or not PySpin.IsWritable(node_sequencer_configuration_mode):
print_retrieve_node_failure('node', 'SequencerConfigurationMode')
return False
sequencer_configuration_mode_on = node_sequencer_configuration_mode.GetEntryByName('On')
if not PySpin.IsReadable(sequencer_configuration_mode_on):
print_retrieve_node_failure('entry', 'SequencerConfigurationMode On')
return False
node_sequencer_configuration_mode.SetIntValue(sequencer_configuration_mode_on.GetValue())
print('Sequencer configuration mode enabled...\n')
except PySpin.SpinnakerException as ex:
print('Error: {}'.format(ex))
result = False
return result
def set_single_state(nodemap, sequence_number, width_to_set, height_to_set, exposure_time_to_set, gain_to_set):
"""
This function sets a single state. It sets the sequence number, applies
custom settings, selects the trigger type and next state number, and saves
the state. The custom values that are applied are all calculated in the
function that calls this one, run_single_camera().
:param nodemap: Device nodemap.
:param sequence_number: Sequence number.
:param width_to_set: Width to set for sequencer.
:param height_to_set: Height to set fpr sequencer.
:param exposure_time_to_set: Exposure time to set for sequencer.
:param gain_to_set: Gain to set for sequencer.
:type nodemap: INodeMap
:type sequence_number: int
:type width_to_set: int
:type height_to_set: int
:type exposure_time_to_set: float
:type gain_to_set: float
:return: True if successful, False otherwise.
:rtype: bool
"""
try:
result = True
# Select the current sequence number
#
# *** NOTES ***
# Select the index of the state to be set.
#
# *** LATER ***
# The next state - i.e. the state to be linked to -
# also needs to be set before saving the current state.
node_sequencer_set_selector = PySpin.CIntegerPtr(nodemap.GetNode('SequencerSetSelector'))
if not PySpin.IsWritable(node_sequencer_set_selector):
print_retrieve_node_failure('node', 'SequencerSetSelector')
return False
node_sequencer_set_selector.SetValue(sequence_number)
print('Setting state {}...'.format(sequence_number))
# Set desired settings for the current state
#
# *** NOTES ***
# Width, height, exposure time, and gain are set in this example. If
# the sequencer isn't working properly, it may be important to ensure
# that each feature is enabled on the sequencer. Features are enabled
# by default, so this is not explored in this example.
#
# Changing the height and width for the sequencer is not available
# for all camera models.
#
# Set width; width recorded in pixels
node_width = PySpin.CIntegerPtr(nodemap.GetNode('Width'))
if PySpin.IsReadable(node_width) and PySpin.IsWritable(node_width):
width_inc = node_width.GetInc()
if width_to_set % width_inc != 0:
width_to_set = int(width_to_set / width_inc) * width_inc
node_width.SetValue(width_to_set)
print('\tWidth set to {}...'.format(node_width.GetValue()))
else:
print('\tUnable to set width; width for sequencer not available on all camera models...')
# Set height; height recorded in pixels
node_height = PySpin.CIntegerPtr(nodemap.GetNode('Height'))
if PySpin.IsReadable(node_height) and PySpin.IsWritable(node_height):
height_inc = node_height.GetInc()
if height_to_set % height_inc != 0:
height_to_set = int(height_to_set / height_inc) * height_inc
node_height.SetValue(height_to_set)
print('\tHeight set to %d...' % node_height.GetValue())
else:
print('\tUnable to set height; height for sequencer not available on all camera models...')
# Set exposure time; exposure time recorded in microseconds
node_exposure_time = PySpin.CFloatPtr(nodemap.GetNode('ExposureTime'))
if not PySpin.IsReadable(node_exposure_time) or not PySpin.IsWritable(node_exposure_time):
print_retrieve_node_failure('node', 'ExposureTime')
return False
exposure_time_max = node_exposure_time.GetMax()
if exposure_time_to_set > exposure_time_max:
exposure_time_to_set = exposure_time_max
node_exposure_time.SetValue(exposure_time_to_set)
print('\tExposure set to {0:.0f}...'.format(node_exposure_time.GetValue()))
# Set gain; gain recorded in decibels
node_gain = PySpin.CFloatPtr(nodemap.GetNode('Gain'))
if not PySpin.IsReadable(node_gain) or not PySpin.IsWritable(node_gain):
print_retrieve_node_failure('node', 'Gain')
return False
gain_max = node_gain.GetMax()
if gain_to_set > gain_max:
gain_to_set = gain_max
node_gain.SetValue(gain_to_set)
print('\tGain set to {0:.5f}...'.format(node_gain.GetValue()))
# Set the trigger type for the current state
#
# *** NOTES ***
# It is a requirement of every state to have its trigger source set.
# The trigger source refers to the moment when the sequencer changes
# from one state to the next.
node_sequencer_trigger_source = PySpin.CEnumerationPtr(nodemap.GetNode('SequencerTriggerSource'))
if not PySpin.IsReadable(node_sequencer_trigger_source) or not PySpin.IsWritable(node_sequencer_trigger_source):
print_retrieve_node_failure('node', 'SequencerTriggerSource')
return False
sequencer_trigger_source_frame_start = node_sequencer_trigger_source.GetEntryByName('FrameStart')
if not PySpin.IsReadable(sequencer_trigger_source_frame_start):
print_retrieve_node_failure('entry', 'SequencerTriggerSource FrameStart')
return False
node_sequencer_trigger_source.SetIntValue(sequencer_trigger_source_frame_start.GetValue())
print('\tTrigger source set to start of frame...')
# Set the next state in the sequence
#
# *** NOTES ***
# When setting the next state in the sequence, ensure it does not
# exceed the maximum and that the states loop appropriately.
final_sequence_index = 4
node_sequencer_set_next = PySpin.CIntegerPtr(nodemap.GetNode('SequencerSetNext'))
if not PySpin.IsWritable(node_sequencer_set_next):
print('Unable to select next state. Aborting...\n')
return False
if sequence_number == final_sequence_index:
node_sequencer_set_next.SetValue(0)
else:
node_sequencer_set_next.SetValue(sequence_number + 1)
print('\tNext state set to {}...'.format(node_sequencer_set_next.GetValue()))
# Save current state
#
# *** NOTES ***
# Once all appropriate settings have been configured, make sure to
# save the state to the sequence. Notice that these settings will be
# lost when the camera is power-cycled.
node_sequencer_set_save = PySpin.CCommandPtr(nodemap.GetNode('SequencerSetSave'))
if not PySpin.IsWritable(node_sequencer_set_save):
print('Unable to save state. Aborting...\n')
return False
node_sequencer_set_save.Execute()
print('Current state saved...\n')
except PySpin.SpinnakerException as ex:
print('Error: {}'.format(ex))
result = False
return result
def configure_sequencer_part_two(nodemap):
""""
Now that the states have all been set, this function readies the camera
to use the sequencer during image acquisition.
:param nodemap: Device nodemap.
:type nodemap: INodeMap
:return: True if successful, False otherwise.
:rtype: bool
"""
try:
result = True
# Turn configuration mode off
#
# *** NOTES ***
# Once all desired states have been set, turn sequencer
# configuration mode off in order to turn sequencer mode on.
node_sequencer_configuration_mode = PySpin.CEnumerationPtr(nodemap.GetNode('SequencerConfigurationMode'))
if not PySpin.IsReadable(node_sequencer_configuration_mode) or not PySpin.IsWritable(node_sequencer_configuration_mode):
print_retrieve_node_failure('node', 'SequencerConfigurationMode')
return False
sequencer_configuration_mode_off = node_sequencer_configuration_mode.GetEntryByName('Off')
if not PySpin.IsReadable(sequencer_configuration_mode_off):
print_retrieve_node_failure('entry', 'SequencerConfigurationMode Off')
return False
node_sequencer_configuration_mode.SetIntValue(sequencer_configuration_mode_off.GetValue())
print('Sequencer configuration mode disabled...')
# Turn sequencer mode on
#
# *** NOTES ***
# After sequencer mode has been turned on, the camera will begin using the
# saved states in the order that they were set.
#
# *** LATER ***
# Once all images have been captured, disable the sequencer in order
# to restore the camera to its initial state.
node_sequencer_mode = PySpin.CEnumerationPtr(nodemap.GetNode('SequencerMode'))
if not PySpin.IsReadable(node_sequencer_mode) or not PySpin.IsWritable(node_sequencer_mode):
print_retrieve_node_failure('node', 'SequencerMode')
return False
sequencer_mode_on = node_sequencer_mode.GetEntryByName('On')
if not PySpin.IsReadable(sequencer_mode_on):
print_retrieve_node_failure('entry', 'SequencerMode On')
return False
node_sequencer_mode.SetIntValue(sequencer_mode_on.GetValue())
print('Sequencer mode enabled...')
# Validate sequencer settings
#
# *** NOTES ***
# Once all states have been set, it is a good idea to
# validate them. Although this node cannot ensure that the states
# have been set up correctly, it does ensure that the states have
# been set up in such a way that the camera can function.
node_sequencer_configuration_valid = PySpin.CEnumerationPtr(nodemap.GetNode('SequencerConfigurationValid'))
if not PySpin.IsReadable(node_sequencer_configuration_valid):
print_retrieve_node_failure('node', 'SequencerConfigurationValid')
return False
sequencer_configuration_valid_yes = node_sequencer_configuration_valid.GetEntryByName('Yes')
if not PySpin.IsReadable(sequencer_configuration_valid_yes):
print_retrieve_node_failure('entry', 'SequencerConfigurationValid Yes')
return False
if node_sequencer_configuration_valid.GetCurrentEntry().GetValue() != \
sequencer_configuration_valid_yes.GetValue():
print('Sequencer configuration not valid. Aborting...\n')
return False
print('Sequencer configuration valid...\n')
except PySpin.SpinnakerException as ex:
print('Error: {}'.format(ex))
result = False
return result
def reset_sequencer(nodemap):
""""
This function restores the camera to its default state by turning sequencer mode
off and re-enabling automatic exposure and gain.
:param nodemap: Device nodemap.
:type nodemap: INodeMap
:return: True if successful, False otherwise.
:rtype: bool
"""
try:
result = True
# Turn sequencer mode back off
#
# *** NOTES ***
# The sequencer is turned off in order to return the camera to its default state.
node_sequencer_mode = PySpin.CEnumerationPtr(nodemap.GetNode('SequencerMode'))
if not PySpin.IsReadable(node_sequencer_mode) or not PySpin.IsWritable(node_sequencer_mode):
print_retrieve_node_failure('node', 'SequencerMode')
return False
sequencer_mode_off = node_sequencer_mode.GetEntryByName('Off')
if not PySpin.IsReadable(sequencer_mode_off):
print_retrieve_node_failure('entry', 'SequencerMode Off')
return False
node_sequencer_mode.SetIntValue(sequencer_mode_off.GetValue())
print('Turning off sequencer mode...')
# Turn automatic exposure back on
#
# *** NOTES ***
# Automatic exposure is turned on in order to return the camera to its default state.
node_exposure_auto = PySpin.CEnumerationPtr(nodemap.GetNode('ExposureAuto'))
if PySpin.IsReadable(node_exposure_auto) and PySpin.IsWritable(node_exposure_auto):
exposure_auto_continuous = node_exposure_auto.GetEntryByName('Continuous')
if PySpin.IsReadable(exposure_auto_continuous):
node_exposure_auto.SetIntValue(exposure_auto_continuous.GetValue())
print('Turning automatic exposure back on...')
# Turn automatic gain back on
#
# *** NOTES ***
# Automatic gain is turned on in order to return the camera to its default state.
node_gain_auto = PySpin.CEnumerationPtr(nodemap.GetNode('GainAuto'))
if PySpin.IsReadable(node_gain_auto) and PySpin.IsWritable(node_gain_auto):
gain_auto_continuous = node_gain_auto.GetEntryByName('Continuous')
if PySpin.IsReadable(gain_auto_continuous):
node_gain_auto.SetIntValue(gain_auto_continuous.GetValue())
print('Turning automatic gain mode back on...\n')
except PySpin.SpinnakerException as ex:
print('Error: {}'.format(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)
feature_string = node_feature.ToString() if PySpin.IsReadable(node_feature) else 'Node not readable'
print('{}: {}'.format(node_feature.GetName(), feature_string))
else:
print('Device control information not readable.')
print('')
except PySpin.SpinnakerException as ex:
print('Error: {}'.format(ex))
return False
return result
def acquire_images(cam, nodemap, nodemap_tldevice, timeout):
"""
This function acquires and saves 10 images from a device.
:param cam: Camera to acquire images from.
:param nodemap: Device nodemap.
:param nodemap_tldevice: Transport layer device nodemap.
:param timeout: Timeout for image acquisition.
:type cam: CameraPtr
:type nodemap: INodeMap
:type nodemap_tldevice: INodeMap
:type timeout: int
:return: True if successful, False otherwise.
:rtype: bool
"""
print('*** IMAGE ACQUISITION ***\n')
try:
result = True
# Set acquisition mode to continuous
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
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...')
# Begin acquiring images
cam.BeginAcquisition()
print('Acquiring images...')
# Retrieve device serial number for filename
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 {}...'.format(device_serial_number))
print('')
# Retrieve, convert, and save images
# Create ImageProcessor instance for post processing images
processor = PySpin.ImageProcessor()
# Set default image processor color processing method
#
# *** NOTES ***
# By default, if no specific color processing algorithm is set, the image
# processor will default to NEAREST_NEIGHBOR method.
processor.SetColorProcessing(PySpin.SPINNAKER_COLOR_PROCESSING_ALGORITHM_HQ_LINEAR)
for i in range(NUM_IMAGES):
try:
# Retrieve next received image and ensure image completion
image_result = cam.GetNextImage(timeout)
if image_result.IsIncomplete():
print('Image incomplete with image status {}...'.format(image_result.GetImageStatus()))
else:
# Print image information
width = image_result.GetWidth()
height = image_result.GetHeight()
print('Grabbed image {}, width = {}, height = {}'.format(i, width, height))
# Convert image to mono 8
image_converted = processor.Convert(image_result, PySpin.PixelFormat_Mono8)
# Create a unique filename
if device_serial_number:
filename = 'Sequencer-{}-{}.jpg'.format(device_serial_number, i)
else: # if serial number is empty
filename = 'Sequencer-{}.jpg'.format(i)
# Save image
image_converted.Save(filename)
print('Image saved at {}'.format(filename))
# Release image
image_result.Release()
print('')
except PySpin.SpinnakerException as ex:
print('Error: {}'.format(ex))
return False
# End acquisition
cam.EndAcquisition()
except PySpin.SpinnakerException as ex:
print('Error: {}'.format(ex))
return False
return result
def run_single_camera(cam):
"""
This function acts very similarly to the run_single_camera() functions of other
examples, except that the values for the sequences are also calculated here;
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()
# Configure sequencer to be ready to set sequences
result &= configure_sequencer_part_one(nodemap)
if not result:
return result
# Set sequences
#
# *** NOTES ***
# In the following section, the sequencer values are calculated. This
# section does not appear in the configuration, as the values
# calculated are somewhat arbitrary: width and height are both set to
# 25% of their maximum values, incrementing by 10%; exposure time is
# set to its minimum, also incrementing by 10% of its maximum; and gain
# is set to its minimum, incrementing by 2% of its maximum.
num_sequences = 5
# Retrieve maximum width; width recorded in pixels
node_width = PySpin.CIntegerPtr(nodemap.GetNode('Width'))
if not PySpin.IsReadable(node_width):
print('Unable to retrieve maximum width. Aborting...\n')
return False
width_max = node_width.GetMax()
# Retrieve maximum height; height recorded in pixels
node_height = PySpin.CIntegerPtr(nodemap.GetNode('Height'))
if not PySpin.IsReadable(node_height):
print('Unable to retrieve maximum height. Aborting...\n')
return False
height_max = node_height.GetMax()
# Retrieve maximum exposure time; exposure time recorded in microseconds
exposure_time_max_to_set = 2000000
node_exposure_time = PySpin.CFloatPtr(nodemap.GetNode('ExposureTime'))
if not PySpin.IsReadable(node_exposure_time):
print('Unable to retrieve maximum exposure time. Aborting...\n')
return False
exposure_time_max = node_exposure_time.GetMax()
if exposure_time_max > exposure_time_max_to_set:
exposure_time_max = exposure_time_max_to_set
# Retrieve maximum gain; gain recorded in decibels
node_gain = PySpin.CFloatPtr(nodemap.GetNode('Gain'))
if not PySpin.IsReadable(node_exposure_time):
print('Unable to retrieve maximum gain. Aborting...\n')
return False
gain_max = node_gain.GetMax()
# Set initial values
width_to_set = width_max / 4
height_to_set = height_max / 4
exposure_time_to_set = node_exposure_time.GetMin()
gain_to_set = node_gain.GetMin()
# Set custom values of each sequence
for sequence_num in range(num_sequences):
result &= set_single_state(nodemap,
sequence_num,
int(width_to_set),
int(height_to_set),
exposure_time_to_set,
gain_to_set)
if not result:
return result
# Increment values
width_to_set += width_max / 10
height_to_set += height_max / 10
exposure_time_to_set += exposure_time_max / 10.0
gain_to_set += gain_max / 50.0
# Calculate appropriate acquisition grab timeout window based on exposure time
# Note: exposure_time_to_set is in microseconds and needs to be converted to milliseconds
timeout = (exposure_time_to_set / 1000) + 1000
# Configure sequencer to acquire images
result &= configure_sequencer_part_two(nodemap)
if not result:
return result
# Acquire images
result &= acquire_images(cam, nodemap, nodemap_tldevice, int(timeout))
# Reset sequencer
result &= reset_sequencer(nodemap)
# Deinitialize camera
cam.DeInit()
except PySpin.SpinnakerException as ex:
print('Error: {}'.format(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
"""
# Since this application saves images in the current folder
# we must ensure that we have permission to write to this folder.
# If we do not have permission, fail right away.
try:
test_file = open('test.txt', 'w+')
except IOError:
print('Unable to write to current directory. Please check permissions.')
input('Press Enter to exit...')
return False
test_file.close()
os.remove(test_file.name)
result = True
# Retrieve singleton reference to system object
system = PySpin.System.GetInstance()
# Get current library version
version = system.GetLibraryVersion()
print('Library version: {}.{}.{}.{}\n'.format(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: {}\n'.format(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 {}...\n'.format(i))
result &= run_single_camera(cam)
print('Camera {} example complete...\n'.format(i))
# Release reference to camera
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)