Trigger_QuickSpin
# 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.
# =============================================================================
#
# Trigger_QuickSpin.py shows how to capture images with the
# trigger using the QuickSpin API. QuickSpin is a subset of the Spinnaker
# library that allows for simpler node access and control.
#
# This example demonstrates how to prepare, execute, and clean up the camera
# in regards to using both software and hardware triggers. Retrieving and
# setting node values using QuickSpin is the only portion of the example
# that differs from Trigger.
#
# A much wider range of topics is covered in the full Spinnaker examples than
# in the QuickSpin ones. There are only enough QuickSpin examples to
# demonstrate node access and to get started with the API; please see full
# Spinnaker examples for further or specific knowledge on a topic.
#
# 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 PySpin
import sys
NUM_IMAGES = 10 # number of images to grab
class TriggerType:
SOFTWARE = 1
HARDWARE = 2
CHOSEN_TRIGGER = TriggerType.SOFTWARE
def configure_trigger(cam):
"""
This function configures the camera to use a trigger. First, trigger mode is
ensured to be off in order to select the trigger source. 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
"""
print('*** CONFIGURING TRIGGER ***\n')
print('Note that if the application / user software triggers faster than frame time, the trigger may be dropped / skipped by the camera.\n')
print('If several frames are needed per trigger, a more reliable alternative for such case, is to use the multi-frame mode.\n\n')
if CHOSEN_TRIGGER == TriggerType.SOFTWARE:
print('Software trigger chosen...')
elif CHOSEN_TRIGGER == TriggerType.HARDWARE:
print('Hardware trigger chose...')
try:
result = True
# Ensure trigger mode off
# The trigger must be disabled in order to configure whether the source
# is software or hardware.
if cam.TriggerMode.GetAccessMode() != PySpin.RW:
print('Unable to disable trigger mode (node retrieval). Aborting...')
return False
cam.TriggerMode.SetValue(PySpin.TriggerMode_Off)
print('Trigger mode disabled...')
# Set TriggerSelector to FrameStart
# For this example, the trigger selector should be set to frame start.
# This is the default for most cameras.
if cam.TriggerSelector.GetAccessMode() != PySpin.RW:
print('Unable to get trigger selector (node retrieval). Aborting...')
return False
cam.TriggerSelector.SetValue(PySpin.TriggerSelector_FrameStart)
print('Trigger selector set to frame start...')
# Select trigger source
# The trigger source must be set to hardware or software while trigger
# mode is off.
if cam.TriggerSource.GetAccessMode() != PySpin.RW:
print('Unable to get trigger source (node retrieval). Aborting...')
return False
if CHOSEN_TRIGGER == TriggerType.SOFTWARE:
cam.TriggerSource.SetValue(PySpin.TriggerSource_Software)
print('Trigger source set to software...')
elif CHOSEN_TRIGGER == TriggerType.HARDWARE:
cam.TriggerSource.SetValue(PySpin.TriggerSource_Line0)
print('Trigger source set to hardware...')
# Turn trigger mode on
# Once the appropriate trigger source has been set, turn trigger mode
# on in order to retrieve images using the trigger.
cam.TriggerMode.SetValue(PySpin.TriggerMode_On)
print('Trigger mode turned back on...')
except PySpin.SpinnakerException as ex:
print('Error: %s' % ex)
return False
return result
def grab_next_image_by_trigger(cam):
"""
This function acquires an image by executing the trigger node.
:param cam: Camera to acquire images from.
:type cam: CameraPtr
:return: True if successful, False otherwise.
:rtype: bool
"""
try:
result = True
# Use trigger to capture image
# The software trigger only feigns being executed by the Enter key;
# what might not be immediately apparent is that there is not a
# continuous stream of images being captured; in other examples that
# acquire images, the camera captures a continuous stream of images.
# When an image is retrieved, it is plucked from the stream.
if CHOSEN_TRIGGER == TriggerType.SOFTWARE:
# Get user input
input('Press the Enter key to initiate software trigger.')
# Execute software trigger
if cam.TriggerSoftware.GetAccessMode() != PySpin.WO:
print('Unable to execute trigger. Aborting...')
return False
cam.TriggerSoftware.Execute()
# TODO: Blackfly and Flea3 GEV cameras need 2 second delay after software trigger
elif CHOSEN_TRIGGER == TriggerType.HARDWARE:
print('Use the hardware to trigger image acquisition.')
except PySpin.SpinnakerException as ex:
print('Error: %s' % ex)
return False
return result
def acquire_images(cam):
"""
This function acquires and saves 10 images from a device.
Please see Acquisition example for more in-depth comments on acquiring images.
:param cam: Camera to acquire images from.
:type cam: CameraPtr
:return: True if successful, False otherwise.
:rtype: bool
"""
print('*** IMAGE ACQUISITION ***\n')
try:
result = True
# Set acquisition mode to continuous
if cam.AcquisitionMode.GetAccessMode() != PySpin.RW:
print('Unable to set acquisition mode to continuous. Aborting...')
return False
cam.AcquisitionMode.SetValue(PySpin.AcquisitionMode_Continuous)
print('Acquisition mode set to continuous...')
# Begin acquiring images
cam.BeginAcquisition()
print('Acquiring images...')
# Get device serial number for filename
device_serial_number = ''
if cam.TLDevice.DeviceSerialNumber.GetAccessMode() == PySpin.RO:
device_serial_number = cam.TLDevice.DeviceSerialNumber.GetValue()
print('Device serial number retrieved as %s...' % device_serial_number)
# 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 the next image from the trigger
result &= grab_next_image_by_trigger(cam)
# Retrieve next received image
image_result = cam.GetNextImage(1000)
# Ensure image completion
if image_result.IsIncomplete():
print('Image incomplete with image status %d ...' % image_result.GetImageStatus())
else:
# Print image information
width = image_result.GetWidth()
height = image_result.GetHeight()
print('Grabbed Image %d, width = %d, height = %d' % (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 = 'Trigger-%s-%d.jpg' % (device_serial_number, i)
else: # if serial number is empty
filename = 'Trigger-%d.jpg' % i
# Save image
image_converted.Save(filename)
print('Image saved at %s\n' % filename)
# Release image
image_result.Release()
except PySpin.SpinnakerException as ex:
print('Error: %s' % ex)
return False
# End acquisition
cam.EndAcquisition()
except PySpin.SpinnakerException as ex:
print('Error: %s' % ex)
return False
return result
def reset_trigger(cam):
"""
This function returns the camera to a normal state by turning off trigger mode.
:param cam: Camera to acquire images from.
:type cam: CameraPtr
:returns: True if successful, False otherwise.
:rtype: bool
"""
try:
result = True
# Ensure trigger mode off
# The trigger must be disabled in order to configure whether the source
# is software or hardware.
if cam.TriggerMode.GetAccessMode() != PySpin.RW:
print('Unable to disable trigger mode (node retrieval). Aborting...')
return False
cam.TriggerMode.SetValue(PySpin.TriggerMode_Off)
print('Trigger mode disabled...')
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
err = False
# 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 trigger
if configure_trigger(cam) is False:
return False
# Acquire images
result &= acquire_images(cam)
# Reset trigger
result &= reset_trigger(cam)
# 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)