# 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.
# =============================================================================
#
# Inference.py shows how to perform the following:
# - Upload custom inference neural networks to the camera (DDR or Flash)
# - Inject sample test image
# - Enable/Configure chunk data
# - Enable/Configure trigger inference ready sync
# - Acquire images
# - Display inference data from acquired image chunk data
# - Disable previously configured camera configurations
#
# Inference is only available for Firefly deep learning cameras.
# See the related content section on the Firefly DL product page for relevant
# documentation.
# https://www.teledynevisionsolutions.com/products/firefly-dl/
# It can also be helpful to familiarize yourself with the Acquisition,
# ChunkData and FileAccess_QuickSpin examples.
#
# 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 numpy as np
import os
import sys
from enum import Enum
# Use the following enum and global constant to select whether inference network
# type is Detection or Classification.
class InferenceNetworkType(Enum):
# This network determines the most likely class given a set of predetermined,
# trained options. Object detection can also provide a location within the
# image (in the form of a "bounding box" surrounding the class), and can
# detect multiple objects.
DETECTION = 1
# This network determines the best option from a list of predetermined options;
# the camera gives a percentage that determines the likelihood of the currently
# perceived image being one of the classes it has been trained to recognize.
CLASSIFICATION = 2
CHOSEN_INFERENCE_NETWORK_TYPE = InferenceNetworkType.DETECTION
# Use the following enum and global constant to select whether uploaded inference
# network and injected image should be written to camera flash or DDR
class FileUploadPersistence(Enum):
FLASH = 1 # Slower upload but data persists after power cycling the camera
DDR = 2 # Faster upload but data clears after power cycling the camera
CHOSEN_FILE_UPLOAD_PERSISTENCE = FileUploadPersistence.DDR
# The example provides two existing custom networks that can be uploaded
# on to the camera to demonstrate classification and detection capabilities.
# "Network_Classification" file is created with Tensorflow using a mobilenet
# neural network for classifying flowers.
# "Network_Detection" file is created with Caffe using mobilenet SSD network
# for people object detection.
# Note: Make sure these files exist on the system and are accessible by the example
NETWORK_FILE_PATH = ("Network_Classification" if ((CHOSEN_INFERENCE_NETWORK_TYPE) \
== InferenceNetworkType.CLASSIFICATION) \
else "Network_Detection")
# The example provides two raw images that can be injected into the camera
# to demonstrate camera inference classification and detection capabilities. Jpeg
# representation of the raw images can be found packaged with the example with
# the names "Injected_Image_Classification_Daisy.jpg" and "Injected_Image_Detection_Aeroplane.jpg".
# Note: Make sure these files exist on the system and are accessible by the example
INJECTED_IMAGE_FILE_PATH = ("Injected_Image_Classification.raw" if ((CHOSEN_INFERENCE_NETWORK_TYPE) \
== InferenceNetworkType.CLASSIFICATION) \
else "Injected_Image_Detection.raw")
# The injected images have different ROI sizes so the camera needs to be
# configured to the appropriate width and height to match the injected image
INJECTED_IMAGE_WIDTH = 640 if CHOSEN_INFERENCE_NETWORK_TYPE == InferenceNetworkType.CLASSIFICATION else 720
INJECTED_IMAGE_HEIGHT = 400 if CHOSEN_INFERENCE_NETWORK_TYPE == InferenceNetworkType.CLASSIFICATION else 540
# Use the following enum to represent the inference bounding box type
class InferenceBoundingBoxType(Enum):
INFERENCE_BOX_TYPE_RECTANGLE = 0
INFERENCE_BOX_TYPE_CIRCLE = 1
INFERENCE_BOX_TYPE_ROTATED_RECTANGLE = 2
# The sample classification inference network file was trained with the following
# data set labels
# Note: This list should match the list of labels used during the training
# stage of the network file
LABEL_CLASSIFICATION = ["daisy", "dandelion", "roses", "sunflowers", "tulips"]
# The sample detection inference network file was trained with the following
# data set labels
# Note: This list should match the list of labels used during the training
# stage of the network file
LABEL_DETECTION = ["background", "aeroplane", "bicycle", "bird", "boat", "bottle", "bus",
"car", "cat", "chair", "cow", "diningtable", "dog", "horse",
"motorbike", "person", "pottedplant", "sheep", "sofa", "train", "monitor"]
# 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.
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
# This function executes a file delete operation on the camera.
def camera_delete_file(nodemap):
ptr_file_size = PySpin.CIntegerPtr(nodemap.GetNode("FileSize"))
if not PySpin.IsReadable(ptr_file_size):
print('Unable to query FileSize. Aborting...')
return False
if ptr_file_size.GetValue() == 0:
# No file uploaded yet. Skip delete
print('No files found, skipping file deletion.')
return True
print('Deleting file...')
try:
ptr_file_operation_selector = PySpin.CEnumerationPtr(nodemap.GetNode("FileOperationSelector"))
if not PySpin.IsReadable(ptr_file_operation_selector) or not PySpin.IsWritable(ptr_file_operation_selector):
print('Unable to configure FileOperationSelector. Aborting...')
return False
ptr_file_operation_delete = PySpin.CEnumEntryPtr(ptr_file_operation_selector.GetEntryByName("Delete"))
if not PySpin.IsReadable(ptr_file_operation_delete):
print('Unable to configure FileOperationSelector Delete. Aborting...')
return False
ptr_file_operation_selector.SetIntValue(int(ptr_file_operation_delete.GetNumericValue()))
ptr_file_operation_execute = PySpin.CCommandPtr(nodemap.GetNode("FileOperationExecute"))
if not PySpin.IsWritable(ptr_file_operation_execute):
print('Unable to configure FileOperationExecute. Aborting...')
return False
ptr_file_operation_execute.Execute()
ptr_file_operation_status = PySpin.CEnumerationPtr(nodemap.GetNode("FileOperationStatus"))
if not PySpin.IsReadable(ptr_file_operation_status):
print('Unable to query FileOperationStatus. Aborting...')
return False
ptr_file_operation_status_success = PySpin.CEnumEntryPtr(ptr_file_operation_status.GetEntryByName("Success"))
if not PySpin.IsReadable(ptr_file_operation_status_success):
print('Unable to query FileOperationStatus. Aborting...')
return False
if ptr_file_operation_status.GetCurrentEntry().GetNumericValue() != ptr_file_operation_status_success.GetNumericValue():
print('Failed to delete file! File Operation Status : %s' %ptr_file_operation_status.GetCurrentEntry().GetSymbolic())
return False
except PySpin.SpinnakerException as ex:
print('Unexpected exception: %s' % ex)
return False
return True
# This function executes file open/write on the camera, sets the uploaded file persistence
# and attempt to set FileAccessLength to FileAccessBufferNode length to speed up the write.
def camera_open_file(nodemap):
print('Opening file for writing...')
try:
ptr_file_operation_selector = PySpin.CEnumerationPtr(nodemap.GetNode("FileOperationSelector"))
if not PySpin.IsReadable(ptr_file_operation_selector) or not PySpin.IsWritable(ptr_file_operation_selector):
print('Unable to configure FileOperationSelector. Aborting...')
return False
ptr_file_operation_open = PySpin.CEnumEntryPtr(ptr_file_operation_selector.GetEntryByName("Open"))
if not PySpin.IsReadable(ptr_file_operation_open):
print('Unable to configure FileOperationSelector Open. Aborting...')
return False
ptr_file_operation_selector.SetIntValue(int(ptr_file_operation_open.GetNumericValue()))
ptr_file_open_mode = PySpin.CEnumerationPtr(nodemap.GetNode("FileOpenMode"))
if not PySpin.IsReadable(ptr_file_open_mode) or not PySpin.IsWritable(ptr_file_open_mode):
print('Unable to configure ptr_file_open_mode. Aborting...')
return False
ptr_file_open_mode_write = PySpin.CEnumEntryPtr(ptr_file_open_mode.GetEntryByName("Write"))
if not PySpin.IsReadable(ptr_file_open_mode_write):
print('Unable to configure FileOperationSelector Write. Aborting...')
return False
ptr_file_open_mode.SetIntValue(int(ptr_file_open_mode_write.GetNumericValue()))
ptr_file_operation_execute = PySpin.CCommandPtr(nodemap.GetNode("FileOperationExecute"))
if not PySpin.IsWritable(ptr_file_operation_execute):
print('Unable to configure FileOperationExecute. Aborting...')
return False
ptr_file_operation_execute.Execute()
ptr_file_operation_status = PySpin.CEnumerationPtr(nodemap.GetNode("FileOperationStatus"))
if not PySpin.IsReadable(ptr_file_operation_status):
print('Unable to query FileOperationStatus. Aborting...')
return False
ptr_file_operation_status_success = PySpin.CEnumEntryPtr(ptr_file_operation_status.GetEntryByName("Success"))
if not PySpin.IsReadable(ptr_file_operation_status_success):
print('Unable to query FileOperationStatus. Aborting...')
return False
if ptr_file_operation_status.GetCurrentEntry().GetNumericValue() != ptr_file_operation_status_success.GetNumericValue():
print('Failed to open file for writing! File Operation Status : %s' %ptr_file_operation_status.GetCurrentEntry().GetSymbolic())
return False
# Set file upload persistence settings
ptr_file_write_to_flash = PySpin.CBooleanPtr(nodemap.GetNode("FileWriteToFlash"))
if PySpin.IsWritable(ptr_file_write_to_flash):
if CHOSEN_FILE_UPLOAD_PERSISTENCE == FileUploadPersistence.FLASH:
ptr_file_write_to_flash.SetValue(True)
print('FileWriteToFlash is set to true')
else:
ptr_file_write_to_flash.SetValue(False)
print('FileWriteToFlash is set to false')
# Attempt to set FileAccessLength to FileAccessBufferNode length to speed up the write
ptr_file_access_length = PySpin.CIntegerPtr(nodemap.GetNode("FileAccessLength"))
if not PySpin.IsReadable(ptr_file_access_length) or not PySpin.IsWritable(ptr_file_access_length):
print('Unable to query/configure FileAccessLength. Aborting...')
return False
# Attempt to set FileAccessLength to FileAccessBufferNode length to speed up the write
ptr_file_access_buffer = PySpin.CRegisterPtr(nodemap.GetNode("FileAccessBuffer"))
if not PySpin.IsReadable(ptr_file_access_buffer):
print('Unable to query FileAccessBuffer. Aborting...')
return False
if ptr_file_access_length.GetValue() < ptr_file_access_buffer.GetLength():
try:
ptr_file_access_length.SetValue(ptr_file_access_buffer.GetLength())
except PySpin.SpinnakerException as ex:
print('Unexpected exception: %s' % ex)
# Set File Access Offset to zero
ptr_file_access_offset = PySpin.CIntegerPtr(nodemap.GetNode("FileAccessOffset"))
if not PySpin.IsWritable(ptr_file_access_offset):
print('Unable to query/configure ptrFileAccessOffset. Aborting...')
return False
ptr_file_access_offset.SetValue(0)
except PySpin.SpinnakerException as ex:
print('Unexpected exception: %s' % ex)
return False
return True
# This function executes a file write operation on the camera.
def camera_write_to_file(nodemap, offset, length):
try:
ptr_file_operation_selector = PySpin.CEnumerationPtr(nodemap.GetNode("FileOperationSelector"))
if not PySpin.IsReadable(ptr_file_operation_selector) or not PySpin.IsWritable(ptr_file_operation_selector):
print('Unable to configure FileOperationSelector. Aborting...')
return False
ptr_file_operation_write = PySpin.CEnumEntryPtr(ptr_file_operation_selector.GetEntryByName("Write"))
if not PySpin.IsReadable(ptr_file_operation_write):
print('Unable to configure FileOperationSelector Write. Aborting...')
return False
# Set Selector first, then Offset and Length
ptr_file_operation_selector.SetIntValue(int(ptr_file_operation_write.GetNumericValue()))
ptr_file_access_offset = PySpin.CIntegerPtr(nodemap.GetNode('FileAccessOffset'))
if not PySpin.IsWritable(ptr_file_access_offset):
print('Unable to query FileAccessOffset. Aborting...')
return False
ptr_file_access_offset.SetValue(offset)
ptr_file_access_length = PySpin.CIntegerPtr(nodemap.GetNode('FileAccessLength'))
if not PySpin.IsWritable(ptr_file_access_length):
print('Unable to query FileAccessLength. Aborting...')
return False
ptr_file_access_length.SetValue(length)
ptr_file_operation_execute = PySpin.CCommandPtr(nodemap.GetNode("FileOperationExecute"))
if not PySpin.IsWritable(ptr_file_operation_execute):
print('Unable to configure FileOperationExecute. Aborting...')
return False
ptr_file_operation_execute.Execute()
ptr_file_operation_status = PySpin.CEnumerationPtr(nodemap.GetNode("FileOperationStatus"))
if not PySpin.IsReadable(ptr_file_operation_status):
print('Unable to query FileOperationStatus. Aborting...')
return False
ptr_file_operation_status_success = PySpin.CEnumEntryPtr(ptr_file_operation_status.GetEntryByName("Success"))
if not PySpin.IsReadable(ptr_file_operation_status_success):
print('Unable to query FileOperationStatus Success. Aborting...')
return False
if ptr_file_operation_status.GetCurrentEntry().GetNumericValue() != ptr_file_operation_status_success.GetNumericValue():
print('Failed to write to file! File Operation Status : %s' %ptr_file_operation_status.GetCurrentEntry().GetSymbolic())
return False
except PySpin.SpinnakerException as ex:
print('Unexpected exception: %s' % ex)
return False
return True
# This function executes a file close operation on the camera.
def camera_close_file(nodemap):
print('Closing file...')
try:
ptr_file_operation_selector = PySpin.CEnumerationPtr(nodemap.GetNode("FileOperationSelector"))
if not PySpin.IsReadable(ptr_file_operation_selector) or not PySpin.IsWritable(ptr_file_operation_selector):
print('Unable to configure FileOperationSelector. Aborting...')
return False
ptr_file_operation_close = PySpin.CEnumEntryPtr(ptr_file_operation_selector.GetEntryByName("Close"))
if not PySpin.IsReadable(ptr_file_operation_close):
print('Unable to configure FileOperationSelector Close. Aborting...')
return False
ptr_file_operation_selector.SetIntValue(int(ptr_file_operation_close.GetNumericValue()))
ptr_file_operation_execute = PySpin.CCommandPtr(nodemap.GetNode("FileOperationExecute"))
if not PySpin.IsWritable(ptr_file_operation_execute):
print('Unable to configure FileOperationExecute. Aborting...')
return False
ptr_file_operation_execute.Execute()
ptr_file_operation_status = PySpin.CEnumerationPtr(nodemap.GetNode("FileOperationStatus"))
if not PySpin.IsReadable(ptr_file_operation_status):
print('Unable to query FileOperationStatus. Aborting...')
return False
ptr_file_operation_status_success = PySpin.CEnumEntryPtr(ptr_file_operation_status.GetEntryByName("Success"))
if not PySpin.IsReadable(ptr_file_operation_status_success):
print('Unable to query FileOperationStatus. Aborting...')
return False
if ptr_file_operation_status.GetCurrentEntry().GetNumericValue() != ptr_file_operation_status_success.GetNumericValue():
print('Failed to close the file! File Operation Status : %s' %ptr_file_operation_status.GetCurrentEntry().GetSymbolic())
return False
except PySpin.SpinnakerException as ex:
print('Unexpected exception: %s' % ex)
return False
return True
# This function uploads a file on the system to the camera given the selected
# file selector entry.
def upload_file_to_camera(nodemap, file_selector_entry_name, file_path):
print('\n*** CONFIGURING FILE SELECTOR ***')
ptr_file_selector = PySpin.CEnumerationPtr(nodemap.GetNode('FileSelector'))
if not PySpin.IsReadable(ptr_file_selector) or not PySpin.IsWritable(ptr_file_selector):
print('Unable to configure FileSelector. Aborting...')
return False
ptr_inference_selector_entry = PySpin.CEnumEntryPtr(ptr_file_selector.GetEntryByName(file_selector_entry_name))
if not PySpin.IsReadable(ptr_inference_selector_entry):
print('Unable to query FileSelector entry %s ' %file_selector_entry_name + '. Aborting...')
return False
# Set file selector to entry
print('Setting FileSelector to %s ' %ptr_inference_selector_entry.GetSymbolic() + '...\n')
ptr_file_selector.SetIntValue(int(ptr_inference_selector_entry.GetNumericValue()))
# Delete file on camera before writing in case camera runs out of space
if camera_delete_file(nodemap) != True:
print('Failed to delete existing file for selector entry %s' %ptr_inference_selector_entry.GetSymbolic() + '. Aborting...')
return False
# Open file on camera for write
if camera_open_file(nodemap) != True:
if not camera_close_file(nodemap):
print('Problem opening file node. Aborting...')
return False
if not camera_open_file(nodemap):
print('Problem opening file node. Aborting...')
return False
# check node
ptr_file_access_length = PySpin.CIntegerPtr(nodemap.GetNode('FileAccessLength'))
if not PySpin.IsReadable(ptr_file_access_length) or not PySpin.IsWritable(ptr_file_access_length):
print('Unable to query FileAccessLength. Aborting...')
return False
ptr_file_access_buffer = PySpin.CRegisterPtr(nodemap.GetNode('FileAccessBuffer'))
if not PySpin.IsWritable(ptr_file_access_buffer):
print('Unable to query FileAccessBuffer. Aborting...')
return False
ptr_file_access_offset = PySpin.CIntegerPtr(nodemap.GetNode('FileAccessOffset'))
if not PySpin.IsReadable(ptr_file_access_offset) or not PySpin.IsWritable(ptr_file_access_offset):
print('Unable to query FileAccessOffset. Aborting...')
return False
ptr_file_access_result = PySpin.CIntegerPtr(nodemap.GetNode('FileOperationResult'))
if not PySpin.IsReadable(ptr_file_access_result):
print('Unable to query FileOperationResult. Aborting...')
return False
# Load network file from path depending on network type
with open(file_path, 'rb') as fd:
fd.seek(0, os.SEEK_END)
num_bytes = fd.tell()
fd.seek(0,0)
file_bytes = np.fromfile(fd, dtype=np.ubyte, count=num_bytes)
if len(file_bytes) == 0:
print('Failed to load file path : %s' %file_path + '. Aborting...')
return False
total_bytes_to_write = len(file_bytes)
intermediate_buffer_size = ptr_file_access_length.GetValue()
write_iterations = (total_bytes_to_write // intermediate_buffer_size) + \
(0 if ((total_bytes_to_write % intermediate_buffer_size) == 0) else 1)
if total_bytes_to_write == 0:
print('Empty Image. No data will be written to camera. Aborting...')
return False
print('Start uploading %s' %file_path + ' to device...')
print('Total bytes to write: %s' % total_bytes_to_write)
print('FileAccessLength: %s' % intermediate_buffer_size)
print('Write iterations: %s' % write_iterations)
bytes_left_to_write = total_bytes_to_write
total_bytes_written = 0
print('Writing data to device...')
# Splitting the file into equal chunks (except the last chunk)
sections = []
for index in range(write_iterations):
num = index * intermediate_buffer_size
if num == 0:
continue
sections.append(num)
split_data = np.array_split(file_bytes, sections)
# Writing split data to camera
for i in range(write_iterations):
# Set up data to write
tmp_buffer = split_data[i]
# Write to AccessBufferNode
ptr_file_access_buffer.Set(tmp_buffer)
# Perform Write command
requested_length = intermediate_buffer_size if intermediate_buffer_size <= bytes_left_to_write else bytes_left_to_write
if not camera_write_to_file(nodemap, total_bytes_written, requested_length):
print('Writing to stream failed. Aborting...')
return False
# Verify size of bytes written
size_written = ptr_file_access_result.GetValue()
# Fallback: If hardware returns 0, but status was success and we have data left,
# assume the requested block was written. This handles cameras that don't reliably update ResultNode.
if size_written == 0 and bytes_left_to_write > 0:
size_written = requested_length
print("Write returned 0 bytes at offset {0}. Falling back to assumed length: {1}".format(total_bytes_written, size_written))
# Clamp: Ensure size_written does not cause total_bytes_written to exceed total_bytes_to_write
if total_bytes_written + size_written > total_bytes_to_write:
size_written = total_bytes_to_write - total_bytes_written
# Keep track of total bytes written
total_bytes_written += size_written
# Keep track of bytes left to write
bytes_left_to_write = total_bytes_to_write - total_bytes_written
sys.stdout.write('\r')
sys.stdout.write('Progress: %s' % int((i * 100 / write_iterations)) + '%')
sys.stdout.flush()
print('\nWriting complete')
# Validate upload completion
if total_bytes_written < total_bytes_to_write:
print("Incomplete upload. Wrote {0} bytes to device, but expected {1}.".format(total_bytes_written, total_bytes_to_write))
return False
if not camera_close_file(nodemap):
print('Failed to close file!')
return True
# This function deletes the file uploaded to the camera given the selected
# file selector entry.
def delete_file_on_camera(nodemap, file_selector_entry_name):
print('\n*** CLEANING UP FILE SELECTOR **')
ptr_file_selector = PySpin.CEnumerationPtr(nodemap.GetNode("FileSelector"))
if not PySpin.IsReadable(ptr_file_selector) or not PySpin.IsWritable(ptr_file_selector):
print('Unable to configure FileSelector. Aborting...')
return False
ptr_inference_selector_entry = PySpin.CEnumEntryPtr(ptr_file_selector.GetEntryByName(file_selector_entry_name))
if not PySpin.IsReadable(ptr_inference_selector_entry):
print('Unable to query FileSelector entry ' + file_selector_entry_name + '. Aborting...')
return False
# Set file Selector entry
print('Setting FileSelector to %s ' %ptr_inference_selector_entry.GetSymbolic() + '...\n')
ptr_file_selector.SetIntValue(int(ptr_inference_selector_entry.GetNumericValue()))
if camera_delete_file(nodemap) != True:
print('Failed to delete existing file for selector entry')
return False
return True
# This function enables or disables the given chunk data type based on
# the specified entry name.
def set_chunk_enable(nodemap, entry_name, enable):
result = True
ptr_chunk_selector = PySpin.CEnumerationPtr(nodemap.GetNode("ChunkSelector"))
ptr_entry = PySpin.CEnumEntryPtr(ptr_chunk_selector.GetEntryByName(entry_name))
if not PySpin.IsReadable(ptr_entry):
print('Unable to find ' + entry_name + ' in ChunkSelector...')
return False
ptr_chunk_selector.SetIntValue(ptr_entry.GetValue())
# Enable the boolean, thus enabling the corresponding chunk data
print('Enabling ' + entry_name + '...')
ptr_chunk_enable = PySpin.CBooleanPtr(nodemap.GetNode("ChunkEnable"))
if not PySpin.IsAvailable(ptr_chunk_enable):
print('not available')
return False
if enable:
if ptr_chunk_enable.GetValue():
print('enabled')
elif PySpin.IsWritable(ptr_chunk_enable):
ptr_chunk_enable.SetValue(True)
print('enabled')
else:
print('not writable')
result = False
else:
if not ptr_chunk_enable.GetValue():
print('disabled')
elif PySpin.IsWritable(ptr_chunk_enable):
ptr_chunk_enable.SetValue(False)
print('disabled')
else:
print('not writable')
result = False
return result
# This function configures the camera to add inference chunk data to each image.
# When chunk data is turned on, the data is made available in both the nodemap
# and each image.
def configure_chunk_data(nodemap):
result = True
print('\n*** CONFIGURING CHUNK DATA ***')
try:
# Activate chunk mode
#
# *** NOTES ***
# Once enabled, chunk data will be available at the end of the payload
# of every image captured until it is disabled. Chunk data can also be
# retrieved from the nodemap.
ptr_chunk_mode_active = PySpin.CBooleanPtr(nodemap.GetNode("ChunkModeActive"))
if not PySpin.IsWritable(ptr_chunk_mode_active):
print('Unable to active chunk mode. Aborting...')
return False
ptr_chunk_mode_active.SetValue(True)
print('Chunk mode activated...')
# Enable inference related chunks in chunk data
# Retrieve the chunk data selector node
ptr_chunk_selector = PySpin.CEnumerationPtr(nodemap.GetNode("ChunkSelector"))
if not PySpin.IsReadable(ptr_chunk_selector):
print('Unable to retrieve chunk selector (enum retrieval). Aborting...')
return False
# Enable chunk data inference Frame Id
result = set_chunk_enable(nodemap, "InferenceFrameId", True)
if result == False:
print("Unable to enable Inference Frame Id chunk data. Aborting...")
return result
if CHOSEN_INFERENCE_NETWORK_TYPE == InferenceNetworkType.DETECTION:
# Detection network type
# Enable chunk data inference bounding box
result = set_chunk_enable(nodemap, "InferenceBoundingBoxResult", True)
if result == False:
print("Unable to enable Inference Bounding Box chunk data. Aborting...")
return result
else:
# Enable chunk data inference result
result = set_chunk_enable(nodemap, "InferenceResult", True)
if result == False:
print("Unable to enable Inference Result chunk data. Aborting...")
return result
# Enable chunk data inference confidence
result = set_chunk_enable(nodemap, "InferenceConfidence", True)
if result == False:
print("Unable to enable Inference Confidence chunk data. Aborting...")
return result
except PySpin.SpinnakerException as ex:
print('Unexpected exception: %s' % ex)
return False
return result
# This function disables each type of chunk data before disabling chunk data mode.
def disable_chunk_data(nodemap):
print('\n*** DISABLING CHUNK DATA ***')
result = True
try:
ptr_chunk_selector = PySpin.CEnumerationPtr(nodemap.GetNode("ChunkSelector"))
if not PySpin.IsReadable(ptr_chunk_selector):
print('Unable to retrieve chunk selector. Aborting...')
return False
result = set_chunk_enable(nodemap, "InferenceFrameId", False)
if result == False:
print('Unable to disable Inference Frame Id chunk data. Aborting...')
return result
if CHOSEN_INFERENCE_NETWORK_TYPE == InferenceNetworkType.DETECTION:
# Detection network type
# Disable chunk data inference bounding box
result = set_chunk_enable(nodemap, "InferenceBoundingBoxResult", False)
if result == False:
print('Unable to disable Inference Bounding Box chunk data. Aborting...')
return result
else:
# Classification network type
# Disable chunk data inference result
result = set_chunk_enable(nodemap, "InferenceResult", False)
if result == False:
print('Unable to disable Inference Result chunk data. Aborting...')
return result
# Disable chunk data inference confidence
result = set_chunk_enable(nodemap, "InferenceConfidence", False)
if result == False:
print('Unable to disable Inference Confidence chunk data. Aborting...')
return result
# Deactivate ChunkMode
ptr_chunk_mode_active = PySpin.CBooleanPtr(nodemap.GetNode("ChunkModeActive"))
if not PySpin.IsWritable(ptr_chunk_mode_active):
print('Unable to deactivate chunk mode. Aborting...')
return False
ptr_chunk_mode_active.SetValue(False)
print('Chunk mode deactivated...')
# Disable Inference
ptr_inference_enable = PySpin.CBooleanPtr(nodemap.GetNode("InferenceEnable"))
if not PySpin.IsWritable(ptr_inference_enable):
print('Unable to disable inference. Aborting...')
return False
ptr_inference_enable.SetValue(False)
print('Inference disabled...')
except PySpin.SpinnakerException as ex:
print('Unexpected exception: %s' % ex)
return False
return result
# This function displays the inference-related chunk data from the image.
def display_chunk_data(image):
result = True
print('Printing chunk data from image...')
try:
chunk_data = image.GetChunkData()
inference_frame_ID = chunk_data.GetInferenceFrameId()
print('\tInference Frame ID: %s' % inference_frame_ID)
if CHOSEN_INFERENCE_NETWORK_TYPE == InferenceNetworkType.DETECTION:
box_result = chunk_data.GetInferenceBoundingBoxResult()
box_count = box_result.GetBoxCount()
print('\tInference Bounding Box Result:')
if box_count == 0:
print('\t No bounding box')
for i in range(box_count):
box = box_result.GetBoxAt(i)
if box.boxType == InferenceBoundingBoxType.INFERENCE_BOX_TYPE_RECTANGLE.value:
print('\t\tBox {0}: Class {1} ({2}): - {3:.4f}% - {4} (X={5} Y={6} W={7} H={8})'
.format(i+1,
box.classId,
LABEL_DETECTION[box.classId] if box.classId < len(LABEL_DETECTION) else "N/A",
box.confidence * 100,
"Rectangle",
box.rect.topLeftXCoord,
box.rect.topLeftYCoord,
box.rect.bottomRightXCoord - box.rect.topLeftXCoord,
box.rect.bottomRightYCoord - box.rect.topLeftYCoord))
elif box.boxType == InferenceBoundingBoxType.INFERENCE_BOX_TYPE_CIRCLE.value:
print('\t\tBox {0}: Class {1} ({2}): - {3:.4f}% - {4} (X={5} Y={6} R={7})'
.format(i+1,
box.classId,
LABEL_DETECTION[box.classId] if box.classId < len(LABEL_DETECTION) else "N/A",
box.confidence * 100,
"Circle",
box.rect.topLeftXCoord,
box.rect.topLeftYCoord,
box.circle.radius))
elif box.boxType == InferenceBoundingBoxType.INFERENCE_BOX_TYPE_ROTATED_RECTANGLE.value:
print('\t\tBox {0}: Class {1} ({2}): - {3:.4f}% - {4} (X1={5} Y1={6} X2={7} Y2={8} angle={9})'
.format(i+1,
box.classId,
LABEL_DETECTION[box.classId] if box.classId < len(LABEL_DETECTION) else "N/A",
box.confidence * 100,
"Rotated Rectangle",
box.rotatedRect.topLeftXCoord,
box.rotatedRect.topLeftYCoord,
box.rotatedRect.bottomRightXCoord,
box.rotatedRect.bottomRightYCoord,
box.rotatedRect.rotationAngle))
else:
print('\t\tBox {0}: Class {1} ({2}): - {3:.4f}% - {4})'
.format(i+1,
box.classId,
LABEL_DETECTION[box.classId] if box.classId < len(LABEL_DETECTION) else "N/A",
box.confidence * 100,
"Unknown bounding box type (not supported)"))
else:
inference_result = chunk_data.GetInferenceResult()
print('\t Inference Result: %s' %inference_result, end = '')
print(' (%s)' % LABEL_CLASSIFICATION[inference_result] if inference_result < len(LABEL_CLASSIFICATION) else "N/A")
inference_confidence = chunk_data.GetInferenceConfidence()
print('\t Inference Confidence: %.6f' %inference_confidence)
except PySpin.SpinnakerException as ex:
print('Unexpected exception: %s' % ex)
return False
return result
# This function disables trigger mode on the camera.
def disable_trigger(nodemap):
print('\n*** IMAGE ACQUISITION ***')
try:
ptr_trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode("TriggerMode"))
if not PySpin.IsReadable(ptr_trigger_mode) or not PySpin.IsWritable(ptr_trigger_mode):
print('Unable to configure TriggerMode. Aborting...')
return False
ptr_trigger_off = PySpin.CEnumEntryPtr(ptr_trigger_mode.GetEntryByName("Off"))
if not PySpin.IsReadable(ptr_trigger_off):
print('Unable to query TriggerMode Off. Aborting...')
return False
print('Configure TriggerMode to ' + ptr_trigger_off.GetSymbolic())
ptr_trigger_mode.SetIntValue(int(ptr_trigger_off.GetNumericValue()))
except PySpin.SpinnakerException as ex:
print('Unexpected exception: %s' % ex)
return False
return True
# This function configures camera to run in "inference sync" trigger mode.
def configure_trigger(nodemap):
print('\n*** CONFIGURING TRIGGER ***')
try:
# Configure TriggerSelector
ptr_trigger_selector = PySpin.CEnumerationPtr(nodemap.GetNode("TriggerSelector"))
if not PySpin.IsReadable(ptr_trigger_selector) or not PySpin.IsWritable(ptr_trigger_selector):
print('Unable to configure TriggerSelector. Aborting...')
return False
ptr_frame_start = PySpin.CEnumEntryPtr(ptr_trigger_selector.GetEntryByName("FrameStart"))
if not PySpin.IsReadable(ptr_frame_start):
print('Unable to query TriggerSelector FrameStart. Aborting...')
return False
print('Configure TriggerSelector to ' + ptr_frame_start.GetSymbolic())
ptr_trigger_selector.SetIntValue(int(ptr_frame_start.GetNumericValue()))
# Configure TriggerSource
ptr_trigger_source = PySpin.CEnumerationPtr(nodemap.GetNode("TriggerSource"))
if not PySpin.IsReadable(ptr_trigger_source) or not PySpin.IsWritable(ptr_trigger_source):
print('Unable to configure TriggerSource. Aborting...')
return False
ptr_inference_ready = PySpin.CEnumEntryPtr(ptr_trigger_source.GetEntryByName("InferenceReady"))
if not PySpin.IsReadable(ptr_inference_ready):
print('Unable to query TriggerSource InferenceReady. Aborting...')
return False
print('Configure TriggerSource to ' + ptr_inference_ready.GetSymbolic())
ptr_trigger_source.SetIntValue(int(ptr_inference_ready.GetNumericValue()))
# Configure TriggerMode
ptr_trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode("TriggerMode"))
if not PySpin.IsReadable(ptr_trigger_mode) or not PySpin.IsWritable(ptr_trigger_mode):
print('Unable to configure TriggerMode. Aborting...')
return False
ptr_trigger_on = PySpin.CEnumEntryPtr(ptr_trigger_mode.GetEntryByName("On"))
if not PySpin.IsReadable(ptr_trigger_on):
print('Unable to query TriggerMode On. Aborting...')
return False
print('Configure TriggerMode to ' + ptr_trigger_on.GetSymbolic())
ptr_trigger_mode.SetIntValue(int(ptr_trigger_on.GetNumericValue()))
except PySpin.SpinnakerException as ex:
print('Unexpected exception: %s' % ex)
return False
return True
# This function enables/disables inference on the camera and configures the inference network type
def configure_inference(nodemap, is_enabled):
if is_enabled:
print('\n*** CONFIGURING INFERENCE (' + ("DETECTION" if ((CHOSEN_INFERENCE_NETWORK_TYPE) \
== InferenceNetworkType.DETECTION) \
else 'CLASSIFICATION') + ') ***')
else:
print('\n*** DISABLING INFERENCE ***')
try:
if is_enabled:
ptr_inference_network_type_selector = PySpin.CEnumerationPtr(nodemap.GetNode("InferenceNetworkTypeSelector"))
if not PySpin.IsReadable(ptr_inference_network_type_selector) or not PySpin.IsWritable(ptr_inference_network_type_selector):
print('Unable to query InferenceNetworkTypeSelector. Aborting...')
return False
network_type_string = ("Detection" if CHOSEN_INFERENCE_NETWORK_TYPE == InferenceNetworkType.DETECTION
else "Classification")
# Retrieve entry node from enumeration node
ptr_inference_network_type = PySpin.CEnumEntryPtr(ptr_inference_network_type_selector.GetEntryByName(network_type_string))
if not PySpin.IsReadable(ptr_inference_network_type):
print('Unable to set inference network type to %s' %network_type_string + ' (entry retrieval). Aborting...')
return False
inference_network_value = ptr_inference_network_type.GetNumericValue()
ptr_inference_network_type_selector.SetIntValue(int(inference_network_value))
print('Inference network type set to' + network_type_string + '...')
print(('Enabling' if is_enabled else 'Disabling') + ' inference...')
ptr_inference_enable = PySpin.CBooleanPtr(nodemap.GetNode("InferenceEnable"))
if not PySpin.IsWritable(ptr_inference_enable):
print('Unable to enable inference. Aborting...')
return False
ptr_inference_enable.SetValue(is_enabled)
print('Inference '+'enabled...' if is_enabled else 'disabled...')
except PySpin.SpinnakerException as ex:
print('Unexpected exception: %s' % ex)
return False
return True
# This function configures camera test pattern to make use of the injected test image for inference
def configure_test_pattern(nodemap, is_enabled):
if is_enabled:
print('\n*** CONFIGURING TEST PATTERN ***')
else:
print('\n*** DISABLING TEST PATTERN ***')
try:
# Set TestPatternGeneratorSelector to PipelineStart
ptr_test_pattern_generator_selector = PySpin.CEnumerationPtr(nodemap.GetNode("TestPatternGeneratorSelector"))
if not PySpin.IsWritable(ptr_test_pattern_generator_selector):
print('Unable to query TestPatternGeneratorSelector. Aborting...')
return False
if is_enabled:
ptr_test_pattern_generator_pipeline_start = PySpin.CEnumEntryPtr(ptr_test_pattern_generator_selector.GetEntryByName("PipelineStart"))
if not PySpin.IsReadable(ptr_test_pattern_generator_pipeline_start):
print('Unable to query TestPatternGeneratorSelector PipelineStart. Aborting...')
return False
ptr_test_pattern_generator_selector.SetIntValue(int(ptr_test_pattern_generator_pipeline_start.GetNumericValue()))
print('TestPatternGeneratorSelector set to ' + ptr_test_pattern_generator_pipeline_start.GetSymbolic() + '...')
else:
ptr_test_pattern_generator_sensor = PySpin.CEnumEntryPtr(ptr_test_pattern_generator_selector.GetEntryByName("Sensor"))
if not PySpin.IsReadable(ptr_test_pattern_generator_sensor):
print('Unable to query TestPatternGeneratorSelector Sensor. Aborting...')
return False
ptr_test_pattern_generator_selector.SetIntValue(int(ptr_test_pattern_generator_sensor.GetNumericValue()))
print('TestPatternGeneratorSelector set to ' + ptr_test_pattern_generator_sensor.GetSymbolic() + '...')
# Set TestPattern to InjectedImage
ptr_test_pattern = PySpin.CEnumerationPtr(nodemap.GetNode("TestPattern"))
if not PySpin.IsReadable(ptr_test_pattern) or not PySpin.IsWritable(ptr_test_pattern):
print('Unable to query TestPattern. Aborting...')
return False
if is_enabled:
ptr_injected_image = PySpin.CEnumEntryPtr(ptr_test_pattern.GetEntryByName("InjectedImage"))
if not PySpin.IsReadable(ptr_injected_image):
print('Unable to query TestPattern InjectedImage. Aborting...')
return False
ptr_test_pattern.SetIntValue(int(ptr_injected_image.GetNumericValue()))
print('TestPattern set to ' + ptr_injected_image.GetSymbolic() + '...')
else:
ptr_test_pattern_off = PySpin.CEnumEntryPtr(ptr_test_pattern.GetEntryByName("Off"))
if not PySpin.IsReadable(ptr_test_pattern_off):
print('Unable to query TestPattern Off. Aborting...')
return False
ptr_test_pattern.SetIntValue(int(ptr_test_pattern_off.GetNumericValue()))
print('TestPattern set to ' + ptr_test_pattern_off.GetSymbolic() + '...')
if is_enabled:
# The inject images have different ROI sizes so camera needs to be configured to the appropriate
# injected width and height
ptr_injected_width = PySpin.CIntegerPtr(nodemap.GetNode("InjectedWidth"))
if not PySpin.IsWritable(ptr_injected_width):
print('Unable to query InjectedWidth. Aborting...')
return False
ptr_injected_width.SetValue(INJECTED_IMAGE_WIDTH if is_enabled else ptr_injected_width.GetMax())
ptr_injected_height = PySpin.CIntegerPtr(nodemap.GetNode("InjectedHeight"))
if not PySpin.IsWritable(ptr_injected_height):
print('Unable to query InjectedHeight. Aborting...')
return False
ptr_injected_height.SetValue(INJECTED_IMAGE_HEIGHT if is_enabled else ptr_injected_height.GetMax())
except PySpin.SpinnakerException as ex:
print('Unexpected exception: %s' % ex)
return False
return True
# This function acquires and saves 10 images from a device; please see
# Acquisition example for more in-depth comments on acquiring images.
def acquire_images(cam, nodemap, nodemap_tldevice):
result = True
print('\n*** IMAGE ACQUISITION ***')
try:
# Set acquisition mode to continuous
ptr_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode("AcquisitionMode"))
if not PySpin.IsReadable(ptr_acquisition_mode) or not PySpin.IsWritable(ptr_acquisition_mode):
print('Unable to set acquisition mode to continuous (node retrieval). Aborting...')
return False
ptr_acquisition_mode_continuous = PySpin.CEnumEntryPtr(ptr_acquisition_mode.GetEntryByName("Continuous"))
if not PySpin.IsReadable(ptr_acquisition_mode_continuous):
print("'Unable to set acquisition mode to continuous (entry 'continuous' retrieval). Aborting...")
return False
acquisition_mode_continuous = ptr_acquisition_mode_continuous.GetValue()
ptr_acquisition_mode.SetIntValue(int(acquisition_mode_continuous))
# Begin acquiring images
cam.BeginAcquisition()
print('Acquiring images...')
ptr_string_serial = PySpin.CStringPtr(nodemap.GetNode("DeviceSerialNumber"))
if PySpin.IsReadable(ptr_string_serial):
device_serial_number = ptr_string_serial.GetValue()
print('Device serial number retrieved as %s' %device_serial_number)
print('\n')
# Retrieve and display image chunk information
num_images = 10
for i in range(num_images):
try:
result_image = cam.GetNextImage(1000)
if result_image.IsIncomplete():
print('Image incomplete with image status %d ...' % result_image.GetImageStatus())
else:
print('Grabbed Image %d, width = %d, height = %d' \
% (i, result_image.GetWidth(), result_image.GetHeight()))
result = display_chunk_data(result_image)
# Release image
result_image.Release()
print('')
except PySpin.SpinnakerException as ex:
print('Unexpected exception: %s' % ex)
result = False
cam.EndAcquisition()
except PySpin.SpinnakerException as ex:
print('Unexpected exception: %s' % ex)
return False
return result
# This function acts as the body of the example; please see NodeMapInfo example
# for more in-depth comments on setting up cameras.
def run_single_camera(cam):
result = False
err = 0
try:
nodemap_tldevice = cam.GetTLDeviceNodeMap()
result = print_device_info(nodemap_tldevice)
cam.Init()
nodemap = cam.GetNodeMap()
# Check to make sure camera supports inference
print('Checking camera inference support...')
ptr_inference_enable = PySpin.CBooleanPtr(nodemap.GetNode('InferenceEnable'))
if not PySpin.IsWritable(ptr_inference_enable):
print('Inference is not supported on this camera. Aborting...')
return False
# Upload custom inference network onto the camera
# The inference network file is in a movidius specific neural network format.
# Uploading the network to the camera allows for "inference on the edge" where
# camera can apply deep learning on a live stream. Refer to "Getting Started
# with Firefly-DL" for information on how to create your own custom inference
# network files using pre-existing neural network.
err = upload_file_to_camera(nodemap, "InferenceNetwork", NETWORK_FILE_PATH)
if err != True:
return err
# Upload injected test image
# Instead of applying deep learning on a live stream, the camera can be
# tested with an injected test image.
err = upload_file_to_camera(nodemap, "InjectedImage", INJECTED_IMAGE_FILE_PATH)
if err != True:
return err
# Configure inference
err = configure_inference(nodemap, True)
if err != True:
return err
# Configure test pattern to make use of the injected image
err = configure_test_pattern(nodemap, True)
if err != True:
return err
# Configure trigger
# When enabling inference results via chunk data, the results that accompany a frame
# will likely not be the frame that inference was run on. In order to guarantee that
# the chunk inference results always correspond to the frame that they are sent with,
# the camera needs to be put into the "inference sync" trigger mode.
# Note: Enabling this setting will limit frame rate so that every frame contains new
# inference dataset. To not limit the frame rate, you can enable InferenceFrameID
# chunk data to help determine which frame is associated with a particular
# inference data.
err = configure_trigger(nodemap)
if err != True:
return err
# Configure chunk data
err = configure_chunk_data(nodemap)
if err != True:
return err
# Acquire images and display chunk data
result = result | acquire_images(cam, nodemap, nodemap_tldevice)
# Disable chunk data
err = disable_chunk_data(nodemap)
if err != True:
return err
# Disable trigger
err = disable_trigger(nodemap)
if err != True:
return err
# Disable test pattern
err = configure_test_pattern(nodemap, False)
if err != True:
return err
# Disable inference
err = configure_inference(nodemap, False)
if err != True:
return err
# Clear injected test image
err = delete_file_on_camera(nodemap, "InjectedImage")
if err != True:
return err
# Clear uploaded inference network
err = delete_file_on_camera(nodemap, "InferenceNetwork")
if err != True:
return err
# Deinitialize camera
cam.DeInit()
except PySpin.SpinnakerException as ex:
print('Unexpected exception: %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
"""
# 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 = False
# 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: %s\n' % num_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
for i, cam in enumerate(cam_list):
print('Running example for camera %d...' % i)
result = 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)