text: # coding=utf-8
  # =============================================================================
  # Copyright (c) 2001-2021 FLIR Systems, 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.
  
  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 chosen...'
  
      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.TriggerSource.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
              raw_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()
  
              # NOTE: 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
          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 = image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR)
  
                      # 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.IsAvailable(node_device_information) and 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 available.'
  
      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!'
          raw_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()
  
      raw_input('Done! Press Enter to exit...')
      return result
  
  
  if __name__ == '__main__':
      if main():
          sys.exit(0)
      else:
          sys.exit(1)
  