diff --git a/FLIR/DavidsReadme.txt b/FLIR/DavidsReadme.txt index 3e57f8c..1b8fbf9 100644 --- a/FLIR/DavidsReadme.txt +++ b/FLIR/DavidsReadme.txt @@ -1,4 +1,5 @@ Since it was less than 100mb, I copied the entire python SDK here. You must have it locally installed to be able to run it from here! The OneNote has instructions on how to install. Dont use their install guide! -FLIRcodev3.0 is the first version I released. It is stable on the software end but the hardware end is untested. v3.1 is the hardware testing end. \ No newline at end of file +FLIRcodev3.0 is the first version I released. It is stable on the software end but the hardware end is untested. v3.1 is the hardware testing end. +v3.3 is a rewriting of 3.2 code to clean it up and simplify. \ No newline at end of file diff --git a/FLIR/FLIRcodev3.1/build/lib/flir/driver.py b/FLIR/FLIRcodev3.1/build/lib/flir/driver.py index 3e7d393..f6295b4 100644 --- a/FLIR/FLIRcodev3.1/build/lib/flir/driver.py +++ b/FLIR/FLIRcodev3.1/build/lib/flir/driver.py @@ -390,37 +390,41 @@ def run_single_camera(cam): :return: True if successful, False otherwise. :rtype: bool """ + print("393-postfunction") try: + print("395") result = True err = False - + print("398") # Retrieve TL device nodemap and print device information nodemap_tldevice = cam.GetTLDeviceNodeMap() - + print("401") result &= print_device_info(nodemap_tldevice) - + print("403") # Initialize camera cam.Init() - + print("406") # Retrieve GenICam nodemap nodemap = cam.GetNodeMap() - + print("409") # Configure trigger if configure_trigger(cam) is False: return False - + print("413") # Acquire images result &= grab_next_image_by_trigger(cam) #acquire_images(cam) THIS IS WHAT I CHANGED TO TRY TO GRAB ONLY ONE IMAGE AT A TIME! - + print("416") # Reset trigger result &= reset_trigger(cam) - + print("419") # Deinitialize camera cam.DeInit() - + print("422") except PySpin.SpinnakerException as ex: + print("424-exception") print('Error: %s' % ex) result = False + return result @@ -459,13 +463,14 @@ def picture(cam): print('Not enough cameras!') print("Closing camera instance...") #input('Done! Press Enter to exit...') return False - + print(cam) # 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("472-prefunction") + result &= run_single_camera(cam) print('Camera %d example complete... \n' % i) # Release reference to camera diff --git a/FLIR/FLIRcodev3.1/dist/flir-0.0.0-py3.7.egg b/FLIR/FLIRcodev3.1/dist/flir-0.0.0-py3.7.egg new file mode 100644 index 0000000..01cece7 Binary files /dev/null and b/FLIR/FLIRcodev3.1/dist/flir-0.0.0-py3.7.egg differ diff --git a/FLIR/FLIRcodev3.1/dist/flir-0.0.0-py3.8.egg b/FLIR/FLIRcodev3.1/dist/flir-0.0.0-py3.8.egg index 7cdfe84..c8be4c1 100644 Binary files a/FLIR/FLIRcodev3.1/dist/flir-0.0.0-py3.8.egg and b/FLIR/FLIRcodev3.1/dist/flir-0.0.0-py3.8.egg differ diff --git a/FLIR/FLIRcodev3.1/flir/driver.py b/FLIR/FLIRcodev3.1/flir/driver.py index 3e7d393..f6295b4 100644 --- a/FLIR/FLIRcodev3.1/flir/driver.py +++ b/FLIR/FLIRcodev3.1/flir/driver.py @@ -390,37 +390,41 @@ def run_single_camera(cam): :return: True if successful, False otherwise. :rtype: bool """ + print("393-postfunction") try: + print("395") result = True err = False - + print("398") # Retrieve TL device nodemap and print device information nodemap_tldevice = cam.GetTLDeviceNodeMap() - + print("401") result &= print_device_info(nodemap_tldevice) - + print("403") # Initialize camera cam.Init() - + print("406") # Retrieve GenICam nodemap nodemap = cam.GetNodeMap() - + print("409") # Configure trigger if configure_trigger(cam) is False: return False - + print("413") # Acquire images result &= grab_next_image_by_trigger(cam) #acquire_images(cam) THIS IS WHAT I CHANGED TO TRY TO GRAB ONLY ONE IMAGE AT A TIME! - + print("416") # Reset trigger result &= reset_trigger(cam) - + print("419") # Deinitialize camera cam.DeInit() - + print("422") except PySpin.SpinnakerException as ex: + print("424-exception") print('Error: %s' % ex) result = False + return result @@ -459,13 +463,14 @@ def picture(cam): print('Not enough cameras!') print("Closing camera instance...") #input('Done! Press Enter to exit...') return False - + print(cam) # 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("472-prefunction") + result &= run_single_camera(cam) print('Camera %d example complete... \n' % i) # Release reference to camera diff --git a/FLIR/FLIRcodev3.1/readme.txt b/FLIR/FLIRcodev3.1/readme.txt index 5778c2c..45a965e 100644 --- a/FLIR/FLIRcodev3.1/readme.txt +++ b/FLIR/FLIRcodev3.1/readme.txt @@ -1,4 +1,23 @@ v1.0 was a failure based on the simplistic code of the manual. Scrapped. v2.0 was a copy-paste of novatech code with all names and unique functions REMOVED v3.0 is v2.0 but with the addition of the flir camera functions. Methods are working without the camera. Call "sipyco_rpctool ::1 3200 call picture" to get trigger picture. -v3.1 I dont want to ruin v3.0 stability when hardware testing. v3.1 is hardware testing. \ No newline at end of file +v3.1 I dont want to ruin v3.0 stability when hardware testing. v3.1 is hardware testing. + + +Installation: +1. Install Spinnaker with python3.8 +conda install python3.8 +2. In Flircodevx.x directory, run: + +conda install sipyco +conda install asyncserial +python setup.py build +python setup.py install + +3. Change directories to flir and start server with: + +python aqctl_flir.py + +4. In another anaconda window, in the flir directory, take picture with: + +sipyco_rpctool ::1 3200 call picture \ No newline at end of file diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/AcquireAndDisplay.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/AcquireAndDisplay.py new file mode 100644 index 0000000..2aee556 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/AcquireAndDisplay.py @@ -0,0 +1,313 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# This AcquireAndDisplay.py shows how to get the image data, and then display images in a GUI. +# This example relies on information provided in the ImageChannelStatistics.py example. +# +# This example demonstrates how to display images represented as numpy arrays. +# Currently, this program is limited to single camera use. +# NOTE: keyboard and matplotlib must be installed on Python interpreter prior to running this example. + +import os +import PySpin +import matplotlib.pyplot as plt +import sys +import keyboard +import time + +global continue_recording +continue_recording = True + + +def handle_close(evt): + """ + This function will close the GUI when close event happens. + + :param evt: Event that occurs when the figure closes. + :type evt: Event + """ + + global continue_recording + continue_recording = False + + +def acquire_and_display_images(cam, nodemap, nodemap_tldevice): + """ + This function continuously acquires images from a device and display them in a GUI. + + :param cam: Camera to acquire images from. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + global continue_recording + + sNodemap = cam.GetTLStreamNodeMap() + + # Change bufferhandling mode to NewestOnly + node_bufferhandling_mode = PySpin.CEnumerationPtr(sNodemap.GetNode('StreamBufferHandlingMode')) + if not PySpin.IsAvailable(node_bufferhandling_mode) or not PySpin.IsWritable(node_bufferhandling_mode): + print('Unable to set stream buffer handling mode.. Aborting...') + return False + + # Retrieve entry node from enumeration node + node_newestonly = node_bufferhandling_mode.GetEntryByName('NewestOnly') + if not PySpin.IsAvailable(node_newestonly) or not PySpin.IsReadable(node_newestonly): + print('Unable to set stream buffer handling mode.. Aborting...') + return False + + # Retrieve integer value from entry node + node_newestonly_mode = node_newestonly.GetValue() + + # Set integer value from entry node as new value of enumeration node + node_bufferhandling_mode.SetIntValue(node_newestonly_mode) + + print('*** IMAGE ACQUISITION ***\n') + try: + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # What happens when the camera begins acquiring images depends on the + # acquisition mode. Single frame captures only a single image, multi + # frame catures a set number of images, and continuous captures a + # continuous stream of images. + # + # *** LATER *** + # Image acquisition must be ended when no more images are needed. + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve device serial number for filename + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Close program + print('Press enter to close the program..') + + # Figure(1) is default so you can omit this line. Figure(0) will create a new window every time program hits this line + fig = plt.figure(1) + + # Close the GUI when close event happens + fig.canvas.mpl_connect('close_event', handle_close) + + # Retrieve and display images + while(continue_recording): + try: + + # Retrieve next received image + # + # *** NOTES *** + # Capturing an image houses images on the camera buffer. Trying + # to capture an image that does not exist will hang the camera. + # + # *** LATER *** + # Once an image from the buffer is saved and/or no longer + # needed, the image must be released in order to keep the + # buffer from filling up. + + image_result = cam.GetNextImage(1000) + + # Ensure image completion + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + + else: + + # Getting the image data as a numpy array + image_data = image_result.GetNDArray() + + # Draws an image on the current figure + plt.imshow(image_data, cmap='gray') + + # Interval in plt.pause(interval) determines how fast the images are displayed in a GUI + # Interval is in seconds. + plt.pause(0.001) + + # Clear current reference of a figure. This will improve display speed significantly + plt.clf() + + # If user presses enter, close the program + if keyboard.is_pressed('ENTER'): + print('Program is closing...') + + # Close figure + plt.close('all') + input('Done! Press Enter to exit...') + continue_recording=False + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return True + + +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 + + nodemap_tldevice = cam.GetTLDeviceNodeMap() + + # Initialize camera + cam.Init() + + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + + # Acquire images + result &= acquire_and_display_images(cam, nodemap, nodemap_tldevice) + + # Deinitialize camera + cam.DeInit() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def main(): + """ + Example entry point; notice the volume of data that the logging event handler + prints out on debug despite the fact that very little really happens in this + example. Because of this, it may be better to have the logger set to lower + level in order to provide a more concise, focused log. + + :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) diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/Acquisition.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Acquisition.py new file mode 100644 index 0000000..3459923 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Acquisition.py @@ -0,0 +1,372 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# Acquisition.py shows how to acquire images. It relies on +# information provided in the Enumeration example. Also, check out the +# ExceptionHandling and NodeMapInfo examples if you haven't already. +# ExceptionHandling shows the handling of standard and Spinnaker exceptions +# while NodeMapInfo explores retrieving information from various node types. +# +# This example touches on the preparation and cleanup of a camera just before +# and just after the acquisition of images. Image retrieval and conversion, +# grabbing image data, and saving images are all covered as well. +# +# Once comfortable with Acquisition, we suggest checking out +# AcquisitionMultipleCamera, NodeMapCallback, or SaveToAvi. +# AcquisitionMultipleCamera demonstrates simultaneously acquiring images from +# a number of cameras, NodeMapCallback serves as a good introduction to +# programming with callbacks and events, and SaveToAvi exhibits video creation. + +import os +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +def acquire_images(cam, nodemap, nodemap_tldevice): + """ + 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. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** IMAGE ACQUISITION ***\n') + try: + result = True + + # Set acquisition mode to continuous + # + # *** NOTES *** + # Because the example acquires and saves 10 images, setting acquisition + # mode to continuous lets the example finish. If set to single frame + # or multiframe (at a lower number of images), the example would just + # hang. This would happen because the example has been written to + # acquire 10 images while the camera would have been programmed to + # retrieve less than that. + # + # Setting the value of an enumeration node is slightly more complicated + # than other node types. Two nodes must be retrieved: first, the + # enumeration node is retrieved from the nodemap; and second, the entry + # node is retrieved from the enumeration node. The integer value of the + # entry node is then set as the new value of the enumeration node. + # + # Notice that both the enumeration and the entry nodes are checked for + # availability and readability/writability. Enumeration nodes are + # generally readable and writable whereas their entry nodes are only + # ever readable. + # + # Retrieve enumeration node from nodemap + + # In order to access the node entries, they have to be casted to a pointer type (CEnumerationPtr here) + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # What happens when the camera begins acquiring images depends on the + # acquisition mode. Single frame captures only a single image, multi + # frame catures a set number of images, and continuous captures a + # continuous stream of images. Because the example calls for the + # retrieval of 10 images, continuous mode has been set. + # + # *** LATER *** + # Image acquisition must be ended when no more images are needed. + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve device serial number for filename + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Retrieve, convert, and save images + for i in range(NUM_IMAGES): + try: + + # Retrieve next received image + # + # *** NOTES *** + # Capturing an image houses images on the camera buffer. Trying + # to capture an image that does not exist will hang the camera. + # + # *** LATER *** + # Once an image from the buffer is saved and/or no longer + # needed, the image must be released in order to keep the + # buffer from filling up. + image_result = cam.GetNextImage(1000) + + # Ensure image completion + # + # *** NOTES *** + # Images can easily be checked for completion. This should be + # done whenever a complete image is expected or required. + # Further, check image status for a little more insight into + # why an image is incomplete. + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + + else: + + # Print image information; height and width recorded in pixels + # + # *** NOTES *** + # Images have quite a bit of available metadata including + # things such as CRC, image status, and offset values, to + # name a few. + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed Image %d, width = %d, height = %d' % (i, width, height)) + + # Convert image to mono 8 + # + # *** NOTES *** + # Images can be converted between pixel formats by using + # the appropriate enumeration value. Unlike the original + # image, the converted one does not need to be released as + # it does not affect the camera buffer. + # + # When converting images, color processing algorithm is an + # optional parameter. + image_converted = image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + # Create a unique filename + if device_serial_number: + filename = 'Acquisition-%s-%d.jpg' % (device_serial_number, i) + else: # if serial number is empty + filename = 'Acquisition-%d.jpg' % i + + # Save image + # + # *** NOTES *** + # The standard practice of the examples is to use device + # serial numbers to keep images of one device from + # overwriting those of another. + image_converted.Save(filename) + print('Image saved at %s' % filename) + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + print('') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return 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 + + # 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() + + # Acquire images + result &= acquire_images(cam, nodemap, nodemap_tldevice) + + # 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 + """ + + # 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: %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) diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/AcquisitionMultipleCamera.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/AcquisitionMultipleCamera.py new file mode 100644 index 0000000..6fd7cc8 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/AcquisitionMultipleCamera.py @@ -0,0 +1,334 @@ +# ============================================================================ +# Copyright (c) 2001-2019 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. +# ============================================================================ +# +# AcquisitionMultipleCamera.py shows how to capture images from +# multiple cameras simultaneously. It relies on information provided in the +# Enumeration, Acquisition, and NodeMapInfo examples. +# +# This example reads similarly to the Acquisition example, +# except that loops are used to allow for simultaneous acquisitions. + +import os +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + +def acquire_images(cam_list): + """ + This function acquires and saves 10 images from each device. + + :param cam_list: List of cameras + :type cam_list: CameraList + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** IMAGE ACQUISITION ***\n') + try: + result = True + + # Prepare each camera to acquire images + # + # *** NOTES *** + # For pseudo-simultaneous streaming, each camera is prepared as if it + # were just one, but in a loop. Notice that cameras are selected with + # an index. We demonstrate pseduo-simultaneous streaming because true + # simultaneous streaming would require multiple process or threads, + # which is too complex for an example. + # + + for i, cam in enumerate(cam_list): + + # Set acquisition mode to continuous + node_acquisition_mode = PySpin.CEnumerationPtr(cam.GetNodeMap().GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (node retrieval; camera %d). Aborting... \n' % i) + return False + + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or not PySpin.IsReadable( + node_acquisition_mode_continuous): + print('Unable to set acquisition mode to continuous (entry \'continuous\' retrieval %d). \ + Aborting... \n' % i) + return False + + acquisition_mode_continuous = node_acquisition_mode_continuous.GetValue() + + node_acquisition_mode.SetIntValue(acquisition_mode_continuous) + + print('Camera %d acquisition mode set to continuous...' % i) + + # Begin acquiring images + cam.BeginAcquisition() + + print('Camera %d started acquiring images...' % i) + + print() + + # Retrieve, convert, and save images for each camera + # + # *** NOTES *** + # In order to work with simultaneous camera streams, nested loops are + # needed. It is important that the inner loop be the one iterating + # through the cameras; otherwise, all images will be grabbed from a + # single camera before grabbing any images from another. + for n in range(NUM_IMAGES): + for i, cam in enumerate(cam_list): + try: + # Retrieve device serial number for filename + node_device_serial_number = PySpin.CStringPtr(cam.GetTLDeviceNodeMap().GetNode('DeviceSerialNumber')) + + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Camera %d serial number set to %s...' % (i, device_serial_number)) + + # Retrieve next received image and ensure image completion + image_result = cam.GetNextImage(1000) + + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ... \n' % image_result.GetImageStatus()) + else: + # Print image information + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Camera %d grabbed image %d, width = %d, height = %d' % (i, n, 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 = 'AcquisitionMultipleCamera-%s-%d.jpg' % (device_serial_number, n) + else: + filename = 'AcquisitionMultipleCamera-%d-%d.jpg' % (i, n) + + # Save image + image_converted.Save(filename) + print('Image saved at %s' % filename) + + # Release image + image_result.Release() + print() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + # End acquisition for each camera + # + # *** NOTES *** + # Notice that what is usually a one-step process is now two steps + # because of the additional step of selecting the camera. It is worth + # repeating that camera selection needs to be done once per loop. + # + # It is possible to interact with cameras through the camera list with + # GetByIndex(); this is an alternative to retrieving cameras as + # CameraPtr objects that can be quick and easy for small tasks. + for cam in cam_list: + + # End acquisition + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def print_device_info(nodemap, cam_num): + """ + 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. + :param cam_num: Camera number. + :type nodemap: INodeMap + :type cam_num: int + :returns: True if successful, False otherwise. + :rtype: bool + """ + + print('Printing device information for camera %d... \n' % cam_num) + + 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.') + print() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + +def run_multiple_cameras(cam_list): + """ + This function acts as the body of the example; please see NodeMapInfo example + for more in-depth comments on setting up cameras. + + :param cam_list: List of cameras + :type cam_list: CameraList + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Retrieve transport layer nodemaps and print device information for + # each camera + # *** NOTES *** + # This example retrieves information from the transport layer nodemap + # twice: once to print device information and once to grab the device + # serial number. Rather than caching the nodem#ap, each nodemap is + # retrieved both times as needed. + print('*** DEVICE INFORMATION ***\n') + + for i, cam in enumerate(cam_list): + + # Retrieve TL device nodemap + nodemap_tldevice = cam.GetTLDeviceNodeMap() + + # Print device information + result &= print_device_info(nodemap_tldevice, i) + + # Initialize each camera + # + # *** NOTES *** + # You may notice that the steps in this function have more loops with + # less steps per loop; this contrasts the AcquireImages() function + # which has less loops but more steps per loop. This is done for + # demonstrative purposes as both work equally well. + # + # *** LATER *** + # Each camera needs to be deinitialized once all images have been + # acquired. + for i, cam in enumerate(cam_list): + + # Initialize camera + cam.Init() + + # Acquire images on all cameras + result &= acquire_images(cam_list) + + # Deinitialize each camera + # + # *** NOTES *** + # Again, each camera must be deinitialized separately by first + # selecting the camera and then deinitializing it. + for cam in cam_list: + + # Deinitialize camera + cam.DeInit() + + # 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 + + 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 + """ + + # 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: %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 all cameras + print('Running example for all cameras...') + + result = run_multiple_cameras(cam_list) + + print('Example complete... \n') + + # 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) \ No newline at end of file diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/BufferHandling.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/BufferHandling.py new file mode 100644 index 0000000..587038f --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/BufferHandling.py @@ -0,0 +1,493 @@ +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= + +# BufferHandling.py shows how the different buffer handling modes work. +# It relies on information provided in the Acquisition and Trigger examples. +# +# Buffer handling determines the ordering at which images are retrieved, and +# what occurs when an image is transmitted while the buffer is full. There are +# four different buffer handling modes available; NewestFirst, NewestOnly, +# OldestFirst and OldestFirstOverwrite. +# +# This example explores retrieving images in a set pattern; triggering the camera +# while not retrieving an image (letting the buffer fill up), and retrieving +# images while not triggering. We cycle through the different buffer handling +# modes to see which images are retrieved, confirming their identites via their +# Frame ID values. + +import os +import PySpin +import time +import sys + +# Total number of buffers +NUM_BUFFERS = 3 +# Number of triggers +NUM_TRIGGERS = 6 +# Total number of loops +NUM_LOOPS = 9 + +def configure_trigger(nodemap): + """ + This function configures the camera to use a trigger. First, trigger mode is + set to off in order to select the trigger source. Once the trigger source + has been selected, trigger mode is then enabled, which has the camera + capture only a single image upon the execution of the trigger. + + :param nodemap: Device nodemap to retrieve images from. + :type nodemap: INodeMap + :return: True if successful, False otherwise + :rtype: bool + """ + try: + result = True + print('\n*** CONFIGURING TRIGGER ***\n') + + # Ensure trigger mode off + # + # *** NOTES *** + # The trigger must be disabled in order to configure the + # trigger source. + trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerMode')) + if not PySpin.IsAvailable(trigger_mode) or not PySpin.IsWritable(trigger_mode): + print('Unable to disable trigger mode (node retrieval). Aborting...\n') + return False + + trigger_mode_off = PySpin.CEnumEntryPtr(trigger_mode.GetEntryByName('Off')) + if not PySpin.IsAvailable(trigger_mode_off) or not PySpin.IsReadable(trigger_mode_off): + print('Unable to disable trigger mode (enum entry retrieval). Aborting...\n') + return False + + trigger_mode.SetIntValue(trigger_mode_off.GetValue()) + print('Trigger mode disabled...') + + # Set trigger source to software + trigger_source = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerSource')) + if not PySpin.IsAvailable(trigger_source) or not PySpin.IsWritable(trigger_source): + print('Unable to set trigger mode (node retrieval). Aborting...') + return False + + trigger_source_software = PySpin.CEnumEntryPtr(trigger_source.GetEntryByName('Software')) + if not PySpin.IsAvailable(trigger_source_software) or not PySpin.IsReadable(trigger_source_software): + print('Unable to set trigger mode (enum entry retrieval). Aborting...') + return False + + trigger_source.SetIntValue(trigger_source_software.GetValue()) + print('Trigger source set to software...') + + # Turn trigger mode on + trigger_mode_on = PySpin.CEnumEntryPtr(trigger_mode.GetEntryByName('On')) + if not PySpin.IsAvailable(trigger_mode_on) or not PySpin.IsReadable(trigger_mode_on): + print('Unable to enable trigger mode (enum entry retrieval). Aborting...\n') + return False + + trigger_mode.SetIntValue(trigger_mode_on.GetValue()) + print('Trigger mode turned back on...') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + +def grab_next_image_by_trigger(nodemap): + """ + This function retrieves a single image using the trigger. In this example, + only a single image is captured and made available for acquisition - as such, + attempting to acquire two images for a single trigger execution would cause + the example to hang. This is different from other examples, whereby a + constant stream of images are being captured and made available for image + acquisition. + + :param nodemap: Device nodemap to retrieve images from. + :type nodemap: INodeMap + :return: True if successful, False otherwise + :rtype: bool + """ + try: + result = True + + # Execute software trigger + software_trigger_command = PySpin.CCommandPtr(nodemap.GetNode('TriggerSoftware')) + if not PySpin.IsAvailable(software_trigger_command) or not PySpin.IsWritable(software_trigger_command): + print('Unable to execute trigger. Aborting...\n') + return False + + software_trigger_command.Execute() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + +def reset_trigger(nodemap): + """ + This function returns the camera to a normal state by turning off trigger mode. + + :param nodemap: Device nodemap to retrieve images from. + :type nodemap: INodeMap + :return: True if successful, False otherwise + :rtype: bool + """ + try: + result = True + + # Turn trigger mode back off + # + # *** NOTES *** + # Once all images have been captured, turn trigger mode back off to + # restore the camera to a clean state. + trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerMode')) + if not PySpin.IsAvailable(trigger_mode) or not PySpin.IsWritable(trigger_mode): + print('Unable to disable trigger mode (node retrieval). Non-fatal error...\n') + return False + + trigger_mode_off = PySpin.CEnumEntryPtr(trigger_mode.GetEntryByName('Off')) + if not PySpin.IsAvailable(trigger_mode_off) or not PySpin.IsReadable(trigger_mode_off): + print('Unable to disable trigger mode (enum entry retrieval). Non-fatal error...\n') + return False + + trigger_mode.SetIntValue(trigger_mode_off.GetValue()) + print('Trigger mode disabled...\n') + + 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 from camera. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + print('\n*** DEVICE INFORMATION ***\n') + + # Retrieve and display Device Information + 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) + result = False + + return result + +def acquire_images(cam, nodemap, nodemap_tldevice): + """ + This function cycles through the four different buffer handling modes. + It saves three images for three of the buffer handling modes + (NewestFirst, OldestFirst, and OldestFirstOverwrite). For NewestOnly, + it saves one image. + + :param cam: Camera instance to grab images from. + :param nodemap: Device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + print('\n*** IMAGE ACQUISITION ***\n') + + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (node retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration mode + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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...') + + # Retrieve device serial number for filename + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Retrieve Stream Parameters device nodemap + s_node_map = cam.GetTLStreamNodeMap() + + # Retrieve Buffer Handling Mode Information + handling_mode = PySpin.CEnumerationPtr(s_node_map.GetNode('StreamBufferHandlingMode')) + if not PySpin.IsAvailable(handling_mode) or not PySpin.IsWritable(handling_mode): + print('Unable to set Buffer Handling mode (node retrieval). Aborting...\n') + return False + + handling_mode_entry = PySpin.CEnumEntryPtr(handling_mode.GetCurrentEntry()) + if not PySpin.IsAvailable(handling_mode_entry) or not PySpin.IsReadable(handling_mode_entry): + print('Unable to set Buffer Handling mode (Entry retrieval). Aborting...\n') + return False + + # Set stream buffer Count Mode to manual + stream_buffer_count_mode = PySpin.CEnumerationPtr(s_node_map.GetNode('StreamBufferCountMode')) + if not PySpin.IsAvailable(stream_buffer_count_mode) or not PySpin.IsWritable(stream_buffer_count_mode): + print('Unable to set Buffer Count Mode (node retrieval). Aborting...\n') + return False + + stream_buffer_count_mode_manual = PySpin.CEnumEntryPtr(stream_buffer_count_mode.GetEntryByName('Manual')) + if not PySpin.IsAvailable(stream_buffer_count_mode_manual) or not PySpin.IsReadable(stream_buffer_count_mode_manual): + print('Unable to set Buffer Count Mode entry (Entry retrieval). Aborting...\n') + return False + + stream_buffer_count_mode.SetIntValue(stream_buffer_count_mode_manual.GetValue()) + print('Stream Buffer Count Mode set to manual...') + + # Retrieve and modify Stream Buffer Count + buffer_count = PySpin.CIntegerPtr(s_node_map.GetNode('StreamBufferCountManual')) + if not PySpin.IsAvailable(buffer_count) or not PySpin.IsWritable(buffer_count): + print('Unable to set Buffer Count (Integer node retrieval). Aborting...\n') + return False + + # Display Buffer Info + print('\nDefault Buffer Handling Mode: %s' % handling_mode_entry.GetDisplayName()) + print('Default Buffer Count: %d' % buffer_count.GetValue()) + print('Maximum Buffer Count: %d' % buffer_count.GetMax()) + + buffer_count.SetValue(NUM_BUFFERS) + + print('Buffer count now set to: %d' % buffer_count.GetValue()) + print('\nCamera will be triggered %d times in a row before %d images will be retrieved' % (NUM_TRIGGERS,(NUM_LOOPS-NUM_TRIGGERS))) + + for x in range (0, 4): + if x == 0: + handling_mode_entry = handling_mode.GetEntryByName('NewestFirst') + handling_mode.SetIntValue(handling_mode_entry.GetValue()) + print('\n\nBuffer Handling Mode has been set to %s' % handling_mode_entry.GetDisplayName()) + elif x == 1: + handling_mode_entry = handling_mode.GetEntryByName('NewestOnly') + handling_mode.SetIntValue(handling_mode_entry.GetValue()) + print('\n\nBuffer Handling Mode has been set to %s' % handling_mode_entry.GetDisplayName()) + elif x == 2: + handling_mode_entry = handling_mode.GetEntryByName('OldestFirst') + handling_mode.SetIntValue(handling_mode_entry.GetValue()) + print('\n\nBuffer Handling Mode has been set to %s' % handling_mode_entry.GetDisplayName()) + elif x == 3: + handling_mode_entry = handling_mode.GetEntryByName('OldestFirstOverwrite') + handling_mode.SetIntValue(handling_mode_entry.GetValue()) + print('\n\nBuffer Handling Mode has been set to %s' % handling_mode_entry.GetDisplayName()) + + # Begin capturing images + cam.BeginAcquisition() + + # Sleep for one second; only necessary when using non-BFS/ORX cameras on startup + if x == 0: + time.sleep(1) + + try: + # Software Trigger the camera then save images + for loop_cnt in range (0, NUM_LOOPS): + if loop_cnt < NUM_TRIGGERS: + # Retrieve the next image from the trigger + result &= grab_next_image_by_trigger(nodemap) + print('\nCamera triggered. No image grabbed') + else: + print('\nNo trigger. Grabbing image %d' %(loop_cnt-NUM_TRIGGERS)) + result_image = cam.GetNextImage(500) + + if result_image.IsIncomplete(): + print('Image incomplete with image status %s ...\n' % result_image.GetImageStatus()) + + if loop_cnt >= NUM_TRIGGERS: + # Retrieve Frame ID + print('Frame ID: %d' % result_image.GetFrameID()) + + # Create a unique filename + if device_serial_number: + filename = '%s-%s-%d.jpg' % (handling_mode_entry.GetSymbolic(),device_serial_number, (loop_cnt-NUM_TRIGGERS)) + else: + filename = '%s-%d.jpg' % (handling_mode_entry.GetSymbolic(),(loop_cnt-NUM_TRIGGERS)) + + # Save image + result_image.Save(filename) + print('Image saved at %s' % filename) + + # Release image + result_image.Release() + + # To control the framerate, have the application pause for 250ms. + time.sleep(0.25) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + if handling_mode_entry.GetSymbolic() == 'NewestOnly': + print('Error should occur when grabbing image 1 with handling mode set to NewestOnly') + result = False + + # End acquisition + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = 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 acquire images from. + :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 chunk data + if configure_trigger(nodemap) is False: + return False + + # Acquire images and display chunk data + result &= acquire_images(cam, nodemap, nodemap_tldevice) + + # Reset trigger + result &= reset_trigger(nodemap) + + # De-initialize 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 + """ + + # 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: %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('\n\nRunning 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) + + + diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/ChunkData.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/ChunkData.py new file mode 100644 index 0000000..4214d69 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/ChunkData.py @@ -0,0 +1,674 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# ChunkData.py shows how to get chunk data on an image, either from +# the nodemap or from the image itself. 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 samples. As they are somewhat shorter and simpler, either +# provides a strong introduction to camera customization. +# +# Chunk data provides information on various traits of an image. This includes +# identifiers such as frame ID, properties such as black level, and more. This +# information can be acquired from either the nodemap or the image itself. +# +# It may be preferable to grab chunk data from each individual image, as it +# can be hard to verify whether data is coming from the correct image when +# using the nodemap. This is because chunk data retrieved from the nodemap is +# only valid for the current image; when GetNextImage() is called, chunk data +# will be updated to that of the new current image. +# + +import os +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +# Use the following class and global variable to select whether +# chunk data is displayed from the image or the nodemap. +class ChunkDataTypes: + IMAGE = 1 + NODEMAP = 2 + + +CHOSEN_CHUNK_DATA_TYPE = ChunkDataTypes.NODEMAP + + +def configure_chunk_data(nodemap): + """ + This function configures the camera to add chunk data to each image. It does + this by enabling each type of chunk data before enabling chunk data mode. + When chunk data is turned on, the data is made available in both the nodemap + and each image. + + :param nodemap: Transport layer device nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise + :rtype: bool + """ + try: + result = True + print('\n*** CONFIGURING CHUNK DATA ***\n') + + # 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. + chunk_mode_active = PySpin.CBooleanPtr(nodemap.GetNode('ChunkModeActive')) + + if PySpin.IsAvailable(chunk_mode_active) and PySpin.IsWritable(chunk_mode_active): + chunk_mode_active.SetValue(True) + + print('Chunk mode activated...') + + # Enable all types of chunk data + # + # *** NOTES *** + # Enabling chunk data requires working with nodes: "ChunkSelector" + # is an enumeration selector node and "ChunkEnable" is a boolean. It + # requires retrieving the selector node (which is of enumeration node + # type), selecting the entry of the chunk data to be enabled, retrieving + # the corresponding boolean, and setting it to be true. + # + # In this example, all chunk data is enabled, so these steps are + # performed in a loop. Once this is complete, chunk mode still needs to + # be activated. + chunk_selector = PySpin.CEnumerationPtr(nodemap.GetNode('ChunkSelector')) + + if not PySpin.IsAvailable(chunk_selector) or not PySpin.IsReadable(chunk_selector): + print('Unable to retrieve chunk selector. Aborting...\n') + return False + + # Retrieve entries + # + # *** NOTES *** + # PySpin handles mass entry retrieval in a different way than the C++ + # API. Instead of taking in a NodeList_t reference, GetEntries() takes + # no parameters and gives us a list of INodes. Since we want these INodes + # to be of type CEnumEntryPtr, we can use a list comprehension to + # transform all of our collected INodes into CEnumEntryPtrs at once. + entries = [PySpin.CEnumEntryPtr(chunk_selector_entry) for chunk_selector_entry in chunk_selector.GetEntries()] + + print('Enabling entries...') + + # Iterate through our list and select each entry node to enable + for chunk_selector_entry in entries: + # Go to next node if problem occurs + if not PySpin.IsAvailable(chunk_selector_entry) or not PySpin.IsReadable(chunk_selector_entry): + continue + + chunk_selector.SetIntValue(chunk_selector_entry.GetValue()) + + chunk_str = '\t {}:'.format(chunk_selector_entry.GetSymbolic()) + + # Retrieve corresponding boolean + chunk_enable = PySpin.CBooleanPtr(nodemap.GetNode('ChunkEnable')) + + # Enable the boolean, thus enabling the corresponding chunk data + if not PySpin.IsAvailable(chunk_enable): + print('{} not available'.format(chunk_str)) + result = False + elif chunk_enable.GetValue() is True: + print('{} enabled'.format(chunk_str)) + elif PySpin.IsWritable(chunk_enable): + chunk_enable.SetValue(True) + print('{} enabled'.format(chunk_str)) + else: + print('{} not writable'.format(chunk_str)) + result = False + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def display_chunk_data_from_nodemap(nodemap): + """ + This function displays all available chunk data by looping through the + chunk data category node on the nodemap. + + :param nodemap: Device nodemap to retrieve images from. + :type nodemap: INodeMap + :return: True if successful, False otherwise + :rtype: bool + """ + print('Printing chunk data from nodemap...') + try: + result = True + # Retrieve chunk data information nodes + # + # *** NOTES *** + # As well as being written into the payload of the image, chunk data is + # accessible on the GenICam nodemap. When chunk data is enabled, it is + # made available from both the image payload and the nodemap. + chunk_data_control = PySpin.CCategoryPtr(nodemap.GetNode('ChunkDataControl')) + if not PySpin.IsAvailable(chunk_data_control) or not PySpin.IsReadable(chunk_data_control): + print('Unable to retrieve chunk data control. Aborting...\n') + return False + + features = chunk_data_control.GetFeatures() + + # Iterate through children + for feature in features: + feature_node = PySpin.CNodePtr(feature) + feature_display_name = '\t{}:'.format(feature_node.GetDisplayName()) + + if not PySpin.IsAvailable(feature_node) or not PySpin.IsReadable(feature_node): + print('{} node not available'.format(feature_display_name)) + result &= False + continue + # Print node type value + # + # *** NOTES *** + # All nodes can be cast as value nodes and have their information + # retrieved as a string using the ToString() method. This is much + # easier than dealing with each individual node type. + else: + feature_value = PySpin.CValuePtr(feature) + print('{} {}'.format(feature_display_name, feature_value.ToString())) + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def display_chunk_data_from_image(image): + """ + This function displays a select amount of chunk data from the image. Unlike + accessing chunk data via the nodemap, there is no way to loop through all + available data. + + :param image: Image to acquire chunk data from + :type image: Image object + :return: True if successful, False otherwise. + :rtype: bool + """ + print('Printing chunk data from image...') + try: + result = True + print(type(image)) + # Retrieve chunk data from image + # + # *** NOTES *** + # When retrieving chunk data from an image, the data is stored in a + # ChunkData object and accessed with getter functions. + chunk_data = image.GetChunkData() + + # Retrieve exposure time (recorded in microseconds) + exposure_time = chunk_data.GetExposureTime() + print('\tExposure time: {}'.format(exposure_time)) + + # Retrieve frame ID + frame_id = chunk_data.GetFrameID() + print('\tFrame ID: {}'.format(frame_id)) + + # Retrieve gain; gain recorded in decibels + gain = chunk_data.GetGain() + print('\tGain: {}'.format(gain)) + + # Retrieve height; height recorded in pixels + height = chunk_data.GetHeight() + print('\tHeight: {}'.format(height)) + + # Retrieve offset X; offset X recorded in pixels + offset_x = chunk_data.GetOffsetX() + print('\tOffset X: {}'.format(offset_x)) + + # Retrieve offset Y; offset Y recorded in pixels + offset_y = chunk_data.GetOffsetY() + print('\tOffset Y: {}'.format(offset_y)) + + # Retrieve sequencer set active + sequencer_set_active = chunk_data.GetSequencerSetActive() + print('\tSequencer set active: {}'.format(sequencer_set_active)) + + # Retrieve timestamp + timestamp = chunk_data.GetTimestamp() + print('\tTimestamp: {}'.format(timestamp)) + + # Retrieve width; width recorded in pixels + width = chunk_data.GetWidth() + print('\tWidth: {}'.format(width)) + + 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 + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('\n*** 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) + result = False + + return result + + +def acquire_images(cam, nodemap, nodemap_tldevice): + """ + 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. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** IMAGE ACQUISTION ***\n') + + try: + result = True + # Set acquisition mode to continuous + # + # *** NOTES *** + # Because the example acquires and saves 10 images, setting acquisition + # mode to continuous lets the example finish. If set to single frame + # or multiframe (at a lower number of images), the example would just + # hang. This would happen because the example has been written to + # acquire 10 images while the camera would have been programmed to + # retrieve less than that. + # + # Setting the value of an enumeration node is slightly more complicated + # than other node types. Two nodes must be retrieved: first, the + # enumeration node is retrieved from the nodemap; and second, the entry + # node is retrieved from the enumeration node. The integer value of the + # entry node is then set as the new value of the enumeration node. + # + # Notice that both the enumeration and the entry nodes are checked for + # availability and readability/writability. Enumeration nodes are + # generally readable and writable whereas their entry nodes are only + # ever readable. + # + # Retrieve enumeration node from nodemap + + # In order to access the node entries, they have to be casted to a pointer type (CEnumerationPtr here) + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (node retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration mode + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # What happens when the camera begins acquiring images depends on the + # acquisition mode. Single frame captures only a single image, multi + # frame captures a set number of images, and continuous captures a + # continuous stream of images. As the example calls for the + # retrieval of 10 images, continuous mode has been set. + # + # *** LATER *** + # Image acquisition must be ended when no more images are needed. + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve device serial number for filename + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Retrieve, convert, and save images + for i in range(NUM_IMAGES): + try: + # Retrieve next received image + # + # *** NOTES *** + # Capturing an image houses images on the camera buffer. Trying + # to capture an image that does not exist will hang the camera. + # + # *** LATER *** + # Once an image from the buffer is saved and/or no longer + # needed, the image must be released in order to keep the + # buffer from filling up. + image_result = cam.GetNextImage(1000) + + # Ensure image completion + # + # *** NOTES *** + # Images can be easily checked for completion. This should be + # done whenever a complete image is expected or required. + # Further, check image status for a little more insight into + # why an image is incomplete. + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + else: + + # Print image information + # + # *** NOTES *** + # Images have quite a bit of available metadata including + # things such as CRC, image status, and offset values, to + # name a few. + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed Image %d, width = %d, height = %d' % (i, width, height)) + + # Convert image to mono 8 + # + # *** NOTES *** + # Images can be converted between pixel formats by using + # the appropriate enumeration value. Unlike the original + # image, the converted one does not need to be released as + # it does not affect the camera buffer. + # + # When converting images, color processing algorithm is an + # optional parameter. + image_converted = image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + # Create a unique filename + if device_serial_number: + filename = 'ChunkData-%s-%d.jpg' % (device_serial_number, i) + else: + filename = 'ChunkData-%d.jpg' % i + + # Save image + # + # *** NOTES *** + # The standard practice of the examples is to use device + # serial numbers to keep images of one device from + # overwriting those of another. + image_converted.Save(filename) + print('Image saved at %s' % filename) + + # Display chunk data + + if CHOSEN_CHUNK_DATA_TYPE == ChunkDataTypes.IMAGE: + result &= display_chunk_data_from_image(image_result) + elif CHOSEN_CHUNK_DATA_TYPE == ChunkDataTypes.NODEMAP: + result = display_chunk_data_from_nodemap(nodemap) + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + print('') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def disable_chunk_data(nodemap): + """ + This function disables each type of chunk data before disabling chunk data mode. + + :param nodemap: Transport layer device nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise + :rtype: bool + """ + try: + result = True + + # Retrieve the selector node + chunk_selector = PySpin.CEnumerationPtr(nodemap.GetNode('ChunkSelector')) + + if not PySpin.IsAvailable(chunk_selector) or not PySpin.IsReadable(chunk_selector): + print('Unable to retrieve chunk selector. Aborting...\n') + return False + + # Retrieve entries + # + # *** NOTES *** + # PySpin handles mass entry retrieval in a different way than the C++ + # API. Instead of taking in a NodeList_t reference, GetEntries() takes + # no parameters and gives us a list of INodes. Since we want these INodes + # to be of type CEnumEntryPtr, we can use a list comprehension to + # transform all of our collected INodes into CEnumEntryPtrs at once. + entries = [PySpin.CEnumEntryPtr(chunk_selector_entry) for chunk_selector_entry in chunk_selector.GetEntries()] + + print('Disabling entries...') + + for chunk_selector_entry in entries: + # Go to next node if problem occurs + if not PySpin.IsAvailable(chunk_selector_entry) or not PySpin.IsReadable(chunk_selector_entry): + continue + + chunk_selector.SetIntValue(chunk_selector_entry.GetValue()) + + chunk_symbolic_form = '\t {}:'.format(chunk_selector_entry.GetSymbolic()) + + # Retrieve corresponding boolean + chunk_enable = PySpin.CBooleanPtr(nodemap.GetNode('ChunkEnable')) + + # Disable the boolean, thus disabling the corresponding chunk data + if not PySpin.IsAvailable(chunk_enable): + print('{} not available'.format(chunk_symbolic_form)) + result = False + elif not chunk_enable.GetValue(): + print('{} disabled'.format(chunk_symbolic_form)) + elif PySpin.IsWritable(chunk_enable): + chunk_enable.SetValue(False) + print('{} disabled'.format(chunk_symbolic_form)) + else: + print('{} not writable'.format(chunk_symbolic_form)) + + # Deactivate Chunk Mode + chunk_mode_active = PySpin.CBooleanPtr(nodemap.GetNode('ChunkModeActive')) + + if not PySpin.IsAvailable(chunk_mode_active) or not PySpin.IsWritable(chunk_mode_active): + print('Unable to deactivate chunk mode. Aborting...\n') + return False + + chunk_mode_active.SetValue(False) + + print('Chunk mode deactivated...') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def run_single_camera(cam): + """ + This function acts as the body of the example; please see NodeMapInfo example + for more in-depth comments on setting up cameras. + + :param cam: Camera to run on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Retrieve TL device nodemap and print device information + nodemap_tldevice = cam.GetTLDeviceNodeMap() + + result &= print_device_info(nodemap_tldevice) + + # Initialize camera + cam.Init() + + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + + # Configure chunk data + if configure_chunk_data(nodemap) is False: + return False + + # Acquire images and display chunk data + result &= acquire_images(cam, nodemap, nodemap_tldevice) + + # Disable chunk data + if disable_chunk_data(nodemap) is False: + return False + + # De-initialize 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 + """ + + # 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: %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) diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/CounterAndTimer.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/CounterAndTimer.py new file mode 100644 index 0000000..537d5d4 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/CounterAndTimer.py @@ -0,0 +1,669 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# CounterAndTimer.py shows how to setup a Pulse Width Modulation (PWM) +# signal using counters and timers. The camera will output the PWM signal via +# strobe, and capture images at a rate defined by the PWM signal as well. +# Users should take care to use a PWM signal within the camera's max +# frame rate (by default, the PWM signal is set to 50 Hz). +# +# Counter and Timer functionality is only available for BFS and Oryx Cameras. +# For details on the hardware setup, see our kb article, "Using Counter and +# Timer Control"; https://www.flir.com/support-center/iis/machine-vision/application-note/using-counter-and-timer-control + +import os +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +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: Device nodemap. + :type nodemap: INodeMap + :return: 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) + 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 available.') + + print('') + + except PySpin.SpinnakerException as ex: + print('Error: {}'.format(ex)) + return False + + return result + + +def setup_counter_and_timer(nodemap): + """ + This function configures the camera to setup a Pulse Width Modulation signal using + Counter and Timer functionality. By default, the PWM signal will be set to run at + 50hz, with a duty cycle of 70%. + + :param nodemap: Device nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('Configuring Pulse Width Modulation signal') + + try: + result = True + + # Set Counter Selector to Counter 0 + node_counter_selector = PySpin.CEnumerationPtr(nodemap.GetNode('CounterSelector')) + + # Check to see if camera supports Counter and Timer functionality + if not PySpin.IsAvailable(node_counter_selector): + print('\nCamera does not support Counter and Timer Functionality. Aborting...\n') + return False + + if not PySpin.IsWritable(node_counter_selector): + print('\nUnable to set Counter Selector (enumeration retrieval). Aborting...\n') + return False + + entry_counter_0 = node_counter_selector.GetEntryByName('Counter0') + if not PySpin.IsAvailable(entry_counter_0) or not PySpin.IsReadable(entry_counter_0): + print('\nUnable to set Counter Selector (entry retrieval). Aborting...\n') + return False + + counter_0 = entry_counter_0.GetValue() + + node_counter_selector.SetIntValue(counter_0) + + # Set Counter Event Source to MHzTick + node_counter_event_source = PySpin.CEnumerationPtr(nodemap.GetNode('CounterEventSource')) + if not PySpin.IsAvailable(node_counter_event_source) or not PySpin.IsWritable(node_counter_event_source): + print('\nUnable to set Counter Event Source (enumeration retrieval). Aborting...\n') + return False + + entry_counter_event_source_mhz_tick = node_counter_event_source.GetEntryByName('MHzTick') + if not PySpin.IsAvailable(entry_counter_event_source_mhz_tick) \ + or not PySpin.IsReadable(entry_counter_event_source_mhz_tick): + print('\nUnable to set Counter Event Source (entry retrieval). Aborting...\n') + return False + + counter_event_source_mhz_tick = entry_counter_event_source_mhz_tick.GetValue() + + node_counter_event_source.SetIntValue(counter_event_source_mhz_tick) + + # Set Counter Duration to 14000 + node_counter_duration = PySpin.CIntegerPtr(nodemap.GetNode('CounterDuration')) + if not PySpin.IsAvailable(node_counter_duration) or not PySpin.IsWritable(node_counter_duration): + print('\nUnable to set Counter Duration (integer retrieval). Aborting...\n') + return False + + node_counter_duration.SetValue(14000) + + # Set Counter Delay to 6000 + node_counter_delay = PySpin.CIntegerPtr(nodemap.GetNode('CounterDelay')) + if not PySpin.IsAvailable(node_counter_delay) or not PySpin.IsWritable(node_counter_delay): + print('\nUnable to set Counter Delay (integer retrieval). Aborting...\n') + return False + + node_counter_delay.SetValue(6000) + + # Determine Duty Cycle of PWM signal + duty_cycle = float(node_counter_duration.GetValue()) / (float(node_counter_duration.GetValue() + + node_counter_delay.GetValue())) * 100 + + print('\nThe duty cycle has been set to {}%'.format(duty_cycle)) + + # Determine pulse rate of PWM signal + pulse_rate = 1000000 / float(node_counter_duration.GetValue() + node_counter_delay.GetValue()) + + print('\nThe pulse rate has been set to {} Hz'.format(pulse_rate)) + + # Set Counter Trigger Source to Frame Trigger Wait + node_counter_trigger_source = PySpin.CEnumerationPtr(nodemap.GetNode('CounterTriggerSource')) + if not PySpin.IsAvailable(node_counter_trigger_source) or not PySpin.IsWritable(node_counter_trigger_source): + print('\nUnable to set Counter Trigger Source (enumeration retrieval). Aborting...\n') + return False + + entry_counter_trigger_source_ftw = node_counter_trigger_source.GetEntryByName('FrameTriggerWait') + if not PySpin.IsAvailable(entry_counter_trigger_source_ftw)\ + or not PySpin.IsReadable(entry_counter_trigger_source_ftw): + print('\nUnable to set Counter Trigger Source (entry retrieval). Aborting...\n') + return False + + counter_trigger_source_ftw = entry_counter_trigger_source_ftw.GetValue() + + node_counter_trigger_source.SetIntValue(counter_trigger_source_ftw) + + # Set Counter Trigger Activation to Level High + node_counter_trigger_activation = PySpin.CEnumerationPtr(nodemap.GetNode('CounterTriggerActivation')) + if not PySpin.IsAvailable(node_counter_trigger_activation) or \ + not PySpin.IsWritable(node_counter_trigger_activation): + print('\nUnable to set Counter Trigger Activation (enumeration retrieval). Aborting...\n') + return False + + entry_counter_trigger_source_lh = node_counter_trigger_activation.GetEntryByName('LevelHigh') + if not PySpin.IsAvailable(entry_counter_trigger_source_lh) \ + or not PySpin.IsReadable(entry_counter_trigger_source_lh): + print('\nUnable to set Counter Trigger Activation (entry retrieval). Aborting...\n') + return False + + counter_trigger_level_high = entry_counter_trigger_source_lh.GetValue() + + node_counter_trigger_activation.SetIntValue(counter_trigger_level_high) + + except PySpin.SpinnakerException as ex: + print('Error: {}'.format(ex)) + return False + + return result + + +def configure_digital_io(nodemap): + """ + This function configures the GPIO to output the PWM signal. + + :param nodemap: Device nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('\nConfiguring GPIO strobe output') + + try: + result = True + camera_family_bfs = "BFS" + camera_family_oryx = "ORX" + + # Determine camera family + node_device_name = PySpin.CStringPtr(nodemap.GetNode('DeviceModelName')) + if not PySpin.IsAvailable(node_device_name) or not PySpin.IsReadable(node_device_name): + print('\nUnable to determine camera family. Aborting...\n') + return False + + camera_model = node_device_name.GetValue() + + # Set Line Selector + node_line_selector = PySpin.CEnumerationPtr(nodemap.GetNode('LineSelector')) + if not PySpin.IsAvailable(node_line_selector) or not PySpin.IsWritable(node_line_selector): + print('\nUnable to set Line Selector (enumeration retrieval). Aborting...\n') + return False + + if camera_family_bfs in camera_model: + + entry_line_selector_line_1 = node_line_selector.GetEntryByName('Line1') + if not PySpin.IsAvailable(entry_line_selector_line_1) or not PySpin.IsReadable(entry_line_selector_line_1): + print('\nUnable to set Line Selector (entry retrieval). Aborting...\n') + return False + + line_selector_line_1 = entry_line_selector_line_1.GetValue() + + node_line_selector.SetIntValue(line_selector_line_1) + + elif camera_family_oryx in camera_model: + + entry_line_selector_line_2 = node_line_selector.GetEntryByName('Line2') + if not PySpin.IsAvailable(entry_line_selector_line_2) or not PySpin.IsReadable(entry_line_selector_line_2): + print('\nUnable to set Line Selector (entry retrieval). Aborting...\n') + return False + + line_selector_line_2 = entry_line_selector_line_2.GetValue() + + node_line_selector.SetIntValue(line_selector_line_2) + + # Set Line Mode to output + node_line_mode = PySpin.CEnumerationPtr(nodemap.GetNode('LineMode')) + if not PySpin.IsAvailable(node_line_mode) or not PySpin.IsWritable(node_line_mode): + print('\nUnable to set Line Mode (enumeration retrieval). Aborting...\n') + return False + + entry_line_mode_output = node_line_mode.GetEntryByName('Output') + if not PySpin.IsAvailable(entry_line_mode_output) or not PySpin.IsReadable(entry_line_mode_output): + print('\nUnable to set Line Mode (entry retrieval). Aborting...\n') + return False + + line_mode_output = entry_line_mode_output.GetValue() + + node_line_mode.SetIntValue(line_mode_output) + + # Set Line Source for Selected Line to Counter 0 Active + node_line_source = PySpin.CEnumerationPtr(nodemap.GetNode('LineSource')) + if not PySpin.IsAvailable(node_line_source) or not PySpin.IsWritable(node_line_source): + print('\nUnable to set Line Source (enumeration retrieval). Aborting...\n') + return False + + entry_line_source_counter_0_active = node_line_source.GetEntryByName('Counter0Active') + if not PySpin.IsAvailable(entry_line_source_counter_0_active) \ + or not PySpin.IsReadable(entry_line_source_counter_0_active): + print('\nUnable to set Line Source (entry retrieval). Aborting...\n') + return False + + line_source_counter_0_active = entry_line_source_counter_0_active.GetValue() + + node_line_source.SetIntValue(line_source_counter_0_active) + + if camera_family_bfs in camera_model: + # Change Line Selector to Line 2 and Enable 3.3 Voltage Rail + entry_line_selector_line_2 = node_line_selector.GetEntryByName('Line2') + if not PySpin.IsAvailable(entry_line_selector_line_2) or not PySpin.IsReadable(entry_line_selector_line_2): + print('\nUnable to set Line Selector (entry retrieval). Aborting...\n') + return False + + line_selector_line_2 = entry_line_selector_line_2.GetValue() + + node_line_selector.SetIntValue(line_selector_line_2) + + node_voltage_enable = PySpin.CBooleanPtr(nodemap.GetNode('V3_3Enable')) + if not PySpin.IsAvailable(node_voltage_enable) or not PySpin.IsWritable(node_voltage_enable): + print('\nUnable to set Voltage Enable (boolean retrieval). Aborting...\n') + return False + + node_voltage_enable.SetValue(True) + + except PySpin.SpinnakerException as ex: + print('Error: {}'.format(ex)) + return False + + return result + + +def configure_exposure_and_trigger(nodemap): + """ + This function configures the camera to set a manual exposure value and enables + camera to be triggered by the PWM signal. + + :param nodemap: Device nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('\nConfiguring Exposure and Trigger') + + try: + result = True + + # Turn off auto exposure + node_exposure_auto = PySpin.CEnumerationPtr(nodemap.GetNode('ExposureAuto')) + if not PySpin.IsAvailable(node_exposure_auto) or not PySpin.IsWritable(node_exposure_auto): + print('\nUnable to set Exposure Auto (enumeration retrieval). Aborting...\n') + return False + + entry_exposure_auto_off = node_exposure_auto.GetEntryByName('Off') + if not PySpin.IsAvailable(entry_exposure_auto_off) or not PySpin.IsReadable(entry_exposure_auto_off): + print('\nUnable to set Exposure Auto (entry retrieval). Aborting...\n') + return False + + exposure_auto_off = entry_exposure_auto_off.GetValue() + + node_exposure_auto.SetIntValue(exposure_auto_off) + + # Set Exposure Time to less than 1/50th of a second (5000 us is used as an example) + node_exposure_time = PySpin.CFloatPtr(nodemap.GetNode('ExposureTime')) + if not PySpin.IsAvailable(node_exposure_time) or not PySpin.IsWritable(node_exposure_time): + print('\nUnable to set Exposure Time (float retrieval). Aborting...\n') + return False + + node_exposure_time.SetValue(5000) + + # Ensure trigger mode is off + # + # *** NOTES *** + # The trigger must be disabled in order to configure + node_trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerMode')) + if not PySpin.IsAvailable(node_trigger_mode) or not PySpin.IsWritable(node_trigger_mode): + print('\nUnable to disable trigger mode (node retrieval). Aborting...\n') + return False + + entry_trigger_mode_off = node_trigger_mode.GetEntryByName('Off') + if not PySpin.IsAvailable(entry_trigger_mode_off) or not PySpin.IsReadable(entry_trigger_mode_off): + print('\nUnable to disable trigger mode (enum entry retrieval). Aborting...\n') + return False + + node_trigger_mode.SetIntValue(entry_trigger_mode_off.GetValue()) + + # Set Trigger Source to Counter 0 Start + node_trigger_source = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerSource')) + if not PySpin.IsAvailable(node_trigger_source) or not PySpin.IsWritable(node_trigger_source): + print('\nUnable to set trigger source (enumeration retrieval). Aborting...\n') + return False + + entry_trigger_source_counter_0_start = node_trigger_source.GetEntryByName('Counter0Start') + if not PySpin.IsAvailable(entry_trigger_source_counter_0_start)\ + or not PySpin.IsReadable(entry_trigger_source_counter_0_start): + print('\nUnable to set trigger mode (enum entry retrieval). Aborting...\n') + return False + + node_trigger_source.SetIntValue(entry_trigger_source_counter_0_start.GetValue()) + + # Set Trigger Overlap to Readout + node_trigger_overlap = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerOverlap')) + if not PySpin.IsAvailable(node_trigger_overlap) or not PySpin.IsWritable(node_trigger_overlap): + print('\nUnable to set Trigger Overlap (enumeration retrieval). Aborting...\n') + return False + + entry_trigger_overlap_ro = node_trigger_overlap.GetEntryByName('ReadOut') + if not PySpin.IsAvailable(entry_trigger_overlap_ro) or not PySpin.IsReadable(entry_trigger_overlap_ro): + print('\nUnable to set Trigger Overlap (entry retrieval). Aborting...\n') + return False + + trigger_overlap_ro = entry_trigger_overlap_ro.GetValue() + + node_trigger_overlap.SetIntValue(trigger_overlap_ro) + + # Turn trigger mode on + entry_trigger_mode_on = node_trigger_mode.GetEntryByName('On') + if not PySpin.IsAvailable(entry_trigger_mode_on) or not PySpin.IsReadable(entry_trigger_mode_on): + print('\nUnable to enable trigger mode (enum entry retrieval). Aborting...\n') + return False + + node_trigger_mode.SetIntValue(entry_trigger_mode_on.GetValue()) + + except PySpin.SpinnakerException as ex: + print('Error: {}'.format(ex)) + return False + + return result + + +def acquire_images(cam, nodemap, nodemap_tldevice): + """ + 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. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('\n*** IMAGE ACQUISITION ***\n') + try: + result = True + + # Set acquisition mode to continuous + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enumeration retrieval). Aborting...\n') + return False + + entry_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(entry_acquisition_mode_continuous)\ + or not PySpin.IsReadable(entry_acquisition_mode_continuous): + print('Unable to set acquisition mode to continuous (enum entry retrieval). Aborting...\n') + return False + + acquisition_mode_continuous = entry_acquisition_mode_continuous.GetValue() + + 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.IsAvailable(node_device_serial_number) and 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 + for i in range(NUM_IMAGES): + try: + + # Retrieve next received image and ensure image completion + image_result = cam.GetNextImage(1000) + + if image_result.IsIncomplete(): + print('Image incomplete with image status {} ...'.format(image_result.GetImageStatus())) + + else: + + # Print image information; height and width recorded in pixels + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed image {}, width = {}, height = {}'.format(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 = 'CounterAndTimer-{}-{}.jpg'.format(device_serial_number, i) + else: # if serial number is empty + filename = 'CounterAndTimer-{}.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 reset_trigger(nodemap): + """ + This function returns the camera to a normal state by turning off trigger mode. + + *** NOTES *** + This function turns off trigger mode, but does not change the trigger source. + + :param nodemap: Transport layer device nodemap. + :type nodemap: INodeMap + :returns: True if successful, False otherwise. + :rtype: bool + """ + + try: + result = True + + # Turn trigger mode back off + node_trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerMode')) + if not PySpin.IsAvailable(node_trigger_mode) or not PySpin.IsWritable(node_trigger_mode): + print('Unable to disable trigger mode (node retrieval). Non-fatal error...\n') + + entry_trigger_mode_off = node_trigger_mode.GetEntryByName('Off') + if not PySpin.IsAvailable(entry_trigger_mode_off) or not PySpin.IsReadable(entry_trigger_mode_off): + print('Unable to disable trigger mode (enum entry retrieval). Non-fatal error...\n') + + node_trigger_mode.SetIntValue(entry_trigger_mode_off.GetValue()) + + except PySpin.SpinnakerException as ex: + print('Error: {}'.format(ex)) + return False + + return result + + +def run_single_camera(cam): + """ + This function acts as the body of the example; please see the 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 Counter and Timer setup + result &= setup_counter_and_timer(nodemap) + if not result: + return result + + # Configure DigitalIO (GPIO output) + result &= configure_digital_io(nodemap) + if not result: + return result + + # Configure Exposure and Trigger + result &= configure_exposure_and_trigger(nodemap) + if not result: + return result + + # Acquire images + result &= acquire_images(cam, nodemap, nodemap_tldevice) + + # Reset trigger + result &= reset_trigger(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: {}.{}.{}.{}'.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: {}'.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 {}...'.format(i)) + + result &= run_single_camera(cam) + print('Camera {} example complete... \n'.format(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) diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/DeviceEvents.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/DeviceEvents.py new file mode 100644 index 0000000..53ee365 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/DeviceEvents.py @@ -0,0 +1,494 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# =============================================================================*/ +# +# DeviceEvents.py shows how to create a handler to access device +# events. It relies on information provided in the Enumeration, Acquisition, +# and NodeMapInfo examples. +# +# It can also be helpful to familiarize yourself with the NodeMapCallback +# example, as nodemap callbacks follow the same general procedure as events. +# +# Device events can be thought of as camera-related events. This example +# creates a user-defined class, DeviceEventHandler, which allows the user to +# define any properties, parameters, and the event handler itself while DeviceEventHandler, +# the parent class, allows the child class to appropriately interface with +# the Spinnaker SDK. + +import os +import PySpin +import sys + + +class EventType: + """ + 'Enum' for choosing whether to register a event specifically for exposure end events + or universally for all events. + """ + GENERIC = 0 + SPECIFIC = 1 + +CHOSEN_EVENT = EventType.GENERIC # change me! +NUM_IMAGES = 10 # number of images to acquire + + +class DeviceEventHandler(PySpin.DeviceEventHandler): + """ + This class defines the properties, parameters, and the event handler itself. Take a + moment to notice what parts of the class are mandatory, and what have been + added for demonstration purposes. First, any class used to define device + events must inherit from DeviceEventHandler. Second, the method signature of + OnDeviceEvent() must also be consistent. Everything else - including the + constructor, destructor, properties, and body of OnDeviceEvent() - are + particular to the example. + """ + def __init__(self, eventname): + """ + This constructor registers an event name to be used on device events. + + :param eventname: Name of event to register. + :type eventname: str + :rtype: None + """ + super(DeviceEventHandler, self).__init__() + self.event_name = eventname + self.count = 0 + + def OnDeviceEvent(self, eventname): + """ + Callback function when a device event occurs. + Note eventname is a wrapped gcstring, not a Python string, but basic operations such as printing and comparing + with Python strings are supported. + + :param eventname: gcstring representing the name of the occurred event. + :type eventname: gcstring + :rtype: None + """ + if eventname == self.event_name: + self.count += 1 + + # Print information on specified device event + print('\tDevice event %s with ID %i number %i...' % (eventname, + self.GetDeviceEventId(), + self.count)) + else: + # Print no information on non-specified event + print('\tDevice event occurred; not %s; ignoring...' % self.event_name) + + +def configure_device_events(nodemap, cam): + """ + This function configures the example to execute device events by enabling all + types of device events, and then creating and registering a device event handler that + only concerns itself with an end of exposure event. + + :param INodeMap nodemap: Device nodemap. + :param CameraPtr cam: Pointer to camera. + :returns: tuple (result, device_event_handler) + WHERE + result is True if successful, False otherwise + device_event_handler is the event handler + :rtype: (bool, DeviceEventHandler) + """ + print('\n*** CONFIGURING DEVICE EVENTS ***\n') + + try: + result = True + + # Retrieve device event selector + # + # *** NOTES *** + # Each type of device event must be enabled individually. This is done + # by retrieving "EventSelector" (an enumeration node) and then enabling + # the device event on "EventNotification" (another enumeration node). + # + # This example only deals with exposure end events. However, instead of + # only enabling exposure end events with a simpler device event function, + # all device events are enabled while the device event handler deals with + # ensuring that only exposure end events are considered. A more standard + # use-case might be to enable only the events of interest. + node_event_selector = PySpin.CEnumerationPtr(nodemap.GetNode('EventSelector')) + if not PySpin.IsAvailable(node_event_selector) or not PySpin.IsReadable(node_event_selector): + print('Unable to retrieve event selector entries. Aborting...') + return False + + entries = node_event_selector.GetEntries() + print('Enabling event selector entries...') + + # Enable device events + # + # *** NOTES *** + # In order to enable a device event, the event selector and event + # notification nodes (both of type enumeration) must work in unison. + # The desired event must first be selected on the event selector node + # and then enabled on the event notification node. + for entry in entries: + + # Select entry on selector node + node_entry = PySpin.CEnumEntryPtr(entry) + if not PySpin.IsAvailable(node_entry) or not PySpin.IsReadable(node_entry): + + # Skip if node fails + result = False + continue + + node_event_selector.SetIntValue(node_entry.GetValue()) + + # Retrieve event notification node (an enumeration node) + node_event_notification = PySpin.CEnumerationPtr(nodemap.GetNode('EventNotification')) + if not PySpin.IsAvailable(node_event_notification) or not PySpin.IsWritable(node_event_notification): + + # Skip if node fails + result = False + continue + + # Retrieve entry node to enable device event + node_event_notification_on = PySpin.CEnumEntryPtr(node_event_notification.GetEntryByName('On')) + if not PySpin.IsAvailable(node_event_notification_on) or not PySpin.IsReadable(node_event_notification_on): + + # Skip if node fails + result = False + continue + + node_event_notification.SetIntValue(node_event_notification_on.GetValue()) + + print('\t%s: enabled...' % node_entry.GetDisplayName()) + + # Create device event handler + # + # *** NOTES *** + # The class has been designed to take in the name of an event. If all + # events are registered generically, all event types will trigger a + # device event; on the other hand, if an event handler is registered + # specifically, only that event will trigger an event. + device_event_handler = DeviceEventHandler('EventExposureEnd') + + # Register device event handler + # + # *** NOTES *** + # Device event handlers are registered to cameras. If there are multiple + # cameras, each camera must have any device event handlers registered to it + # separately. Note that multiple device event handlers may be registered to a + # single camera. + # + # *** LATER *** + # Device event handlers must be unregistered manually. This must be done prior + # to releasing the system and while the device event handlers are still in + # scope. + if CHOSEN_EVENT == EventType.GENERIC: + + # Device event handlers registered generally will be triggered by any device events. + cam.RegisterEventHandler(device_event_handler) + + print('Device event handler registered generally...') + + elif CHOSEN_EVENT == EventType.SPECIFIC: + + # Device event handlers registered to a specified event will only + # be triggered by the type of event is it registered to. + cam.RegisterEventHandler(device_event_handler, 'EventExposureEnd') + + print('Device event handler registered specifically to EventExposureEnd events...') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result, device_event_handler + + +def reset_device_events(cam, device_event_handler): + """ + This function resets the example by unregistering the device event handler. + + :param cam: Camera to unregister event handler from. + :param device_event_handler: Event handler for this example. + :type cam: CameraPtr + :type device_event_handler: DeviceEventHandler + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Unregister device event handler + # + # *** NOTES *** + # It is important to unregister all device event handlers from all cameras that + # they are registered to. + cam.UnregisterEventHandler(device_event_handler) + + print('Device event handler unregistered...\n') + + 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 + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** 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.message) + return False + + return result + + +def acquire_images(cam, nodemap, nodemap_tldevice): + """ + 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. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** IMAGE ACQUISITION ***\n') + try: + result = True + + # Set acquisition mode to continuous + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...\n') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) \ + or not PySpin.IsReadable(node_acquisition_mode_continuous): + print('Unable to set acquisition mode to continuous (entry retrieval). Aborting...\n') + return False + + acquisition_mode_continuous = node_acquisition_mode_continuous.GetValue() + + 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 + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Retrieve, convert, and save images + for i in range(NUM_IMAGES): + try: + # Retrieve next received image and ensure image completion + image_result = cam.GetNextImage(1000) + + if image_result.IsIncomplete(): + print('Image incomplete with image status %s...' % image_result.GetImageStatus()) + + else: + + # Print image information + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed Image %i, width = %i, height = %i' % (i, width, height)) + + # Convert to mono8 + image_converted = image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + if device_serial_number: + filename = 'DeviceEvents-%s-%i.jpg' % (device_serial_number, i) + else: + filename = 'DeviceEvents-%i.jpg' % i + + # Save image + image_converted.Save(filename) + print('Image saved at %s' % filename) + + # Release image + image_result.Release() + print('') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def 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 setup and 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 device event handlers + err, device_event_handler = configure_device_events(nodemap, cam) + if not err: + return err + + # Acquire images + result &= acquire_images(cam, nodemap, nodemap_tldevice) + + # Reset device event handlers + result &= reset_device_events(cam, device_event_handler) + + # Deinitialize camera + cam.DeInit() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex.message) + 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: %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) diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/Enumeration.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Enumeration.py new file mode 100644 index 0000000..489b34a --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Enumeration.py @@ -0,0 +1,272 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# Enumeration.py shows how to enumerate interfaces and cameras. +# Knowing this is mandatory for doing anything with the Spinnaker SDK, and is +# therefore the best place to start learning how to use the SDK. +# +# This example introduces the preparation, use, and cleanup of the system +# object, interface and camera lists, interfaces, and cameras. It also touches +# on retrieving both nodes from nodemaps and information from nodes. +# +# Once comfortable with enumeration, we suggest checking out the Acquisition and/or +# NodeMapInfo examples. Acquisition demonstrates using a camera to acquire images, +# and NodeMapInfo demonstrates retrieving information from various node types. + +import PySpin +import sys + + +def query_interface(interface): + """ + Queries an interface for its cameras and prints out device information. + + :param interface: InterfacePtr + :return: True if successful, False otherwise. + :rtype: bool + """ + + try: + result = True + + # Retrieve TL nodemap from interface + # + # *** NOTES *** + # Each interface has a nodemap that can be retrieved in order to + # access information about the interface itself, any devices + # connected, or addressing information if applicable. + nodemap_interface = interface.GetTLNodeMap() + + # Print interface display name + # + # *** NOTES *** + # Grabbing node information requires first retrieving the node and + # then retrieving its information. There are two things to keep in + # mind. First, a node is distinguished by type, which is related + # to its value's data type. Second, nodes should be checked for + # availability and readability/writability prior to making an + # attempt to read from or write to the node. + # + # Note that for Python, the node retrieved then has to be 'cast' + # to the proper type (CStringPtr in this case) before it can be used. + node_interface_display_name = PySpin.CStringPtr(nodemap_interface.GetNode('InterfaceDisplayName')) + + if PySpin.IsAvailable(node_interface_display_name) and PySpin.IsReadable(node_interface_display_name): + interface_display_name = node_interface_display_name.GetValue() + + print(interface_display_name) + + else: + print('Interface display name not readable') + + # Update list of cameras on the interface + # + # *** NOTES *** + # Updating the cameras on each interface is especially important if + # there has been any device arrivals or removals since the last time + # that UpdateCameras() was called. + interface.UpdateCameras() + + # Retrieve list of cameras from the interface + # + # *** NOTES *** + # Camera lists can be retrieved from an interface or the system object. + # Camera lists retrieved from an interface, such as this one, only + # return cameras attached on that specific interface whereas camera + # lists retrieved from the system will return all cameras on all + # interfaces. + # + # *** LATER *** + # Camera lists must be cleared manually. This must be done prior to + # releasing the system and while the camera list is still in scope. + cam_list = interface.GetCameras() + + # Retrieve number of cameras + num_cams = cam_list.GetSize() + + # Return if no cameras detected + if num_cams == 0: + print('\tNo devices detected.\n') + return result + + # Print device vendor and model name for each camera on the interface + for i, cam in enumerate(cam_list): + + # Retrieve TL device nodemap; please see NodeMapInfo example for + # additional comments on transport layer nodemaps + nodemap_tldevice = cam.GetTLDeviceNodeMap() + + # Print device vendor name and device model name + # + # *** NOTES *** + # Grabbing node information requires first retrieving the node and + # then retrieving its information. There are two things to keep in + # mind. First, a node is distinguished by type, which is related + # to its value's data type. Second, nodes should be checked for + # availability and readability/writability prior to making an + # attempt to read from or write to the node. + node_device_vendor_name = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceVendorName')) + + if PySpin.IsAvailable(node_device_vendor_name) and PySpin.IsReadable(node_device_vendor_name): + device_vendor_name = node_device_vendor_name.ToString() + + node_device_model_name = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceModelName')) + + if PySpin.IsAvailable(node_device_model_name) and PySpin.IsReadable(node_device_model_name): + device_model_name = node_device_model_name.ToString() + + print('\tDevice %i %s %s \n' % (i, device_vendor_name, device_model_name)) + + # 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 losing scope + # + # *** NOTES *** + # Camera lists (and interface lists) must be cleared manually while in + # the same scope that the system is released. However, in cases like this + # where scope is lost, camera lists (and interface lists) will be cleared + # automatically. + cam_list.Clear() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def main(): + """ + Example entry point. + + :return: True if successful, False otherwise. + :rtype: bool + """ + result = True + + # Retrieve singleton reference to system object + # + # *** NOTES *** + # Everything originates with the system object. It is important to notice + # that it has a singleton implementation, so it is impossible to have + # multiple system objects at the same time. Users can only get a smart + # pointer (SystemPtr) to the system instance. + # + # *** LATER *** + # The system object should be cleared prior to program completion. If not + # released explicitly, it will be released automatically when all SystemPtr + # objects that point to the system go out of scope. + 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 interfaces from the system + # + # *** NOTES *** + # Interface lists are retrieved from the system object. + # + # *** LATER *** + # Interface lists must be cleared manually. This must be done prior to + # releasing the system and while the interface list is still in scope. + iface_list = system.GetInterfaces() + + # Get number of interfaces + num_interfaces = iface_list.GetSize() + + print('Number of interfaces detected: %i' % num_interfaces) + + # Retrieve list of cameras from the system + # + # *** NOTES *** + # Camera lists can be retrieved from an interface or the system object. + # Camera lists retrieved from the system, such as this one, return all + # cameras available on the system. + # + # *** LATER *** + # Camera lists must be cleared manually. This must be done prior to + # releasing the system and while the camera list is still in scope. + cam_list = system.GetCameras() + + num_cams = cam_list.GetSize() + + print('Number of cameras detected: %i' % num_cams) + + # Finish if there are no cameras + if num_cams == 0 or num_interfaces == 0: + + # Clear camera list before releasing system + cam_list.Clear() + + # Clear interface list before releasing system + iface_list.Clear() + + # Release system instance + system.ReleaseInstance() + + print('Not enough cameras!') + input('Done! Press Enter to exit...') + return False + + print('\n*** QUERYING INTERFACES ***\n') + + for iface in iface_list: + + # Query interface + result &= query_interface(iface) + + # Release reference to interface + # 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 iface + + # Clear camera list before releasing system + # + # *** NOTES *** + # Camera lists must be cleared manually prior to a system release call. + cam_list.Clear() + + # Clear interface list before releasing system + # + # *** NOTES *** + # Interface lists must be cleared manually prior to a system release call. + iface_list.Clear() + + # Release system instance + # + # *** NOTES *** + # The system should be released, but if it is not, it will do so itself. + # It is often at the release of the system (whether manual or automatic) + # that unreleased resources and still-registered events will throw an + # exception. + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + return result + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/EnumerationEvents.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/EnumerationEvents.py new file mode 100644 index 0000000..79e8187 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/EnumerationEvents.py @@ -0,0 +1,291 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# EnumerationEvents.py explores arrival and removal events on interfaces and the system. +# It relies on information provided in the Enumeration, Acquisition, and NodeMapInfo examples. +# +# It can also be helpful to familiarize yourself with the NodeMapCallback example, +# as nodemap callbacks follow the same general procedure as events, but with a few less steps. +# +# This example creates two user-defined classes: InterfaceEventHandler and SystemEventHandler. +# These child classes allow the user to define properties, parameters, and the event handler itself +# while the parent classes - DeviceArrivalEventHandler, DeviceRemovalEventHandler, and InterfaceEventHandler - +# allow the child classes to interface with Spinnaker. + +import PySpin + +class InterfaceEventHandler(PySpin.InterfaceEventHandler): + """ + This class defines the properties and methods for device arrivals and removals + on an interface. Take special note of the signatures of the OnDeviceArrival() + and OnDeviceRemoval() methods. Also, enumeration event handlers must inherit from + InterfaceEvent whether they are to be registered to the system or an interface. + """ + def __init__(self, iface, iface_num): + """ + Constructor. Note that this sets the interface instance. + + :param iface: Interface instance. + :param iface_num: Interface number. + """ + super(InterfaceEventHandler, self).__init__() + self.interface = iface + self.interface_num = iface_num + + def OnDeviceArrival(self, serial_number): + """ + This method defines the arrival event on an interface. It prints out + the device serial number of the camera arriving and the interface + number. The argument is the serial number of the camera that triggered + the arrival event. + + :param serial_number: gcstring representing the device serial number of arriving camera + :type serial_number: gcstring + :return: None + """ + print('Interface event handler:') + print('\tDevice %i has arrived on interface %i.' % (serial_number, self.interface_num)) + + def OnDeviceRemoval(self, serial_number): + """ + This method defines removal events on an interface. It prints out the + device serial number of the camera being removed and the interface + number. The argument is the serial number of the camera that triggered + the removal event. + + :param serial_number: gcstring representing the device serial number of removed camera + :type serial_number: gcstring + :return: None + """ + print('Interface event handler:') + print('\tDevice %i was removed from interface %i.' % (serial_number, self.interface_num)) + + +class SystemEventHandler(PySpin.InterfaceEventHandler): + """ + In the C++ example, the SystemEventHandler inherits from both DeviceArrivalEventHandler and + DeviceRemovalEventHandler. This doesn't work for this wrapper, as it will only inherit the abstract + method from the first base class listed, so for this example both System and Interface + event handlers inherit from InterfaceEventHandler. + All three event handler types - DeviceArrivalEventHandler, DeviceRemovalEventHandler, and InterfaceEventHandler - can be + registered to interfaces, the system, or both. + """ + def __init__(self, system): + """ + Constructor. This sets the system instance. + + :param system: Instance of the system. + :type system: SystemPtr + :rtype: None + """ + super(SystemEventHandler, self).__init__() + self.system = system + + def OnDeviceArrival(self, serial_number): + """ + This method defines the arrival event on the system. It retrieves the + number of cameras currently connected and prints it out. + + :param serial_number: gcstring representing the serial number of the arriving camera. + :type serial_number: gcstring + :return: None + """ + cam_list = self.system.GetCameras() + count = cam_list.GetSize() + print('System event handler:') + print('\tThere %s %i %s on the system.' % ('is' if count == 1 else 'are', + count, + 'device' if count == 1 else 'devices')) + + def OnDeviceRemoval(self, serial_number): + """ + This method defines the removal event on the system. It does the same + as the system arrival event - it retrieves the number of cameras + currently connected and prints it out. + + :param serial_number: gcstring representing the serial number of the removed camera. + :type serial_number: gcstring + :return: None + """ + cam_list = self.system.GetCameras() + count = cam_list.GetSize() + print('System event handler:') + print('\tThere %s %i %s on the system.' % ('is' if count == 1 else 'are', + count, + 'device' if count == 1 else 'devices')) + + +def check_gev_enabled(system): + """ + This function checks if GEV enumeration is enabled on the system. + + :param system: Current system instance. + :type system: SystemPtr + + """ + + # Retrieve the System TL NodeMap and EnumerateGEVInterfaces node + system_node_map = system.GetTLNodeMap() + node_gev_enumeration = PySpin.CBooleanPtr(system_node_map.GetNode('EnumerateGEVInterfaces')) + + # Ensure the node is valid + if not PySpin.IsAvailable(node_gev_enumeration) or not PySpin.IsReadable(node_gev_enumeration): + print('EnumerateGEVInterfaces node is unavailable or unreadable. Aborting...') + return + + # Check if node is enabled + gev_enabled = node_gev_enumeration.GetValue() + if not gev_enabled: + print('\nWARNING: GEV Enumeration is disabled.') + print('If you intend to use GigE cameras please run the EnableGEVInterfaces shortcut\n' + 'or set EnumerateGEVInterfaces to true and relaunch your application.\n') + return + print('GEV enumeration is enabled. Continuing..') + + +def main(): + """ + Example entry point; please see Enumeration example for more in-depth + comments on preparing and cleaning up the system. + + :rtype: None + """ + # 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)) + + # Check if GEV enumeration is enabled + check_gev_enabled(system) + + # Retrieve list of cameras from the system + cam_list = system.GetCameras() + + num_cams = cam_list.GetSize() + + print('Number of cameras detected: %i' % num_cams) + + # Retrieve list of interfaces from the system + # + # *** NOTES *** + # MacOS interfaces are only registered if they are active. + # For this example to have the desired outcome all devices must be connected + # at the beginning and end of this example in order to register and deregister + # an event handler on each respective interface. + iface_list = system.GetInterfaces() + + num_ifaces = iface_list.GetSize() + + print('Number of interfaces detected: %i' % num_ifaces) + + print('*** CONFIGURING ENUMERATION EVENTS *** \n') + + # Create interface event handler for the system + # + # *** NOTES *** + # The SystemEventHandler has been constructed to accept a system object in + # order to print the number of cameras on the system. + system_event_handler = SystemEventHandler(system) + + # Register interface event handler for the system + # + # *** NOTES *** + # Arrival, removal, and interface event handlers can all be registered to + # interfaces or the system. Do not think that interface event handlers can only be + # registered to an interface. An interface event handler is merely a combination + # of an arrival and a removal event handler. + # + # *** LATER *** + # Arrival, removal, and interface event handlers must all be unregistered manually. + # This must be done prior to releasing the system and while they are still + # in scope. + system.RegisterInterfaceEventHandler(system_event_handler) + + # Create and register interface event handler to each interface + # + # *** NOTES *** + # The process of event handler creation and registration on interfaces is similar + # to the process of event creation and registration on the system. The + # class for interfaces has been constructed to accept an interface and an + # interface number (this is just to separate the interfaces). + # + # *** LATER *** + # Arrival, removal, and interface event handlers must all be unregistered manually. + # This must be done prior to releasing the system and while they are still + # in scope. + interface_events = [] + + for i, iface in enumerate(iface_list): + + # Create interface event handler + iface_event_handler = InterfaceEventHandler(iface, i) + interface_events.append(iface_event_handler) + + # Register interface event handler + iface.RegisterEventHandler(interface_events[i]) + + print('Event handler registered to interface %i ...' % i) + + # Release reference to interface event handler + # 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 iface_event_handler + + # Wait for user to plug in and/or remove camera devices + input('\nReady! Remove/Plug in cameras to test or press Enter to exit...\n') + + # Unregister interface event handler from each interface + # + # *** NOTES *** + # It is important to unregister all arrival, removal, and interface event handlers + # from all interfaces that they may be registered to. + for i, iface in enumerate(iface_list): + iface.UnregisterEventHandler(interface_events[i]) + + # Release reference to interface and interface event handlers + del iface + del interface_events + print('Event handler unregistered from interfaces...') + + # Unregister system event handler from system object + # + # *** NOTES *** + # It is important to unregister all arrival, removal, and interface event handlers + # registered to the system. + system.UnregisterInterfaceEventHandler(system_event_handler) + + # Delete system event handler, which has a system reference + del system_event_handler + print('Event handler unregistered from system...') + + # Clear camera list before releasing system + cam_list.Clear() + + # Clear interface list before releasing system + iface_list.Clear() + + # Release system instance + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + +if __name__ == '__main__': + main() diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/Enumeration_QuickSpin.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Enumeration_QuickSpin.py new file mode 100644 index 0000000..f016f64 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Enumeration_QuickSpin.py @@ -0,0 +1,260 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# Enumeration_QuickSpin.py shows how to enumerate interfaces +# and cameras using the QuickSpin API. QuickSpin is a subset of the Spinnaker +# library that allows for simpler node access and control. This is a great +# example to start learning about QuickSpin. +# +# This example introduces the preparation, use, and cleanup of the system +# object, interface and camera lists, interfaces, and cameras. It also +# touches on retrieving information from pre-fetched nodes using QuickSpin. +# Retrieving node information is the only portion of the example that +# differs from Enumeration. +# +# 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 + + +def query_interface(interface): + """ + Queries an interface for its cameras and prints out device information. + + :param interface: InterfacePtr + :return: True if successful, False otherwise. + :rtype: bool + """ + + try: + result = True + + # Print interface display name + # + # *** NOTES *** + # QuickSpin allows for the retrieval of interface information directly + # from an interface. Because interface information is made available + # on the transport layer, camera initialization is not required. + node_interface_display_name = interface.TLInterface.InterfaceDisplayName + if PySpin.IsAvailable(node_interface_display_name) and PySpin.IsReadable(node_interface_display_name): + + interface_display_name = node_interface_display_name.GetValue() + + print(interface_display_name) + + else: + print('Interface display name not readable') + + # Update list of cameras on the interface + # + # *** NOTES *** + # Updating the cameras on each interface is especially important if + # there has been any device arrivals or removals since the last time + # that UpdateCameras() was called. + interface.UpdateCameras() + + # Retrieve list of cameras from the interface + # + # *** NOTES *** + # Camera lists can be retrieved from an interface or the system object. + # Camera lists retrieved from an interface, such as this one, only + # return cameras attached on that specific interface whereas camera + # lists retrieved from the system will return all cameras on all + # interfaces. + # + # *** LATER *** + # Camera lists must be cleared manually. This must be done prior to + # releasing the system and while the camera list is still in scope. + cam_list = interface.GetCameras() + + # Retrieve number of cameras + num_cams = cam_list.GetSize() + + # Return if no cameras detected + if num_cams == 0: + print('\tNo devices detected.\n') + return True + + # Print device vendor and model name for each camera on the interface + for i, cam in enumerate(cam_list): + + # Print device vendor name and device model name + # + # *** NOTES *** + # In QuickSpin, accessing nodes does not require first retrieving a + # nodemap. Instead, GenICam nodes are made available + # directly through the camera, and transport layer nodes are made + # available through the camera's TLDevice and TLStream properties. + # + # Most camera interaction happens through the GenICam nodemap, which + # requires the device to be initialized. Simpler reads, like the + # ones below, can often be accomplished at the transport layer, + # which does not require initialization; please see + # NodeMapInfo_QuickSpin for additional information on this topic. + # + # Readability/writability should be checked prior to interacting with + # nodes. Readability and writability are ensured by checking the + # access mode or by using the methods + if cam.TLDevice.DeviceVendorName.GetAccessMode() == PySpin.RO: + device_vendor_name = cam.TLDevice.DeviceVendorName.ToString() + + if cam.TLDevice.DeviceModelName.GetAccessMode() == PySpin.RO: + device_model_name = cam.TLDevice.DeviceModelName.GetValue() + + print('\tDevice %i %s %s \n' % (i, device_vendor_name, device_model_name)) + + # 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 losing scope + # + # *** NOTES *** + # Camera lists (and interface lists) must be cleared manually while in + # the same scope that the system is released. However, in cases like this + # where scope is lost, camera lists (and interface lists) will be cleared + cam_list.Clear() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def main(): + """ + Example entry point. + :return: True if successful, False otherwise. + :rtype: bool + """ + result = True + + # Retrieve singleton reference to system object + # + # *** NOTES *** + # Everything originates with the system object. It is important to notice + # that it has a singleton implementation, so it is impossible to have + # multiple system objects at the same time. Users can only get a smart + # pointer (SystemPtr) to the system instance. + # + # *** LATER *** + # The system object should be cleared prior to program completion. If not + # released explicitly, it will be released automatically when all SystemPtr + # objects that point to the system go out of scope. + 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 interfaces from the system + # + # *** NOTES *** + # Interface lists are retrieved from the system object. + # + # *** LATER *** + # Interface lists must be cleared manually. This must be done prior to + # releasing the system and while the interface list is still in scope. + iface_list = system.GetInterfaces() + + # Get number of interfaces + num_ifaces = iface_list.GetSize() + + print('Number of interfaces detected: %i' % num_ifaces) + + # Retrieve list of cameras from the system + # + # *** NOTES *** + # Camera lists can be retrieved from an interface or the system object. + # Camera lists retrieved from the system, such as this one, return all + # cameras available on the system. + # + # *** LATER *** + # Camera lists must be cleared manually. This must be done prior to + # releasing the system and while the camera list is still in scope. + cam_list = system.GetCameras() + + num_cams = cam_list.GetSize() + + print('Number of cameras detected: %i' % num_cams) + + # Finish if there are no cameras + if num_cams == 0 or num_ifaces == 0: + + # Clear camera list before releasing system + cam_list.Clear() + + # Clear interface list before releasing system + iface_list.Clear() + + # Release system instance + system.ReleaseInstance() + + print('Not enough cameras!') + input('Done! Press Enter to exit...') + return False + + print('\n*** QUERYING INTERFACES ***\n') + + for iface in iface_list: + + # Query interface + result &= query_interface(iface) + + # Release reference to interface + # 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 iface + + # Clear camera list before releasing system + # + # *** NOTES *** + # Camera lists must be cleared manually prior to a system release call. + cam_list.Clear() + + # Clear interface list before releasing system + # + # *** NOTES *** + # Interface lists must be cleared manually prior to a system release call. + iface_list.Clear() + + # Release system instance + # + # *** NOTES *** + # The system should be released, but if it is not, it will do so itself. + # It is often at the release of the system (whether manual or automatic) + # that unreleased resources and still registered events will throw an + # exception. + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + return result + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) \ No newline at end of file diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/Exposure_QuickSpin.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Exposure_QuickSpin.py new file mode 100644 index 0000000..af71c34 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Exposure_QuickSpin.py @@ -0,0 +1,369 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# Exposure_QuickSpin.py shows how to customize image exposure time +# using the QuickSpin API. QuickSpin is a subset of the Spinnaker library +# that allows for simpler node access and control. +# +# This example prepares the camera, sets a new exposure time, and restores +# the camera to its default state. Ensuring custom values fall within an +# acceptable range is also touched on. Retrieving and setting information +# is the only portion of the example that differs from Exposure. +# +# 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 = 5 # number of images to save + + +def configure_exposure(cam): + """ + This function configures a custom exposure time. Automatic exposure is turned + off in order to allow for the customization, and then the custom setting is + applied. + + :param cam: Camera to configure exposure for. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** CONFIGURING EXPOSURE ***\n') + + try: + result = True + + # Turn off automatic exposure mode + # + # *** NOTES *** + # Automatic exposure prevents the manual configuration of exposure + # times and needs to be turned off for this example. Enumerations + # representing entry nodes have been added to QuickSpin. This allows + # for the much easier setting of enumeration nodes to new values. + # + # The naming convention of QuickSpin enums is the name of the + # enumeration node followed by an underscore and the symbolic of + # the entry node. Selecting "Off" on the "ExposureAuto" node is + # thus named "ExposureAuto_Off". + # + # *** LATER *** + # Exposure time can be set automatically or manually as needed. This + # example turns automatic exposure off to set it manually and back + # on to return the camera to its default state. + + if cam.ExposureAuto.GetAccessMode() != PySpin.RW: + print('Unable to disable automatic exposure. Aborting...') + return False + + cam.ExposureAuto.SetValue(PySpin.ExposureAuto_Off) + print('Automatic exposure disabled...') + + # Set exposure time manually; exposure time recorded in microseconds + # + # *** NOTES *** + # Notice that the node is checked for availability and writability + # prior to the setting of the node. In QuickSpin, availability and + # writability are ensured by checking the access mode. + # + # Further, it is ensured that the desired exposure time does not exceed + # the maximum. Exposure time is counted in microseconds - this can be + # found out either by retrieving the unit with the GetUnit() method or + # by checking SpinView. + + if cam.ExposureTime.GetAccessMode() != PySpin.RW: + print('Unable to set exposure time. Aborting...') + return False + + # Ensure desired exposure time does not exceed the maximum + exposure_time_to_set = 2000000.0 + exposure_time_to_set = min(cam.ExposureTime.GetMax(), exposure_time_to_set) + cam.ExposureTime.SetValue(exposure_time_to_set) + print('Shutter time set to %s us...\n' % exposure_time_to_set) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def reset_exposure(cam): + """ + This function returns the camera to a normal state by re-enabling automatic exposure. + + :param cam: Camera to reset exposure on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Turn automatic exposure back on + # + # *** NOTES *** + # Automatic exposure is turned on in order to return the camera to its + # default state. + + if cam.ExposureAuto.GetAccessMode() != PySpin.RW: + print('Unable to enable automatic exposure (node retrieval). Non-fatal error...') + return False + + cam.ExposureAuto.SetValue(PySpin.ExposureAuto_Continuous) + + print('Automatic exposure enabled...') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def print_device_info(cam): + """ + 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 cam: Camera to get device information from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** DEVICE INFORMATION ***\n') + + try: + result = True + nodemap = cam.GetTLDeviceNodeMap() + + 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.message) + 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 the acquisition of images. + + :param cam: Camera to acquire images from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + print('*** IMAGE ACQUISITION ***') + + 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 is not None and cam.TLDevice.DeviceSerialNumber.GetAccessMode() == PySpin.RO: + device_serial_number = cam.TLDevice.DeviceSerialNumber.GetValue() + + print('Device serial number retrieved as %s...' % device_serial_number) + + # Get the value of exposure time to set an appropriate timeout for GetNextImage + timeout = 0 + if cam.ExposureTime.GetAccessMode() == PySpin.RW or cam.ExposureTime.GetAccessMode() == PySpin.RO: + # The exposure time is retrieved in µs so it needs to be converted to ms to keep consistency with the unit being used in GetNextImage + timeout = (int)(cam.ExposureTime.GetValue() / 1000 + 1000) + else: + print ('Unable to get exposure time. Aborting...') + return False + + # Retrieve, convert, and save images + for i in range(NUM_IMAGES): + try: + # Retrieve next received image and ensure image completion + # By default, GetNextImage will block indefinitely until an image arrives. + # In this example, the timeout value is set to [exposure time + 1000]ms to ensure that an image has enough time to arrive under normal conditions + image_result = cam.GetNextImage(timeout) + + 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 Mono8 + image_converted = image_result.Convert(PySpin.PixelFormat_Mono8) + + # Create a unique filename + filename = 'ExposureQS-%s-%d.jpg' % (device_serial_number, i) + + # Save image + image_converted.Save(filename) + + print('Image saved at %s' % filename) + + # Release image + image_result.Release() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + # End acquisition + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def run_single_camera(cam): + """ + This function acts as the body of the example; please see NodeMapInfo_QuickSpin example for more + in-depth comments on setting up cameras. + + :param cam: Camera to run example on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + # Initialize camera + cam.Init() + + # Print device info + result = print_device_info(cam) + + # Configure exposure + if not configure_exposure(cam): + return False + + # Acquire images + result &= acquire_images(cam) + + # Reset exposure + result &= reset_exposure(cam) + + # Deinitialize camera + cam.DeInit() + + return result + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + +def main(): + """ + Example entry point; please see Enumeration_QuickSpin 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) diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/FileAccess_QuickSpin.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/FileAccess_QuickSpin.py new file mode 100644 index 0000000..f2dae8c --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/FileAccess_QuickSpin.py @@ -0,0 +1,692 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# FileAccess_QuickSpin.py shows shows how to read and write images using camera File Access function. +# +# This example uploads an image to the camera File Access storage and also +# downloads the image from the camera File Access storage and saves it to +# the disk. +# +# It also provides debug message when an additional argument `--verbose` is passed in, +# giving more detailed status of the progress to the users. +# +# Run with arguments in format (no quotes): "--mode --verbose (optional)" +# /d: Download saved image from camera and save it to the working directory. +# /u: Grab an image and store it on camera. +# + +import PySpin +import numpy as np +import os +import argparse +import sys + +parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter) +subparsers = parser.add_subparsers() + +class ImageAcquisitionUtil: + @staticmethod + def check_node_readable(node): + return PySpin.IsAvailable(node) and PySpin.IsReadable(node) + + @staticmethod + def grab_reference_image(cam): + """ + This function first grabs 5 images to stablize the camera, + then it grabs a reference image and returns its pointer. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: Pointer to the reference image + :rtype: ImagePtr + """ + reference_image = PySpin.Image.Create() + + # Start capturing images + cam.BeginAcquisition() + + # Grab a couple of images to stabilize the camera + for image_count in range(5): + try: + result_image = cam.GetNextImage(1000) + if result_image.IsIncomplete(): + print('Imgae incomplete with image status %s' % result_image.GetImageStatus()) + else: + print('Grabbed image %s' %str(image_count) + ', width = %s' % str(result_image.GetWidth())\ + + ', height = %s' % str(result_image.GetHeight())) + reference_image.DeepCopy(result_image) + result_image.Release() + except PySpin.SpinnakerException as ex: + print(ex) + continue + + cam.EndAcquisition() + + return reference_image + +class FileAccess: + @staticmethod + 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 ImageAcquisitionUtil.check_node_readable(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')) + print('') + else: + print('Device control information not available.') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + @staticmethod + def execute_delete_command(cam): + """ + This function executes delete operation on the camera. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + cam.FileOperationSelector.SetValue(PySpin.FileOperationSelector_Delete) + cam.FileOperationExecute.Execute() + + if cam.FileOperationStatus.GetValue() != PySpin.FileOperationStatus_Success: + print('Failed to delete file!') + return False + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return True + + @staticmethod + def open_file_to_write(cam): + """ + This function opens the camera file for writing. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + cam.FileOperationSelector.SetValue(PySpin.FileOperationSelector_Open) + cam.FileOpenMode.SetValue(PySpin.FileOpenMode_Write) + cam.FileOperationExecute.Execute() + + if cam.FileOperationStatus.GetValue() != PySpin.FileOperationStatus_Success: + print('Failed to open file for writing!') + return False + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return True + + @staticmethod + def execute_write_command(cam): + """ + This function executes write command on the camera. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + cam.FileOperationSelector.SetValue(PySpin.FileOperationSelector_Write) + cam.FileOperationExecute.Execute() + + if cam.FileOperationStatus.GetValue() != PySpin.FileOperationStatus_Success: + print('Failed to write to file!') + return False + except PySpin.SpinnakerException as ex: + print('Unexpected exception : %s' % ex) + return False + return True + + @staticmethod + def close_file(cam): + """ + This function closes the file. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + cam.FileOperationSelector.SetValue(PySpin.FileOperationSelector_Close) + cam.FileOperationExecute.Execute() + + if cam.FileOperationStatus.GetValue() != PySpin.FileOperationStatus_Success: + print('Failed to close file!') + return False + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return True + + @staticmethod + def upload_image(cam, verbose=False): + """ + This function first acquires a reference image from the camera, + then it writes the image file to the camera with file selector UserFile1. + + :param cam: Camera used to download file from. + :param verbose: Prints additional details of file download (False by default) + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + success = True + + nodemap_tldevice = cam.GetTLDeviceNodeMap() + FileAccess.print_device_info(nodemap_tldevice) + + cam.Init() + + # Check file selector support + print('Checking file selector support') + if cam.FileSelector.GetAccessMode() == PySpin.NA or cam.FileSelector.GetAccessMode() == PySpin.NI: + print('File selector not supported on device!') + return False + + # Apply small pixel format + if ImageAcquisitionUtil.check_node_readable(cam.PixelFormat.GetEntry(PySpin.PixelFormat_Mono8)): + cam.PixelFormat.SetValue(PySpin.PixelFormat_Mono8) + else: + # Use Bayer8 if Mono8 is not available + cam.PixelFormat.SetValue(PySpin.PixelFormat_BayerGB8) + + # Display camera setup information + print('Width: %s' % cam.Width.GetValue()) + print('Height: %s' % cam.Height.GetValue()) + print('offsetX: %s' % cam.OffsetX.GetValue()) + print('OffsetY: %s' % cam.OffsetY.GetValue()) + print('PixelFormat: %s' % cam.PixelFormat.GetValue()) + + # Grab reference image + try: + reference_image = ImageAcquisitionUtil.grab_reference_image(cam) + except PySpin.SpinnakerException as ex: + cam.DeInit() + del cam + print('Unexpected error grabbing reference image: %s' % ex) + return False + + # Form file path + filename = "DeviceStreamWrite-" + if cam.DeviceSerialNumber.GetAccessMode() == PySpin.RW or cam.DeviceSerialNumber.GetAccessMode() == PySpin.RO: + filename += "%s-" % cam.DeviceSerialNumber.ToString() + filename += ".bmp" + + # Save image + reference_image.Save(filename) + print('Image saved at %s' % filename) + + print('*** UPLOADING IMAGE ***') + + # Perform file stream write + selector_list = cam.FileSelector.GetEntries() + + for entry in selector_list: + # Get current enum entry node + node = PySpin.CEnumEntryPtr(entry) + + if verbose: + print('\nChecking FileSelector EnumEntry - %s' % node.GetSymbolic()) + + # Check file selector entry support + if not node or not ImageAcquisitionUtil.check_node_readable(node): + # Go to next entry node + print('%s not supported!' % node.GetSymbolic()) + continue + + if node.GetSymbolic() == "UserFile1": + # Set file selector + cam.FileSelector.SetIntValue(int(node.GetNumericValue())) + + # Delete file on camera before writing in case camera runs out of space + file_size = cam.FileSize.GetValue() + if file_size > 0: + if not FileAccess.execute_delete_command(cam): + print('Failed to delete file!') + success = False + continue + + # Open file on camera for write + if not FileAccess.open_file_to_write(cam): + print('Failed to open file!') + success = False + continue + + # Attempt to set FileAccessLength to FileAccessBufferNode length to speed up the write + if cam.FileAccessLength.GetValue() < cam.FileAccessBuffer.GetLength(): + try: + cam.FileAccessLength.SetValue(cam.FileAccessBuffer.GetLength()) + except PySpin.SpinnakerException as ex: + print('Unable to set FileAccessLength to FileAccessBuffer length: %s' % ex) + + # Set file access offset to zero if it's not + cam.FileAccessOffset.SetValue(0) + + # Compute number of write operations required + total_bytes_to_write = reference_image.GetBufferSize() + intermediate_buffer_size = cam.FileAccessLength.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.') + return False + + if verbose: + print('') + 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): + offset = index * intermediate_buffer_size + if offset == 0: + continue + sections.append(offset) + + # Get image data and split into equal chunks + image_data = reference_image.GetData() + split_data = np.array_split(image_data, sections) + + for i in range(len(split_data)): + # Setup data to write + tmp_buffer = split_data[i] + + # Write to AccessBufferNode + cam.FileAccessBuffer.Set(tmp_buffer) + + if intermediate_buffer_size > bytes_left_to_write: + # Update FileAccessLength, otherwise garbage data outside the range would be written to device + cam.FileAccessLength.SetValue(bytes_left_to_write) + + # Perform write command + if not FileAccess.execute_write_command(cam): + print('Writing stream failed!') + success = False + break + + # Verify size of bytes written + size_written = cam.FileOperationResult.GetValue() + + # Log current file access offset + if verbose: + print('File Access Offset: %s' % cam.FileAccessOffset.GetValue()) + + # Keep track of total bytes written + total_bytes_written += size_written + if verbose: + print('Bytes written: %s of %s' % (total_bytes_written, total_bytes_to_write)) + + # Keep track of bytes left to write + bytes_left_to_write = total_bytes_to_write - total_bytes_written + + if verbose: + print('Progress: (%s//%s)' % (i, write_iterations)) + else: + print('Progress: %s' % int((i*100 / write_iterations)) + "%") + + print('Writing complete') + + if not FileAccess.close_file(cam): + success = False + + cam.DeInit() + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return success + + @staticmethod + def open_file_to_read(cam): + """ + This function opens the file to read. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + cam.FileOperationSelector.SetValue(PySpin.FileOperationSelector_Open) + cam.FileOpenMode.SetValue(PySpin.FileOpenMode_Read) + cam.FileOperationExecute.Execute() + + if cam.FileOperationStatus.GetValue() != PySpin.FileOperationStatus_Success: + print('Failed to open file for reading!') + return False + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return True + + @staticmethod + def execute_read_command(cam): + """ + This function executes read command on the camera. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + cam.FileOperationSelector.SetValue(PySpin.FileOperationSelector_Read) + cam.FileOperationExecute.Execute() + + if cam.FileOperationStatus.GetValue() != PySpin.FileOperationStatus_Success: + print('Failed to read file!') + return False + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return True + + @staticmethod + def download_image(cam, verbose=False): + """ + This function reads the image file stored in the camera file selector UserFile1, + saving the file to the working directory of this example. + + :param cam: Camera used to download file from. + :param verbose: Prints additional details of file download (False by default) + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + success = True + + nodemap_tldevice = cam.GetTLDeviceNodeMap() + FileAccess.print_device_info(nodemap_tldevice) + + cam.Init() + + # Check file selector support + print('Checking file selector support') + if cam.FileSelector.GetAccessMode() == PySpin.NA or cam.FileSelector.GetAccessMode() == PySpin.NI: + print('File selector not supported on device!') + return False + + print('*** DOWNLOADING IMAGE ***') + + selector_list = cam.FileSelector.GetEntries() + + for entry in selector_list: + node = PySpin.CEnumEntryPtr(entry) + if verbose: + print('\nChecking FileSelector EnumEntry - %s' % node.GetSymbolic()) + + # Check file selector entry support + if not node or not ImageAcquisitionUtil.check_node_readable(node): + # Go to next entry node + print('%s not supported!' % node.GetSymbolic()) + continue + + # Use UserFile1 as the selector in this example. + # Available file selector entries varies across different cameras + if node.GetSymbolic() == "UserFile1": + # Set file selector + cam.FileSelector.SetIntValue(int(node.GetNumericValue())) + + # Get file size + total_bytes_to_read = cam.FileSize.GetValue() + if total_bytes_to_read == 0: + print('%s - No data available to read!' % node.GetSymbolic()) + success = False + continue + + print('Total data to download: %s' % total_bytes_to_read) + + # Open file on camera for reading + if not FileAccess.open_file_to_read(cam): + print('Failed to open file!') + success = False + continue + + # Attempt to set FileAccessLength to FileAccessBufferNode length to speed up the write + if cam.FileAccessLength.GetValue() < cam.FileAccessBuffer.GetLength(): + try: + cam.FileAccessLength.SetValue(cam.FileAccessBuffer.GetLength()) + except PySpin.SpinnakerException as ex: + print('Unable to set FileAccessLength to FileAccessBuffer length: %s' % ex) + + # Set file access offset to zero + cam.FileAccessOffset.SetValue(0) + + # Computer number of read operations required + intermediate_buffer_size = cam.FileAccessLength.GetValue() + read_iterations = (total_bytes_to_read // intermediate_buffer_size) + \ + (0 if ((total_bytes_to_read % intermediate_buffer_size) == 0) else 1) + + if verbose: + print('') + print('Total bytes to read: %s' % total_bytes_to_read) + print('FileAccessLength: %s' % intermediate_buffer_size) + print('Write iterations: %s' % read_iterations) + + print('Fetching image from camera.') + + total_size_read = 0 + size_read = cam.FileOperationResult.GetValue() + image_data = np.array(size_read, dtype=np.uint8) + + for i in range(read_iterations): + if not FileAccess.execute_read_command(cam): + print('Reading stream failed!') + success = False + break + + # Verify size of bytes read + size_read = cam.FileOperationResult.GetValue() + + # Read from buffer Node + buffer_read = cam.FileAccessBuffer.Get(size_read) + if i == 0: + image_data = buffer_read + else: + image_data = np.append(image_data, buffer_read) + + # Keep track of total bytes read + total_size_read += size_read + if verbose: + print('Bytes read: %s of %s' % (total_size_read, total_bytes_to_read)) + print('Progress: (%s//%s)' % (i, read_iterations)) + else: + print('Progress: %s' % int((i*100 / read_iterations)) + "%") + + print('Reading complete') + + if not FileAccess.close_file(cam): + success = False + + # Form file path + filename = "DeviceStreamRead-" + + if cam.DeviceSerialNumber.GetAccessMode() == PySpin.RW or cam.DeviceSerialNumber.GetAccessMode() == PySpin.RO: + filename += "%s-" % cam.DeviceSerialNumber.ToString() + + filename += ".bmp" + + # Image should be captured with Mono8 or Bayer8, it sets camera to correct pixel format + # in order to grab image ROI + if ImageAcquisitionUtil.check_node_readable(cam.PixelFormat.GetEntry(PySpin.PixelFormat_Mono8)): + cam.PixelFormat.SetValue(PySpin.PixelFormat_Mono8) + elif ImageAcquisitionUtil.check_node_readable(cam.PixelFormat.GetEntry(PySpin.PixelFormat_BayerGB8)): + # Use Bayer8 if Mono8 is not available + cam.PixelFormat.SetValue(PySpin.PixelFormat_BayerGB8) + else: + print('Failed to set camera pixel format.') + return False + + width = cam.Width.GetValue() + height = cam.Height.GetValue() + offset_x = cam.OffsetX.GetValue() + offset_y = cam.OffsetY.GetValue() + pixel_format = cam.PixelFormat.GetValue() + + # Form image and save data + print('Width: %s' % width) + print('Height: %s' % height) + print('OffsetX: %s' % offset_x) + print('OffsetY: %s' % offset_y) + print('PixelFormat: %s' % pixel_format) + + # Create image + image = PySpin.Image.Create(width, height, offset_x, offset_y, pixel_format, image_data) + + # Save image + image.Save(filename) + print('Image saved at %s' % filename) + + cam.DeInit() + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return success + +def main(): + """ + Example entry point; please see Enumeration.py example for more in-depth + comments on preparing and cleaning up the system with PySpin. + + :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)) + + parser = argparse.ArgumentParser() + parser = subparsers.add_parser('stop', formatter_class=argparse.RawTextHelpFormatter) + + parser.add_argument('--mode', required=True, type=str, + help='/u : Grab an image and store it on camera.\n/d : Download saved image from camera and save it to the working directory.\n') + parser.add_argument('--verbose', default=False, action='store_true', + help='Enable verbose output.') + + args = parser.parse_args() + + cam_list = system.GetCameras() + num_cameras = cam_list.GetSize() + + # This example only works with 1 camera is connected. + 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 + elif num_cameras > 1: + # Clear camera list before releasing system + cam_list.Clear() + + # Release system instance + system.ReleaseInstance() + + print('This example only works when 1 camera is connected.') + input('Done! Press Enter to exit...') + return False + else: + if args.mode == '/u' or args.mode == '/U': + result = FileAccess.upload_image(cam_list[0], args.verbose) + elif args.mode == '/d' or args.mode == '/D': + result = FileAccess.download_image(cam_list[0], args.verbose) + else: + print("Invalid Argument! Use '--help' to learn available arguments.") + input('Done! Press Enter to exit...') + return False + + if not result: + print('File Access failed') + else: + print('File Access is successful!') + + 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) \ No newline at end of file diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/HighDynamicRange.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/HighDynamicRange.py new file mode 100644 index 0000000..da60789 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/HighDynamicRange.py @@ -0,0 +1,302 @@ +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# HighDynamicRange.py +# This example shows how to set High Dynamic Range (HDR) if it is available on the camera. + +import PySpin +import os +import sys + +NUM_IMAGES = 4 # number of images to grab + +K_HDR_SHUTTER1 = 1000 # us +K_HDR_SHUTTER2 = 5000 +K_HDR_SHUTTER3 = 15000 +K_HDR_SHUTTER4 = 30000 + +K_HDR_GAIN1 = 0 # dB +K_HDR_GAIN2 = 5 +K_HDR_GAIN3 = 10 +K_HDR_GAIN4 = 15 + + +def print_device_info(nodemap): + """ + Helper for outputting camera information + + :param nodemap: Transport layer device nodemap. + :type INodeMap + :returns: True if successful, False otherwise. + :rtype: bool + """ + + print('*** DEVICE INFORMATION ***') + + try: + node_device_information = PySpin.CCategoryPtr(nodemap.GetNode('DeviceControl')) + + 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 True + +def check_node_accessibility(node): + """ + Helper for checking GenICam node accessibility + + :param node: GenICam node being checked + :type node: CNodePtr + :return: True if accessible, False otherwise + :rtype: bool + """ + + return PySpin.IsAvailable(node) and (PySpin.IsReadable(node) or PySpin.IsWritable(node)) + +def toggle_hdr_mode(nodemap, hdr_on): + """ + Helper for toggling HDR mode on camera + + :param nodemap: Transport layer device nodemap. + :type: INodeMap + :param hdr_on: True if want to turn hdr mode on, False otherwise. + :type hdr_on: bool + :return: True if successful, False otherwise. + :rtype: bool + """ + + node_hdr_enabled = PySpin.CBooleanPtr(nodemap.GetNode("PGR_HDRModeEnabled")) + + if check_node_accessibility(node_hdr_enabled): + node_hdr_enabled.SetValue(hdr_on) + else: + return False + + print('HDR mode turned to', hdr_on) + + return True + +def initialize_hdr_images(nodemap): + """ + Helper for initializing HDR images + + :param nodemap: Transport layer device nodemap. + :type: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + hdr_image_selector = PySpin.CEnumerationPtr(nodemap.GetNode("PGR_HDRImageSelector")) + hdr_exposure_abs = PySpin.CFloatPtr(nodemap.GetNode("PGR_HDR_ExposureTimeAbs")) + hdr_gain_abs = PySpin.CFloatPtr(nodemap.GetNode("PGR_HDR_GainAbs")) + + if not check_node_accessibility(hdr_image_selector): + return False + if not check_node_accessibility(hdr_exposure_abs): + return False + if not check_node_accessibility(hdr_gain_abs): + return False + + # Configure Image1 + hdr_image_selector.SetIntValue(hdr_image_selector.GetEntryByName("Image1").GetValue()) + hdr_exposure_abs.SetValue(K_HDR_SHUTTER1) + hdr_gain_abs.SetValue(K_HDR_GAIN1) + print('Initialized HDR Image1...') + + # Configure Image2 + hdr_image_selector.SetIntValue(hdr_image_selector.GetEntryByName("Image2").GetValue()) + hdr_exposure_abs.SetValue(K_HDR_SHUTTER2) + hdr_gain_abs.SetValue(K_HDR_GAIN2) + print('Initialized HDR Image2...') + + # Configure Image3 + hdr_image_selector.SetIntValue(hdr_image_selector.GetEntryByName("Image3").GetValue()) + hdr_exposure_abs.SetValue(K_HDR_SHUTTER3) + hdr_gain_abs.SetValue(K_HDR_GAIN3) + print('Initialized HDR Image3...') + + # Configure Image4 + hdr_image_selector.SetIntValue(hdr_image_selector.GetEntryByName("Image4").GetValue()) + hdr_exposure_abs.SetValue(K_HDR_SHUTTER4) + hdr_gain_abs.SetValue(K_HDR_GAIN4) + print('Initialized HDR Image4...') + + return True + +def run_single_camera(cam): + """ + Helper for running example on single camera + + :param cam: Camera to run on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Initialize camera + cam.Init() + + # Get GenICam NodeMap info from camera + nodemap = cam.GetNodeMap() + + # Get camera information through NodeMap + print_device_info(nodemap) + + # Verify whether HDR is supported on this device + node_hdr_enabled = PySpin.CBooleanPtr(nodemap.GetNode("PGR_HDRModeEnabled")) + if not PySpin.IsAvailable(node_hdr_enabled): + print('HDR is not supported! Exiting...') + return True + + # HDR needs to be enabled prior to configure individual HDR images + toggle_hdr_mode(nodemap, True) + + if not initialize_hdr_images(nodemap): + print('Error configuring HDR image! Exiting...') + return False + + # Retrieve Device ID + device_id = cam.GetTLDeviceNodeMap().GetNode("DeviceID") + + # Begin capturing images + print('Starting grabbing images...') + cam.BeginAcquisition() + + for i in range(NUM_IMAGES): + try: + # Retrieve the next received image + raw_image = cam.GetNextImage(1000) + width = raw_image.GetWidth() + height = raw_image.GetHeight() + print('Grabbed image %d, width = %d, height = %d' % (i, width, height)) + + # Convert image to Mono8 + converted_image = raw_image.Convert(PySpin.PixelFormat_Mono8) + + # Create a unique filename + filename = 'HighDynamicRange-%s-%d.jpg' % (device_id, i) + + # Save image + converted_image.Save(filename) + + # Image need to be released after use + raw_image.Release() + + except PySpin.SpinnakerException as ex: + print('Error Retrieving Image: %s' % ex) + result = False + continue + + # End capturing of images + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + print() + + 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: %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 cam in cam_list: + result &= run_single_camera(cam) + + # 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) diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/ImageChannelStatistics.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/ImageChannelStatistics.py new file mode 100644 index 0000000..7589b73 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/ImageChannelStatistics.py @@ -0,0 +1,302 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# ImageChannelStatisitcs.py shows how to get the image data and channel statistics, and then saves / displays them. +# This example relies on information provided in the Acquisition examples. +# +# This example demonstrates how to visualize the image histogram using Python, and display an image represented as +# a numpy array. +# +# NOTE: matplotlib must be installed on Python interpreter prior to running this example + +import os +import sys +import PySpin +import matplotlib.pyplot as plt + +NUM_IMAGES = 10 # number of images to grab + + +def acquire_and_display_images(cam, nodemap, nodemap_tldevice): + """ + This function acquires and displays the channel statistics of N images from a device. + + :param cam: Camera to acquire images from. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** IMAGE ACQUISITION ***\n') + try: + result = True + + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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...') + + node_pixel_format = PySpin.CEnumerationPtr(nodemap.GetNode('PixelFormat')) + if not PySpin.IsAvailable(node_pixel_format) or not PySpin.IsWritable(node_pixel_format): + print('Unable to set Pixel Format. Aborting...') + return False + + else: + # Retrieve entry node from enumeration node + node_pixel_format_mono8 = PySpin.CEnumEntryPtr(node_pixel_format.GetEntryByName('Mono8')) + if not PySpin.IsAvailable(node_pixel_format_mono8) or not PySpin.IsReadable(node_pixel_format_mono8): + print('Unable to set Pixel Format to MONO8. Aborting...') + return False + + # Retrieve integer value from entry node + pixel_format_mono8 = node_pixel_format_mono8.GetValue() + + # Set integer value from entry node as new value of enumeration node + node_pixel_format.SetIntValue(pixel_format_mono8) + + print('Pixel Format set to MONO8 ...') + + cam.BeginAcquisition() + + print('Acquiring images...') + + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + plt.ion() + for i in range(NUM_IMAGES): + try: + image_result = cam.GetNextImage(1000) + + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + else: + fig = plt.figure(1) + + try: + image_stats = image_result.CalculateChannelStatistics(PySpin.GREY) + # Getting the image data as a numpy array + image_data = image_result.GetNDArray() + + # Display Statistics + print('SN%s image %d:' % (device_serial_number, i)) + print('\tNumber pixel values : %d' % image_stats.num_pixel_values) + print('\tRange: Min = %d, Max = %d' % (image_stats.range_min, + image_stats.range_max)) + print('\tPixel Value: Min = %d, Max = %d, Mean = %.2f' % (image_stats.pixel_value_min, + image_stats.pixel_value_max, + image_stats.pixel_value_mean)) + + # Using matplotlib, two subplots are created where the top subplot is the histogram and the + # bottom subplot is the image. + # + # Refer to https://matplotlib.org/2.0.2/api/pyplot_api.html#module-matplotlib.pyplot + + # Clear the figure to reuse for next plot + plt.clf() + + # Plot the histogram in the first subplot in a 2 row by 1 column grid + plt.subplot(211) + plt.cla() + plt.plot(image_stats.histogram, label='Grey') + plt.title('SN%s Histogram (%d)' % (device_serial_number, i)) + plt.legend() + + # Plot the image in the second subplot in a 2 row by 1 column grid + plt.subplot(212) + plt.cla() + plt.imshow(image_data, cmap='gray') + + # Show the image + plt.show() + plt.pause(0.01) + + # Create a unique filename + if device_serial_number: + filename = 'ImageChannelStatistics-%s-%d.png' % (device_serial_number, i) + else: # if serial number is empty + filename = 'ImageChannelStatistics-%d.png' % i + + fig.savefig(filename) + print('\tSave to %s' % filename) + print() + + except PySpin.SpinnakerException: + raise + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + + except PySpin.SpinnakerException: + raise + + cam.EndAcquisition() + print('End Acquisition') + + plt.close() + + 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 + + nodemap_tldevice = cam.GetTLDeviceNodeMap() + + #Initialize camera + cam.Init() + + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + + # Acquire images + result &= acquire_and_display_images(cam, nodemap, nodemap_tldevice) + + # Deinitialize camera + cam.DeInit() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + +def main(): + """ + Example entry point; notice the volume of data that the logging event handler + prints out on debug despite the fact that very little really happens in this + example. Because of this, it may be better to have the logger set to lower + level in order to provide a more concise, focused log. + + :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: %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) + diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/ImageEvents.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/ImageEvents.py new file mode 100644 index 0000000..ac85f18 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/ImageEvents.py @@ -0,0 +1,452 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# ImageEvents.py shows how to acquire images using the image event handler. +# It relies on information provided in the Enumeration, Acquisition, +# and NodeMapInfo examples. +# +# It can also be helpful to familiarize yourself with the NodeMapCallback +# example, as nodemap callbacks follow the same general procedure as +# events, but with a few less steps. +# +# This example creates a user-defined class, ImageEventHandler, that inherits +# from the Spinnaker class, ImageEventHandler. ImageEventHandler allows the user to +# define any properties, parameters, and the event handler itself while ImageEvent +# allows the child class to appropriately interface with Spinnaker. + +import os +import sys +import PySpin +from time import sleep + +SLEEP_DURATION = 200 # amount of time for main thread to sleep for (in milliseconds) until _NUM_IMAGES have been saved + + +class ImageEventHandler(PySpin.ImageEventHandler): + """ + This class defines the properties, parameters, and the event handler itself. Take a + moment to notice what parts of the class are mandatory, and what have been + added for demonstration purposes. First, any class used to define image event handlers + must inherit from ImageEventHandler. Second, the method signature of OnImageEvent() + must also be consistent. Everything else - including the constructor, + destructor, properties, body of OnImageEvent(), and other functions - + is particular to the example. + """ + _NUM_IMAGES = 10 + + def __init__(self, cam): + """ + Constructor. Retrieves serial number of given camera and sets image counter to 0. + + :param cam: Camera instance, used to get serial number for unique image filenames. + :type cam: CameraPtr + :rtype: None + """ + super(ImageEventHandler, self).__init__() + + nodemap = cam.GetTLDeviceNodeMap() + + # Retrieve device serial number + node_device_serial_number = PySpin.CStringPtr(nodemap.GetNode('DeviceSerialNumber')) + + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + self._device_serial_number = node_device_serial_number.GetValue() + + # Initialize image counter to 0 + self._image_count = 0 + + # 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 + + def OnImageEvent(self, image): + """ + This method defines an image event. In it, the image that triggered the + event is converted and saved before incrementing the count. Please see + Acquisition example for more in-depth comments on the acquisition + of images. + + :param image: Image from event. + :type image: ImagePtr + :rtype: None + """ + # Save max of _NUM_IMAGES Images + if self._image_count < self._NUM_IMAGES: + print('Image event occurred...') + + # Check if image is incomplete + if image.IsIncomplete(): + print('Image incomplete with image status %i...' % image.GetImageStatus()) + + else: + # Print image info + print('Grabbed image %i, width = %i, height = %i' % (self._image_count, + image.GetWidth(), + image.GetHeight())) + + # Convert to mono8 + image_converted = image.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + # Create unique filename and save image + if self._device_serial_number: + filename = 'ImageEvents-%s-%i.jpg' % (self._device_serial_number, self._image_count) + + else: # if serial number is empty + filename = 'ImageEvents-%i.jpg' % self._image_count + + image_converted.Save(filename) + + print('Image saved at %s\n' % filename) + + # Increment image counter + self._image_count += 1 + + def get_image_count(self): + """ + Getter for image count. + + :return: Number of images saved. + :rtype: int + """ + return self._image_count + + def get_max_images(self): + """ + Getter for maximum images. + + :return: Total number of images to save. + :rtype: int + """ + return self._NUM_IMAGES + + +def configure_image_events(cam): + """ + This function configures the example to execute image events by preparing and + registering an image event. + + :param cam: Camera instance to configure image event. + :return: tuple(result, image_event_handler) + WHERE + result is True if successful, False otherwise + image_event_handler is the event handler + :rtype: (bool, ImageEventHandler) + """ + try: + result = True + + # Create image event handler + # + # *** NOTES *** + # The class has been constructed to accept a camera pointer in order + # to allow the saving of images with the device serial number. + image_event_handler = ImageEventHandler(cam) + + # Register image event handler + # + # *** NOTES *** + # Image events are registered to cameras. If there are multiple + # cameras, each camera must have the image events registered to it + # separately. Also, multiple image events may be registered to a + # single camera. + # + # *** LATER *** + # Image event handlers must be unregistered manually. This must be done prior + # to releasing the system and while the image events are still in + # scope. + cam.RegisterEventHandler(image_event_handler) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result, image_event_handler + + +def wait_for_images(image_event_handler): + """ + This function waits for the appropriate amount of images. Notice that + whereas most examples actively retrieve images, the acquisition of images is + handled passively in this example. + + :param image_event_handler: Image event handler. + :type image_event_handler: ImageEventHandler + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Wait for images + # + # *** NOTES *** + # In order to passively capture images using image event handlers and + # automatic polling, the main thread sleeps in increments of SLEEP_DURATION ms + # until _MAX_IMAGES images have been acquired and saved. + while image_event_handler.get_image_count() < image_event_handler.get_max_images(): + print('\t//\n\t// Sleeping for %i ms. Grabbing images...' % SLEEP_DURATION) + sleep(SLEEP_DURATION / 1000.0) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def reset_image_events(cam, image_event_handler): + """ + This functions resets the example by unregistering the image event handler. + + :param cam: Camera instance. + :param image_event_handler: Image event handler for cam. + :type cam: CameraPtr + :type image_event_handler: ImageEventHandler + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Unregister image event handler + # + # *** NOTES *** + # It is important to unregister all image events from all cameras they are registered to. + # Unlike SystemEventHandler and InterfaceEventHandler in the EnumerationEvents example, + # there is no need to explicitly delete the ImageEventHandler here as it does not store + # an instance of the camera (it gets deleted in the constructor already). + cam.UnregisterEventHandler(image_event_handler) + + print('Image events unregistered...') + + 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 from camera. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + print('*** DEVICE INFORMATION ***') + + 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.message) + result = False + + return result + + +def acquire_images(cam, nodemap, image_event_handler): + """ + This function passively waits for images by calling wait_for_images(). Notice that + this function is much shorter than the acquire_images() function of other examples. + This is because most of the code has been moved to the image event's OnImageEvent() + method. + + :param cam: Camera instance to grab images from. + :param nodemap: Device nodemap. + :param image_event_handler: Image event handler. + :type cam: CameraPtr + :type nodemap: INodeMap + :type image_event_handler: ImageEventHandler + :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.IsAvailable(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.IsAvailable(node_acquisition_mode_continuous) or not PySpin.IsReadable(node_acquisition_mode_continuous): + print('Unable to set acquisition mode to continuous (entry retrieval). Aborting...') + return False + + acquisition_mode_continuous = node_acquisition_mode_continuous.GetValue() + node_acquisition_mode.SetIntValue(acquisition_mode_continuous) + + print('Acquisition mode set to continuous...') + + # Begin acquiring images + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve images using image event handler + wait_for_images(image_event_handler) + + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = 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 acquire images from. + :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 image events + err, image_event_handler = configure_image_events(cam) + if not err: + return err + + # Acquire images using the image event handler + result &= acquire_images(cam, nodemap, image_event_handler) + + # Reset image event handlers + result &= reset_image_events(cam, image_event_handler) + + # 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 additional + comments on the steps in this function. + + :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: %d.%d.%d.%d' % (version.major, version.minor, version.type, version.build)) + + # Retrieve list of cameras from the system + cam_list = system.GetCameras() + + num_cams = cam_list.GetSize() + + print('Number of cameras detected: %i' % num_cams) + + # Finish if there are no cameras + if num_cams == 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 + 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) diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/ImageFormatControl.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/ImageFormatControl.py new file mode 100644 index 0000000..e8b19f2 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/ImageFormatControl.py @@ -0,0 +1,501 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# ImageFormatControl.py shows how to apply custom image settings to +# the camera. It relies on information provided in the Enumeration, +# Acquisition, and NodeMapInfo examples. +# +# This example demonstrates setting minimums to offsets, X and Y, and maximums +# to width and height. It also shows the setting of a new pixel format, which +# is an enumeration type node. +# +# Following this, we suggest familiarizing yourself with the Exposure example +# if you haven't already. Exposure is another example on camera customization +# that is shorter and simpler than many of the others. Once comfortable with +# Exposure and ImageFormatControl, we suggest checking out any of the longer, +# more complicated examples related to camera configuration: ChunkData, +# LookupTable, Sequencer, or Trigger. + +import os +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +def configure_custom_image_settings(nodemap): + """ + Configures a number of settings on the camera including offsets X and Y, width, + height, and pixel format. These settings must be applied before BeginAcquisition() + is called; otherwise, they will be read only. Also, it is important to note that + settings are applied immediately. This means if you plan to reduce the width and + move the x offset accordingly, you need to apply such changes in the appropriate order. + + :param nodemap: GenICam nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** CONFIGURING CUSTOM IMAGE SETTINGS *** \n') + + try: + result = True + + # Apply mono 8 pixel format + # + # *** NOTES *** + # Enumeration nodes are slightly more complicated to set than other + # nodes. This is because setting an enumeration node requires working + # with two nodes instead of the usual one. + # + # As such, there are a number of steps to setting an enumeration node: + # retrieve the enumeration node from the nodemap, retrieve the desired + # entry node from the enumeration node, retrieve the integer value from + # the entry node, and set the new value of the enumeration node with + # the integer value from the entry node. + # + # Retrieve the enumeration node from the nodemap + node_pixel_format = PySpin.CEnumerationPtr(nodemap.GetNode('PixelFormat')) + if PySpin.IsAvailable(node_pixel_format) and PySpin.IsWritable(node_pixel_format): + + # Retrieve the desired entry node from the enumeration node + node_pixel_format_mono8 = PySpin.CEnumEntryPtr(node_pixel_format.GetEntryByName('Mono8')) + if PySpin.IsAvailable(node_pixel_format_mono8) and PySpin.IsReadable(node_pixel_format_mono8): + + # Retrieve the integer value from the entry node + pixel_format_mono8 = node_pixel_format_mono8.GetValue() + + # Set integer as new value for enumeration node + node_pixel_format.SetIntValue(pixel_format_mono8) + + print('Pixel format set to %s...' % node_pixel_format.GetCurrentEntry().GetSymbolic()) + + else: + print('Pixel format mono 8 not available...') + + else: + print('Pixel format not available...') + + # Apply minimum to offset X + # + # *** NOTES *** + # Numeric nodes have both a minimum and maximum. A minimum is retrieved + # with the method GetMin(). Sometimes it can be important to check + # minimums to ensure that your desired value is within range. + node_offset_x = PySpin.CIntegerPtr(nodemap.GetNode('OffsetX')) + if PySpin.IsAvailable(node_offset_x) and PySpin.IsWritable(node_offset_x): + + node_offset_x.SetValue(node_offset_x.GetMin()) + print('Offset X set to %i...' % node_offset_x.GetMin()) + + else: + print('Offset X not available...') + + # Apply minimum to offset Y + # + # *** NOTES *** + # It is often desirable to check the increment as well. The increment + # is a number of which a desired value must be a multiple of. Certain + # nodes, such as those corresponding to offsets X and Y, have an + # increment of 1, which basically means that any value within range + # is appropriate. The increment is retrieved with the method GetInc(). + node_offset_y = PySpin.CIntegerPtr(nodemap.GetNode('OffsetY')) + if PySpin.IsAvailable(node_offset_y) and PySpin.IsWritable(node_offset_y): + + node_offset_y.SetValue(node_offset_y.GetMin()) + print('Offset Y set to %i...' % node_offset_y.GetMin()) + + else: + print('Offset Y not available...') + + # Set maximum width + # + # *** NOTES *** + # Other nodes, such as those corresponding to image width and height, + # might have an increment other than 1. In these cases, it can be + # important to check that the desired value is a multiple of the + # increment. However, as these values are being set to the maximum, + # there is no reason to check against the increment. + node_width = PySpin.CIntegerPtr(nodemap.GetNode('Width')) + if PySpin.IsAvailable(node_width) and PySpin.IsWritable(node_width): + + width_to_set = node_width.GetMax() + node_width.SetValue(width_to_set) + print('Width set to %i...' % node_width.GetValue()) + + else: + print('Width not available...') + + # Set maximum height + # + # *** NOTES *** + # A maximum is retrieved with the method GetMax(). A node's minimum and + # maximum should always be a multiple of its increment. + node_height = PySpin.CIntegerPtr(nodemap.GetNode('Height')) + if PySpin.IsAvailable(node_height) and PySpin.IsWritable(node_height): + + height_to_set = node_height.GetMax() + node_height.SetValue(height_to_set) + print('Height set to %i...' % node_height.GetValue()) + + else: + print('Height not available...') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return 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 acquire_images(cam, nodemap, nodemap_tldevice): + """ + 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. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** IMAGE ACQUISITION ***\n') + try: + result = True + + # Set acquisition mode to continuous + # + # *** NOTES *** + # Because the example acquires and saves 10 images, setting acquisition + # mode to continuous lets the example finish. If set to single frame + # or multiframe (at a lower number of images), the example would just + # hang. This would happen because the example has been written to + # acquire 10 images while the camera would have been programmed to + # retrieve less than that. + # + # Setting the value of an enumeration node is slightly more complicated + # than other node types. Two nodes must be retrieved: first, the + # enumeration node is retrieved from the nodemap; and second, the entry + # node is retrieved from the enumeration node. The integer value of the + # entry node is then set as the new value of the enumeration node. + # + # Notice that both the enumeration and the entry nodes are checked for + # availability and readability/writability. Enumeration nodes are + # generally readable and writable whereas their entry nodes are only + # ever readable. + # + # Retrieve enumeration node from nodemap + + # In order to access the node entries, they have to be casted to a pointer type (CEnumerationPtr here) + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # What happens when the camera begins acquiring images depends on the + # acquisition mode. Single frame captures only a single image, multi + # frame catures a set number of images, and continuous captures a + # continuous stream of images. Because the example calls for the + # retrieval of 10 images, continuous mode has been set. + # + # *** LATER *** + # Image acquisition must be ended when no more images are needed. + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve device serial number for filename + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Retrieve, convert, and save images + for i in range(NUM_IMAGES): + try: + + # Retrieve next received image + # + # *** NOTES *** + # Capturing an image houses images on the camera buffer. Trying + # to capture an image that does not exist will hang the camera. + # + # *** LATER *** + # Once an image from the buffer is saved and/or no longer + # needed, the image must be released in order to keep the + # buffer from filling up. + image_result = cam.GetNextImage(1000) + + # Ensure image completion + # + # *** NOTES *** + # Images can easily be checked for completion. This should be + # done whenever a complete image is expected or required. + # Further, check image status for a little more insight into + # why an image is incomplete. + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + + else: + + # Print image information; height and width recorded in pixels + # + # *** NOTES *** + # Images have quite a bit of available metadata including + # things such as CRC, image status, and offset values, to + # name a few. + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed Image %d, width = %d, height = %d' % (i, width, height)) + + # Convert image to mono 8 + # + # *** NOTES *** + # Images can be converted between pixel formats by using + # the appropriate enumeration value. Unlike the original + # image, the converted one does not need to be released as + # it does not affect the camera buffer. + # + # When converting images, color processing algorithm is an + # optional parameter. + image_converted = image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + # Create a unique filename + if device_serial_number: + filename = 'ImageFormatControl-%s-%d.jpg' % (device_serial_number, i) + else: # if serial number is empty + filename = 'ImageFormatControl-%d.jpg' % i + + # Save image + # + # *** NOTES *** + # The standard practice of the examples is to use device + # serial numbers to keep images of one device from + # overwriting those of another. + image_converted.Save(filename) + print('Image saved at %s' % filename) + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + print('') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def run_single_camera(cam): + """ + This function acts as the body of the example; please see NodeMapInfo example + for more in-depth comments on setting up cameras. + + :param cam: Camera to run on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Retrieve TL device nodemap and print device information + nodemap_tldevice = cam.GetTLDeviceNodeMap() + + result &= print_device_info(nodemap_tldevice) + + # Initialize camera + cam.Init() + + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + + # Configure custom image settings + if not configure_custom_image_settings(nodemap): + return False + + # Acquire images + result &= acquire_images(cam, nodemap, nodemap_tldevice) + + # 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 + """ + + # 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: %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) diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/ImageFormatControl_QuickSpin.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/ImageFormatControl_QuickSpin.py new file mode 100644 index 0000000..8fba164 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/ImageFormatControl_QuickSpin.py @@ -0,0 +1,358 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# ImageFormatControl_QuickSpin.py shows how to apply custom image +# settings to the camera using the QuickSpin API. QuickSpin is a subset of +# the Spinnaker library that allows for simpler node access and control. +# +# This example demonstrates customizing offsets X and Y, width and height, +# and the pixel format. Ensuring custom values fall within an acceptable +# range is also touched on. Retrieving and setting node values using +# QuickSpin is the only portion of the example that differs from +# ImageFormatControl. +# +# 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 + + +def configure_custom_image_settings(cam): + """ + Configures a number of settings on the camera including offsets X and Y, + width, height, and pixel format. These settings must be applied before + BeginAcquisition() is called; otherwise, those nodes would be read only. + Also, it is important to note that settings are applied immediately. + This means if you plan to reduce the width and move the x offset accordingly, + you need to apply such changes in the appropriate order. + + :param cam: Camera to configure settings on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** CONFIGURING CUSTOM IMAGE SETTINGS ***\n') + + try: + result = True + + # Apply mono 8 pixel format + # + # *** NOTES *** + # In QuickSpin, enumeration nodes are as easy to set as other node + # types. This is because enum values representing each entry node + # are added to the API. + if cam.PixelFormat.GetAccessMode() == PySpin.RW: + cam.PixelFormat.SetValue(PySpin.PixelFormat_Mono8) + print('Pixel format set to %s...' % cam.PixelFormat.GetCurrentEntry().GetSymbolic()) + + else: + print('Pixel format not available...') + result = False + + # Apply minimum to offset X + # + # *** NOTES *** + # Numeric nodes have both a minimum and maximum. A minimum is retrieved + # with the method GetMin(). Sometimes it can be important to check + # minimums to ensure that your desired value is within range. + if cam.OffsetX.GetAccessMode() == PySpin.RW: + cam.OffsetX.SetValue(cam.OffsetX.GetMin()) + print('Offset X set to %d...' % cam.OffsetX.GetValue()) + + else: + print('Offset X not available...') + result = False + + # Apply minimum to offset Y + # + # *** NOTES *** + # It is often desirable to check the increment as well. The increment + # is a number of which a desired value must be a multiple. Certain + # nodes, such as those corresponding to offsets X and Y, have an + # increment of 1, which basically means that any value within range + # is appropriate. The increment is retrieved with the method GetInc(). + if cam.OffsetY.GetAccessMode() == PySpin.RW: + cam.OffsetY.SetValue(cam.OffsetY.GetMin()) + print('Offset Y set to %d...' % cam.OffsetY.GetValue()) + + else: + print('Offset Y not available...') + result = False + + # Set maximum width + # + # *** NOTES *** + # Other nodes, such as those corresponding to image width and height, + # might have an increment other than 1. In these cases, it can be + # important to check that the desired value is a multiple of the + # increment. + # + # This is often the case for width and height nodes. However, because + # these nodes are being set to their maximums, there is no real reason + # to check against the increment. + if cam.Width.GetAccessMode() == PySpin.RW and cam.Width.GetInc() != 0 and cam.Width.GetMax != 0: + cam.Width.SetValue(cam.Width.GetMax()) + print('Width set to %i...' % cam.Width.GetValue()) + + else: + print('Width not available...') + result = False + + # Set maximum height + # + # *** NOTES *** + # A maximum is retrieved with the method GetMax(). A node's minimum and + # maximum should always be a multiple of its increment. + if cam.Height.GetAccessMode() == PySpin.RW and cam.Height.GetInc() != 0 and cam.Height.GetMax != 0: + cam.Height.SetValue(cam.Height.GetMax()) + print('Height set to %i...' % cam.Height.GetValue()) + + else: + print('Height not available...') + result = False + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_device_info(cam): + """ + 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 cam: Camera to get device information from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('\n*** DEVICE INFORMATION ***\n') + + try: + result = True + nodemap = cam.GetTLDeviceNodeMap() + + 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.message) + 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 the acquisition of images. + + :param cam: Camera to acquire images from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** 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 is not None and 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 next received image and ensure image completion + image_result = cam.GetNextImage(1000) + + 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 Mono8 + image_converted = image_result.Convert(PySpin.PixelFormat_Mono8) + + # Create a unique filename + if device_serial_number: + filename = 'ImageFormatControlQS-%s-%d.jpg' % (device_serial_number, i) + else: + filename = 'ImageFormatControlQS-%d.jpg' % i + + # Save image + image_converted.Save(filename) + + print('Image saved at %s' % filename) + + # Release image + image_result.Release() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + # End acquisition + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def run_single_camera(cam): + """ + This function acts as the body of the example; please see NodeMapInfo_QuickSpin example for more + in-depth comments on setting up cameras. + + :param cam: Camera to run example on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + # Initialize camera + cam.Init() + + # Print device info + result = print_device_info(cam) + + # Configure exposure + if not configure_custom_image_settings(cam): + return False + + # Acquire images + result &= acquire_images(cam) + + # Deinitialize camera + cam.DeInit() + + return result + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + +def main(): + """ + Example entry point; please see Enumeration_QuickSpin 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 + + # Release 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) diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/Inference.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Inference.py new file mode 100644 index 0000000..524d8ca --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Inference.py @@ -0,0 +1,1218 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# 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.flir.com/products/firefly-dl/ +# It can also be helpful to familiarize yourself with the Acquisition, +# ChunkData and FileAccess_QuickSpin examples. + +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.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 + +# 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.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.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.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.IsReadable(ptr_file_access_offset) or 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): + try: + ptr_file_operation_selector = PySpin.CEnumerationPtr(nodemap.GetNode("FileOperationSelector")) + if 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 + + ptr_file_operation_selector.SetIntValue(int(ptr_file_operation_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 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.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.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.IsReadable(ptr_file_access_buffer) or 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) + + if intermediate_buffer_size > bytes_left_to_write: + ptr_file_access_length.SetValue(bytes_left_to_write) + + # Perform Write command + if not camera_write_to_file(nodemap): + print('Writing to stream failed. Aborting...') + return False + + # Verify size of bytes written + size_written = ptr_file_access_result.GetValue() + + # 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') + + 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.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.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.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.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.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.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.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.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, convert, and save images + 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) \ No newline at end of file diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/Injected_Image_Classification.raw b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Injected_Image_Classification.raw new file mode 100644 index 0000000..e79db8f Binary files /dev/null and b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Injected_Image_Classification.raw differ diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/Injected_Image_Classification_Daisy.jpg b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Injected_Image_Classification_Daisy.jpg new file mode 100644 index 0000000..128f332 Binary files /dev/null and b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Injected_Image_Classification_Daisy.jpg differ diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/Injected_Image_Detection.raw b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Injected_Image_Detection.raw new file mode 100644 index 0000000..e1c3100 Binary files /dev/null and b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Injected_Image_Detection.raw differ diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/Injected_Image_Detection_Aeroplane.jpg b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Injected_Image_Detection_Aeroplane.jpg new file mode 100644 index 0000000..8e3cefc Binary files /dev/null and b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Injected_Image_Detection_Aeroplane.jpg differ diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/Logging.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Logging.py new file mode 100644 index 0000000..4501a54 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Logging.py @@ -0,0 +1,130 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# Logging.py shows how to create a handler to access logging events. +# It relies on information provided in the Enumeration, Acquisition, and +# NodeMapInfo examples. +# +# It can also be helpful to familiarize yourself with the NodeMapCallback +# example, as nodemap callbacks follow the same general procedure as +# events, but with a few less steps. +# +# This example creates a user-defined class, LoggingEventHandler, that inherits +# from the Spinnaker class, LoggingEventHandler. The child class allows the user to +# define any properties, parameters, and the event handler itself while LoggingEventHandler +# allows the child class to appropriately interface with the Spinnaker SDK. + +import PySpin + + +# Define callback priority threshold; please see documentation for additional +# information on logging level philosophy. +LOGGING_LEVEL = PySpin.LOG_LEVEL_DEBUG # change to any LOG_LEVEL_* constant + + +class LoggingEventHandler(PySpin.LoggingEventHandler): + """ + Although logging events are just as flexible and extensible as other events, + they are generally only used for logging purposes, which is why a number of + helpful functions that provide logging information have been added. Generally, + if the purpose is not logging, one of the other event types is probably more + appropriate. + """ + + def __init__(self): + super(LoggingEventHandler, self).__init__() + + def OnLogEvent(self, logging_event_data): + """ + This function displays readily available logging information. + + :param logging_event_data: Logging data. + :type logging_event_data: LoggingEventData + :rtype: None + """ + print('--------Log Event Received----------') + print('Category: %s' % logging_event_data.GetCategoryName()) + print('Priority Value: %s' % logging_event_data.GetPriority()) + print('Priority Name: %s' % logging_event_data.GetPriorityName()) + print('Timestamp: %s' % logging_event_data.GetTimestamp()) + print('NDC: %s' % logging_event_data.GetNDC()) + print('Thread: %s' % logging_event_data.GetThreadName()) + print('Message: %s' % logging_event_data.GetLogMessage()) + print('------------------------------------\n') + + +def main(): + """ + Example entry point; notice the volume of data that the logging event handler + prints out on debug despite the fact that very little really happens in this + example. Because of this, it may be better to have the logger set to lower + level in order to provide a more concise, focused log. + + :rtype: None + """ + + # 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)) + + # Create and register the logging event handler + # + # *** NOTES *** + # Logging event handlers are registered to the system. Take note that a logging + # event handler is very verbose when the logging level is set to debug. + # + # *** LATER *** + # Logging event handlers must be unregistered manually. This must be done prior to + # releasing the system and while the logging event handlers are still in scope. + logging_event_handler = LoggingEventHandler() + system.RegisterLoggingEventHandler(logging_event_handler) + + # Set callback priority level + # + # *** NOTES *** + # Please see documentation for up-to-date information on the logging + # philosophies of the Spinnaker SDK. + system.SetLoggingEventPriorityLevel(LOGGING_LEVEL) + + # Retrieve list of cameras from the system + cam_list = system.GetCameras() + + num_cams = cam_list.GetSize() + + print('Number of cameras detected: %i' % num_cams) + + # Clear camera list before releasing system + cam_list.Clear() + + # Unregister logging event handler + # + # *** NOTES *** + # It is important to unregister all logging event handlers from the system. + system.UnregisterLoggingEventHandler(logging_event_handler) + + # Release system instance + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + + +if __name__ == '__main__': + main() diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/LookupTable.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/LookupTable.py new file mode 100644 index 0000000..851b6d0 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/LookupTable.py @@ -0,0 +1,440 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= + +# LookupTable.py +# +# LookupTable.py shows how to configure lookup tables on the camera. +# 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 they are somewhat shorter and simpler, either +# provides a strong introduction to camera customization. +# +# Lookup tables allow for the customization and control of individual pixels. +# This can be a very powerful and deeply useful tool; however, because use +# cases are context dependent, this example only explores lookup table +# configuration. + +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_lookup_tables(nodemap): + """ + This function configures lookup tables linearly. This involves selecting the + type of lookup table, finding the appropriate increment calculated from the + maximum value, and enabling lookup tables on the camera. + + :param nodemap: Device nodemap + :type nodemap: INodeMap + :return: returns True if successful, False otherwise + :rtype: bool + """ + result = True + print("***CONFIGURING LOOKUP TABLES***\n") + + # Select lookup table type + # + # ***NOTES *** + # Setting the lookup table selector. It is important to note that this + # does not enable lookup tables. + + try: + lut_selector = PySpin.CEnumerationPtr(nodemap.GetNode("LUTSelector")) + if not PySpin.IsAvailable(lut_selector) or not PySpin.IsWritable(lut_selector): + print_retrieve_node_failure("node", "LUTSelector") + return False + + lut_selector_lut1 = lut_selector.GetEntryByName("LUT1") + if not PySpin.IsAvailable(lut_selector_lut1) or not PySpin.IsReadable(lut_selector_lut1): + print_retrieve_node_failure("entry", "LUTSelector LUT1") + return False + + lut_selector.SetIntValue(lut_selector_lut1.GetValue()) + print("Lookup table selector set to LUT 1...\n") + + # Determine pixel increment and set indexes and values as desired + # + # *** NOTES *** + # To get the pixel increment, the maximum range of the value node must + # first be retrieved. The value node represents an index, so its value + # should be one less than a power of 2 (e.g. 511, 1023, etc.). Add 1 to + # this index to get the maximum range. Divide the maximum range by 512 + # to calculate the pixel increment. + # + # Finally, all values (in the value node) and their corresponding + # indexes (in the index node) need to be set. The goal of this example + # is to set the lookup table linearly. As such, the slope of the values + # should be set according to the increment, but the slope of the + # indexes is inconsequential. + + # Retrieve value node + lut_value = PySpin.CIntegerPtr(nodemap.GetNode("LUTValue")) + if not PySpin.IsAvailable(lut_value) or not PySpin.IsWritable(lut_value): + print_retrieve_node_failure("node", "LUTValue") + return False + + # Retrieve maximum range + max_range = lut_value.GetMax() + 1 + print("\tMaximum Range: {}".format(max_range)) + + # Calculate increment + increment = max_range / 512 + print("\tIncrement: {}".format(increment)) + + # Retrieve index node + lut_index = PySpin.CIntegerPtr(nodemap.GetNode("LUTIndex")) + if not PySpin.IsAvailable(lut_index) or not PySpin.IsWritable(lut_index): + print_retrieve_node_failure("node", "LUTIndex") + return False + + # Set values and indexes + i = 0 + while i < max_range: + lut_index.SetValue(int(i)) + lut_value.SetValue(int(i)) + i += increment + + print("All lookup table values set...\n") + + # Enable lookup tables + # + # *** NOTES *** + # Once lookup tables have been configured, don"t forget to enable them + # with the appropriate node. + # + # *** LATER *** + # Once the images with lookup tables have been collected, turn the + # feature off with the same node. + + lut_enable = PySpin.CBooleanPtr(nodemap.GetNode("LUTEnable")) + if not PySpin.IsAvailable(lut_enable) or not PySpin.IsWritable(lut_enable): + print_retrieve_node_failure("node", "LUTEnable") + return False + + lut_enable.SetValue(True) + print("Lookup tables enabled...\n") + + except PySpin.SpinnakerException as ex: + print("Error: {}".format(ex)) + result = False + + return result + + +def reset_lookup_tables(nodemap): + """ + This function resets the camera by disabling lookup tables. + + :param nodemap: Device nodemap. + :type nodemap: INodeMap + :return: returns True if successful, False otherwise + :rtype: bool + """ + result = True + + # Disable lookup tables + # + # *** NOTES *** + # Turn lookup tables off when they are not needed to reduce overhead + + try: + lut_enable = PySpin.CBooleanPtr(nodemap.GetNode("LUTEnable")) + if not PySpin.IsAvailable(lut_enable) or not PySpin.IsWritable(lut_enable): + print("Unable to disable lookup tables. Non-fatal error...\n") + return False + + lut_enable.SetValue(False) + print("Lookup tables disabled...\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: Device nodemap. + :type nodemap: INodeMap + :return: returns True if successful, False otherwise + :rtype: bool + """ + result = True + print("*** DEVICE INFORMATION ***\n") + + try: + 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) + if PySpin.IsReadable(node_feature): + feature_string = node_feature.ToString() + else: + feature_string = "Node not readable" + + print("{}: {}".format(node_feature.GetName(), feature_string)) + + else: + print("Device control information not available.") + + except PySpin.SpinnakerException as ex: + print("Error: {}".format(ex)) + result = False + + return result + + +def acquire_images(cam, nodemap, nodemap_tl_device): + """ + 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 + :param nodemap: Device nodemap + :param nodemap_tl_device: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tl_device: INodeMap + :return: returns True if successful, False otherwise + :rtype: bool + """ + result = True + print("*** IMAGE ACQUISITION ***\n") + + # Set acquisition mode to continuous + try: + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode("AcquisitionMode")) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print("Unable to set acquisition mode to continuous (node retrieval). Aborting...\n") + return False + + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName("Continuous") + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or \ + not PySpin.IsReadable(node_acquisition_mode_continuous): + print("Unable to set acquisition mode to continuous (entry 'continuous' retrieval). Aborting...\n") + 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...\n") + + # Begin acquiring images + cam.BeginAcquisition() + print("Acquiring images...\n") + + # Retrieve device serial number for filename + device_serial_number = "" + node_device_serial_number = PySpin.CStringPtr(nodemap_tl_device.GetNode("DeviceSerialNumber")) + if PySpin.IsAvailable(node_device_serial_number) and 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 + for i in range(NUM_IMAGES): + try: + + # Retrieve next received image and ensure image completion + image_result = cam.GetNextImage(1000) + + 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 = image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + # Create a unique filename + if device_serial_number: + filename = "LookupTable-{}-{}.jpg".format(device_serial_number, i) + else: # if serial number is empty + filename = "LookupTable-{}.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)) + result = 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 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: returns True if successful, False otherwise + :rtype: bool + """ + result = True + + try: + # Retrieve TL device nodemap and print device information + nodemap_tl_device = cam.GetTLDeviceNodeMap() + + result &= print_device_info(nodemap_tl_device) + + # Initialize camera + cam.Init() + + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + + # Configure lookup tables + result &= configure_lookup_tables(nodemap) + if not result: + return result + + # Acquire images + result &= acquire_images(cam, nodemap, nodemap_tl_device) + + # Reset lookup tables + result &= reset_lookup_tables(nodemap) + + # Deinitialize camera + cam.DeInit() + except PySpin.SpinnakerException as ex: + print("Error: {}".format(ex)) + result = False + + return result + + +def main(): + """ + 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. + + :return: returns True if successful, False otherwise + :rtype: bool + """ + try: + test_file = open("test.txt", "w+") + except IOError: + print("Unable to write to current directory. Please check permissions.\n") + 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!\n") + 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) diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/Network_Classification b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Network_Classification new file mode 100644 index 0000000..a7a5513 Binary files /dev/null and b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Network_Classification differ diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/Network_Detection b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Network_Detection new file mode 100644 index 0000000..838b384 Binary files /dev/null and b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Network_Detection differ diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/NodeMapCallback.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/NodeMapCallback.py new file mode 100644 index 0000000..0db4cc7 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/NodeMapCallback.py @@ -0,0 +1,424 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# NodeMapCallback.py shows how to use nodemap callbacks. It relies +# on information provided in the Enumeration, Acquisition, and NodeMapInfo +# examples. As callbacks are very similar to events, it may be a good idea to +# explore this example prior to tackling the events examples. +# +# This example focuses on creating, registering, using, and unregistering +# callbacks. A callback requires a callback class with a callback function signature, +# which allows it to be registered to and access a node. Events follow this same pattern. +# +# Once comfortable with NodeMapCallback, we suggest checking out any of the +# events examples: DeviceEvents, EnumerationEvents, ImageEvents, or Logging. + +import PySpin +import sys + + +class HeightNodeCallback(PySpin.NodeCallback): + """ + This is the first of two callback classes. This callback will be registered to the height node. + Node callbacks must inherit from NodeCallback, and must implement CallbackFunction with the same function signature. + + NOTE: Instances of callback classes must not go out of scope until they are deregistered, otherwise segfaults + will occur. + """ + def __init__(self): + super(HeightNodeCallback, self).__init__() + + def CallbackFunction(self, node): + """ + This function gets called when the height node changes and triggers a callback. + + :param node: Height node. + :type node: INode + :rtype: None + """ + node_height = PySpin.CIntegerPtr(node) + print('Height callback message:\n\tLook! Height changed to %f...\n' % node_height.GetValue()) + + +class GainNodeCallback(PySpin.NodeCallback): + """ + This is the second callback class, registered to the gain node. + """ + def __init__(self): + super(GainNodeCallback, self).__init__() + + def CallbackFunction(self, node): + """ + This function gets called when the gain node changes and triggers a callback. + + :param node: Gain node. + :type node: INode + :rtype: None + """ + node_gain = PySpin.CFloatPtr(node) + print('Gain callback message:\n\tLook! Gain changed to %f...\n' % node_gain.GetValue()) + + +def configure_callbacks(nodemap): + """ + This function sets up the example by disabling automatic gain, creating the callbacks, and registering them to + their specific nodes. + + :param nodemap: Device nodemap. + :type nodemap: INodeMap + :returns: tuple (result, callback_height, callback_gain) + WHERE + result is True if successful, False otherwise + callback_height is the HeightNodeCallback instance registered to the height node + callback_gain is the GainNodeCallback instance registered to the gain node + :rtype: (bool, HeightNodeCallback, GainNodeCallback) + """ + print('\n*** CONFIGURING CALLBACKS ***\n') + try: + result = True + + # Turn off automatic gain + # + # *** NOTES *** + # Automatic gain prevents the manual configuration of gain and needs to + # be turned off for this example. + # + # *** LATER *** + # Automatic exposure is turned off 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.IsAvailable(node_gain_auto) or not PySpin.IsWritable(node_gain_auto): + print('Unable to disable automatic gain (node retrieval). Aborting...') + return False + + node_gain_auto_off = PySpin.CEnumEntryPtr(node_gain_auto.GetEntryByName('Off')) + if not PySpin.IsAvailable(node_gain_auto_off) or not PySpin.IsReadable(node_gain_auto_off): + print('Unable to disable automatic gain (enum entry retrieval). Aborting...') + return False + + node_gain_auto.SetIntValue(node_gain_auto_off.GetValue()) + print('Automatic gain disabled...') + + # Register callback to height node + # + # *** NOTES *** + # Callbacks need to be registered to nodes, which should be writable + # if the callback is to ever be triggered. Also ensure that the callback + # instance does not go out of scope, as it will get garbage-collected + # and a segfault will result once the callback actually occurs. + # + # *** LATER *** + # Each callback needs to be unregistered individually before releasing + # the system or an exception will be thrown. + node_height = PySpin.CIntegerPtr(nodemap.GetNode('Height')) + if not PySpin.IsAvailable(node_height) or not PySpin.IsWritable(node_height): + print('Unable to retrieve height. Aborting...\n') + return False + + print('Height ready...') + + callback_height = HeightNodeCallback() + PySpin.RegisterNodeCallback(node_height.GetNode(), callback_height) + + print('Height callback registered...') + + # Register callback to gain node + # + # *** NOTES *** + # Depending on the specific goal of the function, it can be important + # to notice the node type that a callback is registered to. Notice in + # the callback functions above that the callback registered to height + # casts its node as an integer whereas the callback registered to gain + # casts as a float. + # + # *** LATER *** + # Each callback needs to be unregistered individually before releasing + # the system or an exception will be thrown. + node_gain = PySpin.CFloatPtr(nodemap.GetNode('Gain')) + if not PySpin.IsAvailable(node_gain) or not PySpin.IsWritable(node_gain): + print('Unable to retrieve gain. Aborting...\n') + return False + + print('Gain ready...') + + callback_gain = GainNodeCallback() + PySpin.RegisterNodeCallback(node_gain.GetNode(), callback_gain) + print('Gain callback registered...\n') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result, callback_height, callback_gain + + +def change_height_and_gain(nodemap): + """ + This function demonstrates the triggering of the nodemap callbacks. First it + changes height, which executes the callback registered to the height node, and + then it changes gain, which executes the callback registered to the gain node. + + :param nodemap: Device nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n***CHANGE HEIGHT & GAIN ***\n') + + try: + result = True + + # Change height to trigger height callback + # + # *** NOTES *** + # Notice that changing the height only triggers the callback function + # registered to the height node. + node_height = PySpin.CIntegerPtr(nodemap.GetNode('Height')) + if not PySpin.IsAvailable(node_height) or not PySpin.IsWritable(node_height) \ + or node_height.GetInc() == 0 or node_height.GetMax() == 0: + + print('Unable to retrieve height. Aborting...') + return False + + height_to_set = node_height.GetMax() + + print('Regular function message:\n\tHeight about to be changed to %i...\n' % height_to_set) + + node_height.SetValue(height_to_set) + + # Change gain to trigger gain callback + # + # *** NOTES *** + # The same is true of changing the gain node; changing a node will + # only ever trigger the callback function (or functions) currently + # registered to it. + node_gain = PySpin.CFloatPtr(nodemap.GetNode('Gain')) + if not PySpin.IsAvailable(node_gain) or not PySpin.IsWritable(node_gain) or node_gain.GetMax() == 0: + print('Unable to retrieve gain...') + return False + + gain_to_set = node_gain.GetMax() / 2.0 + + print('Regular function message:\n\tGain about to be changed to %f...\n' % gain_to_set) + node_gain.SetValue(gain_to_set) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def reset_callbacks(nodemap, callback_height, callback_gain): + """ + This function cleans up the example by deregistering the callbacks and + turning automatic gain back on. + + :param nodemap: Device nodemap. + :param callback_height: Height node callback instance to deregister. + :param callback_gain: Gain node callback instance to deregister. + :type nodemap: INodeMap + :type callback_height: HeightNodeCallback + :type callback_gain: GainNodeCallback + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Deregister callbacks + # + # *** NOTES *** + # It is important to deregister each callback function from each node + # that it is registered to. + PySpin.DeregisterNodeCallback(callback_height) + PySpin.DeregisterNodeCallback(callback_gain) + + print('Callbacks deregistered...') + + # Turn automatic gain back on + # + # *** NOTES *** + # Automatic gain is turned back on in order to restore the camera to + # its default state. + node_gain_auto = PySpin.CEnumerationPtr(nodemap.GetNode('GainAuto')) + if not PySpin.IsAvailable(node_gain_auto) or not PySpin.IsWritable(node_gain_auto): + print('Unable to enable automatic gain (node retrieval). Aborting...') + return False + + node_gain_auto_continuous = PySpin.CEnumEntryPtr(node_gain_auto.GetEntryByName('Continuous')) + if not PySpin.IsAvailable(node_gain_auto_continuous) or not PySpin.IsReadable(node_gain_auto_continuous): + print('Unable to enable automatic gain (enum entry retrieval). Aborting...') + return False + + node_gain_auto.SetIntValue(node_gain_auto_continuous.GetValue()) + print('Automatic gain 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 setup and 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 callbacks + err, callback_height, callback_gain = configure_callbacks(nodemap) + if not err: + return err + + # Change height and gain to trigger callbacks + result &= change_height_and_gain(nodemap) + + # Reset callbacks + result &= reset_callbacks(nodemap, callback_height, callback_gain) + + # Deinitialize camera + cam.DeInit() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return 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 instance + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + return result + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/NodeMapInfo.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/NodeMapInfo.py new file mode 100644 index 0000000..c8224cc --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/NodeMapInfo.py @@ -0,0 +1,576 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# NodeMapInfo.py shows how to retrieve node map information. It relies +# on information provided in the Enumeration example. Also, check out the +# Acquisition and ExceptionHandling examples if you haven't already. +# Acquisition demonstrates image acquisition while ExceptionHandling shows the +# handling of standard and Spinnaker exceptions. +# +# This example explores retrieving information from all major node types on the +# camera. This includes string, integer, float, boolean, command, enumeration, +# category, and value types. Looping through multiple child nodes is also +# covered. A few node types are not covered - base, port, and register - as +# they are not fundamental. The final node type - enumeration entry - is +# explored only in terms of its parent node type - enumeration. +# +# Once comfortable with NodeMapInfo, we suggest checking out ImageFormatControl +# and Exposure. ImageFormatControl explores customizing image settings on a +# camera while Exposure introduces the standard structure of configuring a +# device, acquiring some images, and then returning the device to a default +# state. + +import PySpin +import sys + +# Defines max number of characters that will be printed out for any node information +MAX_CHARS = 35 + + +class ReadType: + """ + Use the following constants to determine whether nodes are read + as Value nodes or their individual types. + """ + VALUE = 0, + INDIVIDUAL = 1 + +CHOSEN_READ = ReadType.INDIVIDUAL + + +def print_with_indent(level, text): + """ + Helper function for printing a string prefix with a specifc number of indents. + :param level: Number of indents to generate + :type level: int + :param text: String to print after indent + :type text: str + """ + ind = '' + for i in range(level): + ind += ' ' + print('%s%s' % (ind, text)) + + +def print_value_node(node, level): + """ + Retrieves and prints the display name and value of all node types as value nodes. + A value node is a general node type that allows for the reading and writing of any node type as a string. + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create value node + node_value = PySpin.CValuePtr(node) + + # Retrieve display name + # + # *** NOTES *** + # A node's 'display name' is generally more appropriate for output and + # user interaction whereas its 'name' is what the camera understands. + # Generally, its name is the same as its display name but without + # spaces - for instance, the name of the node that houses a camera's + # serial number is 'DeviceSerialNumber' while its display name is + # 'Device Serial Number'. + display_name = node_value.GetDisplayName() + + # Retrieve value of any node type as string + # + # *** NOTES *** + # Because value nodes return any node type as a string, it can be much + # easier to deal with nodes as value nodes rather than their actual + # individual types. + value = node_value.ToString() + + # Cap length at MAX_CHARS + value = value[:MAX_CHARS] + '...' if len(value) > MAX_CHARS else value + + # Print value + print_with_indent(level, '%s: %s' % (display_name, value)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_string_node(node, level): + """ + Retrieves and prints the display name and value of a string node. + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create string node + node_string = PySpin.CStringPtr(node) + + # Retrieve string node value + # + # *** NOTES *** + # Functions in Spinnaker C++ that use gcstring types + # are substituted with Python strings in PySpin. + # The only exception is shown in the DeviceEvents example, where + # the callback function still uses a wrapped gcstring type. + display_name = node_string.GetDisplayName() + + # Ensure that the value length is not excessive for printing + value = node_string.GetValue() + value = value[:MAX_CHARS] + '...' if len(value) > MAX_CHARS else value + + # Print value; 'level' determines the indentation level of output + print_with_indent(level, '%s: %s' % (display_name, value)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_integer_node(node, level): + """ + Retrieves and prints the display name and value of an integer node. + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create integer node + node_integer = PySpin.CIntegerPtr(node) + + # Get display name + display_name = node_integer.GetDisplayName() + + # Retrieve integer node value + # + # *** NOTES *** + # All node types except base nodes have a ToString() + # method which returns a value as a string. + value = node_integer.GetValue() + + # Print value + print_with_indent(level, '%s: %s' % (display_name, value)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_float_node(node, level): + """ + Retrieves and prints the display name and value of a float node. + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create float node + node_float = PySpin.CFloatPtr(node) + + # Get display name + display_name = node_float.GetDisplayName() + + # Retrieve float value + value = node_float.GetValue() + + # Print value + print_with_indent(level, '%s: %s' % (display_name, value)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_boolean_node(node, level): + """ + Retrieves and prints the display name and value of a Boolean node. + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create Boolean node + node_boolean = PySpin.CBooleanPtr(node) + + # Get display name + display_name = node_boolean.GetDisplayName() + + # Retrieve Boolean value + value = node_boolean.GetValue() + + # Print Boolean value + # NOTE: In Python a Boolean will be printed as "True" or "False". + print_with_indent(level, '%s: %s' % (display_name, value)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_command_node(node, level): + """ + This function retrieves and prints the display name and tooltip of a command + node, limiting the number of printed characters to a macro-defined maximum. + The tooltip is printed below because command nodes do not have an intelligible + value. + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create command node + node_command = PySpin.CCommandPtr(node) + + # Get display name + display_name = node_command.GetDisplayName() + + # Retrieve tooltip + # + # *** NOTES *** + # All node types have a tooltip available. Tooltips provide useful + # information about nodes. Command nodes do not have a method to + # retrieve values as their is no intelligible value to retrieve. + tooltip = node_command.GetToolTip() + + # Ensure that the value length is not excessive for printing + tooltip = tooltip[:MAX_CHARS] + '...' if len(tooltip) > MAX_CHARS else tooltip + + # Print display name and tooltip + print_with_indent(level, '%s: %s' % (display_name, tooltip)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_enumeration_node_and_current_entry(node, level): + """ + This function retrieves and prints the display names of an enumeration node + and its current entry (which is actually housed in another node unto itself). + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create enumeration node + node_enumeration = PySpin.CEnumerationPtr(node) + + # Retrieve current entry as enumeration node + # + # *** NOTES *** + # Enumeration nodes have three methods to differentiate between: first, + # GetIntValue() returns the integer value of the current entry node; + # second, GetCurrentEntry() returns the entry node itself; and third, + # ToString() returns the symbolic of the current entry. + node_enum_entry = PySpin.CEnumEntryPtr(node_enumeration.GetCurrentEntry()) + + # Get display name + display_name = node_enumeration.GetDisplayName() + + # Retrieve current symbolic + # + # *** NOTES *** + # Rather than retrieving the current entry node and then retrieving its + # symbolic, this could have been taken care of in one step by using the + # enumeration node's ToString() method. + entry_symbolic = node_enum_entry.GetSymbolic() + + # Print current entry symbolic + print_with_indent(level, '%s: %s' % (display_name, entry_symbolic)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_category_node_and_all_features(node, level): + """ + This function retrieves and prints out the display name of a category node + before printing all child nodes. Child nodes that are also category nodes are + printed recursively. + + :param node: Category node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create category node + node_category = PySpin.CCategoryPtr(node) + + # Get and print display name + display_name = node_category.GetDisplayName() + print_with_indent(level, display_name) + + # Retrieve and iterate through all children + # + # *** NOTES *** + # The two nodes that typically have children are category nodes and + # enumeration nodes. Throughout the examples, the children of category nodes + # are referred to as features while the children of enumeration nodes are + # referred to as entries. Keep in mind that enumeration nodes can be cast as + # category nodes, but category nodes cannot be cast as enumerations. + for node_feature in node_category.GetFeatures(): + + # Ensure node is available and readable + if not PySpin.IsAvailable(node_feature) or not PySpin.IsReadable(node_feature): + continue + + # Category nodes must be dealt with separately in order to retrieve subnodes recursively. + if node_feature.GetPrincipalInterfaceType() == PySpin.intfICategory: + result &= print_category_node_and_all_features(node_feature, level + 1) + + # Cast all non-category nodes as value nodes + # + # *** NOTES *** + # If dealing with a variety of node types and their values, it may be + # simpler to cast them as value nodes rather than as their individual types. + # However, with this increased ease-of-use, functionality is sacrificed. + elif CHOSEN_READ == ReadType.VALUE: + result &= print_value_node(node_feature, level + 1) + + # Cast all non-category nodes as actual types + elif CHOSEN_READ == ReadType.INDIVIDUAL: + if node_feature.GetPrincipalInterfaceType() == PySpin.intfIString: + result &= print_string_node(node_feature, level + 1) + elif node_feature.GetPrincipalInterfaceType() == PySpin.intfIInteger: + result &= print_integer_node(node_feature, level + 1) + elif node_feature.GetPrincipalInterfaceType() == PySpin.intfIFloat: + result &= print_float_node(node_feature, level + 1) + elif node_feature.GetPrincipalInterfaceType() == PySpin.intfIBoolean: + result &= print_boolean_node(node_feature, level + 1) + elif node_feature.GetPrincipalInterfaceType() == PySpin.intfICommand: + result &= print_command_node(node_feature, level + 1) + elif node_feature.GetPrincipalInterfaceType() == PySpin.intfIEnumeration: + result &= print_enumeration_node_and_current_entry(node_feature, level + 1) + + print('') + + 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. First nodes from the TL + device and TL stream nodemaps are retrieved and printed. Following this, + the camera is initialized and then nodes from the GenICam nodemap are + retrieved and printed. + + :param cam: Camera to get nodemaps from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + level = 0 + + # Retrieve TL device nodemap + # + # *** NOTES *** + # The TL device nodemap is available on the transport layer. As such, + # camera initialization is unnecessary. It provides mostly immutable + # information fundamental to the camera such as the serial number, + # vendor, and model. + print('\n*** PRINTING TRANSPORT LAYER DEVICE NODEMAP *** \n') + + nodemap_gentl = cam.GetTLDeviceNodeMap() + + result &= print_category_node_and_all_features(nodemap_gentl.GetNode('Root'), level) + + # Retrieve TL stream nodemap + # + # *** NOTES *** + # The TL stream nodemap is also available on the transport layer. Camera + # initialization is again unnecessary. As you can probably guess, it + # provides information on the camera's streaming performance at any + # given moment. Having this information available on the transport layer + # allows the information to be retrieved without affecting camera performance. + print('*** PRINTING TL STREAM NODEMAP ***\n') + + nodemap_tlstream = cam.GetTLStreamNodeMap() + + result &= print_category_node_and_all_features(nodemap_tlstream.GetNode('Root'), level) + + # Initialize camera + # + # *** NOTES *** + # The camera becomes connected upon initialization. This provides + # access to configurable options and additional information, accessible + # through the GenICam nodemap. + # + # *** LATER *** + # Cameras should be deinitialized when no longer needed. + print('*** PRINTING GENICAM NODEMAP ***\n') + + cam.Init() + + # Retrieve GenICam nodemap + # + # *** NOTES *** + # The GenICam nodemap is the primary gateway to customizing + # and configuring the camera to suit your needs. Configuration options + # such as image height and width, trigger mode enabling and disabling, + # and the sequencer are found on this nodemap. + nodemap_applayer = cam.GetNodeMap() + + result &= print_category_node_and_all_features(nodemap_applayer.GetNode('Root'), level) + + # Deinitialize camera + # + # *** NOTES *** + # Camera deinitialization helps ensure that devices clean up properly + # and do not need to be power-cycled to maintain integrity. + cam.DeInit() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return True + + +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 instance + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + return result + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/NodeMapInfo_QuickSpin.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/NodeMapInfo_QuickSpin.py new file mode 100644 index 0000000..3381bb6 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/NodeMapInfo_QuickSpin.py @@ -0,0 +1,359 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# NodeMapInfo_QuickSpin.py shows how to interact with nodes +# using the QuickSpin API. QuickSpin is a subset of the Spinnaker library +# that allows for simpler node access and control. +# +# This example demonstrates the retrieval of information from both the +# transport layer and the camera. Because the focus of this example is node +# access, which is where QuickSpin and regular Spinnaker differ, this +# example differs from NodeMapInfo quite a bit. +# +# 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 + + +def print_transport_layer_device_info(cam): + """ + Prints device information from the transport layer. + + *** NOTES *** + In QuickSpin, accessing device information on the transport layer is + accomplished via a camera's TLDevice property. The TLDevice property + houses nodes related to general device information such as the three + demonstrated below, device access status, XML and GUI paths and + locations, and GEV information to name a few. The TLDevice property + allows access to nodes that would generally be retrieved through the + TL device nodemap in full Spinnaker. + + Notice that each node is checked for availability and readability + prior to value retrieval. Checking for availability and readability + (or writability when applicable) whenever a node is accessed is + important in terms of error handling. If a node retrieval error + occurs but remains unhandled, an exception is thrown. + + :param cam: Camera to get information from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Print device serial number + if cam.TLDevice.DeviceSerialNumber.GetAccessMode() == PySpin.RO: + print('Device serial number: %s' % cam.TLDevice.DeviceSerialNumber.ToString()) + + else: + print('Device serial number: unavailable') + result = False + + # Print device vendor name + # + # *** NOTE *** + # To check node readability/writability, you can either + # compare its access mode with RO, RW, etc. or you can use + # the IsReadable/IsWritable functions on the node. + if PySpin.IsReadable(cam.TLDevice.DeviceVendorName): + print('Device vendor name: %s' % cam.TLDevice.DeviceVendorName.ToString()) + else: + print('Device vendor name: unavailable') + result = False + + # Print device display name + if PySpin.IsReadable(cam.TLDevice.DeviceDisplayName): + print('Device display name: %s' % cam.TLDevice.DeviceDisplayName.ToString()) + else: + print('Device display name: unavailable') + result = False + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_transport_layer_stream_info(cam): + """ + Prints stream information from transport layer. + + *** NOTES *** + In QuickSpin, accessing stream information on the transport layer is + accomplished via a camera's TLStream property. The TLStream property + houses nodes related to streaming such as the two demonstrated below, + buffer information, and GEV packet information to name a few. The + TLStream property allows access to nodes that would generally be + retrieved through the TL stream nodemap in full Spinnaker. + + :param cam: Camera to get information from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Print stream ID + if cam.TLStream.StreamID.GetAccessMode() == PySpin.RO: + print('Stream ID: %s' % cam.TLStream.StreamID.ToString()) + else: + print('Stream ID: unavailable') + result = False + + # Print stream type + if PySpin.IsReadable(cam.TLStream.StreamType): + print('Stream type: %s' % cam.TLStream.StreamType.ToString()) + else: + print('Stream type: unavailable') + result = False + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_transport_layer_interface_info(interface): + """ + Prints stream information from the transport layer. + + *** NOTES *** + In QuickSpin, accessing interface information is accomplished via an + interface's TLInterface property. The TLInterface property houses + nodes that hold information about the interface such as the three + demonstrated below, other general interface information, and + GEV addressing information. The TLInterface property allows access to + nodes that would generally be retrieved through the interface nodemap + in full Spinnaker. + + Interface nodes should also always be checked for availability and + readability (or writability when applicable). If a node retrieval + error occurs but remains unhandled, an exception is thrown. + + :param interface: Interface to get information from. + :type interface: InterfacePtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Print interface display name + if interface.TLInterface.InterfaceDisplayName.GetAccessMode() == PySpin.RO: + print('Interface display name: %s' % interface.TLInterface.InterfaceDisplayName.ToString()) + else: + print('Interface display name: unavailable') + result = False + + # Print interface ID + if interface.TLInterface.InterfaceID.GetAccessMode() == PySpin.RO: + print('Interface ID: %s' % interface.TLInterface.InterfaceID.ToString()) + else: + print('Interface ID: unavailable') + result = False + + # Print interface type + if PySpin.IsReadable(interface.TLInterface.InterfaceType.GetAccessMode()): + print('Interface type: %s' % interface.TLInterface.InterfaceType.ToString()) + else: + print('Interface type: unavailable') + result = False + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_genicam_device_info(cam): + """ + Prints device information from the camera. + + *** NOTES *** + Most camera interaction happens through GenICam nodes. The + advantages of these nodes is that there is a lot more of them, they + allow for a much deeper level of interaction with a camera, and no + intermediate property (i.e. TLDevice or TLStream) is required. The + disadvantage is that they require initialization. + + :param cam: Camera to get information from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Print exposure time + if cam.ExposureTime.GetAccessMode() == PySpin.RO or cam.ExposureTime.GetAccessMode() == PySpin.RW: + print('Exposure time: %s' % cam.ExposureTime.ToString()) + else: + print('Exposure time: unavailable') + result = False + + # Print black level + if PySpin.IsReadable(cam.BlackLevel): + print('Black level: %s' % cam.BlackLevel.ToString()) + else: + print('Black level: unavailable') + result = False + + # Print height + if PySpin.IsReadable(cam.Height): + print('Height: %s' % cam.Height.ToString()) + else: + print('Height: unavailable') + result = False + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def main(): + """ + Example entry point; this function prints transport layer information from + each interface and transport and GenICam information from each camera. + + :return: True if successful, False otherwise. + :rtype: bool + """ + result = True + + # Retrieve singleton reference to system object + sys = PySpin.System.GetInstance() + + # Get current library version + version = sys.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 = sys.GetCameras() + + num_cams = cam_list.GetSize() + + print('Number of cameras detected: %i \n' % num_cams) + + # Finish if there are no cameras + if num_cams == 0: + # Clear camera list before releasing system + cam_list.Clear() + + # Release system instance + sys.ReleaseInstance() + + print('Not enough cameras!') + input('Done! Press Enter to exit...') + return False + + # Retrieve list of interfaces from the system + iface_list = sys.GetInterfaces() + + num_ifaces = iface_list.GetSize() + + print('Number of interfaces detected: %i \n' % num_ifaces) + + # Print information on each interface + # + # *** NOTES *** + # All USB 3 Vision and GigE Vision interfaces should enumerate for + # Spinnaker. + print('\n*** PRINTING INTERFACE INFORMATION ***\n') + + for iface in iface_list: + result &= print_transport_layer_interface_info(iface) + + # Release reference to interface + # 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 iface + + # Print general device information on each camera from transport layer + # + # *** NOTES *** + # Transport layer nodes do not require initialization in order to interact + # with them. + print('\n*** PRINTING TRANSPORT LAYER DEVICE INFORMATION ***\n') + + for cam in cam_list: + result &= print_transport_layer_device_info(cam) + + # Print streaming information on each camera from transport layer + # + # *** NOTES *** + # Again, initialization is not required to print information from the + # transport layer; this is equally true of streaming information. + print('\n*** PRINTING TRANSPORT LAYER STREAMING INFORMATION ***\n') + + for cam in cam_list: + result &= print_transport_layer_stream_info(cam) + + # Print device information on each camera from GenICam nodemap + # + # *** NOTES *** + # GenICam nodes require initialization in order to interact with + # them; as such, this loop initializes the camera, prints some information + # from the GenICam nodemap, and then deinitializes it. If the camera were + # not initialized, node availability would fail. + print('\n*** PRINTING GENICAM INFORMATION ***\n') + + for cam in cam_list: + # Initialize camera + cam.Init() + + # Print info + result &= print_genicam_device_info(cam) + + # Deinitialize camera + cam.DeInit() + + # 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() + + # Clear interface list before releasing system + iface_list.Clear() + + # Release system instance + sys.ReleaseInstance() + + input('\nDone! Press Enter to exit...') + return result + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/SaveToAvi.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/SaveToAvi.py new file mode 100644 index 0000000..1f79203 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/SaveToAvi.py @@ -0,0 +1,378 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# SaveToAvi.py shows how to create an AVI video from a vector of +# images. It relies on information provided in the Enumeration, Acquisition, +# and NodeMapInfo examples. +# +# This example introduces the SpinVideo class, which is used to quickly and +# easily create various types of AVI videos. It demonstrates the creation of +# three types: uncompressed, MJPG, and H264. + +import PySpin +import sys + + +class AviType: + """'Enum' to select AVI video type to be created and saved""" + UNCOMPRESSED = 0 + MJPG = 1 + H264 = 2 + +chosenAviType = AviType.UNCOMPRESSED # change me! +NUM_IMAGES = 10 # number of images to use in AVI file + + +def save_list_to_avi(nodemap, nodemap_tldevice, images): + """ + This function prepares, saves, and cleans up an AVI video from a vector of images. + + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :param images: List of images to save to an AVI video. + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :type images: list of ImagePtr + :return: True if successful, False otherwise. + :rtype: bool + """ + print('*** CREATING VIDEO ***') + + try: + result = True + + # Retrieve device serial number for filename + device_serial_number = '' + node_serial = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + + if PySpin.IsAvailable(node_serial) and PySpin.IsReadable(node_serial): + device_serial_number = node_serial.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Get the current frame rate; acquisition frame rate recorded in hertz + # + # *** NOTES *** + # The video frame rate can be set to anything; however, in order to + # have videos play in real-time, the acquisition frame rate can be + # retrieved from the camera. + + node_acquisition_framerate = PySpin.CFloatPtr(nodemap.GetNode('AcquisitionFrameRate')) + + if not PySpin.IsAvailable(node_acquisition_framerate) and not PySpin.IsReadable(node_acquisition_framerate): + print('Unable to retrieve frame rate. Aborting...') + return False + + framerate_to_set = node_acquisition_framerate.GetValue() + + print('Frame rate to be set to %d...' % framerate_to_set) + + # Select option and open AVI filetype with unique filename + # + # *** NOTES *** + # Depending on the filetype, a number of settings need to be set in + # an object called an option. An uncompressed option only needs to + # have the video frame rate set whereas videos with MJPG or H264 + # compressions should have more values set. + # + # Once the desired option object is configured, open the AVI file + # with the option in order to create the image file. + # + # Note that the filename does not need to be appended to the + # name of the file. This is because the AVI recorder object takes care + # of the file extension automatically. + # + # *** LATER *** + # Once all images have been added, it is important to close the file - + # this is similar to many other standard file streams. + + avi_recorder = PySpin.SpinVideo() + + if chosenAviType == AviType.UNCOMPRESSED: + avi_filename = 'SaveToAvi-Uncompressed-%s' % device_serial_number + + option = PySpin.AVIOption() + option.frameRate = framerate_to_set + + elif chosenAviType == AviType.MJPG: + avi_filename = 'SaveToAvi-MJPG-%s' % device_serial_number + + option = PySpin.MJPGOption() + option.frameRate = framerate_to_set + option.quality = 75 + + elif chosenAviType == AviType.H264: + avi_filename = 'SaveToAvi-H264-%s' % device_serial_number + + option = PySpin.H264Option() + option.frameRate = framerate_to_set + option.bitrate = 1000000 + option.height = images[0].GetHeight() + option.width = images[0].GetWidth() + + else: + print('Error: Unknown AviType. Aborting...') + return False + + avi_recorder.Open(avi_filename, option) + + # Construct and save AVI video + # + # *** NOTES *** + # Although the video file has been opened, images must be individually + # appended in order to construct the video. + print('Appending %d images to AVI file: %s.avi...' % (len(images), avi_filename)) + + for i in range(len(images)): + avi_recorder.Append(images[i]) + print('Appended image %d...' % i) + + # Close AVI file + # + # *** NOTES *** + # Once all images have been appended, it is important to close the + # AVI file. Notice that once an AVI file has been closed, no more + # images can be added. + + avi_recorder.Close() + print('Video saved at %s.avi' % avi_filename) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return 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 + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** 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 acquire_images(cam, nodemap): + """ + This function acquires 10 images from a device, stores them in a list, and returns the list. + please see the Acquisition example for more in-depth comments on acquiring images. + + :param cam: Camera to acquire images from. + :param nodemap: Device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :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.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or not PySpin.IsReadable(node_acquisition_mode_continuous): + print('Unable to set acquisition mode to continuous (entry retrieval). Aborting...') + return False + + acquisition_mode_continuous = node_acquisition_mode_continuous.GetValue() + + node_acquisition_mode.SetIntValue(acquisition_mode_continuous) + + print('Acquisition mode set to continuous...') + + # Begin acquiring images + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve, convert, and save images + images = list() + + for i in range(NUM_IMAGES): + try: + # 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; height and width recorded in pixels + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed Image %d, width = %d, height = %d' % (i, width, height)) + + # Convert image to mono 8 and append to list + images.append(image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR)) + + # Release image + image_result.Release() + print('') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + # End acquisition + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result, images + + +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 example 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() + + # Acquire list of images + err, images = acquire_images(cam, nodemap) + if err < 0: + return err + + result &= save_list_to_avi(nodemap, nodemap_tldevice, images) + + # 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:', 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 instance + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + return result + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/Sequencer.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Sequencer.py new file mode 100644 index 0000000..23035c7 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Sequencer.py @@ -0,0 +1,873 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# 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. + +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.IsAvailable(node_sequencer_configuration_valid) \ + or 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.IsAvailable(sequencer_configuration_valid_yes) \ + or 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.IsAvailable(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.IsAvailable(sequencer_mode_off) or 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.IsAvailable(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.IsAvailable(exposure_auto_off) or 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.IsAvailable(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.IsAvailable(gain_auto_off) or 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.IsAvailable(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.IsAvailable(sequencer_configuration_mode_on)\ + or 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.IsAvailable(node_sequencer_set_selector) or 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.IsAvailable(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.IsAvailable(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.IsAvailable(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.IsAvailable(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.IsAvailable(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.IsAvailable(sequencer_trigger_source_frame_start) or \ + 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.IsAvailable(node_sequencer_set_next) or 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.IsAvailable(node_sequencer_set_save) or 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.IsAvailable(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.IsAvailable(sequencer_configuration_mode_off)\ + or 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.IsAvailable(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.IsAvailable(sequencer_mode_on) or 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.IsAvailable(node_sequencer_configuration_valid) \ + or 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.IsAvailable(sequencer_configuration_valid_yes) \ + or 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.IsAvailable(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.IsAvailable(sequencer_mode_off) or 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.IsAvailable(node_exposure_auto) and PySpin.IsWritable(node_exposure_auto): + exposure_auto_continuous = node_exposure_auto.GetEntryByName('Continuous') + if PySpin.IsAvailable(exposure_auto_continuous) and 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.IsAvailable(node_gain_auto) and PySpin.IsWritable(node_gain_auto): + gain_auto_continuous = node_exposure_auto.GetEntryByName('Continuous') + if PySpin.IsAvailable(gain_auto_continuous) and 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.IsAvailable(node_device_information) and 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 available.') + + 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.IsAvailable(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.IsAvailable(node_acquisition_mode_continuous) or \ + 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.IsAvailable(node_device_serial_number) and 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 + 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 = image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + # 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.IsAvailable(node_width) or 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.IsAvailable(node_height) or 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.IsAvailable(node_exposure_time) or 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.IsAvailable(node_exposure_time) or 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) diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/SpinUpdate.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/SpinUpdate.py new file mode 100644 index 0000000..409fb80 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/SpinUpdate.py @@ -0,0 +1,89 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# SpinUpdate.py is a sample firmware updater application that takes in +# command line arguments. The example also demonstrates usage of callback +# functions to keep track of current update progress. +# +# Run with arguments in format (no quotes): "-R -P -UU " + +import PySpin +import sys + + +last_action = '' + + +def progress_callback(action, address, global_percent, curr_percent): + """ + Example progress callback function. + NOTE: This function must take exactly 4 arguments, + otherwise the update process will hang/crash! + + :param action: Current action being done in firmware update (as a byte string). + :param address: Address in camera being written to. + :param global_percent: Global completion percentage of update. + :param curr_percent: Completion percentage of current action. + :type action: str + :type address: int + :type global_percent: int + :type curr_percent: int + :rtype: int + """ + global last_action + if action != last_action: + # Prints action only if changed from previous one + print('Action: %s' % action) + last_action = action + + return 1 + + +def message_callback(message): + """ + Example message callback function. + NOTE: This function must take exactly 1 argument, + otherwise the update process will hang/crash! + + :param message: Message from updator (as a byte string). + :type message: str + :rtype: None + """ + print('Message: %s' % message) + + return 1 + + +def main(): + # Register callbacks + PySpin.SetProgressCallback(progress_callback) + PySpin.SetMessageCallback(message_callback) + + # Example usage for firmware update: + # Use either UpdateFirmware() or UpdateFirmwareConsole(): + # + # cmd = "-R3932019 C:\\firmware\\bfly2_u3_python1300.zim" # Add -P to argument list for callbacks + # return UpdateFirmware(cmd); + + return PySpin.UpdateFirmwareConsole(sys.argv) # uses command line args + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/Trigger-20343286-0.jpg b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Trigger-20343286-0.jpg new file mode 100644 index 0000000..1a24b00 Binary files /dev/null and b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Trigger-20343286-0.jpg differ diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/Trigger-20343286-1.jpg b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Trigger-20343286-1.jpg new file mode 100644 index 0000000..8869161 Binary files /dev/null and b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Trigger-20343286-1.jpg differ diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/Trigger-20343286-2.jpg b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Trigger-20343286-2.jpg new file mode 100644 index 0000000..9e72433 Binary files /dev/null and b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Trigger-20343286-2.jpg differ diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/Trigger.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Trigger.py new file mode 100644 index 0000000..aac40ff --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Trigger.py @@ -0,0 +1,516 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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.py shows how to trigger the camera. 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 they are somewhat shorter and simpler, either +# provides a strong introduction to camera customization. +# +# This example shows the process of configuring, using, and cleaning up a +# camera for use with both a software and a hardware trigger. + +import os +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 + set to off in order to select the trigger source. Once the trigger source + has been selected, trigger mode is then enabled, which has the camera + capture only a single image upon the execution of the chosen trigger. + + :param cam: Camera to configure trigger for. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + result = True + + print('*** CONFIGURING TRIGGER ***\n') + + if CHOSEN_TRIGGER == TriggerType.SOFTWARE: + print('Software trigger chosen ...') + elif CHOSEN_TRIGGER == TriggerType.HARDWARE: + print('Hardware trigger chose ...') + + try: + # Ensure trigger mode off + # The trigger must be disabled in order to configure whether the source + # is software or hardware. + nodemap = cam.GetNodeMap() + node_trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerMode')) + if not PySpin.IsAvailable(node_trigger_mode) or not PySpin.IsReadable(node_trigger_mode): + print('Unable to disable trigger mode (node retrieval). Aborting...') + return False + + node_trigger_mode_off = node_trigger_mode.GetEntryByName('Off') + if not PySpin.IsAvailable(node_trigger_mode_off) or not PySpin.IsReadable(node_trigger_mode_off): + print('Unable to disable trigger mode (enum entry retrieval). Aborting...') + return False + + node_trigger_mode.SetIntValue(node_trigger_mode_off.GetValue()) + + 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. + node_trigger_selector= PySpin.CEnumerationPtr(nodemap.GetNode('TriggerSelector')) + if not PySpin.IsAvailable(node_trigger_selector) or not PySpin.IsWritable(node_trigger_selector): + print('Unable to get trigger selector (node retrieval). Aborting...') + return False + + node_trigger_selector_framestart = node_trigger_selector.GetEntryByName('FrameStart') + if not PySpin.IsAvailable(node_trigger_selector_framestart) or not PySpin.IsReadable( + node_trigger_selector_framestart): + print('Unable to set trigger selector (enum entry retrieval). Aborting...') + return False + node_trigger_selector.SetIntValue(node_trigger_selector_framestart.GetValue()) + + 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. + node_trigger_source = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerSource')) + if not PySpin.IsAvailable(node_trigger_source) or not PySpin.IsWritable(node_trigger_source): + print('Unable to get trigger source (node retrieval). Aborting...') + return False + + if CHOSEN_TRIGGER == TriggerType.SOFTWARE: + node_trigger_source_software = node_trigger_source.GetEntryByName('Software') + if not PySpin.IsAvailable(node_trigger_source_software) or not PySpin.IsReadable( + node_trigger_source_software): + print('Unable to set trigger source (enum entry retrieval). Aborting...') + return False + node_trigger_source.SetIntValue(node_trigger_source_software.GetValue()) + print('Trigger source set to software...') + + elif CHOSEN_TRIGGER == TriggerType.HARDWARE: + node_trigger_source_hardware = node_trigger_source.GetEntryByName('Line0') + if not PySpin.IsAvailable(node_trigger_source_hardware) or not PySpin.IsReadable( + node_trigger_source_hardware): + print('Unable to set trigger source (enum entry retrieval). Aborting...') + return False + node_trigger_source.SetIntValue(node_trigger_source_hardware.GetValue()) + 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. + node_trigger_mode_on = node_trigger_mode.GetEntryByName('On') + if not PySpin.IsAvailable(node_trigger_mode_on) or not PySpin.IsReadable(node_trigger_mode_on): + print('Unable to enable trigger mode (enum entry retrieval). Aborting...') + return False + + node_trigger_mode.SetIntValue(node_trigger_mode_on.GetValue()) + 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(nodemap, cam): + """ + This function acquires an image by executing the trigger node. + + :param cam: Camera to acquire images from. + :param nodemap: Device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :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 + node_softwaretrigger_cmd = PySpin.CCommandPtr(nodemap.GetNode('TriggerSoftware')) + if not PySpin.IsAvailable(node_softwaretrigger_cmd) or not PySpin.IsWritable(node_softwaretrigger_cmd): + print('Unable to execute trigger. Aborting...') + return False + + node_softwaretrigger_cmd.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, nodemap, nodemap_tldevice): + """ + 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. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** IMAGE ACQUISITION ***\n') + try: + result = True + + # Set acquisition mode to continuous + # In order to access the node entries, they have to be casted to a pointer type (CEnumerationPtr here) + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.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(nodemap, 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; height and width recorded in pixels + # + # *** NOTES *** + # Images have quite a bit of available metadata including + # things such as CRC, image status, and offset values, to + # name a few. + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed Image %d, width = %d, height = %d' % (i, width, height)) + + # Convert image to mono 8 + # + # *** NOTES *** + # Images can be converted between pixel formats by using + # the appropriate enumeration value. Unlike the original + # image, the converted one does not need to be released as + # it does not affect the camera buffer. + # + # When converting images, color processing algorithm is an + # optional parameter. + 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 + # + # *** NOTES *** + # The standard practice of the examples is to use device + # serial numbers to keep images of one device from + # overwriting those of another. + image_converted.Save(filename) + print('Image saved at %s\n' % filename) + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def reset_trigger(nodemap): + """ + This function returns the camera to a normal state by turning off trigger mode. + + :param nodemap: Transport layer device nodemap. + :type nodemap: INodeMap + :returns: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + node_trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerMode')) + if not PySpin.IsAvailable(node_trigger_mode) or not PySpin.IsReadable(node_trigger_mode): + print('Unable to disable trigger mode (node retrieval). Aborting...') + return False + + node_trigger_mode_off = node_trigger_mode.GetEntryByName('Off') + if not PySpin.IsAvailable(node_trigger_mode_off) or not PySpin.IsReadable(node_trigger_mode_off): + print('Unable to disable trigger mode (enum entry retrieval). Aborting...') + return False + + node_trigger_mode.SetIntValue(node_trigger_mode_off.GetValue()) + + 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, nodemap, nodemap_tldevice) + + # Reset trigger + result &= reset_trigger(nodemap) + + # 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 + """ + + # 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: %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) diff --git a/FLIR/FLIRcodev3.2/Spinnaker/Examples/Trigger_QuickSpin.py b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Trigger_QuickSpin.py new file mode 100644 index 0000000..a1eb67e --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/Examples/Trigger_QuickSpin.py @@ -0,0 +1,419 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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') + + 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.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 + 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 + 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!') + 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) diff --git a/FLIR/FLIRcodev3.2/Spinnaker/README.txt b/FLIR/FLIRcodev3.2/Spinnaker/README.txt new file mode 100644 index 0000000..42057f3 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/README.txt @@ -0,0 +1,342 @@ +============================================================================= +Copyright (c) 2001-2019 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. +============================================================================= + +============================================================================= +== +== README +== +============================================================================= + +PySpin is a wrapper for FLIR Integrated Imaging Solutions' Spinnaker library. + +FLIR Integrated Imaging Solutions' website is located at https://www.flir.com/iis/machine-vision + +The PySpin Python extension provides a common software interface +to control and acquire images from FLIR USB 3.0, GigE, +and USB 2.0 cameras using the same API under 32- or 64-bit Windows. + +============================================================================= +TABLE OF CONTENTS +============================================================================= +1. INSTALLATION +1.1 INSTALLATION ON WINDOWS +1.2 INSTALLATION ON LINUX +1.3 INSTALLATION ON MACOS +2. API DIFFERENCES +3. REMOVE PYSPIN + +============================================================================= +1. INSTALLATION +============================================================================= + +----------------------------------------------------------------------------- +1.1 WINDOWS +----------------------------------------------------------------------------- + +1. Install Python. Currently we support Python 2.7, 3.5, 3.6, and 3.7. To + download Python, visit https://www.python.org/downloads/. Note that the + Python website defaults to 32-bit interpreters, so if you want a 64-bit + version of Python you have to click into the specific release version. + +2. (Optional) Set the PATH environment variable for your Python installation. + This may have been done automatically as part of installation, but to do + this manually you have to open Environment Variables through the following: + + My Computer > Properties > Advanced System Settings > Environment Variables + + Add your Python installation location to your PATH variable. For example, + if you installed Python at C:\Python37\, you would add the following entry + to the PATH variable: + + C:\Python37\ + +3. Configure your Python installation. From a command line, run the following + commands to update and install dependencies for your associated Python version: + + -m ensurepip + -m pip install --upgrade pip numpy matplotlib + + NumPy is a requirement for PySpin and needs to be at least version 1.15 or + above. Matplotlib is not required for the library itself but is used in some + of our examples to highlight possible usages of PySpin. For better support of + matplotlib output image file formats, Pillow is suggested to be installed. + Note: some versions of Pillow might NOT support some Python versions. + + The full list of supported Pillow versions given a Python version can be found here: + https://pillow.readthedocs.io/en/stable/installation.html#notes + + For example, with Python 3.7, install a supported Pillow using the following command: + + ex. py -3.7 -m pip install Pillow==5.2.0 + + Older installations of Python 2.7 do NOT come with enum34, which is required by + the Inference.py Python2 example. Install enum34 for Python 2.7 using the following command: + + py -2.7 -m pip install enum34 + +4. To ensure prerequisites such as drivers and Visual Studio redistributables + are installed on the system, run the Spinnaker SDK installer that corresponds + with the PySpin version number. For example, if installing PySpin 1.8.0.0, + install Spinnaker 1.8.0.0 beforehand, selecting only the Visual Studio + runtimes and drivers. + +5. Run the following command to install PySpin to your associated Python version. + This command assumes you have your PATH variable set correctly for Python: + + -m pip install spinnaker_python-1.x.x.x-cp37-cp37m-win_amd64.whl + + Ensure that the wheel downloaded matches the Python version you are installing to! + +After installation, PySpin examples can be ran directly from the command prompt. +For example, if PySpin is installed for Python 3.7, run a preinstalled example +using the following: + + ex. py -3.7 Examples\Python3\Acquisition.py + +----------------------------------------------------------------------------- +1.2 LINUX +----------------------------------------------------------------------------- + +1. Check that pip is available for your respective Python versions + by running the following command: + + sudo apt-get install python-pip python3-pip + +2. Install library dependencies for PySpin: numpy and matplotlib. NumPy is a + requirement for PySpin and needs to be at least version 1.15 or above. + Matplotlib is not required for the library itself but is used in some of + our examples to highlight possible usages of PySpin. Install these + dependencies by running one of the following commands. + + - Install for Python 2.7, user only: + python -m pip install --upgrade --user numpy matplotlib + + - Install for Python 2.7, site wide: + sudo python -m pip install --upgrade numpy matplotlib + + - Install for Python 3.5, user only (16.04 only): + python3.5 -m pip install --upgrade --user numpy matplotlib + + - Install for Python 3.5, site wide (16.04 only): + sudo python3.5 -m pip install --upgrade numpy matplotlib + + - Install for Python 3.6, user only: + python3.6 -m pip install --upgrade --user numpy matplotlib + + - Install for Python 3.6, site wide: + sudo python3.6 -m pip install --upgrade numpy matplotlib + + - Install for Python 3.7, user only: + python3.7 -m pip install --upgrade --user numpy matplotlib + + - Install for Python 3.7, site wide: + sudo python3.7 -m pip install --upgrade numpy matplotlib + + For better support of matplotlib output image file formats, Pillow is suggested to be installed. + Note: some versions of Pillow might NOT support some Python versions. + + The full list of supported Pillow versions given a Python version can be found here: + https://pillow.readthedocs.io/en/stable/installation.html#notes + + For example, with Python 3.7, install a supported Pillow using the following command: + + ex. python3.7 -m pip install Pillow==5.2.0 + + Older installations of Python 2.7 do NOT come with enum34, which is required by + the Inference.py Python2 example. Install enum34 for Python 2.7 using the following command: + + python2.7 -m pip install enum34 + +3. Ensure that the corresponding version of the Spinnaker SDK Debian packages + and their prerequisites are installed beforehand + (ex. install the 1.21.0.61 packages if the wheel version is also 1.21.0.61) + +4. Install wheel for specific Python version. This can be installed site-wide + for all users or for a specific user. + + - Python 2.7, site wide: + sudo python -m pip install spinnaker_python-1.x.x.x-cp27-cp27mu-linux_x86_64.whl + + - Python 2.7, user only: + python -m pip install --user spinnaker_python-1.x.x.x-cp27-cp27mu-linux_x86_64.whl + + - Python 3.5, site wide (16.04 only): + sudo python3.5 -m pip install spinnaker_python-1.x.x.x-cp35-cp35m-linux_x86_64.whl + + - Python 3.5, user only (16.04 only): + python3.5 -m pip install --user spinnaker_python-1.x.x.x-cp35-cp35m-linux_x86_64.whl + + - Python 3.6, site wide: + sudo python3.6 -m pip install spinnaker_python-1.x.x.x-cp36-cp36m-linux_x86_64.whl + + - Python 3.6, user only: + python3.6 -m pip install --user spinnaker_python-1.x.x.x-cp36-cp36m-linux_x86_64.whl + + - Python 3.7, site wide: + sudo python3.7 -m pip install spinnaker_python-1.x.x.x-cp37-cp37m-linux_x86_64.whl + + - Python 3.7, user only: + python3.7 -m pip install --user spinnaker_python-1.x.x.x-cp37-cp37m-linux_x86_64.whl + +5. The examples are located in the Examples folder of the extracted tarball. Run with: + ex. python3.7 Examples/Python3/DeviceEvents.py + +----------------------------------------------------------------------------- +1.3 MACOS +----------------------------------------------------------------------------- + +1. Check that Python is installed. MacOS comes with Python 2.7 installed, + but it may be an older build of Python. Up-to-date Python packages + can be downloaded from https://www.python.org/downloads. + +2. Update pip for Python. Run the following command for your version of Python: + + sudo -m ensurepip + + This will install a version of pip and allow you to update or install new wheels. + +3. Install library dependencies for PySpin: numpy and matplotlib. NumPy is a + requirement for PySpin and needs to be at least version 1.15 or above. + Matplotlib is not required for the library itself but is used in some of + our examples to highlight possible usages of PySpin. Install these + dependencies by running one of the following commands. + + - Install for Python 2.7, user only: + python -m pip install --upgrade --user numpy matplotlib + + - Install for Python 2.7, site wide: + sudo python -m pip install --upgrade numpy matplotlib + + - Install for Python 3.6, user only: + python3.6 -m pip install --upgrade --user numpy matplotlib + + - Install for Python 3.6, site wide: + sudo python3.6 -m pip install --upgrade numpy matplotlib + + - Install for Python 3.7, user only: + python3.7 -m pip install --upgrade --user numpy matplotlib + + - Install for Python 3.7, site wide: + sudo python3.7 -m pip install --upgrade numpy matplotlib + + For better support of matplotlib output image file formats, Pillow is suggested to be installed. + Note: some versions of Pillow might NOT support some Python versions. + + The full list of supported Pillow versions given a Python version can be found here: + https://pillow.readthedocs.io/en/stable/installation.html#notes + + For example, with Python 3.7, install a supported Pillow using the following command: + + ex. python3.7 -m pip install Pillow==5.2.0 + + Older installations of Python 2.7 do NOT come with enum34, which is required by + the Inference.py Python2 example. Install enum34 for Python 2.7 using the following command: + + python2.7 -m pip install enum34 + +4. Ensure that the corresponding version of the Spinnaker SDK MacOS packages + and their prerequisites are installed beforehand. + (ex. install 1.21.0.61 packages if the wheel version is also 1.21.0.61) + +5. Install the PySpin wheel for specific Python version. + ex. sudo python3.7 -m pip install spinnaker_python-1.x.x.x-cp37-cp37mu-macos_x86_x64.whl" for 64-bit Python 3.7 + +6. The examples are located in the Examples folder of the extracted tarball. Run with: + ex. python3.7 Examples/Python3/DeviceEvents.py + +============================================================================= +2. API DIFFERENCES +============================================================================= + +Except for the changes listed below, most function names are exactly the same +as the C++ API. See examples for PySpin usage! + +- All methods of SpinnakerException no longer exist, please replace all + usages of SpinnakerException with any of the following attributes: + message: Normal exception message. + fullmessage: Exception message including line, file, function, + build date, and time (from C++ library). + errorcode: Integer error code of the exception. + The SpinnakerException instance itself can be printed, as it derives from + the BaseException class and has a default __str__ representation. + See examples for usage. + +- Image creation using NumPy arrays (although the int type of the array must be uint8) + +- The majority of headers from the C++ API have been wrapped, with the exception of: + - Headers with "Adapter" or "Port" in the name + - NodeMapRef.h, NodeMapFactory.h + - Synch.h, GCSynch.h, Counter.h, filestream.h + +- INode and IValue types (esp. returned from GetNode()) have to + be initialized to their respective pointer types + (ex. CFloatPtr, CEnumerationPtr) to access their functions + +- CameraPtr, CameraList, InterfacePtr, InterfaceList, and SystemPtr + have to be manually released and/or deleted before program exit (use del operator) + - See EnumerationEvents example + +- Image.GetData() returns a 1-D NumPy array of integers, the int type + depends on the pixel format of the image + +- Image.GetNDArray() returns a 2 or 3-D NumPy array of integers, only for select + image formats. This can be used in libraries such as PIL and/or OpenCV. + +- Node callbacks take in a callback class instead of a function pointer + - Register is now RegisterNodeCallback, Deregister is now DeregisterNodeCallback + - See NodeMapCallback example for more details + +- IImage.CalculateChannelStatistics(StatisticsChannel channel) returns + a ChannelStatistics object representing stats for the given channel + in the image. These stats are properties within the ChannelStatistics object, + Please see the docstring for details. This replaces ImageStatistics! + +- Pass-by-reference functions now return the type and take in void + - GetFeatures() returns a Python list of IValue, instead of taking + in a FeatureList_t reference + - GetChildren() returns a Python list of INode, instead of taking + in a NodeList_t reference + - Same with GetEntries(), GetNodes() + - GetPropertyNames() returns a Python list of str, + instead of taking in a gcstring_vector reference + - See DeviceEvents example for usage + +- Methods Get() and Set() for IRegister and register nodes use NumPy arrays + - Get() takes in the length of the register to read and two optional + bools, returns a NumPy array + - Set() takes in a single NumPy array + +============================================================================= +3. REMOVE PYSPIN +============================================================================= + +Removing or updating PySpin is similar to removing or updating other wheels. + +For Windows, if you need to remove PySpin, the following command needs to be +run from an administrator command prompt to remove your associated Python version: + + -m pip uninstall spinnaker-python + +For Linux or MacOS, if you need to remove PySpin from a user-specific install, run +the following command to remove your associated Python version: + + -m pip uninstall spinnaker-python + +For Linux or MacOS, if you need to remove PySpin from a site-wide install the +following command needs to be run as sudo to remove your associated Python version: + +sudo -m pip uninstall spinnaker-python \ No newline at end of file diff --git a/FLIR/FLIRcodev3.2/Spinnaker/docs/PySpinDoc.chm b/FLIR/FLIRcodev3.2/Spinnaker/docs/PySpinDoc.chm new file mode 100644 index 0000000..4e69f95 Binary files /dev/null and b/FLIR/FLIRcodev3.2/Spinnaker/docs/PySpinDoc.chm differ diff --git a/FLIR/FLIRcodev3.2/Spinnaker/docs/PySpinDoc.pdf b/FLIR/FLIRcodev3.2/Spinnaker/docs/PySpinDoc.pdf new file mode 100644 index 0000000..5b2a889 Binary files /dev/null and b/FLIR/FLIRcodev3.2/Spinnaker/docs/PySpinDoc.pdf differ diff --git a/FLIR/FLIRcodev3.2/Spinnaker/licenses/FFmpeg_compliance_doc.txt b/FLIR/FLIRcodev3.2/Spinnaker/licenses/FFmpeg_compliance_doc.txt new file mode 100644 index 0000000..7b06e29 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Spinnaker/licenses/FFmpeg_compliance_doc.txt @@ -0,0 +1,2 @@ +This software uses code of FFmpeg http://ffmpeg.org licensed under the LGPL v2.1 (http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html). +The FFmpeg code can be found online at https://github.com/FFmpeg/FFmpeg/tree/5156578d1f486163d5b83f1d63246cd23d107933. \ No newline at end of file diff --git a/FLIR/FLIRcodev3.2/Spinnaker/licenses/Spinnaker-Open-Source-Licenses.pdf b/FLIR/FLIRcodev3.2/Spinnaker/licenses/Spinnaker-Open-Source-Licenses.pdf new file mode 100644 index 0000000..55a8894 Binary files /dev/null and b/FLIR/FLIRcodev3.2/Spinnaker/licenses/Spinnaker-Open-Source-Licenses.pdf differ diff --git a/FLIR/FLIRcodev3.2/Spinnaker/spinnaker_python-2.0.0.146-cp38-cp38-win_amd64.whl b/FLIR/FLIRcodev3.2/Spinnaker/spinnaker_python-2.0.0.146-cp38-cp38-win_amd64.whl new file mode 100644 index 0000000..bd0497a Binary files /dev/null and b/FLIR/FLIRcodev3.2/Spinnaker/spinnaker_python-2.0.0.146-cp38-cp38-win_amd64.whl differ diff --git a/FLIR/FLIRcodev3.2/Trigger_QuickSpin.py b/FLIR/FLIRcodev3.2/Trigger_QuickSpin.py new file mode 100644 index 0000000..9a33cb4 --- /dev/null +++ b/FLIR/FLIRcodev3.2/Trigger_QuickSpin.py @@ -0,0 +1,422 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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 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.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 + 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 + 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!') + 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) diff --git a/FLIR/FLIRcodev3.2/build/lib/flir/__init__.py b/FLIR/FLIRcodev3.2/build/lib/flir/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/FLIR/FLIRcodev3.2/build/lib/flir/aqctl_flir.py b/FLIR/FLIRcodev3.2/build/lib/flir/aqctl_flir.py new file mode 100644 index 0000000..fb086a9 --- /dev/null +++ b/FLIR/FLIRcodev3.2/build/lib/flir/aqctl_flir.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 + +# Written by Joe Britton, 2015 + +import argparse +import logging +import sys +import os +import asyncio + +from flir.driver import FLIR +from flir.driver import TriggerType +from sipyco.pc_rpc import simple_server_loop +from sipyco import common_args + + +logger = logging.getLogger(__name__) + + +def get_argparser(): + parser = argparse.ArgumentParser( + description="ARTIQ controller for the FLIR camera") + common_args.simple_network_args(parser, 3200) + parser.add_argument( + "-d", "--device", default=None, + help="serial port.") + parser.add_argument( + "--softtrig", default=False, action="store_true", + help="Sets trigger to software. Default is hardware") + parser.add_argument( + "--num", default=1, + help="Sets number of images. Default is hardware") + parser.add_argument( + "--simulation", action="store_true", + help="Put the driver in simulation mode, even if --device is used.") + common_args.verbosity_args(parser) + return parser + + +def main(): + args = get_argparser().parse_args() + common_args.init_logger_from_args(args) + if os.name == "nt": + asyncio.set_event_loop(asyncio.ProactorEventLoop()) + # if args.device is None: + # print("Starting in Simulation mode...") + # dev = FLIR(args.device if not args.simulation else None) + + print("Software trigger is:",args.softtrig) + triggerset=TriggerType(args.softtrig) + dev = FLIR(args.num) + asyncio.get_event_loop().run_until_complete(dev.setup()) + try: + print("Startup on port",args.port,"successful...") + simple_server_loop( + {"flir": dev}, common_args.bind_address_from_args(args), args.port) + finally: + dev.close() +if __name__ == "__main__": + main() diff --git a/FLIR/FLIRcodev3.2/build/lib/flir/driver(backup).py b/FLIR/FLIRcodev3.2/build/lib/flir/driver(backup).py new file mode 100644 index 0000000..f6295b4 --- /dev/null +++ b/FLIR/FLIRcodev3.2/build/lib/flir/driver(backup).py @@ -0,0 +1,535 @@ +# Written by Joe Britton, 2015 + +import math +import logging +import asyncio +import asyncserial + +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +class TriggerType: + SOFTWARE = 1 + HARDWARE = 2 + +CHOSEN_TRIGGER = TriggerType.SOFTWARE + + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + pass + + +class FLIR: + """Driver for FLIR camera """ + + error_codes = { + "?0": "Unrecognized Command", + "?1": "Bad Frequency", + "?2": "Bad AM Command", + "?3": "Input line too long", + "?4": "Bad Phase", + "?5": "Bad Time", + "?6": "Bad Mode", + "?7": "Bad Amp", + "?8": "Bad Constant", + "?f": "Bad Byte" + } + + def __init__(self, serial_dev): + if serial_dev is None: + self.simulation = True + else: + self.simulation = False + self.port = asyncserial.AsyncSerial( + serial_dev, + baudrate=19200, + bytesize=8, + parity="N", + stopbits=1, + xonxoff=0) + + async def _ser_readline(self): + c = await self.port.read(1) + print(c) + r = c + while c != b"\n": + c = await self.port.read(1) + r += c + return r + + async def _ser_send(self, cmd, get_response=True): + """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + if self.simulation: + logger.info("simulation _ser_send(\"%s\")", cmd) + else: + logger.debug("_ser_send(\"%s\")", cmd) + self.port.ser.reset_input_buffer() + await self.port.write((cmd + "\r\n").encode()) + if get_response: + result = (await self._ser_readline()).rstrip().decode() + logger.debug("got response from device: %s", result) + if result != "OK": + errstr = self.error_codes.get(result, "Unrecognized reply") + s = "Erroneous reply from device: {ec}, {ecs}".format( + ec=result, ecs=errstr) + raise ValueError(s) + else: + pass + + async def setup(self): + """Initial setup of FLIR.""" + await self._ser_send("E d", get_response=False) + + + def close(self): + """Close the serial hardware port.""" + if not self.simulation: + self.port.close() + + async def ping(self): + try: + stat = await self.get_status() + except asyncio.CancelledError: + raise + except: + return False + # check that version number matches is "21" + if stat[4][20:] == "21": + logger.debug("ping successful") + return True + else: + return False + + + 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.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 + 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 + 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 + """ + print("393-postfunction") + try: + print("395") + result = True + err = False + print("398") + # Retrieve TL device nodemap and print device information + nodemap_tldevice = cam.GetTLDeviceNodeMap() + print("401") + result &= print_device_info(nodemap_tldevice) + print("403") + # Initialize camera + cam.Init() + print("406") + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + print("409") + # Configure trigger + if configure_trigger(cam) is False: + return False + print("413") + # Acquire images + result &= grab_next_image_by_trigger(cam) #acquire_images(cam) THIS IS WHAT I CHANGED TO TRY TO GRAB ONLY ONE IMAGE AT A TIME! + print("416") + # Reset trigger + result &= reset_trigger(cam) + print("419") + # Deinitialize camera + cam.DeInit() + print("422") + except PySpin.SpinnakerException as ex: + print("424-exception") + print('Error: %s' % ex) + result = False + + + return result + + + def picture(cam): + """ + Run this code to take a single triggered picture! + + :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!') + print("Closing camera instance...") #input('Done! Press Enter to exit...') + return False + print(cam) + # Run example on each camera + for i, cam in enumerate(cam_list): + + print('Running example for camera %d...' % i) + + print("472-prefunction") + 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() + + print("Closing camera instance...") #input('Done! Press Enter to exit...') + return result + + + # if __name__ == '__picture__': + # if picture(): + # sys.exit(0) + # else: + # sys.exit(1) + + + + +############################################################ + + + + + + # async def reset(self): + # """Hardware reset of FLIR.""" + # await self._ser_send("R", get_response=False) + # await asyncio.sleep(1) + # await self.setup() + + # async def setup(self): + # """Initial setup of FLIR.""" + + # await self._ser_send("E d", get_response=False) + + # async def get_status(self): + # if self.simulation: + # return ["00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "80 BC0000 0000 0102 21"] + # else: + # self.port.ser.reset_input_buffer() + # result = [] + # await self.port.write(("QUE" + "\r\n").encode()) + # for i in range(5): + # m = (await self._ser_readline()).rstrip().decode() + # result.append(m) + # logger.debug("got device status: %s", result) + # return result + + \ No newline at end of file diff --git a/FLIR/FLIRcodev3.2/build/lib/flir/driver(complex).py b/FLIR/FLIRcodev3.2/build/lib/flir/driver(complex).py new file mode 100644 index 0000000..b4167c8 --- /dev/null +++ b/FLIR/FLIRcodev3.2/build/lib/flir/driver(complex).py @@ -0,0 +1,202 @@ +# Written by Joe Britton, 2015 + +import math +import logging +import asyncio +import asyncserial + + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + print("Exception Error :(") + pass + + +class FLIR: + """Driver for Novatech 409B 4-channel DDS. + + All output channels are in range [0, 1, 2, 3]. + All frequencies are in Hz. + All phases are in turns. + All amplitudes are in volts. + """ + + error_codes = { + "?0": "Unrecognized Command", + "?1": "Bad Frequency", + "?2": "Bad AM Command", + "?3": "Input line too long", + "?4": "Bad Phase", + "?5": "Bad Time", + "?6": "Bad Mode", + "?7": "Bad Amp", + "?8": "Bad Constant", + "?f": "Bad Byte" + } + + def __init__(self, serial_dev): + if serial_dev is None: + self.simulation = True + else: + self.simulation = False + self.port = asyncserial.AsyncSerial( + serial_dev, + baudrate=19200, + bytesize=8, + parity="N", + stopbits=1, + xonxoff=0) + + def close(self): + """Close the serial port.""" + if not self.simulation: + self.port.close() + + async def _ser_readline(self): + c = await self.port.read(1) + print(c) + r = c + while c != b"\n": + c = await self.port.read(1) + r += c + return r + + async def _ser_send(self, cmd, get_response=True): + """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + if self.simulation: + logger.info("simulation _ser_send(\"%s\")", cmd) + else: + logger.debug("_ser_send(\"%s\")", cmd) + self.port.ser.reset_input_buffer() + await self.port.write((cmd + "\r\n").encode()) + if get_response: + result = (await self._ser_readline()).rstrip().decode() + logger.debug("got response from device: %s", result) + if result != "OK": + errstr = self.error_codes.get(result, "Unrecognized reply") + s = "Erroneous reply from device: {ec}, {ecs}".format( + ec=result, ecs=errstr) + raise ValueError(s) + else: + pass + + async def reset(self): + """Hardware reset of 409B.""" + await self._ser_send("R", get_response=False) + await asyncio.sleep(1) + await self.setup() + + async def setup(self): + """Initial setup of 409B.""" + + # Setup the Novatech 409B with the following defaults: + # * command echo off ("E d") + # * external clock ("") 10 MHz sinusoid -1 to +7 dBm + print("setup is working") + await self._ser_send("E d", get_response=False) + await self.set_phase_continuous(True) + await self.set_simultaneous_update(False) + + async def save_state_to_eeprom(self): + """Save current state to EEPROM.""" + await self._ser_send("S") + + async def set_phase_continuous(self, is_continuous): + """Toggle phase continuous mode. + + Sends the "M n" command. This turns off the automatic + clearing of the phase register. In this mode, the phase + register is left intact when a command is performed. + Use this mode if you want frequency changes to remain + phase synchronous, with no phase discontinuities. + + :param is_continuous: True or False + """ + if is_continuous: + await self._ser_send("M n") + else: + await self._ser_send("M a") + + async def set_simultaneous_update(self, simultaneous): + """Set simultaneous update mode. + + Sends the "I m" command. In this mode an update + pulse will not be sent to the DDS chip until + an "I p" command is sent. This is useful when it is + important to change all the outputs to new values + simultaneously. + """ + if simultaneous: + await self._ser_send("I m") + else: + await self._ser_send("I a") + + async def do_simultaneous_update(self): + """Apply update in simultaneous update mode.""" + await self._ser_send("I p") + + async def set_freq(self, ch_no, freq): + """Set frequency of one channel.""" + # Novatech expects MHz + await self._ser_send("F{:d} {:f}".format(ch_no, freq/1e6)) + + async def set_phase(self, ch_no, phase): + """Set phase of one channel.""" + # phase word is required by device + # N is an integer from 0 to 16383. Phase is set to + # N*360/16384 deg; in ARTIQ represent phase in cycles [0, 1] + phase_word = round(phase*16383) + cmd = "P{:d} {:d}".format(ch_no, phase_word) + await self._ser_send(cmd) + + async def set_gain(self, ch_no, volts): + """Set amplitude of one channel.""" + + # due to error in Novatech it doesn't generate an error for + # dac_value>1024, so need to trap. + dac_value = int(math.floor(volts/0.51*1024)) + if dac_value < 0 or dac_value > 1023: + s = "Amplitude out of range {v}".format(v=volts) + raise ValueError(s) + + s = "V{:d} {:d}".format(ch_no, dac_value) + await self._ser_send(s) + + async def get_status(self): + if self.simulation: + return ["00989680 2000 01F5 0000 00000000 00000000 000301", + "00989680 2000 01F5 0000 00000000 00000000 000301", + "00989680 2000 01F5 0000 00000000 00000000 000301", + "00989680 2000 01F5 0000 00000000 00000000 000301", + "80 BC0000 0000 0102 21"] + else: + self.port.ser.reset_input_buffer() + result = [] + await self.port.write(("QUE" + "\r\n").encode()) + for i in range(5): + m = (await self._ser_readline()).rstrip().decode() + result.append(m) + logger.debug("got device status: %s", result) + return result + + async def ping(self): + try: + stat = await self.get_status() + except asyncio.CancelledError: + raise + except: + return False + # check that version number matches is "21" + if stat[4][20:] == "21": + logger.debug("ping successful") + return True + else: + return False diff --git a/FLIR/FLIRcodev3.2/build/lib/flir/driver.py b/FLIR/FLIRcodev3.2/build/lib/flir/driver.py new file mode 100644 index 0000000..b3a5d83 --- /dev/null +++ b/FLIR/FLIRcodev3.2/build/lib/flir/driver.py @@ -0,0 +1,714 @@ +import math +import logging +import asyncio +import asyncserial +import os +import matplotlib.pyplot as plt +import keyboard +import time +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + +global continue_recording +continue_recording = True + +global trigtype +trigtype=5 +SOFTWARE = 1 +HARDWARE = 2 + +class TriggerType(): + def __init__(self, softtrig): + global trigtype + if softtrig is True: + trigtype=SOFTWARE + else: + trigtype=HARDWARE + +CHOSEN_TRIGGER = trigtype + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + pass + + +class FLIR: + """Driver for FLIR camera """ + + error_codes = { + "?0": "Unrecognized Command", + "?1": "Bad Frequency", + "?2": "Bad AM Command", + "?3": "Input line too long", + "?4": "Bad Phase", + "?5": "Bad Time", + "?6": "Bad Mode", + "?7": "Bad Amp", + "?8": "Bad Constant", + "?f": "Bad Byte" + } + + def __init__(self,num): + serial_dev = None + cam=0 + cam_list=0 + self.cameras=0 + result = True + self.num=num + system = PySpin.System.GetInstance() + version = system.GetLibraryVersion() + print('Library version: %d.%d.%d.%d' % (version.major, version.minor, version.type, version.build)) + cam_list = system.GetCameras() + self.system = system + self.cam_list = cam_list + self.cam=cam_list[0] + + num_cameras = cam_list.GetSize() + print('Number of cameras detected: %d' % num_cameras) + if num_cameras == 0: + cam_list.Clear() + system.ReleaseInstance() + print('Not enough cameras!') + print("Closing camera instance...") #input('Done! Press Enter to exit...') + return False + for i, cam in enumerate(cam_list): + + print('Defining camera %d...' % i) + + if serial_dev is None: + self.simulation = True + else: + self.simulation = False + self.port = asyncserial.AsyncSerial( + serial_dev, + baudrate=19200, + bytesize=8, + parity="N", + stopbits=1, + xonxoff=0) + + # Retrieve TL device nodemap and print device information + self.nodemap_tldevice = cam.GetTLDeviceNodeMap() + result &= self.print_device_info(self.nodemap_tldevice) + # Initialize camera + cam.Init() + # Retrieve GenICam nodemap + self.nodemap = cam.GetNodeMap() + + print("Going back to server now...") + + + + #return result + + + # def picture(self): + # """ + # Run this code to take a single triggered picture! + + # :return: True if successful, False otherwise. + # :rtype: bool + # """ + # result = True + # print(self.cam) + # result &= self.run_single_camera(self.cam) + # for i, cam in enumerate(cam_list): + + # print('Running example for camera %d...' % i) + + # print("472-prefunction") + # result &= run_single_camera(cam) + # print('Camera %d example complete... \n' % i) + # return result + + def picture(self):#run_single_camera(self): + """ + 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 + cam=self.cam + + # Configure trigger + if self.configure_trigger(cam) is False: + return False + # Acquire images + result &= self.grab_next_image_by_trigger(cam) #acquire_images(cam) THIS IS WHAT I CHANGED TO TRY TO GRAB ONLY ONE IMAGE AT A TIME! + # Reset trigger + result &= self.reset_trigger(cam) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + + return result + + async def _ser_readline(self): + c = await self.port.read(1) + print(c) + r = c + while c != b"\n": + c = await self.port.read(1) + r += c + return r + + async def _ser_send(self, cmd, get_response=True): + """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + if self.simulation: + logger.info("simulation _ser_send(\"%s\")", cmd) + else: + logger.debug("_ser_send(\"%s\")", cmd) + self.port.ser.reset_input_buffer() + await self.port.write((cmd + "\r\n").encode()) + if get_response: + result = (await self._ser_readline()).rstrip().decode() + logger.debug("got response from device: %s", result) + if result != "OK": + errstr = self.error_codes.get(result, "Unrecognized reply") + s = "Erroneous reply from device: {ec}, {ecs}".format( + ec=result, ecs=errstr) + raise ValueError(s) + else: + pass + + async def setup(self): + """Initial setup of FLIR.""" + await self._ser_send("E d", get_response=False) + + + def close(self): + """Close the serial hardware port.""" + # Deinitialize camera + self.cam.DeInit() + del self.cam + self.system.ReleaseInstance() + self.cam_list.Clear() + print("Closing camera instance...") #input('Done! Press Enter to exit...') + # if not self.simulation: + # self.port.close() + + async def ping(self): + try: + stat = await self.get_status() + except asyncio.CancelledError: + raise + except: + return False + # check that version number matches is "21" + if stat[4][20:] == "21": + logger.debug("ping successful") + return True + else: + return False + + + def configure_trigger(self,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 == SOFTWARE: + print('Software trigger chosen...') + elif CHOSEN_TRIGGER == 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.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 == SOFTWARE: + cam.TriggerSource.SetValue(PySpin.TriggerSource_Software) + print('Trigger source set to software...') + elif CHOSEN_TRIGGER == 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(self,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 == 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 == 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(self): + """ + 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 + """ + cam=self.cam + NUM_IMAGES=self.num + 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 &= self.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(self): + # Deinitialize camera + self.cam.DeInit() + + self.cam.Init() + + + def reset_trigger(self,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(self,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 handle_close(self,evt): + """ + This function will close the GUI when close event happens. + + :param evt: Event that occurs when the figure closes. + :type evt: Event + """ + + global continue_recording + continue_recording = False + + def display(self): + """ + This function continuously acquires images from a device and display them in a GUI. + + :param cam: Camera to acquire images from. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + global continue_recording + + cam=self.cam + nodemap=self.nodemap + nodemap_tldevice=self.nodemap_tldevice + sNodemap = cam.GetTLStreamNodeMap() + + # Change bufferhandling mode to NewestOnly + node_bufferhandling_mode = PySpin.CEnumerationPtr(sNodemap.GetNode('StreamBufferHandlingMode')) + if not PySpin.IsAvailable(node_bufferhandling_mode) or not PySpin.IsWritable(node_bufferhandling_mode): + print('Unable to set stream buffer handling mode.. Aborting...') + return False + + # Retrieve entry node from enumeration node + node_newestonly = node_bufferhandling_mode.GetEntryByName('NewestOnly') + if not PySpin.IsAvailable(node_newestonly) or not PySpin.IsReadable(node_newestonly): + print('Unable to set stream buffer handling mode.. Aborting...') + return False + + # Retrieve integer value from entry node + node_newestonly_mode = node_newestonly.GetValue() + + # Set integer value from entry node as new value of enumeration node + node_bufferhandling_mode.SetIntValue(node_newestonly_mode) + + print('*** IMAGE ACQUISITION ***\n') + try: + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # What happens when the camera begins acquiring images depends on the + # acquisition mode. Single frame captures only a single image, multi + # frame catures a set number of images, and continuous captures a + # continuous stream of images. + # + # *** LATER *** + # Image acquisition must be ended when no more images are needed. + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve device serial number for filename + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Close program + print('Press enter to close the program..') + + # Figure(1) is default so you can omit this line. Figure(0) will create a new window every time program hits this line + fig = plt.figure(1) + + # Close the GUI when close event happens + fig.canvas.mpl_connect('close_event', self.handle_close) + + # Retrieve and display images + while(continue_recording): + try: + + # Retrieve next received image + # + # *** NOTES *** + # Capturing an image houses images on the camera buffer. Trying + # to capture an image that does not exist will hang the camera. + # + # *** LATER *** + # Once an image from the buffer is saved and/or no longer + # needed, the image must be released in order to keep the + # buffer from filling up. + + image_result = cam.GetNextImage(1000) + + # Ensure image completion + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + + else: + + # Getting the image data as a numpy array + image_data = image_result.GetNDArray() + + # Draws an image on the current figure + plt.imshow(image_data, cmap='gray') + + # Interval in plt.pause(interval) determines how fast the images are displayed in a GUI + # Interval is in seconds. + plt.pause(0.001) + + # Clear current reference of a figure. This will improve display speed significantly + plt.clf() + + # If user presses enter, close the program + if keyboard.is_pressed('ENTER'): + print('Program is closing...') + + # Close figure + plt.close('all') + input('Done! Press Enter to exit...') + continue_recording=False + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return True + + + + + + + + + +############################################################ + + + + + + # async def reset(self): + # """Hardware reset of FLIR.""" + # await self._ser_send("R", get_response=False) + # await asyncio.sleep(1) + # await self.setup() + + # async def setup(self): + # """Initial setup of FLIR.""" + + # await self._ser_send("E d", get_response=False) + + # async def get_status(self): + # if self.simulation: + # return ["00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "80 BC0000 0000 0102 21"] + # else: + # self.port.ser.reset_input_buffer() + # result = [] + # await self.port.write(("QUE" + "\r\n").encode()) + # for i in range(5): + # m = (await self._ser_readline()).rstrip().decode() + # result.append(m) + # logger.debug("got device status: %s", result) + # return result + + \ No newline at end of file diff --git a/FLIR/FLIRcodev3.2/dist/flir-0.0.0-py3.5.egg b/FLIR/FLIRcodev3.2/dist/flir-0.0.0-py3.5.egg new file mode 100644 index 0000000..82bb8da Binary files /dev/null and b/FLIR/FLIRcodev3.2/dist/flir-0.0.0-py3.5.egg differ diff --git a/FLIR/FLIRcodev3.2/dist/flir-0.0.0-py3.7.egg b/FLIR/FLIRcodev3.2/dist/flir-0.0.0-py3.7.egg new file mode 100644 index 0000000..01cece7 Binary files /dev/null and b/FLIR/FLIRcodev3.2/dist/flir-0.0.0-py3.7.egg differ diff --git a/FLIR/FLIRcodev3.2/dist/flir-0.0.0-py3.8.egg b/FLIR/FLIRcodev3.2/dist/flir-0.0.0-py3.8.egg new file mode 100644 index 0000000..6470df7 Binary files /dev/null and b/FLIR/FLIRcodev3.2/dist/flir-0.0.0-py3.8.egg differ diff --git a/FLIR/FLIRcodev3.2/doc/Makefile b/FLIR/FLIRcodev3.2/doc/Makefile new file mode 100644 index 0000000..298ea9e --- /dev/null +++ b/FLIR/FLIRcodev3.2/doc/Makefile @@ -0,0 +1,19 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/FLIR/FLIRcodev3.2/doc/conf.py b/FLIR/FLIRcodev3.2/doc/conf.py new file mode 100644 index 0000000..6cdd72e --- /dev/null +++ b/FLIR/FLIRcodev3.2/doc/conf.py @@ -0,0 +1,176 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config + + +import os +import sys +from unittest.mock import Mock + +sys.path.insert(0, os.path.abspath('..')) + +mock_modules = ["asyncserial"] + +for module in mock_modules: + sys.modules[module] = Mock() + +# -- Project information ----------------------------------------------------- + +project = 'FLIR' +copyright = '2019, M-Labs' +author = 'M-Labs' + +# The short X.Y version +version = '1.0' +# The full version, including alpha/beta/rc tags +release = '1.0' + + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinxarg.ext' +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = None + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'FLIRdoc' + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'FLIR.tex', 'FLIR Documentation', + 'M-Labs', 'manual'), +] + + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'flir', 'FLIR Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'FLIR', 'FLIR Documentation', + author, 'FLIR', 'One line description of project.', + 'Miscellaneous'), +] + + +# -- Options for Epub output ------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +# +# epub_identifier = '' + +# A unique identification for the text. +# +# epub_uid = '' + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] diff --git a/FLIR/FLIRcodev3.2/doc/index.rst b/FLIR/FLIRcodev3.2/doc/index.rst new file mode 100644 index 0000000..a92b827 --- /dev/null +++ b/FLIR/FLIRcodev3.2/doc/index.rst @@ -0,0 +1,24 @@ +Welcome to Novatech409B's documentation! +======================================== + +API +--- + +.. automodule:: flir.driver + :members: + + +ARTIQ controller +---------------- + +.. argparse:: + :ref: flir.aqctl_flir.get_argparser + :prog: aqctl_flir + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/FLIR/FLIRcodev3.2/flir.egg-info/PKG-INFO b/FLIR/FLIRcodev3.2/flir.egg-info/PKG-INFO new file mode 100644 index 0000000..bfed401 --- /dev/null +++ b/FLIR/FLIRcodev3.2/flir.egg-info/PKG-INFO @@ -0,0 +1,10 @@ +Metadata-Version: 1.0 +Name: flir +Version: 0.0.0 +Summary: UNKNOWN +Home-page: UNKNOWN +Author: UNKNOWN +Author-email: UNKNOWN +License: UNKNOWN +Description: UNKNOWN +Platform: UNKNOWN diff --git a/FLIR/FLIRcodev3.2/flir.egg-info/SOURCES.txt b/FLIR/FLIRcodev3.2/flir.egg-info/SOURCES.txt new file mode 100644 index 0000000..7f7dce7 --- /dev/null +++ b/FLIR/FLIRcodev3.2/flir.egg-info/SOURCES.txt @@ -0,0 +1,10 @@ +setup.py +flir/__init__.py +flir/aqctl_flir.py +flir/driver(backup).py +flir/driver.py +flir.egg-info/PKG-INFO +flir.egg-info/SOURCES.txt +flir.egg-info/dependency_links.txt +flir.egg-info/entry_points.txt +flir.egg-info/top_level.txt \ No newline at end of file diff --git a/FLIR/FLIRcodev3.2/flir.egg-info/dependency_links.txt b/FLIR/FLIRcodev3.2/flir.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/FLIR/FLIRcodev3.2/flir.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/FLIR/FLIRcodev3.2/flir.egg-info/entry_points.txt b/FLIR/FLIRcodev3.2/flir.egg-info/entry_points.txt new file mode 100644 index 0000000..62c21bb --- /dev/null +++ b/FLIR/FLIRcodev3.2/flir.egg-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +aqctl_flir = flir.aqctl_flir:main + diff --git a/FLIR/FLIRcodev3.2/flir.egg-info/top_level.txt b/FLIR/FLIRcodev3.2/flir.egg-info/top_level.txt new file mode 100644 index 0000000..c523cfe --- /dev/null +++ b/FLIR/FLIRcodev3.2/flir.egg-info/top_level.txt @@ -0,0 +1 @@ +flir diff --git a/FLIR/FLIRcodev3.2/flir/__init__.py b/FLIR/FLIRcodev3.2/flir/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/FLIR/FLIRcodev3.2/flir/__pycache__/driver.cpython-38.pyc b/FLIR/FLIRcodev3.2/flir/__pycache__/driver.cpython-38.pyc new file mode 100644 index 0000000..b1ebf2b Binary files /dev/null and b/FLIR/FLIRcodev3.2/flir/__pycache__/driver.cpython-38.pyc differ diff --git a/FLIR/FLIRcodev3.2/flir/aqctl_flir.py b/FLIR/FLIRcodev3.2/flir/aqctl_flir.py new file mode 100644 index 0000000..fb086a9 --- /dev/null +++ b/FLIR/FLIRcodev3.2/flir/aqctl_flir.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 + +# Written by Joe Britton, 2015 + +import argparse +import logging +import sys +import os +import asyncio + +from flir.driver import FLIR +from flir.driver import TriggerType +from sipyco.pc_rpc import simple_server_loop +from sipyco import common_args + + +logger = logging.getLogger(__name__) + + +def get_argparser(): + parser = argparse.ArgumentParser( + description="ARTIQ controller for the FLIR camera") + common_args.simple_network_args(parser, 3200) + parser.add_argument( + "-d", "--device", default=None, + help="serial port.") + parser.add_argument( + "--softtrig", default=False, action="store_true", + help="Sets trigger to software. Default is hardware") + parser.add_argument( + "--num", default=1, + help="Sets number of images. Default is hardware") + parser.add_argument( + "--simulation", action="store_true", + help="Put the driver in simulation mode, even if --device is used.") + common_args.verbosity_args(parser) + return parser + + +def main(): + args = get_argparser().parse_args() + common_args.init_logger_from_args(args) + if os.name == "nt": + asyncio.set_event_loop(asyncio.ProactorEventLoop()) + # if args.device is None: + # print("Starting in Simulation mode...") + # dev = FLIR(args.device if not args.simulation else None) + + print("Software trigger is:",args.softtrig) + triggerset=TriggerType(args.softtrig) + dev = FLIR(args.num) + asyncio.get_event_loop().run_until_complete(dev.setup()) + try: + print("Startup on port",args.port,"successful...") + simple_server_loop( + {"flir": dev}, common_args.bind_address_from_args(args), args.port) + finally: + dev.close() +if __name__ == "__main__": + main() diff --git a/FLIR/FLIRcodev3.2/flir/driver(backup).py b/FLIR/FLIRcodev3.2/flir/driver(backup).py new file mode 100644 index 0000000..f6295b4 --- /dev/null +++ b/FLIR/FLIRcodev3.2/flir/driver(backup).py @@ -0,0 +1,535 @@ +# Written by Joe Britton, 2015 + +import math +import logging +import asyncio +import asyncserial + +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +class TriggerType: + SOFTWARE = 1 + HARDWARE = 2 + +CHOSEN_TRIGGER = TriggerType.SOFTWARE + + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + pass + + +class FLIR: + """Driver for FLIR camera """ + + error_codes = { + "?0": "Unrecognized Command", + "?1": "Bad Frequency", + "?2": "Bad AM Command", + "?3": "Input line too long", + "?4": "Bad Phase", + "?5": "Bad Time", + "?6": "Bad Mode", + "?7": "Bad Amp", + "?8": "Bad Constant", + "?f": "Bad Byte" + } + + def __init__(self, serial_dev): + if serial_dev is None: + self.simulation = True + else: + self.simulation = False + self.port = asyncserial.AsyncSerial( + serial_dev, + baudrate=19200, + bytesize=8, + parity="N", + stopbits=1, + xonxoff=0) + + async def _ser_readline(self): + c = await self.port.read(1) + print(c) + r = c + while c != b"\n": + c = await self.port.read(1) + r += c + return r + + async def _ser_send(self, cmd, get_response=True): + """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + if self.simulation: + logger.info("simulation _ser_send(\"%s\")", cmd) + else: + logger.debug("_ser_send(\"%s\")", cmd) + self.port.ser.reset_input_buffer() + await self.port.write((cmd + "\r\n").encode()) + if get_response: + result = (await self._ser_readline()).rstrip().decode() + logger.debug("got response from device: %s", result) + if result != "OK": + errstr = self.error_codes.get(result, "Unrecognized reply") + s = "Erroneous reply from device: {ec}, {ecs}".format( + ec=result, ecs=errstr) + raise ValueError(s) + else: + pass + + async def setup(self): + """Initial setup of FLIR.""" + await self._ser_send("E d", get_response=False) + + + def close(self): + """Close the serial hardware port.""" + if not self.simulation: + self.port.close() + + async def ping(self): + try: + stat = await self.get_status() + except asyncio.CancelledError: + raise + except: + return False + # check that version number matches is "21" + if stat[4][20:] == "21": + logger.debug("ping successful") + return True + else: + return False + + + 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.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 + 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 + 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 + """ + print("393-postfunction") + try: + print("395") + result = True + err = False + print("398") + # Retrieve TL device nodemap and print device information + nodemap_tldevice = cam.GetTLDeviceNodeMap() + print("401") + result &= print_device_info(nodemap_tldevice) + print("403") + # Initialize camera + cam.Init() + print("406") + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + print("409") + # Configure trigger + if configure_trigger(cam) is False: + return False + print("413") + # Acquire images + result &= grab_next_image_by_trigger(cam) #acquire_images(cam) THIS IS WHAT I CHANGED TO TRY TO GRAB ONLY ONE IMAGE AT A TIME! + print("416") + # Reset trigger + result &= reset_trigger(cam) + print("419") + # Deinitialize camera + cam.DeInit() + print("422") + except PySpin.SpinnakerException as ex: + print("424-exception") + print('Error: %s' % ex) + result = False + + + return result + + + def picture(cam): + """ + Run this code to take a single triggered picture! + + :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!') + print("Closing camera instance...") #input('Done! Press Enter to exit...') + return False + print(cam) + # Run example on each camera + for i, cam in enumerate(cam_list): + + print('Running example for camera %d...' % i) + + print("472-prefunction") + 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() + + print("Closing camera instance...") #input('Done! Press Enter to exit...') + return result + + + # if __name__ == '__picture__': + # if picture(): + # sys.exit(0) + # else: + # sys.exit(1) + + + + +############################################################ + + + + + + # async def reset(self): + # """Hardware reset of FLIR.""" + # await self._ser_send("R", get_response=False) + # await asyncio.sleep(1) + # await self.setup() + + # async def setup(self): + # """Initial setup of FLIR.""" + + # await self._ser_send("E d", get_response=False) + + # async def get_status(self): + # if self.simulation: + # return ["00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "80 BC0000 0000 0102 21"] + # else: + # self.port.ser.reset_input_buffer() + # result = [] + # await self.port.write(("QUE" + "\r\n").encode()) + # for i in range(5): + # m = (await self._ser_readline()).rstrip().decode() + # result.append(m) + # logger.debug("got device status: %s", result) + # return result + + \ No newline at end of file diff --git a/FLIR/FLIRcodev3.2/flir/driver.py b/FLIR/FLIRcodev3.2/flir/driver.py new file mode 100644 index 0000000..bfc1eb1 --- /dev/null +++ b/FLIR/FLIRcodev3.2/flir/driver.py @@ -0,0 +1,684 @@ +import math +import logging +import asyncio +import asyncserial +import os +import matplotlib.pyplot as plt +import keyboard +import time +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + +global continue_recording +continue_recording = True + +global trigtype +SOFTWARE = 1 +HARDWARE = 2 +trigtype=SOFTWARE +class TriggerType(): + def __init__(self, softtrig): + global trigtype + if softtrig is True: + trigtype=SOFTWARE + else: + trigtype=HARDWARE + +CHOSEN_TRIGGER = trigtype + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + pass + + +class FLIR: + """Driver for FLIR camera """ + def __init__(self): + serial_dev = None + cam=0 + cam_list=0 + self.cameras=0 + result = True + num=NUM_IMAGES + self.num=num + system = PySpin.System.GetInstance() + version = system.GetLibraryVersion() + print('Library version: %d.%d.%d.%d' % (version.major, version.minor, version.type, version.build)) + cam_list = system.GetCameras() + self.system = system + self.cam_list = cam_list + self.cam=cam_list[0] + + num_cameras = cam_list.GetSize() + print('Number of cameras detected: %d' % num_cameras) + if num_cameras == 0: + cam_list.Clear() + system.ReleaseInstance() + print('Not enough cameras!') + print("Closing camera instance...") + return False + for i, cam in enumerate(cam_list): + print('Defining camera %d...' % i) + + self.nodemap_tldevice = cam.GetTLDeviceNodeMap() + result &= self.print_device_info(self.nodemap_tldevice) + cam.Init() + self.nodemap = cam.GetNodeMap() + + print("Going back to server now...") + + + + + + + # def picture(self): + # """ + # Run this code to take a single triggered picture! + + # :return: True if successful, False otherwise. + # :rtype: bool + # """ + # result = True + # print(self.cam) + # result &= self.run_single_camera(self.cam) + # for i, cam in enumerate(cam_list): + + # print('Running example for camera %d...' % i) + + # print("472-prefunction") + # result &= run_single_camera(cam) + # print('Camera %d example complete... \n' % i) + # return result + + def picture(self):#run_single_camera(self): + """ + 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 + cam=self.cam + # Configure trigger + if self.configure_trigger(cam) is False: + return False + + # Acquire images + result &= self.grab_next_image_by_trigger(cam) #acquire_images(cam) THIS IS WHAT I CHANGED TO TRY TO GRAB ONLY ONE IMAGE AT A TIME! + + + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + + return result + + async def _ser_readline(self): + c = await self.port.read(1) + print(c) + r = c + while c != b"\n": + c = await self.port.read(1) + r += c + return r + + async def _ser_send(self, cmd, get_response=True): + """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + if self.simulation: + logger.info("simulation _ser_send(\"%s\")", cmd) + else: + logger.debug("_ser_send(\"%s\")", cmd) + self.port.ser.reset_input_buffer() + await self.port.write((cmd + "\r\n").encode()) + if get_response: + result = (await self._ser_readline()).rstrip().decode() + logger.debug("got response from device: %s", result) + if result != "OK": + errstr = self.error_codes.get(result, "Unrecognized reply") + s = "Erroneous reply from device: {ec}, {ecs}".format( + ec=result, ecs=errstr) + raise ValueError(s) + else: + pass + + async def setup(self): + """Initial setup of FLIR.""" + await self._ser_send("E d", get_response=False) + + + def close(self): + """Close the serial hardware port.""" + # Deinitialize camera + self.cam.DeInit() + del self.cam + self.system.ReleaseInstance() + self.cam_list.Clear() + print("Closing camera instance...") #input('Done! Press Enter to exit...') + # if not self.simulation: + # self.port.close() + + async def ping(self): + try: + stat = await self.get_status() + except asyncio.CancelledError: + raise + except: + return False + # check that version number matches is "21" + if stat[4][20:] == "21": + logger.debug("ping successful") + return True + else: + return False + + + def configure_trigger(self,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 == SOFTWARE: + print('Software trigger chosen...') + elif CHOSEN_TRIGGER == 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.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 == SOFTWARE: + cam.TriggerSource.SetValue(PySpin.TriggerSource_Software) + print('Trigger source set to software...') + elif CHOSEN_TRIGGER == 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(self,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 == 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 == 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(self): + """ + 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 + """ + cam=self.cam + NUM_IMAGES=self.num + 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 &= self.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(self): + # Deinitialize camera + self.cam.DeInit() + + self.cam.Init() + + + def reset_trigger(self,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(self,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 handle_close(self,evt): + """ + This function will close the GUI when close event happens. + + :param evt: Event that occurs when the figure closes. + :type evt: Event + """ + + global continue_recording + continue_recording = False + + def display(self): + """ + This function continuously acquires images from a device and display them in a GUI. + + :param cam: Camera to acquire images from. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + global continue_recording + + cam=self.cam + nodemap=self.nodemap + nodemap_tldevice=self.nodemap_tldevice + sNodemap = cam.GetTLStreamNodeMap() + + # Change bufferhandling mode to NewestOnly + node_bufferhandling_mode = PySpin.CEnumerationPtr(sNodemap.GetNode('StreamBufferHandlingMode')) + if not PySpin.IsAvailable(node_bufferhandling_mode) or not PySpin.IsWritable(node_bufferhandling_mode): + print('Unable to set stream buffer handling mode.. Aborting...') + return False + + # Retrieve entry node from enumeration node + node_newestonly = node_bufferhandling_mode.GetEntryByName('NewestOnly') + if not PySpin.IsAvailable(node_newestonly) or not PySpin.IsReadable(node_newestonly): + print('Unable to set stream buffer handling mode.. Aborting...') + return False + + # Retrieve integer value from entry node + node_newestonly_mode = node_newestonly.GetValue() + + # Set integer value from entry node as new value of enumeration node + node_bufferhandling_mode.SetIntValue(node_newestonly_mode) + + print('*** IMAGE ACQUISITION ***\n') + try: + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # What happens when the camera begins acquiring images depends on the + # acquisition mode. Single frame captures only a single image, multi + # frame catures a set number of images, and continuous captures a + # continuous stream of images. + # + # *** LATER *** + # Image acquisition must be ended when no more images are needed. + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve device serial number for filename + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Close program + print('Press enter to close the program..') + + # Figure(1) is default so you can omit this line. Figure(0) will create a new window every time program hits this line + fig = plt.figure(1) + + # Close the GUI when close event happens + fig.canvas.mpl_connect('close_event', self.handle_close) + + # Retrieve and display images + while(continue_recording): + try: + + # Retrieve next received image + # + # *** NOTES *** + # Capturing an image houses images on the camera buffer. Trying + # to capture an image that does not exist will hang the camera. + # + # *** LATER *** + # Once an image from the buffer is saved and/or no longer + # needed, the image must be released in order to keep the + # buffer from filling up. + + image_result = cam.GetNextImage(1000) + + # Ensure image completion + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + + else: + + # Getting the image data as a numpy array + image_data = image_result.GetNDArray() + + # Draws an image on the current figure + plt.imshow(image_data, cmap='gray') + + # Interval in plt.pause(interval) determines how fast the images are displayed in a GUI + # Interval is in seconds. + plt.pause(0.001) + + # Clear current reference of a figure. This will improve display speed significantly + plt.clf() + + # If user presses enter, close the program + if keyboard.is_pressed('ENTER'): + print('Program is closing...') + + # Close figure + plt.close('all') + input('Done! Press Enter to exit...') + continue_recording=False + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return True + + + + + + + + + +############################################################ + + + + + + # async def reset(self): + # """Hardware reset of FLIR.""" + # await self._ser_send("R", get_response=False) + # await asyncio.sleep(1) + # await self.setup() + + # async def setup(self): + # """Initial setup of FLIR.""" + + # await self._ser_send("E d", get_response=False) + + # async def get_status(self): + # if self.simulation: + # return ["00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "80 BC0000 0000 0102 21"] + # else: + # self.port.ser.reset_input_buffer() + # result = [] + # await self.port.write(("QUE" + "\r\n").encode()) + # for i in range(5): + # m = (await self._ser_readline()).rstrip().decode() + # result.append(m) + # logger.debug("got device status: %s", result) + # return result + + \ No newline at end of file diff --git a/FLIR/FLIRcodev3.2/readme.txt b/FLIR/FLIRcodev3.2/readme.txt new file mode 100644 index 0000000..6f15efb --- /dev/null +++ b/FLIR/FLIRcodev3.2/readme.txt @@ -0,0 +1,24 @@ +v1.0 was a failure based on the simplistic code of the manual. Scrapped. +v2.0 was a copy-paste of novatech code with all names and unique functions REMOVED +v3.0 is v2.0 but with the addition of the flir camera functions. Methods are working without the camera. Call "sipyco_rpctool ::1 3200 call picture" to get trigger picture. +v3.1 I dont want to ruin v3.0 stability when hardware testing. v3.1 is hardware testing. Camera initialization and parent class problems. +v3.2 Attempt at initializing camera once and passing object to server. + + +Installation: +1. Install Spinnaker with python3.8 +conda install python3.8 +2. In Flircodevx.x directory, run: + +conda install sipyco +conda install asyncserial +python setup.py build +python setup.py install + +3. Change directories to flir and start server with: + +python aqctl_flir.py + +4. In another anaconda window, in the flir directory, take picture with: + +sipyco_rpctool ::1 3200 call picture \ No newline at end of file diff --git a/FLIR/FLIRcodev3.2/setup.py b/FLIR/FLIRcodev3.2/setup.py new file mode 100644 index 0000000..91e6954 --- /dev/null +++ b/FLIR/FLIRcodev3.2/setup.py @@ -0,0 +1,12 @@ +from setuptools import setup, find_packages + +setup( + name="flir", + install_requires=[],#"sipyco", "asyncserial"], #I disabled these because the installs were messed up! + packages=find_packages(), + entry_points={ + "console_scripts": [ + "aqctl_flir = flir.aqctl_flir:main", + ], + }, +) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/AcquireAndDisplay.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/AcquireAndDisplay.py new file mode 100644 index 0000000..2aee556 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/AcquireAndDisplay.py @@ -0,0 +1,313 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# This AcquireAndDisplay.py shows how to get the image data, and then display images in a GUI. +# This example relies on information provided in the ImageChannelStatistics.py example. +# +# This example demonstrates how to display images represented as numpy arrays. +# Currently, this program is limited to single camera use. +# NOTE: keyboard and matplotlib must be installed on Python interpreter prior to running this example. + +import os +import PySpin +import matplotlib.pyplot as plt +import sys +import keyboard +import time + +global continue_recording +continue_recording = True + + +def handle_close(evt): + """ + This function will close the GUI when close event happens. + + :param evt: Event that occurs when the figure closes. + :type evt: Event + """ + + global continue_recording + continue_recording = False + + +def acquire_and_display_images(cam, nodemap, nodemap_tldevice): + """ + This function continuously acquires images from a device and display them in a GUI. + + :param cam: Camera to acquire images from. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + global continue_recording + + sNodemap = cam.GetTLStreamNodeMap() + + # Change bufferhandling mode to NewestOnly + node_bufferhandling_mode = PySpin.CEnumerationPtr(sNodemap.GetNode('StreamBufferHandlingMode')) + if not PySpin.IsAvailable(node_bufferhandling_mode) or not PySpin.IsWritable(node_bufferhandling_mode): + print('Unable to set stream buffer handling mode.. Aborting...') + return False + + # Retrieve entry node from enumeration node + node_newestonly = node_bufferhandling_mode.GetEntryByName('NewestOnly') + if not PySpin.IsAvailable(node_newestonly) or not PySpin.IsReadable(node_newestonly): + print('Unable to set stream buffer handling mode.. Aborting...') + return False + + # Retrieve integer value from entry node + node_newestonly_mode = node_newestonly.GetValue() + + # Set integer value from entry node as new value of enumeration node + node_bufferhandling_mode.SetIntValue(node_newestonly_mode) + + print('*** IMAGE ACQUISITION ***\n') + try: + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # What happens when the camera begins acquiring images depends on the + # acquisition mode. Single frame captures only a single image, multi + # frame catures a set number of images, and continuous captures a + # continuous stream of images. + # + # *** LATER *** + # Image acquisition must be ended when no more images are needed. + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve device serial number for filename + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Close program + print('Press enter to close the program..') + + # Figure(1) is default so you can omit this line. Figure(0) will create a new window every time program hits this line + fig = plt.figure(1) + + # Close the GUI when close event happens + fig.canvas.mpl_connect('close_event', handle_close) + + # Retrieve and display images + while(continue_recording): + try: + + # Retrieve next received image + # + # *** NOTES *** + # Capturing an image houses images on the camera buffer. Trying + # to capture an image that does not exist will hang the camera. + # + # *** LATER *** + # Once an image from the buffer is saved and/or no longer + # needed, the image must be released in order to keep the + # buffer from filling up. + + image_result = cam.GetNextImage(1000) + + # Ensure image completion + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + + else: + + # Getting the image data as a numpy array + image_data = image_result.GetNDArray() + + # Draws an image on the current figure + plt.imshow(image_data, cmap='gray') + + # Interval in plt.pause(interval) determines how fast the images are displayed in a GUI + # Interval is in seconds. + plt.pause(0.001) + + # Clear current reference of a figure. This will improve display speed significantly + plt.clf() + + # If user presses enter, close the program + if keyboard.is_pressed('ENTER'): + print('Program is closing...') + + # Close figure + plt.close('all') + input('Done! Press Enter to exit...') + continue_recording=False + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return True + + +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 + + nodemap_tldevice = cam.GetTLDeviceNodeMap() + + # Initialize camera + cam.Init() + + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + + # Acquire images + result &= acquire_and_display_images(cam, nodemap, nodemap_tldevice) + + # Deinitialize camera + cam.DeInit() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def main(): + """ + Example entry point; notice the volume of data that the logging event handler + prints out on debug despite the fact that very little really happens in this + example. Because of this, it may be better to have the logger set to lower + level in order to provide a more concise, focused log. + + :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) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/Acquisition.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Acquisition.py new file mode 100644 index 0000000..3459923 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Acquisition.py @@ -0,0 +1,372 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# Acquisition.py shows how to acquire images. It relies on +# information provided in the Enumeration example. Also, check out the +# ExceptionHandling and NodeMapInfo examples if you haven't already. +# ExceptionHandling shows the handling of standard and Spinnaker exceptions +# while NodeMapInfo explores retrieving information from various node types. +# +# This example touches on the preparation and cleanup of a camera just before +# and just after the acquisition of images. Image retrieval and conversion, +# grabbing image data, and saving images are all covered as well. +# +# Once comfortable with Acquisition, we suggest checking out +# AcquisitionMultipleCamera, NodeMapCallback, or SaveToAvi. +# AcquisitionMultipleCamera demonstrates simultaneously acquiring images from +# a number of cameras, NodeMapCallback serves as a good introduction to +# programming with callbacks and events, and SaveToAvi exhibits video creation. + +import os +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +def acquire_images(cam, nodemap, nodemap_tldevice): + """ + 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. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** IMAGE ACQUISITION ***\n') + try: + result = True + + # Set acquisition mode to continuous + # + # *** NOTES *** + # Because the example acquires and saves 10 images, setting acquisition + # mode to continuous lets the example finish. If set to single frame + # or multiframe (at a lower number of images), the example would just + # hang. This would happen because the example has been written to + # acquire 10 images while the camera would have been programmed to + # retrieve less than that. + # + # Setting the value of an enumeration node is slightly more complicated + # than other node types. Two nodes must be retrieved: first, the + # enumeration node is retrieved from the nodemap; and second, the entry + # node is retrieved from the enumeration node. The integer value of the + # entry node is then set as the new value of the enumeration node. + # + # Notice that both the enumeration and the entry nodes are checked for + # availability and readability/writability. Enumeration nodes are + # generally readable and writable whereas their entry nodes are only + # ever readable. + # + # Retrieve enumeration node from nodemap + + # In order to access the node entries, they have to be casted to a pointer type (CEnumerationPtr here) + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # What happens when the camera begins acquiring images depends on the + # acquisition mode. Single frame captures only a single image, multi + # frame catures a set number of images, and continuous captures a + # continuous stream of images. Because the example calls for the + # retrieval of 10 images, continuous mode has been set. + # + # *** LATER *** + # Image acquisition must be ended when no more images are needed. + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve device serial number for filename + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Retrieve, convert, and save images + for i in range(NUM_IMAGES): + try: + + # Retrieve next received image + # + # *** NOTES *** + # Capturing an image houses images on the camera buffer. Trying + # to capture an image that does not exist will hang the camera. + # + # *** LATER *** + # Once an image from the buffer is saved and/or no longer + # needed, the image must be released in order to keep the + # buffer from filling up. + image_result = cam.GetNextImage(1000) + + # Ensure image completion + # + # *** NOTES *** + # Images can easily be checked for completion. This should be + # done whenever a complete image is expected or required. + # Further, check image status for a little more insight into + # why an image is incomplete. + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + + else: + + # Print image information; height and width recorded in pixels + # + # *** NOTES *** + # Images have quite a bit of available metadata including + # things such as CRC, image status, and offset values, to + # name a few. + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed Image %d, width = %d, height = %d' % (i, width, height)) + + # Convert image to mono 8 + # + # *** NOTES *** + # Images can be converted between pixel formats by using + # the appropriate enumeration value. Unlike the original + # image, the converted one does not need to be released as + # it does not affect the camera buffer. + # + # When converting images, color processing algorithm is an + # optional parameter. + image_converted = image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + # Create a unique filename + if device_serial_number: + filename = 'Acquisition-%s-%d.jpg' % (device_serial_number, i) + else: # if serial number is empty + filename = 'Acquisition-%d.jpg' % i + + # Save image + # + # *** NOTES *** + # The standard practice of the examples is to use device + # serial numbers to keep images of one device from + # overwriting those of another. + image_converted.Save(filename) + print('Image saved at %s' % filename) + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + print('') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return 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 + + # 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() + + # Acquire images + result &= acquire_images(cam, nodemap, nodemap_tldevice) + + # 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 + """ + + # 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: %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) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/AcquisitionMultipleCamera.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/AcquisitionMultipleCamera.py new file mode 100644 index 0000000..6fd7cc8 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/AcquisitionMultipleCamera.py @@ -0,0 +1,334 @@ +# ============================================================================ +# Copyright (c) 2001-2019 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. +# ============================================================================ +# +# AcquisitionMultipleCamera.py shows how to capture images from +# multiple cameras simultaneously. It relies on information provided in the +# Enumeration, Acquisition, and NodeMapInfo examples. +# +# This example reads similarly to the Acquisition example, +# except that loops are used to allow for simultaneous acquisitions. + +import os +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + +def acquire_images(cam_list): + """ + This function acquires and saves 10 images from each device. + + :param cam_list: List of cameras + :type cam_list: CameraList + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** IMAGE ACQUISITION ***\n') + try: + result = True + + # Prepare each camera to acquire images + # + # *** NOTES *** + # For pseudo-simultaneous streaming, each camera is prepared as if it + # were just one, but in a loop. Notice that cameras are selected with + # an index. We demonstrate pseduo-simultaneous streaming because true + # simultaneous streaming would require multiple process or threads, + # which is too complex for an example. + # + + for i, cam in enumerate(cam_list): + + # Set acquisition mode to continuous + node_acquisition_mode = PySpin.CEnumerationPtr(cam.GetNodeMap().GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (node retrieval; camera %d). Aborting... \n' % i) + return False + + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or not PySpin.IsReadable( + node_acquisition_mode_continuous): + print('Unable to set acquisition mode to continuous (entry \'continuous\' retrieval %d). \ + Aborting... \n' % i) + return False + + acquisition_mode_continuous = node_acquisition_mode_continuous.GetValue() + + node_acquisition_mode.SetIntValue(acquisition_mode_continuous) + + print('Camera %d acquisition mode set to continuous...' % i) + + # Begin acquiring images + cam.BeginAcquisition() + + print('Camera %d started acquiring images...' % i) + + print() + + # Retrieve, convert, and save images for each camera + # + # *** NOTES *** + # In order to work with simultaneous camera streams, nested loops are + # needed. It is important that the inner loop be the one iterating + # through the cameras; otherwise, all images will be grabbed from a + # single camera before grabbing any images from another. + for n in range(NUM_IMAGES): + for i, cam in enumerate(cam_list): + try: + # Retrieve device serial number for filename + node_device_serial_number = PySpin.CStringPtr(cam.GetTLDeviceNodeMap().GetNode('DeviceSerialNumber')) + + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Camera %d serial number set to %s...' % (i, device_serial_number)) + + # Retrieve next received image and ensure image completion + image_result = cam.GetNextImage(1000) + + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ... \n' % image_result.GetImageStatus()) + else: + # Print image information + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Camera %d grabbed image %d, width = %d, height = %d' % (i, n, 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 = 'AcquisitionMultipleCamera-%s-%d.jpg' % (device_serial_number, n) + else: + filename = 'AcquisitionMultipleCamera-%d-%d.jpg' % (i, n) + + # Save image + image_converted.Save(filename) + print('Image saved at %s' % filename) + + # Release image + image_result.Release() + print() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + # End acquisition for each camera + # + # *** NOTES *** + # Notice that what is usually a one-step process is now two steps + # because of the additional step of selecting the camera. It is worth + # repeating that camera selection needs to be done once per loop. + # + # It is possible to interact with cameras through the camera list with + # GetByIndex(); this is an alternative to retrieving cameras as + # CameraPtr objects that can be quick and easy for small tasks. + for cam in cam_list: + + # End acquisition + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def print_device_info(nodemap, cam_num): + """ + 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. + :param cam_num: Camera number. + :type nodemap: INodeMap + :type cam_num: int + :returns: True if successful, False otherwise. + :rtype: bool + """ + + print('Printing device information for camera %d... \n' % cam_num) + + 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.') + print() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + +def run_multiple_cameras(cam_list): + """ + This function acts as the body of the example; please see NodeMapInfo example + for more in-depth comments on setting up cameras. + + :param cam_list: List of cameras + :type cam_list: CameraList + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Retrieve transport layer nodemaps and print device information for + # each camera + # *** NOTES *** + # This example retrieves information from the transport layer nodemap + # twice: once to print device information and once to grab the device + # serial number. Rather than caching the nodem#ap, each nodemap is + # retrieved both times as needed. + print('*** DEVICE INFORMATION ***\n') + + for i, cam in enumerate(cam_list): + + # Retrieve TL device nodemap + nodemap_tldevice = cam.GetTLDeviceNodeMap() + + # Print device information + result &= print_device_info(nodemap_tldevice, i) + + # Initialize each camera + # + # *** NOTES *** + # You may notice that the steps in this function have more loops with + # less steps per loop; this contrasts the AcquireImages() function + # which has less loops but more steps per loop. This is done for + # demonstrative purposes as both work equally well. + # + # *** LATER *** + # Each camera needs to be deinitialized once all images have been + # acquired. + for i, cam in enumerate(cam_list): + + # Initialize camera + cam.Init() + + # Acquire images on all cameras + result &= acquire_images(cam_list) + + # Deinitialize each camera + # + # *** NOTES *** + # Again, each camera must be deinitialized separately by first + # selecting the camera and then deinitializing it. + for cam in cam_list: + + # Deinitialize camera + cam.DeInit() + + # 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 + + 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 + """ + + # 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: %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 all cameras + print('Running example for all cameras...') + + result = run_multiple_cameras(cam_list) + + print('Example complete... \n') + + # 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) \ No newline at end of file diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/BufferHandling.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/BufferHandling.py new file mode 100644 index 0000000..587038f --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/BufferHandling.py @@ -0,0 +1,493 @@ +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= + +# BufferHandling.py shows how the different buffer handling modes work. +# It relies on information provided in the Acquisition and Trigger examples. +# +# Buffer handling determines the ordering at which images are retrieved, and +# what occurs when an image is transmitted while the buffer is full. There are +# four different buffer handling modes available; NewestFirst, NewestOnly, +# OldestFirst and OldestFirstOverwrite. +# +# This example explores retrieving images in a set pattern; triggering the camera +# while not retrieving an image (letting the buffer fill up), and retrieving +# images while not triggering. We cycle through the different buffer handling +# modes to see which images are retrieved, confirming their identites via their +# Frame ID values. + +import os +import PySpin +import time +import sys + +# Total number of buffers +NUM_BUFFERS = 3 +# Number of triggers +NUM_TRIGGERS = 6 +# Total number of loops +NUM_LOOPS = 9 + +def configure_trigger(nodemap): + """ + This function configures the camera to use a trigger. First, trigger mode is + set to off in order to select the trigger source. Once the trigger source + has been selected, trigger mode is then enabled, which has the camera + capture only a single image upon the execution of the trigger. + + :param nodemap: Device nodemap to retrieve images from. + :type nodemap: INodeMap + :return: True if successful, False otherwise + :rtype: bool + """ + try: + result = True + print('\n*** CONFIGURING TRIGGER ***\n') + + # Ensure trigger mode off + # + # *** NOTES *** + # The trigger must be disabled in order to configure the + # trigger source. + trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerMode')) + if not PySpin.IsAvailable(trigger_mode) or not PySpin.IsWritable(trigger_mode): + print('Unable to disable trigger mode (node retrieval). Aborting...\n') + return False + + trigger_mode_off = PySpin.CEnumEntryPtr(trigger_mode.GetEntryByName('Off')) + if not PySpin.IsAvailable(trigger_mode_off) or not PySpin.IsReadable(trigger_mode_off): + print('Unable to disable trigger mode (enum entry retrieval). Aborting...\n') + return False + + trigger_mode.SetIntValue(trigger_mode_off.GetValue()) + print('Trigger mode disabled...') + + # Set trigger source to software + trigger_source = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerSource')) + if not PySpin.IsAvailable(trigger_source) or not PySpin.IsWritable(trigger_source): + print('Unable to set trigger mode (node retrieval). Aborting...') + return False + + trigger_source_software = PySpin.CEnumEntryPtr(trigger_source.GetEntryByName('Software')) + if not PySpin.IsAvailable(trigger_source_software) or not PySpin.IsReadable(trigger_source_software): + print('Unable to set trigger mode (enum entry retrieval). Aborting...') + return False + + trigger_source.SetIntValue(trigger_source_software.GetValue()) + print('Trigger source set to software...') + + # Turn trigger mode on + trigger_mode_on = PySpin.CEnumEntryPtr(trigger_mode.GetEntryByName('On')) + if not PySpin.IsAvailable(trigger_mode_on) or not PySpin.IsReadable(trigger_mode_on): + print('Unable to enable trigger mode (enum entry retrieval). Aborting...\n') + return False + + trigger_mode.SetIntValue(trigger_mode_on.GetValue()) + print('Trigger mode turned back on...') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + +def grab_next_image_by_trigger(nodemap): + """ + This function retrieves a single image using the trigger. In this example, + only a single image is captured and made available for acquisition - as such, + attempting to acquire two images for a single trigger execution would cause + the example to hang. This is different from other examples, whereby a + constant stream of images are being captured and made available for image + acquisition. + + :param nodemap: Device nodemap to retrieve images from. + :type nodemap: INodeMap + :return: True if successful, False otherwise + :rtype: bool + """ + try: + result = True + + # Execute software trigger + software_trigger_command = PySpin.CCommandPtr(nodemap.GetNode('TriggerSoftware')) + if not PySpin.IsAvailable(software_trigger_command) or not PySpin.IsWritable(software_trigger_command): + print('Unable to execute trigger. Aborting...\n') + return False + + software_trigger_command.Execute() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + +def reset_trigger(nodemap): + """ + This function returns the camera to a normal state by turning off trigger mode. + + :param nodemap: Device nodemap to retrieve images from. + :type nodemap: INodeMap + :return: True if successful, False otherwise + :rtype: bool + """ + try: + result = True + + # Turn trigger mode back off + # + # *** NOTES *** + # Once all images have been captured, turn trigger mode back off to + # restore the camera to a clean state. + trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerMode')) + if not PySpin.IsAvailable(trigger_mode) or not PySpin.IsWritable(trigger_mode): + print('Unable to disable trigger mode (node retrieval). Non-fatal error...\n') + return False + + trigger_mode_off = PySpin.CEnumEntryPtr(trigger_mode.GetEntryByName('Off')) + if not PySpin.IsAvailable(trigger_mode_off) or not PySpin.IsReadable(trigger_mode_off): + print('Unable to disable trigger mode (enum entry retrieval). Non-fatal error...\n') + return False + + trigger_mode.SetIntValue(trigger_mode_off.GetValue()) + print('Trigger mode disabled...\n') + + 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 from camera. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + print('\n*** DEVICE INFORMATION ***\n') + + # Retrieve and display Device Information + 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) + result = False + + return result + +def acquire_images(cam, nodemap, nodemap_tldevice): + """ + This function cycles through the four different buffer handling modes. + It saves three images for three of the buffer handling modes + (NewestFirst, OldestFirst, and OldestFirstOverwrite). For NewestOnly, + it saves one image. + + :param cam: Camera instance to grab images from. + :param nodemap: Device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + print('\n*** IMAGE ACQUISITION ***\n') + + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (node retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration mode + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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...') + + # Retrieve device serial number for filename + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Retrieve Stream Parameters device nodemap + s_node_map = cam.GetTLStreamNodeMap() + + # Retrieve Buffer Handling Mode Information + handling_mode = PySpin.CEnumerationPtr(s_node_map.GetNode('StreamBufferHandlingMode')) + if not PySpin.IsAvailable(handling_mode) or not PySpin.IsWritable(handling_mode): + print('Unable to set Buffer Handling mode (node retrieval). Aborting...\n') + return False + + handling_mode_entry = PySpin.CEnumEntryPtr(handling_mode.GetCurrentEntry()) + if not PySpin.IsAvailable(handling_mode_entry) or not PySpin.IsReadable(handling_mode_entry): + print('Unable to set Buffer Handling mode (Entry retrieval). Aborting...\n') + return False + + # Set stream buffer Count Mode to manual + stream_buffer_count_mode = PySpin.CEnumerationPtr(s_node_map.GetNode('StreamBufferCountMode')) + if not PySpin.IsAvailable(stream_buffer_count_mode) or not PySpin.IsWritable(stream_buffer_count_mode): + print('Unable to set Buffer Count Mode (node retrieval). Aborting...\n') + return False + + stream_buffer_count_mode_manual = PySpin.CEnumEntryPtr(stream_buffer_count_mode.GetEntryByName('Manual')) + if not PySpin.IsAvailable(stream_buffer_count_mode_manual) or not PySpin.IsReadable(stream_buffer_count_mode_manual): + print('Unable to set Buffer Count Mode entry (Entry retrieval). Aborting...\n') + return False + + stream_buffer_count_mode.SetIntValue(stream_buffer_count_mode_manual.GetValue()) + print('Stream Buffer Count Mode set to manual...') + + # Retrieve and modify Stream Buffer Count + buffer_count = PySpin.CIntegerPtr(s_node_map.GetNode('StreamBufferCountManual')) + if not PySpin.IsAvailable(buffer_count) or not PySpin.IsWritable(buffer_count): + print('Unable to set Buffer Count (Integer node retrieval). Aborting...\n') + return False + + # Display Buffer Info + print('\nDefault Buffer Handling Mode: %s' % handling_mode_entry.GetDisplayName()) + print('Default Buffer Count: %d' % buffer_count.GetValue()) + print('Maximum Buffer Count: %d' % buffer_count.GetMax()) + + buffer_count.SetValue(NUM_BUFFERS) + + print('Buffer count now set to: %d' % buffer_count.GetValue()) + print('\nCamera will be triggered %d times in a row before %d images will be retrieved' % (NUM_TRIGGERS,(NUM_LOOPS-NUM_TRIGGERS))) + + for x in range (0, 4): + if x == 0: + handling_mode_entry = handling_mode.GetEntryByName('NewestFirst') + handling_mode.SetIntValue(handling_mode_entry.GetValue()) + print('\n\nBuffer Handling Mode has been set to %s' % handling_mode_entry.GetDisplayName()) + elif x == 1: + handling_mode_entry = handling_mode.GetEntryByName('NewestOnly') + handling_mode.SetIntValue(handling_mode_entry.GetValue()) + print('\n\nBuffer Handling Mode has been set to %s' % handling_mode_entry.GetDisplayName()) + elif x == 2: + handling_mode_entry = handling_mode.GetEntryByName('OldestFirst') + handling_mode.SetIntValue(handling_mode_entry.GetValue()) + print('\n\nBuffer Handling Mode has been set to %s' % handling_mode_entry.GetDisplayName()) + elif x == 3: + handling_mode_entry = handling_mode.GetEntryByName('OldestFirstOverwrite') + handling_mode.SetIntValue(handling_mode_entry.GetValue()) + print('\n\nBuffer Handling Mode has been set to %s' % handling_mode_entry.GetDisplayName()) + + # Begin capturing images + cam.BeginAcquisition() + + # Sleep for one second; only necessary when using non-BFS/ORX cameras on startup + if x == 0: + time.sleep(1) + + try: + # Software Trigger the camera then save images + for loop_cnt in range (0, NUM_LOOPS): + if loop_cnt < NUM_TRIGGERS: + # Retrieve the next image from the trigger + result &= grab_next_image_by_trigger(nodemap) + print('\nCamera triggered. No image grabbed') + else: + print('\nNo trigger. Grabbing image %d' %(loop_cnt-NUM_TRIGGERS)) + result_image = cam.GetNextImage(500) + + if result_image.IsIncomplete(): + print('Image incomplete with image status %s ...\n' % result_image.GetImageStatus()) + + if loop_cnt >= NUM_TRIGGERS: + # Retrieve Frame ID + print('Frame ID: %d' % result_image.GetFrameID()) + + # Create a unique filename + if device_serial_number: + filename = '%s-%s-%d.jpg' % (handling_mode_entry.GetSymbolic(),device_serial_number, (loop_cnt-NUM_TRIGGERS)) + else: + filename = '%s-%d.jpg' % (handling_mode_entry.GetSymbolic(),(loop_cnt-NUM_TRIGGERS)) + + # Save image + result_image.Save(filename) + print('Image saved at %s' % filename) + + # Release image + result_image.Release() + + # To control the framerate, have the application pause for 250ms. + time.sleep(0.25) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + if handling_mode_entry.GetSymbolic() == 'NewestOnly': + print('Error should occur when grabbing image 1 with handling mode set to NewestOnly') + result = False + + # End acquisition + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = 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 acquire images from. + :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 chunk data + if configure_trigger(nodemap) is False: + return False + + # Acquire images and display chunk data + result &= acquire_images(cam, nodemap, nodemap_tldevice) + + # Reset trigger + result &= reset_trigger(nodemap) + + # De-initialize 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 + """ + + # 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: %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('\n\nRunning 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) + + + diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/ChunkData.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/ChunkData.py new file mode 100644 index 0000000..4214d69 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/ChunkData.py @@ -0,0 +1,674 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# ChunkData.py shows how to get chunk data on an image, either from +# the nodemap or from the image itself. 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 samples. As they are somewhat shorter and simpler, either +# provides a strong introduction to camera customization. +# +# Chunk data provides information on various traits of an image. This includes +# identifiers such as frame ID, properties such as black level, and more. This +# information can be acquired from either the nodemap or the image itself. +# +# It may be preferable to grab chunk data from each individual image, as it +# can be hard to verify whether data is coming from the correct image when +# using the nodemap. This is because chunk data retrieved from the nodemap is +# only valid for the current image; when GetNextImage() is called, chunk data +# will be updated to that of the new current image. +# + +import os +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +# Use the following class and global variable to select whether +# chunk data is displayed from the image or the nodemap. +class ChunkDataTypes: + IMAGE = 1 + NODEMAP = 2 + + +CHOSEN_CHUNK_DATA_TYPE = ChunkDataTypes.NODEMAP + + +def configure_chunk_data(nodemap): + """ + This function configures the camera to add chunk data to each image. It does + this by enabling each type of chunk data before enabling chunk data mode. + When chunk data is turned on, the data is made available in both the nodemap + and each image. + + :param nodemap: Transport layer device nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise + :rtype: bool + """ + try: + result = True + print('\n*** CONFIGURING CHUNK DATA ***\n') + + # 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. + chunk_mode_active = PySpin.CBooleanPtr(nodemap.GetNode('ChunkModeActive')) + + if PySpin.IsAvailable(chunk_mode_active) and PySpin.IsWritable(chunk_mode_active): + chunk_mode_active.SetValue(True) + + print('Chunk mode activated...') + + # Enable all types of chunk data + # + # *** NOTES *** + # Enabling chunk data requires working with nodes: "ChunkSelector" + # is an enumeration selector node and "ChunkEnable" is a boolean. It + # requires retrieving the selector node (which is of enumeration node + # type), selecting the entry of the chunk data to be enabled, retrieving + # the corresponding boolean, and setting it to be true. + # + # In this example, all chunk data is enabled, so these steps are + # performed in a loop. Once this is complete, chunk mode still needs to + # be activated. + chunk_selector = PySpin.CEnumerationPtr(nodemap.GetNode('ChunkSelector')) + + if not PySpin.IsAvailable(chunk_selector) or not PySpin.IsReadable(chunk_selector): + print('Unable to retrieve chunk selector. Aborting...\n') + return False + + # Retrieve entries + # + # *** NOTES *** + # PySpin handles mass entry retrieval in a different way than the C++ + # API. Instead of taking in a NodeList_t reference, GetEntries() takes + # no parameters and gives us a list of INodes. Since we want these INodes + # to be of type CEnumEntryPtr, we can use a list comprehension to + # transform all of our collected INodes into CEnumEntryPtrs at once. + entries = [PySpin.CEnumEntryPtr(chunk_selector_entry) for chunk_selector_entry in chunk_selector.GetEntries()] + + print('Enabling entries...') + + # Iterate through our list and select each entry node to enable + for chunk_selector_entry in entries: + # Go to next node if problem occurs + if not PySpin.IsAvailable(chunk_selector_entry) or not PySpin.IsReadable(chunk_selector_entry): + continue + + chunk_selector.SetIntValue(chunk_selector_entry.GetValue()) + + chunk_str = '\t {}:'.format(chunk_selector_entry.GetSymbolic()) + + # Retrieve corresponding boolean + chunk_enable = PySpin.CBooleanPtr(nodemap.GetNode('ChunkEnable')) + + # Enable the boolean, thus enabling the corresponding chunk data + if not PySpin.IsAvailable(chunk_enable): + print('{} not available'.format(chunk_str)) + result = False + elif chunk_enable.GetValue() is True: + print('{} enabled'.format(chunk_str)) + elif PySpin.IsWritable(chunk_enable): + chunk_enable.SetValue(True) + print('{} enabled'.format(chunk_str)) + else: + print('{} not writable'.format(chunk_str)) + result = False + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def display_chunk_data_from_nodemap(nodemap): + """ + This function displays all available chunk data by looping through the + chunk data category node on the nodemap. + + :param nodemap: Device nodemap to retrieve images from. + :type nodemap: INodeMap + :return: True if successful, False otherwise + :rtype: bool + """ + print('Printing chunk data from nodemap...') + try: + result = True + # Retrieve chunk data information nodes + # + # *** NOTES *** + # As well as being written into the payload of the image, chunk data is + # accessible on the GenICam nodemap. When chunk data is enabled, it is + # made available from both the image payload and the nodemap. + chunk_data_control = PySpin.CCategoryPtr(nodemap.GetNode('ChunkDataControl')) + if not PySpin.IsAvailable(chunk_data_control) or not PySpin.IsReadable(chunk_data_control): + print('Unable to retrieve chunk data control. Aborting...\n') + return False + + features = chunk_data_control.GetFeatures() + + # Iterate through children + for feature in features: + feature_node = PySpin.CNodePtr(feature) + feature_display_name = '\t{}:'.format(feature_node.GetDisplayName()) + + if not PySpin.IsAvailable(feature_node) or not PySpin.IsReadable(feature_node): + print('{} node not available'.format(feature_display_name)) + result &= False + continue + # Print node type value + # + # *** NOTES *** + # All nodes can be cast as value nodes and have their information + # retrieved as a string using the ToString() method. This is much + # easier than dealing with each individual node type. + else: + feature_value = PySpin.CValuePtr(feature) + print('{} {}'.format(feature_display_name, feature_value.ToString())) + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def display_chunk_data_from_image(image): + """ + This function displays a select amount of chunk data from the image. Unlike + accessing chunk data via the nodemap, there is no way to loop through all + available data. + + :param image: Image to acquire chunk data from + :type image: Image object + :return: True if successful, False otherwise. + :rtype: bool + """ + print('Printing chunk data from image...') + try: + result = True + print(type(image)) + # Retrieve chunk data from image + # + # *** NOTES *** + # When retrieving chunk data from an image, the data is stored in a + # ChunkData object and accessed with getter functions. + chunk_data = image.GetChunkData() + + # Retrieve exposure time (recorded in microseconds) + exposure_time = chunk_data.GetExposureTime() + print('\tExposure time: {}'.format(exposure_time)) + + # Retrieve frame ID + frame_id = chunk_data.GetFrameID() + print('\tFrame ID: {}'.format(frame_id)) + + # Retrieve gain; gain recorded in decibels + gain = chunk_data.GetGain() + print('\tGain: {}'.format(gain)) + + # Retrieve height; height recorded in pixels + height = chunk_data.GetHeight() + print('\tHeight: {}'.format(height)) + + # Retrieve offset X; offset X recorded in pixels + offset_x = chunk_data.GetOffsetX() + print('\tOffset X: {}'.format(offset_x)) + + # Retrieve offset Y; offset Y recorded in pixels + offset_y = chunk_data.GetOffsetY() + print('\tOffset Y: {}'.format(offset_y)) + + # Retrieve sequencer set active + sequencer_set_active = chunk_data.GetSequencerSetActive() + print('\tSequencer set active: {}'.format(sequencer_set_active)) + + # Retrieve timestamp + timestamp = chunk_data.GetTimestamp() + print('\tTimestamp: {}'.format(timestamp)) + + # Retrieve width; width recorded in pixels + width = chunk_data.GetWidth() + print('\tWidth: {}'.format(width)) + + 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 + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('\n*** 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) + result = False + + return result + + +def acquire_images(cam, nodemap, nodemap_tldevice): + """ + 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. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** IMAGE ACQUISTION ***\n') + + try: + result = True + # Set acquisition mode to continuous + # + # *** NOTES *** + # Because the example acquires and saves 10 images, setting acquisition + # mode to continuous lets the example finish. If set to single frame + # or multiframe (at a lower number of images), the example would just + # hang. This would happen because the example has been written to + # acquire 10 images while the camera would have been programmed to + # retrieve less than that. + # + # Setting the value of an enumeration node is slightly more complicated + # than other node types. Two nodes must be retrieved: first, the + # enumeration node is retrieved from the nodemap; and second, the entry + # node is retrieved from the enumeration node. The integer value of the + # entry node is then set as the new value of the enumeration node. + # + # Notice that both the enumeration and the entry nodes are checked for + # availability and readability/writability. Enumeration nodes are + # generally readable and writable whereas their entry nodes are only + # ever readable. + # + # Retrieve enumeration node from nodemap + + # In order to access the node entries, they have to be casted to a pointer type (CEnumerationPtr here) + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (node retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration mode + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # What happens when the camera begins acquiring images depends on the + # acquisition mode. Single frame captures only a single image, multi + # frame captures a set number of images, and continuous captures a + # continuous stream of images. As the example calls for the + # retrieval of 10 images, continuous mode has been set. + # + # *** LATER *** + # Image acquisition must be ended when no more images are needed. + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve device serial number for filename + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Retrieve, convert, and save images + for i in range(NUM_IMAGES): + try: + # Retrieve next received image + # + # *** NOTES *** + # Capturing an image houses images on the camera buffer. Trying + # to capture an image that does not exist will hang the camera. + # + # *** LATER *** + # Once an image from the buffer is saved and/or no longer + # needed, the image must be released in order to keep the + # buffer from filling up. + image_result = cam.GetNextImage(1000) + + # Ensure image completion + # + # *** NOTES *** + # Images can be easily checked for completion. This should be + # done whenever a complete image is expected or required. + # Further, check image status for a little more insight into + # why an image is incomplete. + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + else: + + # Print image information + # + # *** NOTES *** + # Images have quite a bit of available metadata including + # things such as CRC, image status, and offset values, to + # name a few. + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed Image %d, width = %d, height = %d' % (i, width, height)) + + # Convert image to mono 8 + # + # *** NOTES *** + # Images can be converted between pixel formats by using + # the appropriate enumeration value. Unlike the original + # image, the converted one does not need to be released as + # it does not affect the camera buffer. + # + # When converting images, color processing algorithm is an + # optional parameter. + image_converted = image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + # Create a unique filename + if device_serial_number: + filename = 'ChunkData-%s-%d.jpg' % (device_serial_number, i) + else: + filename = 'ChunkData-%d.jpg' % i + + # Save image + # + # *** NOTES *** + # The standard practice of the examples is to use device + # serial numbers to keep images of one device from + # overwriting those of another. + image_converted.Save(filename) + print('Image saved at %s' % filename) + + # Display chunk data + + if CHOSEN_CHUNK_DATA_TYPE == ChunkDataTypes.IMAGE: + result &= display_chunk_data_from_image(image_result) + elif CHOSEN_CHUNK_DATA_TYPE == ChunkDataTypes.NODEMAP: + result = display_chunk_data_from_nodemap(nodemap) + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + print('') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def disable_chunk_data(nodemap): + """ + This function disables each type of chunk data before disabling chunk data mode. + + :param nodemap: Transport layer device nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise + :rtype: bool + """ + try: + result = True + + # Retrieve the selector node + chunk_selector = PySpin.CEnumerationPtr(nodemap.GetNode('ChunkSelector')) + + if not PySpin.IsAvailable(chunk_selector) or not PySpin.IsReadable(chunk_selector): + print('Unable to retrieve chunk selector. Aborting...\n') + return False + + # Retrieve entries + # + # *** NOTES *** + # PySpin handles mass entry retrieval in a different way than the C++ + # API. Instead of taking in a NodeList_t reference, GetEntries() takes + # no parameters and gives us a list of INodes. Since we want these INodes + # to be of type CEnumEntryPtr, we can use a list comprehension to + # transform all of our collected INodes into CEnumEntryPtrs at once. + entries = [PySpin.CEnumEntryPtr(chunk_selector_entry) for chunk_selector_entry in chunk_selector.GetEntries()] + + print('Disabling entries...') + + for chunk_selector_entry in entries: + # Go to next node if problem occurs + if not PySpin.IsAvailable(chunk_selector_entry) or not PySpin.IsReadable(chunk_selector_entry): + continue + + chunk_selector.SetIntValue(chunk_selector_entry.GetValue()) + + chunk_symbolic_form = '\t {}:'.format(chunk_selector_entry.GetSymbolic()) + + # Retrieve corresponding boolean + chunk_enable = PySpin.CBooleanPtr(nodemap.GetNode('ChunkEnable')) + + # Disable the boolean, thus disabling the corresponding chunk data + if not PySpin.IsAvailable(chunk_enable): + print('{} not available'.format(chunk_symbolic_form)) + result = False + elif not chunk_enable.GetValue(): + print('{} disabled'.format(chunk_symbolic_form)) + elif PySpin.IsWritable(chunk_enable): + chunk_enable.SetValue(False) + print('{} disabled'.format(chunk_symbolic_form)) + else: + print('{} not writable'.format(chunk_symbolic_form)) + + # Deactivate Chunk Mode + chunk_mode_active = PySpin.CBooleanPtr(nodemap.GetNode('ChunkModeActive')) + + if not PySpin.IsAvailable(chunk_mode_active) or not PySpin.IsWritable(chunk_mode_active): + print('Unable to deactivate chunk mode. Aborting...\n') + return False + + chunk_mode_active.SetValue(False) + + print('Chunk mode deactivated...') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def run_single_camera(cam): + """ + This function acts as the body of the example; please see NodeMapInfo example + for more in-depth comments on setting up cameras. + + :param cam: Camera to run on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Retrieve TL device nodemap and print device information + nodemap_tldevice = cam.GetTLDeviceNodeMap() + + result &= print_device_info(nodemap_tldevice) + + # Initialize camera + cam.Init() + + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + + # Configure chunk data + if configure_chunk_data(nodemap) is False: + return False + + # Acquire images and display chunk data + result &= acquire_images(cam, nodemap, nodemap_tldevice) + + # Disable chunk data + if disable_chunk_data(nodemap) is False: + return False + + # De-initialize 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 + """ + + # 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: %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) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/CounterAndTimer.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/CounterAndTimer.py new file mode 100644 index 0000000..537d5d4 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/CounterAndTimer.py @@ -0,0 +1,669 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# CounterAndTimer.py shows how to setup a Pulse Width Modulation (PWM) +# signal using counters and timers. The camera will output the PWM signal via +# strobe, and capture images at a rate defined by the PWM signal as well. +# Users should take care to use a PWM signal within the camera's max +# frame rate (by default, the PWM signal is set to 50 Hz). +# +# Counter and Timer functionality is only available for BFS and Oryx Cameras. +# For details on the hardware setup, see our kb article, "Using Counter and +# Timer Control"; https://www.flir.com/support-center/iis/machine-vision/application-note/using-counter-and-timer-control + +import os +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +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: Device nodemap. + :type nodemap: INodeMap + :return: 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) + 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 available.') + + print('') + + except PySpin.SpinnakerException as ex: + print('Error: {}'.format(ex)) + return False + + return result + + +def setup_counter_and_timer(nodemap): + """ + This function configures the camera to setup a Pulse Width Modulation signal using + Counter and Timer functionality. By default, the PWM signal will be set to run at + 50hz, with a duty cycle of 70%. + + :param nodemap: Device nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('Configuring Pulse Width Modulation signal') + + try: + result = True + + # Set Counter Selector to Counter 0 + node_counter_selector = PySpin.CEnumerationPtr(nodemap.GetNode('CounterSelector')) + + # Check to see if camera supports Counter and Timer functionality + if not PySpin.IsAvailable(node_counter_selector): + print('\nCamera does not support Counter and Timer Functionality. Aborting...\n') + return False + + if not PySpin.IsWritable(node_counter_selector): + print('\nUnable to set Counter Selector (enumeration retrieval). Aborting...\n') + return False + + entry_counter_0 = node_counter_selector.GetEntryByName('Counter0') + if not PySpin.IsAvailable(entry_counter_0) or not PySpin.IsReadable(entry_counter_0): + print('\nUnable to set Counter Selector (entry retrieval). Aborting...\n') + return False + + counter_0 = entry_counter_0.GetValue() + + node_counter_selector.SetIntValue(counter_0) + + # Set Counter Event Source to MHzTick + node_counter_event_source = PySpin.CEnumerationPtr(nodemap.GetNode('CounterEventSource')) + if not PySpin.IsAvailable(node_counter_event_source) or not PySpin.IsWritable(node_counter_event_source): + print('\nUnable to set Counter Event Source (enumeration retrieval). Aborting...\n') + return False + + entry_counter_event_source_mhz_tick = node_counter_event_source.GetEntryByName('MHzTick') + if not PySpin.IsAvailable(entry_counter_event_source_mhz_tick) \ + or not PySpin.IsReadable(entry_counter_event_source_mhz_tick): + print('\nUnable to set Counter Event Source (entry retrieval). Aborting...\n') + return False + + counter_event_source_mhz_tick = entry_counter_event_source_mhz_tick.GetValue() + + node_counter_event_source.SetIntValue(counter_event_source_mhz_tick) + + # Set Counter Duration to 14000 + node_counter_duration = PySpin.CIntegerPtr(nodemap.GetNode('CounterDuration')) + if not PySpin.IsAvailable(node_counter_duration) or not PySpin.IsWritable(node_counter_duration): + print('\nUnable to set Counter Duration (integer retrieval). Aborting...\n') + return False + + node_counter_duration.SetValue(14000) + + # Set Counter Delay to 6000 + node_counter_delay = PySpin.CIntegerPtr(nodemap.GetNode('CounterDelay')) + if not PySpin.IsAvailable(node_counter_delay) or not PySpin.IsWritable(node_counter_delay): + print('\nUnable to set Counter Delay (integer retrieval). Aborting...\n') + return False + + node_counter_delay.SetValue(6000) + + # Determine Duty Cycle of PWM signal + duty_cycle = float(node_counter_duration.GetValue()) / (float(node_counter_duration.GetValue() + + node_counter_delay.GetValue())) * 100 + + print('\nThe duty cycle has been set to {}%'.format(duty_cycle)) + + # Determine pulse rate of PWM signal + pulse_rate = 1000000 / float(node_counter_duration.GetValue() + node_counter_delay.GetValue()) + + print('\nThe pulse rate has been set to {} Hz'.format(pulse_rate)) + + # Set Counter Trigger Source to Frame Trigger Wait + node_counter_trigger_source = PySpin.CEnumerationPtr(nodemap.GetNode('CounterTriggerSource')) + if not PySpin.IsAvailable(node_counter_trigger_source) or not PySpin.IsWritable(node_counter_trigger_source): + print('\nUnable to set Counter Trigger Source (enumeration retrieval). Aborting...\n') + return False + + entry_counter_trigger_source_ftw = node_counter_trigger_source.GetEntryByName('FrameTriggerWait') + if not PySpin.IsAvailable(entry_counter_trigger_source_ftw)\ + or not PySpin.IsReadable(entry_counter_trigger_source_ftw): + print('\nUnable to set Counter Trigger Source (entry retrieval). Aborting...\n') + return False + + counter_trigger_source_ftw = entry_counter_trigger_source_ftw.GetValue() + + node_counter_trigger_source.SetIntValue(counter_trigger_source_ftw) + + # Set Counter Trigger Activation to Level High + node_counter_trigger_activation = PySpin.CEnumerationPtr(nodemap.GetNode('CounterTriggerActivation')) + if not PySpin.IsAvailable(node_counter_trigger_activation) or \ + not PySpin.IsWritable(node_counter_trigger_activation): + print('\nUnable to set Counter Trigger Activation (enumeration retrieval). Aborting...\n') + return False + + entry_counter_trigger_source_lh = node_counter_trigger_activation.GetEntryByName('LevelHigh') + if not PySpin.IsAvailable(entry_counter_trigger_source_lh) \ + or not PySpin.IsReadable(entry_counter_trigger_source_lh): + print('\nUnable to set Counter Trigger Activation (entry retrieval). Aborting...\n') + return False + + counter_trigger_level_high = entry_counter_trigger_source_lh.GetValue() + + node_counter_trigger_activation.SetIntValue(counter_trigger_level_high) + + except PySpin.SpinnakerException as ex: + print('Error: {}'.format(ex)) + return False + + return result + + +def configure_digital_io(nodemap): + """ + This function configures the GPIO to output the PWM signal. + + :param nodemap: Device nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('\nConfiguring GPIO strobe output') + + try: + result = True + camera_family_bfs = "BFS" + camera_family_oryx = "ORX" + + # Determine camera family + node_device_name = PySpin.CStringPtr(nodemap.GetNode('DeviceModelName')) + if not PySpin.IsAvailable(node_device_name) or not PySpin.IsReadable(node_device_name): + print('\nUnable to determine camera family. Aborting...\n') + return False + + camera_model = node_device_name.GetValue() + + # Set Line Selector + node_line_selector = PySpin.CEnumerationPtr(nodemap.GetNode('LineSelector')) + if not PySpin.IsAvailable(node_line_selector) or not PySpin.IsWritable(node_line_selector): + print('\nUnable to set Line Selector (enumeration retrieval). Aborting...\n') + return False + + if camera_family_bfs in camera_model: + + entry_line_selector_line_1 = node_line_selector.GetEntryByName('Line1') + if not PySpin.IsAvailable(entry_line_selector_line_1) or not PySpin.IsReadable(entry_line_selector_line_1): + print('\nUnable to set Line Selector (entry retrieval). Aborting...\n') + return False + + line_selector_line_1 = entry_line_selector_line_1.GetValue() + + node_line_selector.SetIntValue(line_selector_line_1) + + elif camera_family_oryx in camera_model: + + entry_line_selector_line_2 = node_line_selector.GetEntryByName('Line2') + if not PySpin.IsAvailable(entry_line_selector_line_2) or not PySpin.IsReadable(entry_line_selector_line_2): + print('\nUnable to set Line Selector (entry retrieval). Aborting...\n') + return False + + line_selector_line_2 = entry_line_selector_line_2.GetValue() + + node_line_selector.SetIntValue(line_selector_line_2) + + # Set Line Mode to output + node_line_mode = PySpin.CEnumerationPtr(nodemap.GetNode('LineMode')) + if not PySpin.IsAvailable(node_line_mode) or not PySpin.IsWritable(node_line_mode): + print('\nUnable to set Line Mode (enumeration retrieval). Aborting...\n') + return False + + entry_line_mode_output = node_line_mode.GetEntryByName('Output') + if not PySpin.IsAvailable(entry_line_mode_output) or not PySpin.IsReadable(entry_line_mode_output): + print('\nUnable to set Line Mode (entry retrieval). Aborting...\n') + return False + + line_mode_output = entry_line_mode_output.GetValue() + + node_line_mode.SetIntValue(line_mode_output) + + # Set Line Source for Selected Line to Counter 0 Active + node_line_source = PySpin.CEnumerationPtr(nodemap.GetNode('LineSource')) + if not PySpin.IsAvailable(node_line_source) or not PySpin.IsWritable(node_line_source): + print('\nUnable to set Line Source (enumeration retrieval). Aborting...\n') + return False + + entry_line_source_counter_0_active = node_line_source.GetEntryByName('Counter0Active') + if not PySpin.IsAvailable(entry_line_source_counter_0_active) \ + or not PySpin.IsReadable(entry_line_source_counter_0_active): + print('\nUnable to set Line Source (entry retrieval). Aborting...\n') + return False + + line_source_counter_0_active = entry_line_source_counter_0_active.GetValue() + + node_line_source.SetIntValue(line_source_counter_0_active) + + if camera_family_bfs in camera_model: + # Change Line Selector to Line 2 and Enable 3.3 Voltage Rail + entry_line_selector_line_2 = node_line_selector.GetEntryByName('Line2') + if not PySpin.IsAvailable(entry_line_selector_line_2) or not PySpin.IsReadable(entry_line_selector_line_2): + print('\nUnable to set Line Selector (entry retrieval). Aborting...\n') + return False + + line_selector_line_2 = entry_line_selector_line_2.GetValue() + + node_line_selector.SetIntValue(line_selector_line_2) + + node_voltage_enable = PySpin.CBooleanPtr(nodemap.GetNode('V3_3Enable')) + if not PySpin.IsAvailable(node_voltage_enable) or not PySpin.IsWritable(node_voltage_enable): + print('\nUnable to set Voltage Enable (boolean retrieval). Aborting...\n') + return False + + node_voltage_enable.SetValue(True) + + except PySpin.SpinnakerException as ex: + print('Error: {}'.format(ex)) + return False + + return result + + +def configure_exposure_and_trigger(nodemap): + """ + This function configures the camera to set a manual exposure value and enables + camera to be triggered by the PWM signal. + + :param nodemap: Device nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('\nConfiguring Exposure and Trigger') + + try: + result = True + + # Turn off auto exposure + node_exposure_auto = PySpin.CEnumerationPtr(nodemap.GetNode('ExposureAuto')) + if not PySpin.IsAvailable(node_exposure_auto) or not PySpin.IsWritable(node_exposure_auto): + print('\nUnable to set Exposure Auto (enumeration retrieval). Aborting...\n') + return False + + entry_exposure_auto_off = node_exposure_auto.GetEntryByName('Off') + if not PySpin.IsAvailable(entry_exposure_auto_off) or not PySpin.IsReadable(entry_exposure_auto_off): + print('\nUnable to set Exposure Auto (entry retrieval). Aborting...\n') + return False + + exposure_auto_off = entry_exposure_auto_off.GetValue() + + node_exposure_auto.SetIntValue(exposure_auto_off) + + # Set Exposure Time to less than 1/50th of a second (5000 us is used as an example) + node_exposure_time = PySpin.CFloatPtr(nodemap.GetNode('ExposureTime')) + if not PySpin.IsAvailable(node_exposure_time) or not PySpin.IsWritable(node_exposure_time): + print('\nUnable to set Exposure Time (float retrieval). Aborting...\n') + return False + + node_exposure_time.SetValue(5000) + + # Ensure trigger mode is off + # + # *** NOTES *** + # The trigger must be disabled in order to configure + node_trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerMode')) + if not PySpin.IsAvailable(node_trigger_mode) or not PySpin.IsWritable(node_trigger_mode): + print('\nUnable to disable trigger mode (node retrieval). Aborting...\n') + return False + + entry_trigger_mode_off = node_trigger_mode.GetEntryByName('Off') + if not PySpin.IsAvailable(entry_trigger_mode_off) or not PySpin.IsReadable(entry_trigger_mode_off): + print('\nUnable to disable trigger mode (enum entry retrieval). Aborting...\n') + return False + + node_trigger_mode.SetIntValue(entry_trigger_mode_off.GetValue()) + + # Set Trigger Source to Counter 0 Start + node_trigger_source = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerSource')) + if not PySpin.IsAvailable(node_trigger_source) or not PySpin.IsWritable(node_trigger_source): + print('\nUnable to set trigger source (enumeration retrieval). Aborting...\n') + return False + + entry_trigger_source_counter_0_start = node_trigger_source.GetEntryByName('Counter0Start') + if not PySpin.IsAvailable(entry_trigger_source_counter_0_start)\ + or not PySpin.IsReadable(entry_trigger_source_counter_0_start): + print('\nUnable to set trigger mode (enum entry retrieval). Aborting...\n') + return False + + node_trigger_source.SetIntValue(entry_trigger_source_counter_0_start.GetValue()) + + # Set Trigger Overlap to Readout + node_trigger_overlap = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerOverlap')) + if not PySpin.IsAvailable(node_trigger_overlap) or not PySpin.IsWritable(node_trigger_overlap): + print('\nUnable to set Trigger Overlap (enumeration retrieval). Aborting...\n') + return False + + entry_trigger_overlap_ro = node_trigger_overlap.GetEntryByName('ReadOut') + if not PySpin.IsAvailable(entry_trigger_overlap_ro) or not PySpin.IsReadable(entry_trigger_overlap_ro): + print('\nUnable to set Trigger Overlap (entry retrieval). Aborting...\n') + return False + + trigger_overlap_ro = entry_trigger_overlap_ro.GetValue() + + node_trigger_overlap.SetIntValue(trigger_overlap_ro) + + # Turn trigger mode on + entry_trigger_mode_on = node_trigger_mode.GetEntryByName('On') + if not PySpin.IsAvailable(entry_trigger_mode_on) or not PySpin.IsReadable(entry_trigger_mode_on): + print('\nUnable to enable trigger mode (enum entry retrieval). Aborting...\n') + return False + + node_trigger_mode.SetIntValue(entry_trigger_mode_on.GetValue()) + + except PySpin.SpinnakerException as ex: + print('Error: {}'.format(ex)) + return False + + return result + + +def acquire_images(cam, nodemap, nodemap_tldevice): + """ + 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. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('\n*** IMAGE ACQUISITION ***\n') + try: + result = True + + # Set acquisition mode to continuous + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enumeration retrieval). Aborting...\n') + return False + + entry_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(entry_acquisition_mode_continuous)\ + or not PySpin.IsReadable(entry_acquisition_mode_continuous): + print('Unable to set acquisition mode to continuous (enum entry retrieval). Aborting...\n') + return False + + acquisition_mode_continuous = entry_acquisition_mode_continuous.GetValue() + + 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.IsAvailable(node_device_serial_number) and 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 + for i in range(NUM_IMAGES): + try: + + # Retrieve next received image and ensure image completion + image_result = cam.GetNextImage(1000) + + if image_result.IsIncomplete(): + print('Image incomplete with image status {} ...'.format(image_result.GetImageStatus())) + + else: + + # Print image information; height and width recorded in pixels + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed image {}, width = {}, height = {}'.format(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 = 'CounterAndTimer-{}-{}.jpg'.format(device_serial_number, i) + else: # if serial number is empty + filename = 'CounterAndTimer-{}.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 reset_trigger(nodemap): + """ + This function returns the camera to a normal state by turning off trigger mode. + + *** NOTES *** + This function turns off trigger mode, but does not change the trigger source. + + :param nodemap: Transport layer device nodemap. + :type nodemap: INodeMap + :returns: True if successful, False otherwise. + :rtype: bool + """ + + try: + result = True + + # Turn trigger mode back off + node_trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerMode')) + if not PySpin.IsAvailable(node_trigger_mode) or not PySpin.IsWritable(node_trigger_mode): + print('Unable to disable trigger mode (node retrieval). Non-fatal error...\n') + + entry_trigger_mode_off = node_trigger_mode.GetEntryByName('Off') + if not PySpin.IsAvailable(entry_trigger_mode_off) or not PySpin.IsReadable(entry_trigger_mode_off): + print('Unable to disable trigger mode (enum entry retrieval). Non-fatal error...\n') + + node_trigger_mode.SetIntValue(entry_trigger_mode_off.GetValue()) + + except PySpin.SpinnakerException as ex: + print('Error: {}'.format(ex)) + return False + + return result + + +def run_single_camera(cam): + """ + This function acts as the body of the example; please see the 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 Counter and Timer setup + result &= setup_counter_and_timer(nodemap) + if not result: + return result + + # Configure DigitalIO (GPIO output) + result &= configure_digital_io(nodemap) + if not result: + return result + + # Configure Exposure and Trigger + result &= configure_exposure_and_trigger(nodemap) + if not result: + return result + + # Acquire images + result &= acquire_images(cam, nodemap, nodemap_tldevice) + + # Reset trigger + result &= reset_trigger(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: {}.{}.{}.{}'.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: {}'.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 {}...'.format(i)) + + result &= run_single_camera(cam) + print('Camera {} example complete... \n'.format(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) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/DeviceEvents.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/DeviceEvents.py new file mode 100644 index 0000000..53ee365 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/DeviceEvents.py @@ -0,0 +1,494 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# =============================================================================*/ +# +# DeviceEvents.py shows how to create a handler to access device +# events. It relies on information provided in the Enumeration, Acquisition, +# and NodeMapInfo examples. +# +# It can also be helpful to familiarize yourself with the NodeMapCallback +# example, as nodemap callbacks follow the same general procedure as events. +# +# Device events can be thought of as camera-related events. This example +# creates a user-defined class, DeviceEventHandler, which allows the user to +# define any properties, parameters, and the event handler itself while DeviceEventHandler, +# the parent class, allows the child class to appropriately interface with +# the Spinnaker SDK. + +import os +import PySpin +import sys + + +class EventType: + """ + 'Enum' for choosing whether to register a event specifically for exposure end events + or universally for all events. + """ + GENERIC = 0 + SPECIFIC = 1 + +CHOSEN_EVENT = EventType.GENERIC # change me! +NUM_IMAGES = 10 # number of images to acquire + + +class DeviceEventHandler(PySpin.DeviceEventHandler): + """ + This class defines the properties, parameters, and the event handler itself. Take a + moment to notice what parts of the class are mandatory, and what have been + added for demonstration purposes. First, any class used to define device + events must inherit from DeviceEventHandler. Second, the method signature of + OnDeviceEvent() must also be consistent. Everything else - including the + constructor, destructor, properties, and body of OnDeviceEvent() - are + particular to the example. + """ + def __init__(self, eventname): + """ + This constructor registers an event name to be used on device events. + + :param eventname: Name of event to register. + :type eventname: str + :rtype: None + """ + super(DeviceEventHandler, self).__init__() + self.event_name = eventname + self.count = 0 + + def OnDeviceEvent(self, eventname): + """ + Callback function when a device event occurs. + Note eventname is a wrapped gcstring, not a Python string, but basic operations such as printing and comparing + with Python strings are supported. + + :param eventname: gcstring representing the name of the occurred event. + :type eventname: gcstring + :rtype: None + """ + if eventname == self.event_name: + self.count += 1 + + # Print information on specified device event + print('\tDevice event %s with ID %i number %i...' % (eventname, + self.GetDeviceEventId(), + self.count)) + else: + # Print no information on non-specified event + print('\tDevice event occurred; not %s; ignoring...' % self.event_name) + + +def configure_device_events(nodemap, cam): + """ + This function configures the example to execute device events by enabling all + types of device events, and then creating and registering a device event handler that + only concerns itself with an end of exposure event. + + :param INodeMap nodemap: Device nodemap. + :param CameraPtr cam: Pointer to camera. + :returns: tuple (result, device_event_handler) + WHERE + result is True if successful, False otherwise + device_event_handler is the event handler + :rtype: (bool, DeviceEventHandler) + """ + print('\n*** CONFIGURING DEVICE EVENTS ***\n') + + try: + result = True + + # Retrieve device event selector + # + # *** NOTES *** + # Each type of device event must be enabled individually. This is done + # by retrieving "EventSelector" (an enumeration node) and then enabling + # the device event on "EventNotification" (another enumeration node). + # + # This example only deals with exposure end events. However, instead of + # only enabling exposure end events with a simpler device event function, + # all device events are enabled while the device event handler deals with + # ensuring that only exposure end events are considered. A more standard + # use-case might be to enable only the events of interest. + node_event_selector = PySpin.CEnumerationPtr(nodemap.GetNode('EventSelector')) + if not PySpin.IsAvailable(node_event_selector) or not PySpin.IsReadable(node_event_selector): + print('Unable to retrieve event selector entries. Aborting...') + return False + + entries = node_event_selector.GetEntries() + print('Enabling event selector entries...') + + # Enable device events + # + # *** NOTES *** + # In order to enable a device event, the event selector and event + # notification nodes (both of type enumeration) must work in unison. + # The desired event must first be selected on the event selector node + # and then enabled on the event notification node. + for entry in entries: + + # Select entry on selector node + node_entry = PySpin.CEnumEntryPtr(entry) + if not PySpin.IsAvailable(node_entry) or not PySpin.IsReadable(node_entry): + + # Skip if node fails + result = False + continue + + node_event_selector.SetIntValue(node_entry.GetValue()) + + # Retrieve event notification node (an enumeration node) + node_event_notification = PySpin.CEnumerationPtr(nodemap.GetNode('EventNotification')) + if not PySpin.IsAvailable(node_event_notification) or not PySpin.IsWritable(node_event_notification): + + # Skip if node fails + result = False + continue + + # Retrieve entry node to enable device event + node_event_notification_on = PySpin.CEnumEntryPtr(node_event_notification.GetEntryByName('On')) + if not PySpin.IsAvailable(node_event_notification_on) or not PySpin.IsReadable(node_event_notification_on): + + # Skip if node fails + result = False + continue + + node_event_notification.SetIntValue(node_event_notification_on.GetValue()) + + print('\t%s: enabled...' % node_entry.GetDisplayName()) + + # Create device event handler + # + # *** NOTES *** + # The class has been designed to take in the name of an event. If all + # events are registered generically, all event types will trigger a + # device event; on the other hand, if an event handler is registered + # specifically, only that event will trigger an event. + device_event_handler = DeviceEventHandler('EventExposureEnd') + + # Register device event handler + # + # *** NOTES *** + # Device event handlers are registered to cameras. If there are multiple + # cameras, each camera must have any device event handlers registered to it + # separately. Note that multiple device event handlers may be registered to a + # single camera. + # + # *** LATER *** + # Device event handlers must be unregistered manually. This must be done prior + # to releasing the system and while the device event handlers are still in + # scope. + if CHOSEN_EVENT == EventType.GENERIC: + + # Device event handlers registered generally will be triggered by any device events. + cam.RegisterEventHandler(device_event_handler) + + print('Device event handler registered generally...') + + elif CHOSEN_EVENT == EventType.SPECIFIC: + + # Device event handlers registered to a specified event will only + # be triggered by the type of event is it registered to. + cam.RegisterEventHandler(device_event_handler, 'EventExposureEnd') + + print('Device event handler registered specifically to EventExposureEnd events...') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result, device_event_handler + + +def reset_device_events(cam, device_event_handler): + """ + This function resets the example by unregistering the device event handler. + + :param cam: Camera to unregister event handler from. + :param device_event_handler: Event handler for this example. + :type cam: CameraPtr + :type device_event_handler: DeviceEventHandler + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Unregister device event handler + # + # *** NOTES *** + # It is important to unregister all device event handlers from all cameras that + # they are registered to. + cam.UnregisterEventHandler(device_event_handler) + + print('Device event handler unregistered...\n') + + 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 + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** 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.message) + return False + + return result + + +def acquire_images(cam, nodemap, nodemap_tldevice): + """ + 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. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** IMAGE ACQUISITION ***\n') + try: + result = True + + # Set acquisition mode to continuous + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...\n') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) \ + or not PySpin.IsReadable(node_acquisition_mode_continuous): + print('Unable to set acquisition mode to continuous (entry retrieval). Aborting...\n') + return False + + acquisition_mode_continuous = node_acquisition_mode_continuous.GetValue() + + 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 + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Retrieve, convert, and save images + for i in range(NUM_IMAGES): + try: + # Retrieve next received image and ensure image completion + image_result = cam.GetNextImage(1000) + + if image_result.IsIncomplete(): + print('Image incomplete with image status %s...' % image_result.GetImageStatus()) + + else: + + # Print image information + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed Image %i, width = %i, height = %i' % (i, width, height)) + + # Convert to mono8 + image_converted = image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + if device_serial_number: + filename = 'DeviceEvents-%s-%i.jpg' % (device_serial_number, i) + else: + filename = 'DeviceEvents-%i.jpg' % i + + # Save image + image_converted.Save(filename) + print('Image saved at %s' % filename) + + # Release image + image_result.Release() + print('') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def 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 setup and 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 device event handlers + err, device_event_handler = configure_device_events(nodemap, cam) + if not err: + return err + + # Acquire images + result &= acquire_images(cam, nodemap, nodemap_tldevice) + + # Reset device event handlers + result &= reset_device_events(cam, device_event_handler) + + # Deinitialize camera + cam.DeInit() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex.message) + 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: %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) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/Enumeration.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Enumeration.py new file mode 100644 index 0000000..489b34a --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Enumeration.py @@ -0,0 +1,272 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# Enumeration.py shows how to enumerate interfaces and cameras. +# Knowing this is mandatory for doing anything with the Spinnaker SDK, and is +# therefore the best place to start learning how to use the SDK. +# +# This example introduces the preparation, use, and cleanup of the system +# object, interface and camera lists, interfaces, and cameras. It also touches +# on retrieving both nodes from nodemaps and information from nodes. +# +# Once comfortable with enumeration, we suggest checking out the Acquisition and/or +# NodeMapInfo examples. Acquisition demonstrates using a camera to acquire images, +# and NodeMapInfo demonstrates retrieving information from various node types. + +import PySpin +import sys + + +def query_interface(interface): + """ + Queries an interface for its cameras and prints out device information. + + :param interface: InterfacePtr + :return: True if successful, False otherwise. + :rtype: bool + """ + + try: + result = True + + # Retrieve TL nodemap from interface + # + # *** NOTES *** + # Each interface has a nodemap that can be retrieved in order to + # access information about the interface itself, any devices + # connected, or addressing information if applicable. + nodemap_interface = interface.GetTLNodeMap() + + # Print interface display name + # + # *** NOTES *** + # Grabbing node information requires first retrieving the node and + # then retrieving its information. There are two things to keep in + # mind. First, a node is distinguished by type, which is related + # to its value's data type. Second, nodes should be checked for + # availability and readability/writability prior to making an + # attempt to read from or write to the node. + # + # Note that for Python, the node retrieved then has to be 'cast' + # to the proper type (CStringPtr in this case) before it can be used. + node_interface_display_name = PySpin.CStringPtr(nodemap_interface.GetNode('InterfaceDisplayName')) + + if PySpin.IsAvailable(node_interface_display_name) and PySpin.IsReadable(node_interface_display_name): + interface_display_name = node_interface_display_name.GetValue() + + print(interface_display_name) + + else: + print('Interface display name not readable') + + # Update list of cameras on the interface + # + # *** NOTES *** + # Updating the cameras on each interface is especially important if + # there has been any device arrivals or removals since the last time + # that UpdateCameras() was called. + interface.UpdateCameras() + + # Retrieve list of cameras from the interface + # + # *** NOTES *** + # Camera lists can be retrieved from an interface or the system object. + # Camera lists retrieved from an interface, such as this one, only + # return cameras attached on that specific interface whereas camera + # lists retrieved from the system will return all cameras on all + # interfaces. + # + # *** LATER *** + # Camera lists must be cleared manually. This must be done prior to + # releasing the system and while the camera list is still in scope. + cam_list = interface.GetCameras() + + # Retrieve number of cameras + num_cams = cam_list.GetSize() + + # Return if no cameras detected + if num_cams == 0: + print('\tNo devices detected.\n') + return result + + # Print device vendor and model name for each camera on the interface + for i, cam in enumerate(cam_list): + + # Retrieve TL device nodemap; please see NodeMapInfo example for + # additional comments on transport layer nodemaps + nodemap_tldevice = cam.GetTLDeviceNodeMap() + + # Print device vendor name and device model name + # + # *** NOTES *** + # Grabbing node information requires first retrieving the node and + # then retrieving its information. There are two things to keep in + # mind. First, a node is distinguished by type, which is related + # to its value's data type. Second, nodes should be checked for + # availability and readability/writability prior to making an + # attempt to read from or write to the node. + node_device_vendor_name = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceVendorName')) + + if PySpin.IsAvailable(node_device_vendor_name) and PySpin.IsReadable(node_device_vendor_name): + device_vendor_name = node_device_vendor_name.ToString() + + node_device_model_name = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceModelName')) + + if PySpin.IsAvailable(node_device_model_name) and PySpin.IsReadable(node_device_model_name): + device_model_name = node_device_model_name.ToString() + + print('\tDevice %i %s %s \n' % (i, device_vendor_name, device_model_name)) + + # 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 losing scope + # + # *** NOTES *** + # Camera lists (and interface lists) must be cleared manually while in + # the same scope that the system is released. However, in cases like this + # where scope is lost, camera lists (and interface lists) will be cleared + # automatically. + cam_list.Clear() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def main(): + """ + Example entry point. + + :return: True if successful, False otherwise. + :rtype: bool + """ + result = True + + # Retrieve singleton reference to system object + # + # *** NOTES *** + # Everything originates with the system object. It is important to notice + # that it has a singleton implementation, so it is impossible to have + # multiple system objects at the same time. Users can only get a smart + # pointer (SystemPtr) to the system instance. + # + # *** LATER *** + # The system object should be cleared prior to program completion. If not + # released explicitly, it will be released automatically when all SystemPtr + # objects that point to the system go out of scope. + 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 interfaces from the system + # + # *** NOTES *** + # Interface lists are retrieved from the system object. + # + # *** LATER *** + # Interface lists must be cleared manually. This must be done prior to + # releasing the system and while the interface list is still in scope. + iface_list = system.GetInterfaces() + + # Get number of interfaces + num_interfaces = iface_list.GetSize() + + print('Number of interfaces detected: %i' % num_interfaces) + + # Retrieve list of cameras from the system + # + # *** NOTES *** + # Camera lists can be retrieved from an interface or the system object. + # Camera lists retrieved from the system, such as this one, return all + # cameras available on the system. + # + # *** LATER *** + # Camera lists must be cleared manually. This must be done prior to + # releasing the system and while the camera list is still in scope. + cam_list = system.GetCameras() + + num_cams = cam_list.GetSize() + + print('Number of cameras detected: %i' % num_cams) + + # Finish if there are no cameras + if num_cams == 0 or num_interfaces == 0: + + # Clear camera list before releasing system + cam_list.Clear() + + # Clear interface list before releasing system + iface_list.Clear() + + # Release system instance + system.ReleaseInstance() + + print('Not enough cameras!') + input('Done! Press Enter to exit...') + return False + + print('\n*** QUERYING INTERFACES ***\n') + + for iface in iface_list: + + # Query interface + result &= query_interface(iface) + + # Release reference to interface + # 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 iface + + # Clear camera list before releasing system + # + # *** NOTES *** + # Camera lists must be cleared manually prior to a system release call. + cam_list.Clear() + + # Clear interface list before releasing system + # + # *** NOTES *** + # Interface lists must be cleared manually prior to a system release call. + iface_list.Clear() + + # Release system instance + # + # *** NOTES *** + # The system should be released, but if it is not, it will do so itself. + # It is often at the release of the system (whether manual or automatic) + # that unreleased resources and still-registered events will throw an + # exception. + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + return result + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/EnumerationEvents.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/EnumerationEvents.py new file mode 100644 index 0000000..79e8187 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/EnumerationEvents.py @@ -0,0 +1,291 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# EnumerationEvents.py explores arrival and removal events on interfaces and the system. +# It relies on information provided in the Enumeration, Acquisition, and NodeMapInfo examples. +# +# It can also be helpful to familiarize yourself with the NodeMapCallback example, +# as nodemap callbacks follow the same general procedure as events, but with a few less steps. +# +# This example creates two user-defined classes: InterfaceEventHandler and SystemEventHandler. +# These child classes allow the user to define properties, parameters, and the event handler itself +# while the parent classes - DeviceArrivalEventHandler, DeviceRemovalEventHandler, and InterfaceEventHandler - +# allow the child classes to interface with Spinnaker. + +import PySpin + +class InterfaceEventHandler(PySpin.InterfaceEventHandler): + """ + This class defines the properties and methods for device arrivals and removals + on an interface. Take special note of the signatures of the OnDeviceArrival() + and OnDeviceRemoval() methods. Also, enumeration event handlers must inherit from + InterfaceEvent whether they are to be registered to the system or an interface. + """ + def __init__(self, iface, iface_num): + """ + Constructor. Note that this sets the interface instance. + + :param iface: Interface instance. + :param iface_num: Interface number. + """ + super(InterfaceEventHandler, self).__init__() + self.interface = iface + self.interface_num = iface_num + + def OnDeviceArrival(self, serial_number): + """ + This method defines the arrival event on an interface. It prints out + the device serial number of the camera arriving and the interface + number. The argument is the serial number of the camera that triggered + the arrival event. + + :param serial_number: gcstring representing the device serial number of arriving camera + :type serial_number: gcstring + :return: None + """ + print('Interface event handler:') + print('\tDevice %i has arrived on interface %i.' % (serial_number, self.interface_num)) + + def OnDeviceRemoval(self, serial_number): + """ + This method defines removal events on an interface. It prints out the + device serial number of the camera being removed and the interface + number. The argument is the serial number of the camera that triggered + the removal event. + + :param serial_number: gcstring representing the device serial number of removed camera + :type serial_number: gcstring + :return: None + """ + print('Interface event handler:') + print('\tDevice %i was removed from interface %i.' % (serial_number, self.interface_num)) + + +class SystemEventHandler(PySpin.InterfaceEventHandler): + """ + In the C++ example, the SystemEventHandler inherits from both DeviceArrivalEventHandler and + DeviceRemovalEventHandler. This doesn't work for this wrapper, as it will only inherit the abstract + method from the first base class listed, so for this example both System and Interface + event handlers inherit from InterfaceEventHandler. + All three event handler types - DeviceArrivalEventHandler, DeviceRemovalEventHandler, and InterfaceEventHandler - can be + registered to interfaces, the system, or both. + """ + def __init__(self, system): + """ + Constructor. This sets the system instance. + + :param system: Instance of the system. + :type system: SystemPtr + :rtype: None + """ + super(SystemEventHandler, self).__init__() + self.system = system + + def OnDeviceArrival(self, serial_number): + """ + This method defines the arrival event on the system. It retrieves the + number of cameras currently connected and prints it out. + + :param serial_number: gcstring representing the serial number of the arriving camera. + :type serial_number: gcstring + :return: None + """ + cam_list = self.system.GetCameras() + count = cam_list.GetSize() + print('System event handler:') + print('\tThere %s %i %s on the system.' % ('is' if count == 1 else 'are', + count, + 'device' if count == 1 else 'devices')) + + def OnDeviceRemoval(self, serial_number): + """ + This method defines the removal event on the system. It does the same + as the system arrival event - it retrieves the number of cameras + currently connected and prints it out. + + :param serial_number: gcstring representing the serial number of the removed camera. + :type serial_number: gcstring + :return: None + """ + cam_list = self.system.GetCameras() + count = cam_list.GetSize() + print('System event handler:') + print('\tThere %s %i %s on the system.' % ('is' if count == 1 else 'are', + count, + 'device' if count == 1 else 'devices')) + + +def check_gev_enabled(system): + """ + This function checks if GEV enumeration is enabled on the system. + + :param system: Current system instance. + :type system: SystemPtr + + """ + + # Retrieve the System TL NodeMap and EnumerateGEVInterfaces node + system_node_map = system.GetTLNodeMap() + node_gev_enumeration = PySpin.CBooleanPtr(system_node_map.GetNode('EnumerateGEVInterfaces')) + + # Ensure the node is valid + if not PySpin.IsAvailable(node_gev_enumeration) or not PySpin.IsReadable(node_gev_enumeration): + print('EnumerateGEVInterfaces node is unavailable or unreadable. Aborting...') + return + + # Check if node is enabled + gev_enabled = node_gev_enumeration.GetValue() + if not gev_enabled: + print('\nWARNING: GEV Enumeration is disabled.') + print('If you intend to use GigE cameras please run the EnableGEVInterfaces shortcut\n' + 'or set EnumerateGEVInterfaces to true and relaunch your application.\n') + return + print('GEV enumeration is enabled. Continuing..') + + +def main(): + """ + Example entry point; please see Enumeration example for more in-depth + comments on preparing and cleaning up the system. + + :rtype: None + """ + # 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)) + + # Check if GEV enumeration is enabled + check_gev_enabled(system) + + # Retrieve list of cameras from the system + cam_list = system.GetCameras() + + num_cams = cam_list.GetSize() + + print('Number of cameras detected: %i' % num_cams) + + # Retrieve list of interfaces from the system + # + # *** NOTES *** + # MacOS interfaces are only registered if they are active. + # For this example to have the desired outcome all devices must be connected + # at the beginning and end of this example in order to register and deregister + # an event handler on each respective interface. + iface_list = system.GetInterfaces() + + num_ifaces = iface_list.GetSize() + + print('Number of interfaces detected: %i' % num_ifaces) + + print('*** CONFIGURING ENUMERATION EVENTS *** \n') + + # Create interface event handler for the system + # + # *** NOTES *** + # The SystemEventHandler has been constructed to accept a system object in + # order to print the number of cameras on the system. + system_event_handler = SystemEventHandler(system) + + # Register interface event handler for the system + # + # *** NOTES *** + # Arrival, removal, and interface event handlers can all be registered to + # interfaces or the system. Do not think that interface event handlers can only be + # registered to an interface. An interface event handler is merely a combination + # of an arrival and a removal event handler. + # + # *** LATER *** + # Arrival, removal, and interface event handlers must all be unregistered manually. + # This must be done prior to releasing the system and while they are still + # in scope. + system.RegisterInterfaceEventHandler(system_event_handler) + + # Create and register interface event handler to each interface + # + # *** NOTES *** + # The process of event handler creation and registration on interfaces is similar + # to the process of event creation and registration on the system. The + # class for interfaces has been constructed to accept an interface and an + # interface number (this is just to separate the interfaces). + # + # *** LATER *** + # Arrival, removal, and interface event handlers must all be unregistered manually. + # This must be done prior to releasing the system and while they are still + # in scope. + interface_events = [] + + for i, iface in enumerate(iface_list): + + # Create interface event handler + iface_event_handler = InterfaceEventHandler(iface, i) + interface_events.append(iface_event_handler) + + # Register interface event handler + iface.RegisterEventHandler(interface_events[i]) + + print('Event handler registered to interface %i ...' % i) + + # Release reference to interface event handler + # 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 iface_event_handler + + # Wait for user to plug in and/or remove camera devices + input('\nReady! Remove/Plug in cameras to test or press Enter to exit...\n') + + # Unregister interface event handler from each interface + # + # *** NOTES *** + # It is important to unregister all arrival, removal, and interface event handlers + # from all interfaces that they may be registered to. + for i, iface in enumerate(iface_list): + iface.UnregisterEventHandler(interface_events[i]) + + # Release reference to interface and interface event handlers + del iface + del interface_events + print('Event handler unregistered from interfaces...') + + # Unregister system event handler from system object + # + # *** NOTES *** + # It is important to unregister all arrival, removal, and interface event handlers + # registered to the system. + system.UnregisterInterfaceEventHandler(system_event_handler) + + # Delete system event handler, which has a system reference + del system_event_handler + print('Event handler unregistered from system...') + + # Clear camera list before releasing system + cam_list.Clear() + + # Clear interface list before releasing system + iface_list.Clear() + + # Release system instance + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + +if __name__ == '__main__': + main() diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/Enumeration_QuickSpin.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Enumeration_QuickSpin.py new file mode 100644 index 0000000..f016f64 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Enumeration_QuickSpin.py @@ -0,0 +1,260 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# Enumeration_QuickSpin.py shows how to enumerate interfaces +# and cameras using the QuickSpin API. QuickSpin is a subset of the Spinnaker +# library that allows for simpler node access and control. This is a great +# example to start learning about QuickSpin. +# +# This example introduces the preparation, use, and cleanup of the system +# object, interface and camera lists, interfaces, and cameras. It also +# touches on retrieving information from pre-fetched nodes using QuickSpin. +# Retrieving node information is the only portion of the example that +# differs from Enumeration. +# +# 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 + + +def query_interface(interface): + """ + Queries an interface for its cameras and prints out device information. + + :param interface: InterfacePtr + :return: True if successful, False otherwise. + :rtype: bool + """ + + try: + result = True + + # Print interface display name + # + # *** NOTES *** + # QuickSpin allows for the retrieval of interface information directly + # from an interface. Because interface information is made available + # on the transport layer, camera initialization is not required. + node_interface_display_name = interface.TLInterface.InterfaceDisplayName + if PySpin.IsAvailable(node_interface_display_name) and PySpin.IsReadable(node_interface_display_name): + + interface_display_name = node_interface_display_name.GetValue() + + print(interface_display_name) + + else: + print('Interface display name not readable') + + # Update list of cameras on the interface + # + # *** NOTES *** + # Updating the cameras on each interface is especially important if + # there has been any device arrivals or removals since the last time + # that UpdateCameras() was called. + interface.UpdateCameras() + + # Retrieve list of cameras from the interface + # + # *** NOTES *** + # Camera lists can be retrieved from an interface or the system object. + # Camera lists retrieved from an interface, such as this one, only + # return cameras attached on that specific interface whereas camera + # lists retrieved from the system will return all cameras on all + # interfaces. + # + # *** LATER *** + # Camera lists must be cleared manually. This must be done prior to + # releasing the system and while the camera list is still in scope. + cam_list = interface.GetCameras() + + # Retrieve number of cameras + num_cams = cam_list.GetSize() + + # Return if no cameras detected + if num_cams == 0: + print('\tNo devices detected.\n') + return True + + # Print device vendor and model name for each camera on the interface + for i, cam in enumerate(cam_list): + + # Print device vendor name and device model name + # + # *** NOTES *** + # In QuickSpin, accessing nodes does not require first retrieving a + # nodemap. Instead, GenICam nodes are made available + # directly through the camera, and transport layer nodes are made + # available through the camera's TLDevice and TLStream properties. + # + # Most camera interaction happens through the GenICam nodemap, which + # requires the device to be initialized. Simpler reads, like the + # ones below, can often be accomplished at the transport layer, + # which does not require initialization; please see + # NodeMapInfo_QuickSpin for additional information on this topic. + # + # Readability/writability should be checked prior to interacting with + # nodes. Readability and writability are ensured by checking the + # access mode or by using the methods + if cam.TLDevice.DeviceVendorName.GetAccessMode() == PySpin.RO: + device_vendor_name = cam.TLDevice.DeviceVendorName.ToString() + + if cam.TLDevice.DeviceModelName.GetAccessMode() == PySpin.RO: + device_model_name = cam.TLDevice.DeviceModelName.GetValue() + + print('\tDevice %i %s %s \n' % (i, device_vendor_name, device_model_name)) + + # 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 losing scope + # + # *** NOTES *** + # Camera lists (and interface lists) must be cleared manually while in + # the same scope that the system is released. However, in cases like this + # where scope is lost, camera lists (and interface lists) will be cleared + cam_list.Clear() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def main(): + """ + Example entry point. + :return: True if successful, False otherwise. + :rtype: bool + """ + result = True + + # Retrieve singleton reference to system object + # + # *** NOTES *** + # Everything originates with the system object. It is important to notice + # that it has a singleton implementation, so it is impossible to have + # multiple system objects at the same time. Users can only get a smart + # pointer (SystemPtr) to the system instance. + # + # *** LATER *** + # The system object should be cleared prior to program completion. If not + # released explicitly, it will be released automatically when all SystemPtr + # objects that point to the system go out of scope. + 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 interfaces from the system + # + # *** NOTES *** + # Interface lists are retrieved from the system object. + # + # *** LATER *** + # Interface lists must be cleared manually. This must be done prior to + # releasing the system and while the interface list is still in scope. + iface_list = system.GetInterfaces() + + # Get number of interfaces + num_ifaces = iface_list.GetSize() + + print('Number of interfaces detected: %i' % num_ifaces) + + # Retrieve list of cameras from the system + # + # *** NOTES *** + # Camera lists can be retrieved from an interface or the system object. + # Camera lists retrieved from the system, such as this one, return all + # cameras available on the system. + # + # *** LATER *** + # Camera lists must be cleared manually. This must be done prior to + # releasing the system and while the camera list is still in scope. + cam_list = system.GetCameras() + + num_cams = cam_list.GetSize() + + print('Number of cameras detected: %i' % num_cams) + + # Finish if there are no cameras + if num_cams == 0 or num_ifaces == 0: + + # Clear camera list before releasing system + cam_list.Clear() + + # Clear interface list before releasing system + iface_list.Clear() + + # Release system instance + system.ReleaseInstance() + + print('Not enough cameras!') + input('Done! Press Enter to exit...') + return False + + print('\n*** QUERYING INTERFACES ***\n') + + for iface in iface_list: + + # Query interface + result &= query_interface(iface) + + # Release reference to interface + # 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 iface + + # Clear camera list before releasing system + # + # *** NOTES *** + # Camera lists must be cleared manually prior to a system release call. + cam_list.Clear() + + # Clear interface list before releasing system + # + # *** NOTES *** + # Interface lists must be cleared manually prior to a system release call. + iface_list.Clear() + + # Release system instance + # + # *** NOTES *** + # The system should be released, but if it is not, it will do so itself. + # It is often at the release of the system (whether manual or automatic) + # that unreleased resources and still registered events will throw an + # exception. + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + return result + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) \ No newline at end of file diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/Exposure_QuickSpin.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Exposure_QuickSpin.py new file mode 100644 index 0000000..af71c34 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Exposure_QuickSpin.py @@ -0,0 +1,369 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# Exposure_QuickSpin.py shows how to customize image exposure time +# using the QuickSpin API. QuickSpin is a subset of the Spinnaker library +# that allows for simpler node access and control. +# +# This example prepares the camera, sets a new exposure time, and restores +# the camera to its default state. Ensuring custom values fall within an +# acceptable range is also touched on. Retrieving and setting information +# is the only portion of the example that differs from Exposure. +# +# 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 = 5 # number of images to save + + +def configure_exposure(cam): + """ + This function configures a custom exposure time. Automatic exposure is turned + off in order to allow for the customization, and then the custom setting is + applied. + + :param cam: Camera to configure exposure for. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** CONFIGURING EXPOSURE ***\n') + + try: + result = True + + # Turn off automatic exposure mode + # + # *** NOTES *** + # Automatic exposure prevents the manual configuration of exposure + # times and needs to be turned off for this example. Enumerations + # representing entry nodes have been added to QuickSpin. This allows + # for the much easier setting of enumeration nodes to new values. + # + # The naming convention of QuickSpin enums is the name of the + # enumeration node followed by an underscore and the symbolic of + # the entry node. Selecting "Off" on the "ExposureAuto" node is + # thus named "ExposureAuto_Off". + # + # *** LATER *** + # Exposure time can be set automatically or manually as needed. This + # example turns automatic exposure off to set it manually and back + # on to return the camera to its default state. + + if cam.ExposureAuto.GetAccessMode() != PySpin.RW: + print('Unable to disable automatic exposure. Aborting...') + return False + + cam.ExposureAuto.SetValue(PySpin.ExposureAuto_Off) + print('Automatic exposure disabled...') + + # Set exposure time manually; exposure time recorded in microseconds + # + # *** NOTES *** + # Notice that the node is checked for availability and writability + # prior to the setting of the node. In QuickSpin, availability and + # writability are ensured by checking the access mode. + # + # Further, it is ensured that the desired exposure time does not exceed + # the maximum. Exposure time is counted in microseconds - this can be + # found out either by retrieving the unit with the GetUnit() method or + # by checking SpinView. + + if cam.ExposureTime.GetAccessMode() != PySpin.RW: + print('Unable to set exposure time. Aborting...') + return False + + # Ensure desired exposure time does not exceed the maximum + exposure_time_to_set = 2000000.0 + exposure_time_to_set = min(cam.ExposureTime.GetMax(), exposure_time_to_set) + cam.ExposureTime.SetValue(exposure_time_to_set) + print('Shutter time set to %s us...\n' % exposure_time_to_set) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def reset_exposure(cam): + """ + This function returns the camera to a normal state by re-enabling automatic exposure. + + :param cam: Camera to reset exposure on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Turn automatic exposure back on + # + # *** NOTES *** + # Automatic exposure is turned on in order to return the camera to its + # default state. + + if cam.ExposureAuto.GetAccessMode() != PySpin.RW: + print('Unable to enable automatic exposure (node retrieval). Non-fatal error...') + return False + + cam.ExposureAuto.SetValue(PySpin.ExposureAuto_Continuous) + + print('Automatic exposure enabled...') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def print_device_info(cam): + """ + 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 cam: Camera to get device information from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** DEVICE INFORMATION ***\n') + + try: + result = True + nodemap = cam.GetTLDeviceNodeMap() + + 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.message) + 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 the acquisition of images. + + :param cam: Camera to acquire images from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + print('*** IMAGE ACQUISITION ***') + + 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 is not None and cam.TLDevice.DeviceSerialNumber.GetAccessMode() == PySpin.RO: + device_serial_number = cam.TLDevice.DeviceSerialNumber.GetValue() + + print('Device serial number retrieved as %s...' % device_serial_number) + + # Get the value of exposure time to set an appropriate timeout for GetNextImage + timeout = 0 + if cam.ExposureTime.GetAccessMode() == PySpin.RW or cam.ExposureTime.GetAccessMode() == PySpin.RO: + # The exposure time is retrieved in µs so it needs to be converted to ms to keep consistency with the unit being used in GetNextImage + timeout = (int)(cam.ExposureTime.GetValue() / 1000 + 1000) + else: + print ('Unable to get exposure time. Aborting...') + return False + + # Retrieve, convert, and save images + for i in range(NUM_IMAGES): + try: + # Retrieve next received image and ensure image completion + # By default, GetNextImage will block indefinitely until an image arrives. + # In this example, the timeout value is set to [exposure time + 1000]ms to ensure that an image has enough time to arrive under normal conditions + image_result = cam.GetNextImage(timeout) + + 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 Mono8 + image_converted = image_result.Convert(PySpin.PixelFormat_Mono8) + + # Create a unique filename + filename = 'ExposureQS-%s-%d.jpg' % (device_serial_number, i) + + # Save image + image_converted.Save(filename) + + print('Image saved at %s' % filename) + + # Release image + image_result.Release() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + # End acquisition + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def run_single_camera(cam): + """ + This function acts as the body of the example; please see NodeMapInfo_QuickSpin example for more + in-depth comments on setting up cameras. + + :param cam: Camera to run example on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + # Initialize camera + cam.Init() + + # Print device info + result = print_device_info(cam) + + # Configure exposure + if not configure_exposure(cam): + return False + + # Acquire images + result &= acquire_images(cam) + + # Reset exposure + result &= reset_exposure(cam) + + # Deinitialize camera + cam.DeInit() + + return result + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + +def main(): + """ + Example entry point; please see Enumeration_QuickSpin 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) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/FileAccess_QuickSpin.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/FileAccess_QuickSpin.py new file mode 100644 index 0000000..f2dae8c --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/FileAccess_QuickSpin.py @@ -0,0 +1,692 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# FileAccess_QuickSpin.py shows shows how to read and write images using camera File Access function. +# +# This example uploads an image to the camera File Access storage and also +# downloads the image from the camera File Access storage and saves it to +# the disk. +# +# It also provides debug message when an additional argument `--verbose` is passed in, +# giving more detailed status of the progress to the users. +# +# Run with arguments in format (no quotes): "--mode --verbose (optional)" +# /d: Download saved image from camera and save it to the working directory. +# /u: Grab an image and store it on camera. +# + +import PySpin +import numpy as np +import os +import argparse +import sys + +parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter) +subparsers = parser.add_subparsers() + +class ImageAcquisitionUtil: + @staticmethod + def check_node_readable(node): + return PySpin.IsAvailable(node) and PySpin.IsReadable(node) + + @staticmethod + def grab_reference_image(cam): + """ + This function first grabs 5 images to stablize the camera, + then it grabs a reference image and returns its pointer. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: Pointer to the reference image + :rtype: ImagePtr + """ + reference_image = PySpin.Image.Create() + + # Start capturing images + cam.BeginAcquisition() + + # Grab a couple of images to stabilize the camera + for image_count in range(5): + try: + result_image = cam.GetNextImage(1000) + if result_image.IsIncomplete(): + print('Imgae incomplete with image status %s' % result_image.GetImageStatus()) + else: + print('Grabbed image %s' %str(image_count) + ', width = %s' % str(result_image.GetWidth())\ + + ', height = %s' % str(result_image.GetHeight())) + reference_image.DeepCopy(result_image) + result_image.Release() + except PySpin.SpinnakerException as ex: + print(ex) + continue + + cam.EndAcquisition() + + return reference_image + +class FileAccess: + @staticmethod + 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 ImageAcquisitionUtil.check_node_readable(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')) + print('') + else: + print('Device control information not available.') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + @staticmethod + def execute_delete_command(cam): + """ + This function executes delete operation on the camera. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + cam.FileOperationSelector.SetValue(PySpin.FileOperationSelector_Delete) + cam.FileOperationExecute.Execute() + + if cam.FileOperationStatus.GetValue() != PySpin.FileOperationStatus_Success: + print('Failed to delete file!') + return False + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return True + + @staticmethod + def open_file_to_write(cam): + """ + This function opens the camera file for writing. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + cam.FileOperationSelector.SetValue(PySpin.FileOperationSelector_Open) + cam.FileOpenMode.SetValue(PySpin.FileOpenMode_Write) + cam.FileOperationExecute.Execute() + + if cam.FileOperationStatus.GetValue() != PySpin.FileOperationStatus_Success: + print('Failed to open file for writing!') + return False + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return True + + @staticmethod + def execute_write_command(cam): + """ + This function executes write command on the camera. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + cam.FileOperationSelector.SetValue(PySpin.FileOperationSelector_Write) + cam.FileOperationExecute.Execute() + + if cam.FileOperationStatus.GetValue() != PySpin.FileOperationStatus_Success: + print('Failed to write to file!') + return False + except PySpin.SpinnakerException as ex: + print('Unexpected exception : %s' % ex) + return False + return True + + @staticmethod + def close_file(cam): + """ + This function closes the file. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + cam.FileOperationSelector.SetValue(PySpin.FileOperationSelector_Close) + cam.FileOperationExecute.Execute() + + if cam.FileOperationStatus.GetValue() != PySpin.FileOperationStatus_Success: + print('Failed to close file!') + return False + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return True + + @staticmethod + def upload_image(cam, verbose=False): + """ + This function first acquires a reference image from the camera, + then it writes the image file to the camera with file selector UserFile1. + + :param cam: Camera used to download file from. + :param verbose: Prints additional details of file download (False by default) + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + success = True + + nodemap_tldevice = cam.GetTLDeviceNodeMap() + FileAccess.print_device_info(nodemap_tldevice) + + cam.Init() + + # Check file selector support + print('Checking file selector support') + if cam.FileSelector.GetAccessMode() == PySpin.NA or cam.FileSelector.GetAccessMode() == PySpin.NI: + print('File selector not supported on device!') + return False + + # Apply small pixel format + if ImageAcquisitionUtil.check_node_readable(cam.PixelFormat.GetEntry(PySpin.PixelFormat_Mono8)): + cam.PixelFormat.SetValue(PySpin.PixelFormat_Mono8) + else: + # Use Bayer8 if Mono8 is not available + cam.PixelFormat.SetValue(PySpin.PixelFormat_BayerGB8) + + # Display camera setup information + print('Width: %s' % cam.Width.GetValue()) + print('Height: %s' % cam.Height.GetValue()) + print('offsetX: %s' % cam.OffsetX.GetValue()) + print('OffsetY: %s' % cam.OffsetY.GetValue()) + print('PixelFormat: %s' % cam.PixelFormat.GetValue()) + + # Grab reference image + try: + reference_image = ImageAcquisitionUtil.grab_reference_image(cam) + except PySpin.SpinnakerException as ex: + cam.DeInit() + del cam + print('Unexpected error grabbing reference image: %s' % ex) + return False + + # Form file path + filename = "DeviceStreamWrite-" + if cam.DeviceSerialNumber.GetAccessMode() == PySpin.RW or cam.DeviceSerialNumber.GetAccessMode() == PySpin.RO: + filename += "%s-" % cam.DeviceSerialNumber.ToString() + filename += ".bmp" + + # Save image + reference_image.Save(filename) + print('Image saved at %s' % filename) + + print('*** UPLOADING IMAGE ***') + + # Perform file stream write + selector_list = cam.FileSelector.GetEntries() + + for entry in selector_list: + # Get current enum entry node + node = PySpin.CEnumEntryPtr(entry) + + if verbose: + print('\nChecking FileSelector EnumEntry - %s' % node.GetSymbolic()) + + # Check file selector entry support + if not node or not ImageAcquisitionUtil.check_node_readable(node): + # Go to next entry node + print('%s not supported!' % node.GetSymbolic()) + continue + + if node.GetSymbolic() == "UserFile1": + # Set file selector + cam.FileSelector.SetIntValue(int(node.GetNumericValue())) + + # Delete file on camera before writing in case camera runs out of space + file_size = cam.FileSize.GetValue() + if file_size > 0: + if not FileAccess.execute_delete_command(cam): + print('Failed to delete file!') + success = False + continue + + # Open file on camera for write + if not FileAccess.open_file_to_write(cam): + print('Failed to open file!') + success = False + continue + + # Attempt to set FileAccessLength to FileAccessBufferNode length to speed up the write + if cam.FileAccessLength.GetValue() < cam.FileAccessBuffer.GetLength(): + try: + cam.FileAccessLength.SetValue(cam.FileAccessBuffer.GetLength()) + except PySpin.SpinnakerException as ex: + print('Unable to set FileAccessLength to FileAccessBuffer length: %s' % ex) + + # Set file access offset to zero if it's not + cam.FileAccessOffset.SetValue(0) + + # Compute number of write operations required + total_bytes_to_write = reference_image.GetBufferSize() + intermediate_buffer_size = cam.FileAccessLength.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.') + return False + + if verbose: + print('') + 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): + offset = index * intermediate_buffer_size + if offset == 0: + continue + sections.append(offset) + + # Get image data and split into equal chunks + image_data = reference_image.GetData() + split_data = np.array_split(image_data, sections) + + for i in range(len(split_data)): + # Setup data to write + tmp_buffer = split_data[i] + + # Write to AccessBufferNode + cam.FileAccessBuffer.Set(tmp_buffer) + + if intermediate_buffer_size > bytes_left_to_write: + # Update FileAccessLength, otherwise garbage data outside the range would be written to device + cam.FileAccessLength.SetValue(bytes_left_to_write) + + # Perform write command + if not FileAccess.execute_write_command(cam): + print('Writing stream failed!') + success = False + break + + # Verify size of bytes written + size_written = cam.FileOperationResult.GetValue() + + # Log current file access offset + if verbose: + print('File Access Offset: %s' % cam.FileAccessOffset.GetValue()) + + # Keep track of total bytes written + total_bytes_written += size_written + if verbose: + print('Bytes written: %s of %s' % (total_bytes_written, total_bytes_to_write)) + + # Keep track of bytes left to write + bytes_left_to_write = total_bytes_to_write - total_bytes_written + + if verbose: + print('Progress: (%s//%s)' % (i, write_iterations)) + else: + print('Progress: %s' % int((i*100 / write_iterations)) + "%") + + print('Writing complete') + + if not FileAccess.close_file(cam): + success = False + + cam.DeInit() + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return success + + @staticmethod + def open_file_to_read(cam): + """ + This function opens the file to read. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + cam.FileOperationSelector.SetValue(PySpin.FileOperationSelector_Open) + cam.FileOpenMode.SetValue(PySpin.FileOpenMode_Read) + cam.FileOperationExecute.Execute() + + if cam.FileOperationStatus.GetValue() != PySpin.FileOperationStatus_Success: + print('Failed to open file for reading!') + return False + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return True + + @staticmethod + def execute_read_command(cam): + """ + This function executes read command on the camera. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + cam.FileOperationSelector.SetValue(PySpin.FileOperationSelector_Read) + cam.FileOperationExecute.Execute() + + if cam.FileOperationStatus.GetValue() != PySpin.FileOperationStatus_Success: + print('Failed to read file!') + return False + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return True + + @staticmethod + def download_image(cam, verbose=False): + """ + This function reads the image file stored in the camera file selector UserFile1, + saving the file to the working directory of this example. + + :param cam: Camera used to download file from. + :param verbose: Prints additional details of file download (False by default) + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + success = True + + nodemap_tldevice = cam.GetTLDeviceNodeMap() + FileAccess.print_device_info(nodemap_tldevice) + + cam.Init() + + # Check file selector support + print('Checking file selector support') + if cam.FileSelector.GetAccessMode() == PySpin.NA or cam.FileSelector.GetAccessMode() == PySpin.NI: + print('File selector not supported on device!') + return False + + print('*** DOWNLOADING IMAGE ***') + + selector_list = cam.FileSelector.GetEntries() + + for entry in selector_list: + node = PySpin.CEnumEntryPtr(entry) + if verbose: + print('\nChecking FileSelector EnumEntry - %s' % node.GetSymbolic()) + + # Check file selector entry support + if not node or not ImageAcquisitionUtil.check_node_readable(node): + # Go to next entry node + print('%s not supported!' % node.GetSymbolic()) + continue + + # Use UserFile1 as the selector in this example. + # Available file selector entries varies across different cameras + if node.GetSymbolic() == "UserFile1": + # Set file selector + cam.FileSelector.SetIntValue(int(node.GetNumericValue())) + + # Get file size + total_bytes_to_read = cam.FileSize.GetValue() + if total_bytes_to_read == 0: + print('%s - No data available to read!' % node.GetSymbolic()) + success = False + continue + + print('Total data to download: %s' % total_bytes_to_read) + + # Open file on camera for reading + if not FileAccess.open_file_to_read(cam): + print('Failed to open file!') + success = False + continue + + # Attempt to set FileAccessLength to FileAccessBufferNode length to speed up the write + if cam.FileAccessLength.GetValue() < cam.FileAccessBuffer.GetLength(): + try: + cam.FileAccessLength.SetValue(cam.FileAccessBuffer.GetLength()) + except PySpin.SpinnakerException as ex: + print('Unable to set FileAccessLength to FileAccessBuffer length: %s' % ex) + + # Set file access offset to zero + cam.FileAccessOffset.SetValue(0) + + # Computer number of read operations required + intermediate_buffer_size = cam.FileAccessLength.GetValue() + read_iterations = (total_bytes_to_read // intermediate_buffer_size) + \ + (0 if ((total_bytes_to_read % intermediate_buffer_size) == 0) else 1) + + if verbose: + print('') + print('Total bytes to read: %s' % total_bytes_to_read) + print('FileAccessLength: %s' % intermediate_buffer_size) + print('Write iterations: %s' % read_iterations) + + print('Fetching image from camera.') + + total_size_read = 0 + size_read = cam.FileOperationResult.GetValue() + image_data = np.array(size_read, dtype=np.uint8) + + for i in range(read_iterations): + if not FileAccess.execute_read_command(cam): + print('Reading stream failed!') + success = False + break + + # Verify size of bytes read + size_read = cam.FileOperationResult.GetValue() + + # Read from buffer Node + buffer_read = cam.FileAccessBuffer.Get(size_read) + if i == 0: + image_data = buffer_read + else: + image_data = np.append(image_data, buffer_read) + + # Keep track of total bytes read + total_size_read += size_read + if verbose: + print('Bytes read: %s of %s' % (total_size_read, total_bytes_to_read)) + print('Progress: (%s//%s)' % (i, read_iterations)) + else: + print('Progress: %s' % int((i*100 / read_iterations)) + "%") + + print('Reading complete') + + if not FileAccess.close_file(cam): + success = False + + # Form file path + filename = "DeviceStreamRead-" + + if cam.DeviceSerialNumber.GetAccessMode() == PySpin.RW or cam.DeviceSerialNumber.GetAccessMode() == PySpin.RO: + filename += "%s-" % cam.DeviceSerialNumber.ToString() + + filename += ".bmp" + + # Image should be captured with Mono8 or Bayer8, it sets camera to correct pixel format + # in order to grab image ROI + if ImageAcquisitionUtil.check_node_readable(cam.PixelFormat.GetEntry(PySpin.PixelFormat_Mono8)): + cam.PixelFormat.SetValue(PySpin.PixelFormat_Mono8) + elif ImageAcquisitionUtil.check_node_readable(cam.PixelFormat.GetEntry(PySpin.PixelFormat_BayerGB8)): + # Use Bayer8 if Mono8 is not available + cam.PixelFormat.SetValue(PySpin.PixelFormat_BayerGB8) + else: + print('Failed to set camera pixel format.') + return False + + width = cam.Width.GetValue() + height = cam.Height.GetValue() + offset_x = cam.OffsetX.GetValue() + offset_y = cam.OffsetY.GetValue() + pixel_format = cam.PixelFormat.GetValue() + + # Form image and save data + print('Width: %s' % width) + print('Height: %s' % height) + print('OffsetX: %s' % offset_x) + print('OffsetY: %s' % offset_y) + print('PixelFormat: %s' % pixel_format) + + # Create image + image = PySpin.Image.Create(width, height, offset_x, offset_y, pixel_format, image_data) + + # Save image + image.Save(filename) + print('Image saved at %s' % filename) + + cam.DeInit() + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return success + +def main(): + """ + Example entry point; please see Enumeration.py example for more in-depth + comments on preparing and cleaning up the system with PySpin. + + :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)) + + parser = argparse.ArgumentParser() + parser = subparsers.add_parser('stop', formatter_class=argparse.RawTextHelpFormatter) + + parser.add_argument('--mode', required=True, type=str, + help='/u : Grab an image and store it on camera.\n/d : Download saved image from camera and save it to the working directory.\n') + parser.add_argument('--verbose', default=False, action='store_true', + help='Enable verbose output.') + + args = parser.parse_args() + + cam_list = system.GetCameras() + num_cameras = cam_list.GetSize() + + # This example only works with 1 camera is connected. + 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 + elif num_cameras > 1: + # Clear camera list before releasing system + cam_list.Clear() + + # Release system instance + system.ReleaseInstance() + + print('This example only works when 1 camera is connected.') + input('Done! Press Enter to exit...') + return False + else: + if args.mode == '/u' or args.mode == '/U': + result = FileAccess.upload_image(cam_list[0], args.verbose) + elif args.mode == '/d' or args.mode == '/D': + result = FileAccess.download_image(cam_list[0], args.verbose) + else: + print("Invalid Argument! Use '--help' to learn available arguments.") + input('Done! Press Enter to exit...') + return False + + if not result: + print('File Access failed') + else: + print('File Access is successful!') + + 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) \ No newline at end of file diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/HighDynamicRange.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/HighDynamicRange.py new file mode 100644 index 0000000..da60789 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/HighDynamicRange.py @@ -0,0 +1,302 @@ +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# HighDynamicRange.py +# This example shows how to set High Dynamic Range (HDR) if it is available on the camera. + +import PySpin +import os +import sys + +NUM_IMAGES = 4 # number of images to grab + +K_HDR_SHUTTER1 = 1000 # us +K_HDR_SHUTTER2 = 5000 +K_HDR_SHUTTER3 = 15000 +K_HDR_SHUTTER4 = 30000 + +K_HDR_GAIN1 = 0 # dB +K_HDR_GAIN2 = 5 +K_HDR_GAIN3 = 10 +K_HDR_GAIN4 = 15 + + +def print_device_info(nodemap): + """ + Helper for outputting camera information + + :param nodemap: Transport layer device nodemap. + :type INodeMap + :returns: True if successful, False otherwise. + :rtype: bool + """ + + print('*** DEVICE INFORMATION ***') + + try: + node_device_information = PySpin.CCategoryPtr(nodemap.GetNode('DeviceControl')) + + 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 True + +def check_node_accessibility(node): + """ + Helper for checking GenICam node accessibility + + :param node: GenICam node being checked + :type node: CNodePtr + :return: True if accessible, False otherwise + :rtype: bool + """ + + return PySpin.IsAvailable(node) and (PySpin.IsReadable(node) or PySpin.IsWritable(node)) + +def toggle_hdr_mode(nodemap, hdr_on): + """ + Helper for toggling HDR mode on camera + + :param nodemap: Transport layer device nodemap. + :type: INodeMap + :param hdr_on: True if want to turn hdr mode on, False otherwise. + :type hdr_on: bool + :return: True if successful, False otherwise. + :rtype: bool + """ + + node_hdr_enabled = PySpin.CBooleanPtr(nodemap.GetNode("PGR_HDRModeEnabled")) + + if check_node_accessibility(node_hdr_enabled): + node_hdr_enabled.SetValue(hdr_on) + else: + return False + + print('HDR mode turned to', hdr_on) + + return True + +def initialize_hdr_images(nodemap): + """ + Helper for initializing HDR images + + :param nodemap: Transport layer device nodemap. + :type: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + hdr_image_selector = PySpin.CEnumerationPtr(nodemap.GetNode("PGR_HDRImageSelector")) + hdr_exposure_abs = PySpin.CFloatPtr(nodemap.GetNode("PGR_HDR_ExposureTimeAbs")) + hdr_gain_abs = PySpin.CFloatPtr(nodemap.GetNode("PGR_HDR_GainAbs")) + + if not check_node_accessibility(hdr_image_selector): + return False + if not check_node_accessibility(hdr_exposure_abs): + return False + if not check_node_accessibility(hdr_gain_abs): + return False + + # Configure Image1 + hdr_image_selector.SetIntValue(hdr_image_selector.GetEntryByName("Image1").GetValue()) + hdr_exposure_abs.SetValue(K_HDR_SHUTTER1) + hdr_gain_abs.SetValue(K_HDR_GAIN1) + print('Initialized HDR Image1...') + + # Configure Image2 + hdr_image_selector.SetIntValue(hdr_image_selector.GetEntryByName("Image2").GetValue()) + hdr_exposure_abs.SetValue(K_HDR_SHUTTER2) + hdr_gain_abs.SetValue(K_HDR_GAIN2) + print('Initialized HDR Image2...') + + # Configure Image3 + hdr_image_selector.SetIntValue(hdr_image_selector.GetEntryByName("Image3").GetValue()) + hdr_exposure_abs.SetValue(K_HDR_SHUTTER3) + hdr_gain_abs.SetValue(K_HDR_GAIN3) + print('Initialized HDR Image3...') + + # Configure Image4 + hdr_image_selector.SetIntValue(hdr_image_selector.GetEntryByName("Image4").GetValue()) + hdr_exposure_abs.SetValue(K_HDR_SHUTTER4) + hdr_gain_abs.SetValue(K_HDR_GAIN4) + print('Initialized HDR Image4...') + + return True + +def run_single_camera(cam): + """ + Helper for running example on single camera + + :param cam: Camera to run on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Initialize camera + cam.Init() + + # Get GenICam NodeMap info from camera + nodemap = cam.GetNodeMap() + + # Get camera information through NodeMap + print_device_info(nodemap) + + # Verify whether HDR is supported on this device + node_hdr_enabled = PySpin.CBooleanPtr(nodemap.GetNode("PGR_HDRModeEnabled")) + if not PySpin.IsAvailable(node_hdr_enabled): + print('HDR is not supported! Exiting...') + return True + + # HDR needs to be enabled prior to configure individual HDR images + toggle_hdr_mode(nodemap, True) + + if not initialize_hdr_images(nodemap): + print('Error configuring HDR image! Exiting...') + return False + + # Retrieve Device ID + device_id = cam.GetTLDeviceNodeMap().GetNode("DeviceID") + + # Begin capturing images + print('Starting grabbing images...') + cam.BeginAcquisition() + + for i in range(NUM_IMAGES): + try: + # Retrieve the next received image + raw_image = cam.GetNextImage(1000) + width = raw_image.GetWidth() + height = raw_image.GetHeight() + print('Grabbed image %d, width = %d, height = %d' % (i, width, height)) + + # Convert image to Mono8 + converted_image = raw_image.Convert(PySpin.PixelFormat_Mono8) + + # Create a unique filename + filename = 'HighDynamicRange-%s-%d.jpg' % (device_id, i) + + # Save image + converted_image.Save(filename) + + # Image need to be released after use + raw_image.Release() + + except PySpin.SpinnakerException as ex: + print('Error Retrieving Image: %s' % ex) + result = False + continue + + # End capturing of images + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + print() + + 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: %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 cam in cam_list: + result &= run_single_camera(cam) + + # 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) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/ImageChannelStatistics.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/ImageChannelStatistics.py new file mode 100644 index 0000000..7589b73 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/ImageChannelStatistics.py @@ -0,0 +1,302 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# ImageChannelStatisitcs.py shows how to get the image data and channel statistics, and then saves / displays them. +# This example relies on information provided in the Acquisition examples. +# +# This example demonstrates how to visualize the image histogram using Python, and display an image represented as +# a numpy array. +# +# NOTE: matplotlib must be installed on Python interpreter prior to running this example + +import os +import sys +import PySpin +import matplotlib.pyplot as plt + +NUM_IMAGES = 10 # number of images to grab + + +def acquire_and_display_images(cam, nodemap, nodemap_tldevice): + """ + This function acquires and displays the channel statistics of N images from a device. + + :param cam: Camera to acquire images from. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** IMAGE ACQUISITION ***\n') + try: + result = True + + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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...') + + node_pixel_format = PySpin.CEnumerationPtr(nodemap.GetNode('PixelFormat')) + if not PySpin.IsAvailable(node_pixel_format) or not PySpin.IsWritable(node_pixel_format): + print('Unable to set Pixel Format. Aborting...') + return False + + else: + # Retrieve entry node from enumeration node + node_pixel_format_mono8 = PySpin.CEnumEntryPtr(node_pixel_format.GetEntryByName('Mono8')) + if not PySpin.IsAvailable(node_pixel_format_mono8) or not PySpin.IsReadable(node_pixel_format_mono8): + print('Unable to set Pixel Format to MONO8. Aborting...') + return False + + # Retrieve integer value from entry node + pixel_format_mono8 = node_pixel_format_mono8.GetValue() + + # Set integer value from entry node as new value of enumeration node + node_pixel_format.SetIntValue(pixel_format_mono8) + + print('Pixel Format set to MONO8 ...') + + cam.BeginAcquisition() + + print('Acquiring images...') + + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + plt.ion() + for i in range(NUM_IMAGES): + try: + image_result = cam.GetNextImage(1000) + + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + else: + fig = plt.figure(1) + + try: + image_stats = image_result.CalculateChannelStatistics(PySpin.GREY) + # Getting the image data as a numpy array + image_data = image_result.GetNDArray() + + # Display Statistics + print('SN%s image %d:' % (device_serial_number, i)) + print('\tNumber pixel values : %d' % image_stats.num_pixel_values) + print('\tRange: Min = %d, Max = %d' % (image_stats.range_min, + image_stats.range_max)) + print('\tPixel Value: Min = %d, Max = %d, Mean = %.2f' % (image_stats.pixel_value_min, + image_stats.pixel_value_max, + image_stats.pixel_value_mean)) + + # Using matplotlib, two subplots are created where the top subplot is the histogram and the + # bottom subplot is the image. + # + # Refer to https://matplotlib.org/2.0.2/api/pyplot_api.html#module-matplotlib.pyplot + + # Clear the figure to reuse for next plot + plt.clf() + + # Plot the histogram in the first subplot in a 2 row by 1 column grid + plt.subplot(211) + plt.cla() + plt.plot(image_stats.histogram, label='Grey') + plt.title('SN%s Histogram (%d)' % (device_serial_number, i)) + plt.legend() + + # Plot the image in the second subplot in a 2 row by 1 column grid + plt.subplot(212) + plt.cla() + plt.imshow(image_data, cmap='gray') + + # Show the image + plt.show() + plt.pause(0.01) + + # Create a unique filename + if device_serial_number: + filename = 'ImageChannelStatistics-%s-%d.png' % (device_serial_number, i) + else: # if serial number is empty + filename = 'ImageChannelStatistics-%d.png' % i + + fig.savefig(filename) + print('\tSave to %s' % filename) + print() + + except PySpin.SpinnakerException: + raise + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + + except PySpin.SpinnakerException: + raise + + cam.EndAcquisition() + print('End Acquisition') + + plt.close() + + 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 + + nodemap_tldevice = cam.GetTLDeviceNodeMap() + + #Initialize camera + cam.Init() + + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + + # Acquire images + result &= acquire_and_display_images(cam, nodemap, nodemap_tldevice) + + # Deinitialize camera + cam.DeInit() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + +def main(): + """ + Example entry point; notice the volume of data that the logging event handler + prints out on debug despite the fact that very little really happens in this + example. Because of this, it may be better to have the logger set to lower + level in order to provide a more concise, focused log. + + :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: %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) + diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/ImageEvents.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/ImageEvents.py new file mode 100644 index 0000000..ac85f18 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/ImageEvents.py @@ -0,0 +1,452 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# ImageEvents.py shows how to acquire images using the image event handler. +# It relies on information provided in the Enumeration, Acquisition, +# and NodeMapInfo examples. +# +# It can also be helpful to familiarize yourself with the NodeMapCallback +# example, as nodemap callbacks follow the same general procedure as +# events, but with a few less steps. +# +# This example creates a user-defined class, ImageEventHandler, that inherits +# from the Spinnaker class, ImageEventHandler. ImageEventHandler allows the user to +# define any properties, parameters, and the event handler itself while ImageEvent +# allows the child class to appropriately interface with Spinnaker. + +import os +import sys +import PySpin +from time import sleep + +SLEEP_DURATION = 200 # amount of time for main thread to sleep for (in milliseconds) until _NUM_IMAGES have been saved + + +class ImageEventHandler(PySpin.ImageEventHandler): + """ + This class defines the properties, parameters, and the event handler itself. Take a + moment to notice what parts of the class are mandatory, and what have been + added for demonstration purposes. First, any class used to define image event handlers + must inherit from ImageEventHandler. Second, the method signature of OnImageEvent() + must also be consistent. Everything else - including the constructor, + destructor, properties, body of OnImageEvent(), and other functions - + is particular to the example. + """ + _NUM_IMAGES = 10 + + def __init__(self, cam): + """ + Constructor. Retrieves serial number of given camera and sets image counter to 0. + + :param cam: Camera instance, used to get serial number for unique image filenames. + :type cam: CameraPtr + :rtype: None + """ + super(ImageEventHandler, self).__init__() + + nodemap = cam.GetTLDeviceNodeMap() + + # Retrieve device serial number + node_device_serial_number = PySpin.CStringPtr(nodemap.GetNode('DeviceSerialNumber')) + + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + self._device_serial_number = node_device_serial_number.GetValue() + + # Initialize image counter to 0 + self._image_count = 0 + + # 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 + + def OnImageEvent(self, image): + """ + This method defines an image event. In it, the image that triggered the + event is converted and saved before incrementing the count. Please see + Acquisition example for more in-depth comments on the acquisition + of images. + + :param image: Image from event. + :type image: ImagePtr + :rtype: None + """ + # Save max of _NUM_IMAGES Images + if self._image_count < self._NUM_IMAGES: + print('Image event occurred...') + + # Check if image is incomplete + if image.IsIncomplete(): + print('Image incomplete with image status %i...' % image.GetImageStatus()) + + else: + # Print image info + print('Grabbed image %i, width = %i, height = %i' % (self._image_count, + image.GetWidth(), + image.GetHeight())) + + # Convert to mono8 + image_converted = image.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + # Create unique filename and save image + if self._device_serial_number: + filename = 'ImageEvents-%s-%i.jpg' % (self._device_serial_number, self._image_count) + + else: # if serial number is empty + filename = 'ImageEvents-%i.jpg' % self._image_count + + image_converted.Save(filename) + + print('Image saved at %s\n' % filename) + + # Increment image counter + self._image_count += 1 + + def get_image_count(self): + """ + Getter for image count. + + :return: Number of images saved. + :rtype: int + """ + return self._image_count + + def get_max_images(self): + """ + Getter for maximum images. + + :return: Total number of images to save. + :rtype: int + """ + return self._NUM_IMAGES + + +def configure_image_events(cam): + """ + This function configures the example to execute image events by preparing and + registering an image event. + + :param cam: Camera instance to configure image event. + :return: tuple(result, image_event_handler) + WHERE + result is True if successful, False otherwise + image_event_handler is the event handler + :rtype: (bool, ImageEventHandler) + """ + try: + result = True + + # Create image event handler + # + # *** NOTES *** + # The class has been constructed to accept a camera pointer in order + # to allow the saving of images with the device serial number. + image_event_handler = ImageEventHandler(cam) + + # Register image event handler + # + # *** NOTES *** + # Image events are registered to cameras. If there are multiple + # cameras, each camera must have the image events registered to it + # separately. Also, multiple image events may be registered to a + # single camera. + # + # *** LATER *** + # Image event handlers must be unregistered manually. This must be done prior + # to releasing the system and while the image events are still in + # scope. + cam.RegisterEventHandler(image_event_handler) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result, image_event_handler + + +def wait_for_images(image_event_handler): + """ + This function waits for the appropriate amount of images. Notice that + whereas most examples actively retrieve images, the acquisition of images is + handled passively in this example. + + :param image_event_handler: Image event handler. + :type image_event_handler: ImageEventHandler + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Wait for images + # + # *** NOTES *** + # In order to passively capture images using image event handlers and + # automatic polling, the main thread sleeps in increments of SLEEP_DURATION ms + # until _MAX_IMAGES images have been acquired and saved. + while image_event_handler.get_image_count() < image_event_handler.get_max_images(): + print('\t//\n\t// Sleeping for %i ms. Grabbing images...' % SLEEP_DURATION) + sleep(SLEEP_DURATION / 1000.0) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def reset_image_events(cam, image_event_handler): + """ + This functions resets the example by unregistering the image event handler. + + :param cam: Camera instance. + :param image_event_handler: Image event handler for cam. + :type cam: CameraPtr + :type image_event_handler: ImageEventHandler + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Unregister image event handler + # + # *** NOTES *** + # It is important to unregister all image events from all cameras they are registered to. + # Unlike SystemEventHandler and InterfaceEventHandler in the EnumerationEvents example, + # there is no need to explicitly delete the ImageEventHandler here as it does not store + # an instance of the camera (it gets deleted in the constructor already). + cam.UnregisterEventHandler(image_event_handler) + + print('Image events unregistered...') + + 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 from camera. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + print('*** DEVICE INFORMATION ***') + + 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.message) + result = False + + return result + + +def acquire_images(cam, nodemap, image_event_handler): + """ + This function passively waits for images by calling wait_for_images(). Notice that + this function is much shorter than the acquire_images() function of other examples. + This is because most of the code has been moved to the image event's OnImageEvent() + method. + + :param cam: Camera instance to grab images from. + :param nodemap: Device nodemap. + :param image_event_handler: Image event handler. + :type cam: CameraPtr + :type nodemap: INodeMap + :type image_event_handler: ImageEventHandler + :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.IsAvailable(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.IsAvailable(node_acquisition_mode_continuous) or not PySpin.IsReadable(node_acquisition_mode_continuous): + print('Unable to set acquisition mode to continuous (entry retrieval). Aborting...') + return False + + acquisition_mode_continuous = node_acquisition_mode_continuous.GetValue() + node_acquisition_mode.SetIntValue(acquisition_mode_continuous) + + print('Acquisition mode set to continuous...') + + # Begin acquiring images + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve images using image event handler + wait_for_images(image_event_handler) + + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = 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 acquire images from. + :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 image events + err, image_event_handler = configure_image_events(cam) + if not err: + return err + + # Acquire images using the image event handler + result &= acquire_images(cam, nodemap, image_event_handler) + + # Reset image event handlers + result &= reset_image_events(cam, image_event_handler) + + # 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 additional + comments on the steps in this function. + + :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: %d.%d.%d.%d' % (version.major, version.minor, version.type, version.build)) + + # Retrieve list of cameras from the system + cam_list = system.GetCameras() + + num_cams = cam_list.GetSize() + + print('Number of cameras detected: %i' % num_cams) + + # Finish if there are no cameras + if num_cams == 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 + 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) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/ImageFormatControl.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/ImageFormatControl.py new file mode 100644 index 0000000..e8b19f2 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/ImageFormatControl.py @@ -0,0 +1,501 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# ImageFormatControl.py shows how to apply custom image settings to +# the camera. It relies on information provided in the Enumeration, +# Acquisition, and NodeMapInfo examples. +# +# This example demonstrates setting minimums to offsets, X and Y, and maximums +# to width and height. It also shows the setting of a new pixel format, which +# is an enumeration type node. +# +# Following this, we suggest familiarizing yourself with the Exposure example +# if you haven't already. Exposure is another example on camera customization +# that is shorter and simpler than many of the others. Once comfortable with +# Exposure and ImageFormatControl, we suggest checking out any of the longer, +# more complicated examples related to camera configuration: ChunkData, +# LookupTable, Sequencer, or Trigger. + +import os +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +def configure_custom_image_settings(nodemap): + """ + Configures a number of settings on the camera including offsets X and Y, width, + height, and pixel format. These settings must be applied before BeginAcquisition() + is called; otherwise, they will be read only. Also, it is important to note that + settings are applied immediately. This means if you plan to reduce the width and + move the x offset accordingly, you need to apply such changes in the appropriate order. + + :param nodemap: GenICam nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** CONFIGURING CUSTOM IMAGE SETTINGS *** \n') + + try: + result = True + + # Apply mono 8 pixel format + # + # *** NOTES *** + # Enumeration nodes are slightly more complicated to set than other + # nodes. This is because setting an enumeration node requires working + # with two nodes instead of the usual one. + # + # As such, there are a number of steps to setting an enumeration node: + # retrieve the enumeration node from the nodemap, retrieve the desired + # entry node from the enumeration node, retrieve the integer value from + # the entry node, and set the new value of the enumeration node with + # the integer value from the entry node. + # + # Retrieve the enumeration node from the nodemap + node_pixel_format = PySpin.CEnumerationPtr(nodemap.GetNode('PixelFormat')) + if PySpin.IsAvailable(node_pixel_format) and PySpin.IsWritable(node_pixel_format): + + # Retrieve the desired entry node from the enumeration node + node_pixel_format_mono8 = PySpin.CEnumEntryPtr(node_pixel_format.GetEntryByName('Mono8')) + if PySpin.IsAvailable(node_pixel_format_mono8) and PySpin.IsReadable(node_pixel_format_mono8): + + # Retrieve the integer value from the entry node + pixel_format_mono8 = node_pixel_format_mono8.GetValue() + + # Set integer as new value for enumeration node + node_pixel_format.SetIntValue(pixel_format_mono8) + + print('Pixel format set to %s...' % node_pixel_format.GetCurrentEntry().GetSymbolic()) + + else: + print('Pixel format mono 8 not available...') + + else: + print('Pixel format not available...') + + # Apply minimum to offset X + # + # *** NOTES *** + # Numeric nodes have both a minimum and maximum. A minimum is retrieved + # with the method GetMin(). Sometimes it can be important to check + # minimums to ensure that your desired value is within range. + node_offset_x = PySpin.CIntegerPtr(nodemap.GetNode('OffsetX')) + if PySpin.IsAvailable(node_offset_x) and PySpin.IsWritable(node_offset_x): + + node_offset_x.SetValue(node_offset_x.GetMin()) + print('Offset X set to %i...' % node_offset_x.GetMin()) + + else: + print('Offset X not available...') + + # Apply minimum to offset Y + # + # *** NOTES *** + # It is often desirable to check the increment as well. The increment + # is a number of which a desired value must be a multiple of. Certain + # nodes, such as those corresponding to offsets X and Y, have an + # increment of 1, which basically means that any value within range + # is appropriate. The increment is retrieved with the method GetInc(). + node_offset_y = PySpin.CIntegerPtr(nodemap.GetNode('OffsetY')) + if PySpin.IsAvailable(node_offset_y) and PySpin.IsWritable(node_offset_y): + + node_offset_y.SetValue(node_offset_y.GetMin()) + print('Offset Y set to %i...' % node_offset_y.GetMin()) + + else: + print('Offset Y not available...') + + # Set maximum width + # + # *** NOTES *** + # Other nodes, such as those corresponding to image width and height, + # might have an increment other than 1. In these cases, it can be + # important to check that the desired value is a multiple of the + # increment. However, as these values are being set to the maximum, + # there is no reason to check against the increment. + node_width = PySpin.CIntegerPtr(nodemap.GetNode('Width')) + if PySpin.IsAvailable(node_width) and PySpin.IsWritable(node_width): + + width_to_set = node_width.GetMax() + node_width.SetValue(width_to_set) + print('Width set to %i...' % node_width.GetValue()) + + else: + print('Width not available...') + + # Set maximum height + # + # *** NOTES *** + # A maximum is retrieved with the method GetMax(). A node's minimum and + # maximum should always be a multiple of its increment. + node_height = PySpin.CIntegerPtr(nodemap.GetNode('Height')) + if PySpin.IsAvailable(node_height) and PySpin.IsWritable(node_height): + + height_to_set = node_height.GetMax() + node_height.SetValue(height_to_set) + print('Height set to %i...' % node_height.GetValue()) + + else: + print('Height not available...') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return 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 acquire_images(cam, nodemap, nodemap_tldevice): + """ + 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. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** IMAGE ACQUISITION ***\n') + try: + result = True + + # Set acquisition mode to continuous + # + # *** NOTES *** + # Because the example acquires and saves 10 images, setting acquisition + # mode to continuous lets the example finish. If set to single frame + # or multiframe (at a lower number of images), the example would just + # hang. This would happen because the example has been written to + # acquire 10 images while the camera would have been programmed to + # retrieve less than that. + # + # Setting the value of an enumeration node is slightly more complicated + # than other node types. Two nodes must be retrieved: first, the + # enumeration node is retrieved from the nodemap; and second, the entry + # node is retrieved from the enumeration node. The integer value of the + # entry node is then set as the new value of the enumeration node. + # + # Notice that both the enumeration and the entry nodes are checked for + # availability and readability/writability. Enumeration nodes are + # generally readable and writable whereas their entry nodes are only + # ever readable. + # + # Retrieve enumeration node from nodemap + + # In order to access the node entries, they have to be casted to a pointer type (CEnumerationPtr here) + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # What happens when the camera begins acquiring images depends on the + # acquisition mode. Single frame captures only a single image, multi + # frame catures a set number of images, and continuous captures a + # continuous stream of images. Because the example calls for the + # retrieval of 10 images, continuous mode has been set. + # + # *** LATER *** + # Image acquisition must be ended when no more images are needed. + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve device serial number for filename + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Retrieve, convert, and save images + for i in range(NUM_IMAGES): + try: + + # Retrieve next received image + # + # *** NOTES *** + # Capturing an image houses images on the camera buffer. Trying + # to capture an image that does not exist will hang the camera. + # + # *** LATER *** + # Once an image from the buffer is saved and/or no longer + # needed, the image must be released in order to keep the + # buffer from filling up. + image_result = cam.GetNextImage(1000) + + # Ensure image completion + # + # *** NOTES *** + # Images can easily be checked for completion. This should be + # done whenever a complete image is expected or required. + # Further, check image status for a little more insight into + # why an image is incomplete. + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + + else: + + # Print image information; height and width recorded in pixels + # + # *** NOTES *** + # Images have quite a bit of available metadata including + # things such as CRC, image status, and offset values, to + # name a few. + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed Image %d, width = %d, height = %d' % (i, width, height)) + + # Convert image to mono 8 + # + # *** NOTES *** + # Images can be converted between pixel formats by using + # the appropriate enumeration value. Unlike the original + # image, the converted one does not need to be released as + # it does not affect the camera buffer. + # + # When converting images, color processing algorithm is an + # optional parameter. + image_converted = image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + # Create a unique filename + if device_serial_number: + filename = 'ImageFormatControl-%s-%d.jpg' % (device_serial_number, i) + else: # if serial number is empty + filename = 'ImageFormatControl-%d.jpg' % i + + # Save image + # + # *** NOTES *** + # The standard practice of the examples is to use device + # serial numbers to keep images of one device from + # overwriting those of another. + image_converted.Save(filename) + print('Image saved at %s' % filename) + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + print('') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def run_single_camera(cam): + """ + This function acts as the body of the example; please see NodeMapInfo example + for more in-depth comments on setting up cameras. + + :param cam: Camera to run on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Retrieve TL device nodemap and print device information + nodemap_tldevice = cam.GetTLDeviceNodeMap() + + result &= print_device_info(nodemap_tldevice) + + # Initialize camera + cam.Init() + + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + + # Configure custom image settings + if not configure_custom_image_settings(nodemap): + return False + + # Acquire images + result &= acquire_images(cam, nodemap, nodemap_tldevice) + + # 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 + """ + + # 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: %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) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/ImageFormatControl_QuickSpin.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/ImageFormatControl_QuickSpin.py new file mode 100644 index 0000000..8fba164 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/ImageFormatControl_QuickSpin.py @@ -0,0 +1,358 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# ImageFormatControl_QuickSpin.py shows how to apply custom image +# settings to the camera using the QuickSpin API. QuickSpin is a subset of +# the Spinnaker library that allows for simpler node access and control. +# +# This example demonstrates customizing offsets X and Y, width and height, +# and the pixel format. Ensuring custom values fall within an acceptable +# range is also touched on. Retrieving and setting node values using +# QuickSpin is the only portion of the example that differs from +# ImageFormatControl. +# +# 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 + + +def configure_custom_image_settings(cam): + """ + Configures a number of settings on the camera including offsets X and Y, + width, height, and pixel format. These settings must be applied before + BeginAcquisition() is called; otherwise, those nodes would be read only. + Also, it is important to note that settings are applied immediately. + This means if you plan to reduce the width and move the x offset accordingly, + you need to apply such changes in the appropriate order. + + :param cam: Camera to configure settings on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** CONFIGURING CUSTOM IMAGE SETTINGS ***\n') + + try: + result = True + + # Apply mono 8 pixel format + # + # *** NOTES *** + # In QuickSpin, enumeration nodes are as easy to set as other node + # types. This is because enum values representing each entry node + # are added to the API. + if cam.PixelFormat.GetAccessMode() == PySpin.RW: + cam.PixelFormat.SetValue(PySpin.PixelFormat_Mono8) + print('Pixel format set to %s...' % cam.PixelFormat.GetCurrentEntry().GetSymbolic()) + + else: + print('Pixel format not available...') + result = False + + # Apply minimum to offset X + # + # *** NOTES *** + # Numeric nodes have both a minimum and maximum. A minimum is retrieved + # with the method GetMin(). Sometimes it can be important to check + # minimums to ensure that your desired value is within range. + if cam.OffsetX.GetAccessMode() == PySpin.RW: + cam.OffsetX.SetValue(cam.OffsetX.GetMin()) + print('Offset X set to %d...' % cam.OffsetX.GetValue()) + + else: + print('Offset X not available...') + result = False + + # Apply minimum to offset Y + # + # *** NOTES *** + # It is often desirable to check the increment as well. The increment + # is a number of which a desired value must be a multiple. Certain + # nodes, such as those corresponding to offsets X and Y, have an + # increment of 1, which basically means that any value within range + # is appropriate. The increment is retrieved with the method GetInc(). + if cam.OffsetY.GetAccessMode() == PySpin.RW: + cam.OffsetY.SetValue(cam.OffsetY.GetMin()) + print('Offset Y set to %d...' % cam.OffsetY.GetValue()) + + else: + print('Offset Y not available...') + result = False + + # Set maximum width + # + # *** NOTES *** + # Other nodes, such as those corresponding to image width and height, + # might have an increment other than 1. In these cases, it can be + # important to check that the desired value is a multiple of the + # increment. + # + # This is often the case for width and height nodes. However, because + # these nodes are being set to their maximums, there is no real reason + # to check against the increment. + if cam.Width.GetAccessMode() == PySpin.RW and cam.Width.GetInc() != 0 and cam.Width.GetMax != 0: + cam.Width.SetValue(cam.Width.GetMax()) + print('Width set to %i...' % cam.Width.GetValue()) + + else: + print('Width not available...') + result = False + + # Set maximum height + # + # *** NOTES *** + # A maximum is retrieved with the method GetMax(). A node's minimum and + # maximum should always be a multiple of its increment. + if cam.Height.GetAccessMode() == PySpin.RW and cam.Height.GetInc() != 0 and cam.Height.GetMax != 0: + cam.Height.SetValue(cam.Height.GetMax()) + print('Height set to %i...' % cam.Height.GetValue()) + + else: + print('Height not available...') + result = False + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_device_info(cam): + """ + 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 cam: Camera to get device information from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('\n*** DEVICE INFORMATION ***\n') + + try: + result = True + nodemap = cam.GetTLDeviceNodeMap() + + 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.message) + 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 the acquisition of images. + + :param cam: Camera to acquire images from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** 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 is not None and 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 next received image and ensure image completion + image_result = cam.GetNextImage(1000) + + 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 Mono8 + image_converted = image_result.Convert(PySpin.PixelFormat_Mono8) + + # Create a unique filename + if device_serial_number: + filename = 'ImageFormatControlQS-%s-%d.jpg' % (device_serial_number, i) + else: + filename = 'ImageFormatControlQS-%d.jpg' % i + + # Save image + image_converted.Save(filename) + + print('Image saved at %s' % filename) + + # Release image + image_result.Release() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + # End acquisition + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def run_single_camera(cam): + """ + This function acts as the body of the example; please see NodeMapInfo_QuickSpin example for more + in-depth comments on setting up cameras. + + :param cam: Camera to run example on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + # Initialize camera + cam.Init() + + # Print device info + result = print_device_info(cam) + + # Configure exposure + if not configure_custom_image_settings(cam): + return False + + # Acquire images + result &= acquire_images(cam) + + # Deinitialize camera + cam.DeInit() + + return result + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + +def main(): + """ + Example entry point; please see Enumeration_QuickSpin 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 + + # Release 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) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/Inference.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Inference.py new file mode 100644 index 0000000..524d8ca --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Inference.py @@ -0,0 +1,1218 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# 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.flir.com/products/firefly-dl/ +# It can also be helpful to familiarize yourself with the Acquisition, +# ChunkData and FileAccess_QuickSpin examples. + +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.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 + +# 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.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.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.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.IsReadable(ptr_file_access_offset) or 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): + try: + ptr_file_operation_selector = PySpin.CEnumerationPtr(nodemap.GetNode("FileOperationSelector")) + if 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 + + ptr_file_operation_selector.SetIntValue(int(ptr_file_operation_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 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.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.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.IsReadable(ptr_file_access_buffer) or 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) + + if intermediate_buffer_size > bytes_left_to_write: + ptr_file_access_length.SetValue(bytes_left_to_write) + + # Perform Write command + if not camera_write_to_file(nodemap): + print('Writing to stream failed. Aborting...') + return False + + # Verify size of bytes written + size_written = ptr_file_access_result.GetValue() + + # 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') + + 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.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.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.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.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.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.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.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.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, convert, and save images + 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) \ No newline at end of file diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/Injected_Image_Classification.raw b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Injected_Image_Classification.raw new file mode 100644 index 0000000..e79db8f Binary files /dev/null and b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Injected_Image_Classification.raw differ diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/Injected_Image_Classification_Daisy.jpg b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Injected_Image_Classification_Daisy.jpg new file mode 100644 index 0000000..128f332 Binary files /dev/null and b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Injected_Image_Classification_Daisy.jpg differ diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/Injected_Image_Detection.raw b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Injected_Image_Detection.raw new file mode 100644 index 0000000..e1c3100 Binary files /dev/null and b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Injected_Image_Detection.raw differ diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/Injected_Image_Detection_Aeroplane.jpg b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Injected_Image_Detection_Aeroplane.jpg new file mode 100644 index 0000000..8e3cefc Binary files /dev/null and b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Injected_Image_Detection_Aeroplane.jpg differ diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/Logging.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Logging.py new file mode 100644 index 0000000..4501a54 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Logging.py @@ -0,0 +1,130 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# Logging.py shows how to create a handler to access logging events. +# It relies on information provided in the Enumeration, Acquisition, and +# NodeMapInfo examples. +# +# It can also be helpful to familiarize yourself with the NodeMapCallback +# example, as nodemap callbacks follow the same general procedure as +# events, but with a few less steps. +# +# This example creates a user-defined class, LoggingEventHandler, that inherits +# from the Spinnaker class, LoggingEventHandler. The child class allows the user to +# define any properties, parameters, and the event handler itself while LoggingEventHandler +# allows the child class to appropriately interface with the Spinnaker SDK. + +import PySpin + + +# Define callback priority threshold; please see documentation for additional +# information on logging level philosophy. +LOGGING_LEVEL = PySpin.LOG_LEVEL_DEBUG # change to any LOG_LEVEL_* constant + + +class LoggingEventHandler(PySpin.LoggingEventHandler): + """ + Although logging events are just as flexible and extensible as other events, + they are generally only used for logging purposes, which is why a number of + helpful functions that provide logging information have been added. Generally, + if the purpose is not logging, one of the other event types is probably more + appropriate. + """ + + def __init__(self): + super(LoggingEventHandler, self).__init__() + + def OnLogEvent(self, logging_event_data): + """ + This function displays readily available logging information. + + :param logging_event_data: Logging data. + :type logging_event_data: LoggingEventData + :rtype: None + """ + print('--------Log Event Received----------') + print('Category: %s' % logging_event_data.GetCategoryName()) + print('Priority Value: %s' % logging_event_data.GetPriority()) + print('Priority Name: %s' % logging_event_data.GetPriorityName()) + print('Timestamp: %s' % logging_event_data.GetTimestamp()) + print('NDC: %s' % logging_event_data.GetNDC()) + print('Thread: %s' % logging_event_data.GetThreadName()) + print('Message: %s' % logging_event_data.GetLogMessage()) + print('------------------------------------\n') + + +def main(): + """ + Example entry point; notice the volume of data that the logging event handler + prints out on debug despite the fact that very little really happens in this + example. Because of this, it may be better to have the logger set to lower + level in order to provide a more concise, focused log. + + :rtype: None + """ + + # 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)) + + # Create and register the logging event handler + # + # *** NOTES *** + # Logging event handlers are registered to the system. Take note that a logging + # event handler is very verbose when the logging level is set to debug. + # + # *** LATER *** + # Logging event handlers must be unregistered manually. This must be done prior to + # releasing the system and while the logging event handlers are still in scope. + logging_event_handler = LoggingEventHandler() + system.RegisterLoggingEventHandler(logging_event_handler) + + # Set callback priority level + # + # *** NOTES *** + # Please see documentation for up-to-date information on the logging + # philosophies of the Spinnaker SDK. + system.SetLoggingEventPriorityLevel(LOGGING_LEVEL) + + # Retrieve list of cameras from the system + cam_list = system.GetCameras() + + num_cams = cam_list.GetSize() + + print('Number of cameras detected: %i' % num_cams) + + # Clear camera list before releasing system + cam_list.Clear() + + # Unregister logging event handler + # + # *** NOTES *** + # It is important to unregister all logging event handlers from the system. + system.UnregisterLoggingEventHandler(logging_event_handler) + + # Release system instance + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + + +if __name__ == '__main__': + main() diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/LookupTable.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/LookupTable.py new file mode 100644 index 0000000..851b6d0 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/LookupTable.py @@ -0,0 +1,440 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= + +# LookupTable.py +# +# LookupTable.py shows how to configure lookup tables on the camera. +# 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 they are somewhat shorter and simpler, either +# provides a strong introduction to camera customization. +# +# Lookup tables allow for the customization and control of individual pixels. +# This can be a very powerful and deeply useful tool; however, because use +# cases are context dependent, this example only explores lookup table +# configuration. + +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_lookup_tables(nodemap): + """ + This function configures lookup tables linearly. This involves selecting the + type of lookup table, finding the appropriate increment calculated from the + maximum value, and enabling lookup tables on the camera. + + :param nodemap: Device nodemap + :type nodemap: INodeMap + :return: returns True if successful, False otherwise + :rtype: bool + """ + result = True + print("***CONFIGURING LOOKUP TABLES***\n") + + # Select lookup table type + # + # ***NOTES *** + # Setting the lookup table selector. It is important to note that this + # does not enable lookup tables. + + try: + lut_selector = PySpin.CEnumerationPtr(nodemap.GetNode("LUTSelector")) + if not PySpin.IsAvailable(lut_selector) or not PySpin.IsWritable(lut_selector): + print_retrieve_node_failure("node", "LUTSelector") + return False + + lut_selector_lut1 = lut_selector.GetEntryByName("LUT1") + if not PySpin.IsAvailable(lut_selector_lut1) or not PySpin.IsReadable(lut_selector_lut1): + print_retrieve_node_failure("entry", "LUTSelector LUT1") + return False + + lut_selector.SetIntValue(lut_selector_lut1.GetValue()) + print("Lookup table selector set to LUT 1...\n") + + # Determine pixel increment and set indexes and values as desired + # + # *** NOTES *** + # To get the pixel increment, the maximum range of the value node must + # first be retrieved. The value node represents an index, so its value + # should be one less than a power of 2 (e.g. 511, 1023, etc.). Add 1 to + # this index to get the maximum range. Divide the maximum range by 512 + # to calculate the pixel increment. + # + # Finally, all values (in the value node) and their corresponding + # indexes (in the index node) need to be set. The goal of this example + # is to set the lookup table linearly. As such, the slope of the values + # should be set according to the increment, but the slope of the + # indexes is inconsequential. + + # Retrieve value node + lut_value = PySpin.CIntegerPtr(nodemap.GetNode("LUTValue")) + if not PySpin.IsAvailable(lut_value) or not PySpin.IsWritable(lut_value): + print_retrieve_node_failure("node", "LUTValue") + return False + + # Retrieve maximum range + max_range = lut_value.GetMax() + 1 + print("\tMaximum Range: {}".format(max_range)) + + # Calculate increment + increment = max_range / 512 + print("\tIncrement: {}".format(increment)) + + # Retrieve index node + lut_index = PySpin.CIntegerPtr(nodemap.GetNode("LUTIndex")) + if not PySpin.IsAvailable(lut_index) or not PySpin.IsWritable(lut_index): + print_retrieve_node_failure("node", "LUTIndex") + return False + + # Set values and indexes + i = 0 + while i < max_range: + lut_index.SetValue(int(i)) + lut_value.SetValue(int(i)) + i += increment + + print("All lookup table values set...\n") + + # Enable lookup tables + # + # *** NOTES *** + # Once lookup tables have been configured, don"t forget to enable them + # with the appropriate node. + # + # *** LATER *** + # Once the images with lookup tables have been collected, turn the + # feature off with the same node. + + lut_enable = PySpin.CBooleanPtr(nodemap.GetNode("LUTEnable")) + if not PySpin.IsAvailable(lut_enable) or not PySpin.IsWritable(lut_enable): + print_retrieve_node_failure("node", "LUTEnable") + return False + + lut_enable.SetValue(True) + print("Lookup tables enabled...\n") + + except PySpin.SpinnakerException as ex: + print("Error: {}".format(ex)) + result = False + + return result + + +def reset_lookup_tables(nodemap): + """ + This function resets the camera by disabling lookup tables. + + :param nodemap: Device nodemap. + :type nodemap: INodeMap + :return: returns True if successful, False otherwise + :rtype: bool + """ + result = True + + # Disable lookup tables + # + # *** NOTES *** + # Turn lookup tables off when they are not needed to reduce overhead + + try: + lut_enable = PySpin.CBooleanPtr(nodemap.GetNode("LUTEnable")) + if not PySpin.IsAvailable(lut_enable) or not PySpin.IsWritable(lut_enable): + print("Unable to disable lookup tables. Non-fatal error...\n") + return False + + lut_enable.SetValue(False) + print("Lookup tables disabled...\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: Device nodemap. + :type nodemap: INodeMap + :return: returns True if successful, False otherwise + :rtype: bool + """ + result = True + print("*** DEVICE INFORMATION ***\n") + + try: + 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) + if PySpin.IsReadable(node_feature): + feature_string = node_feature.ToString() + else: + feature_string = "Node not readable" + + print("{}: {}".format(node_feature.GetName(), feature_string)) + + else: + print("Device control information not available.") + + except PySpin.SpinnakerException as ex: + print("Error: {}".format(ex)) + result = False + + return result + + +def acquire_images(cam, nodemap, nodemap_tl_device): + """ + 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 + :param nodemap: Device nodemap + :param nodemap_tl_device: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tl_device: INodeMap + :return: returns True if successful, False otherwise + :rtype: bool + """ + result = True + print("*** IMAGE ACQUISITION ***\n") + + # Set acquisition mode to continuous + try: + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode("AcquisitionMode")) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print("Unable to set acquisition mode to continuous (node retrieval). Aborting...\n") + return False + + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName("Continuous") + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or \ + not PySpin.IsReadable(node_acquisition_mode_continuous): + print("Unable to set acquisition mode to continuous (entry 'continuous' retrieval). Aborting...\n") + 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...\n") + + # Begin acquiring images + cam.BeginAcquisition() + print("Acquiring images...\n") + + # Retrieve device serial number for filename + device_serial_number = "" + node_device_serial_number = PySpin.CStringPtr(nodemap_tl_device.GetNode("DeviceSerialNumber")) + if PySpin.IsAvailable(node_device_serial_number) and 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 + for i in range(NUM_IMAGES): + try: + + # Retrieve next received image and ensure image completion + image_result = cam.GetNextImage(1000) + + 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 = image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + # Create a unique filename + if device_serial_number: + filename = "LookupTable-{}-{}.jpg".format(device_serial_number, i) + else: # if serial number is empty + filename = "LookupTable-{}.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)) + result = 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 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: returns True if successful, False otherwise + :rtype: bool + """ + result = True + + try: + # Retrieve TL device nodemap and print device information + nodemap_tl_device = cam.GetTLDeviceNodeMap() + + result &= print_device_info(nodemap_tl_device) + + # Initialize camera + cam.Init() + + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + + # Configure lookup tables + result &= configure_lookup_tables(nodemap) + if not result: + return result + + # Acquire images + result &= acquire_images(cam, nodemap, nodemap_tl_device) + + # Reset lookup tables + result &= reset_lookup_tables(nodemap) + + # Deinitialize camera + cam.DeInit() + except PySpin.SpinnakerException as ex: + print("Error: {}".format(ex)) + result = False + + return result + + +def main(): + """ + 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. + + :return: returns True if successful, False otherwise + :rtype: bool + """ + try: + test_file = open("test.txt", "w+") + except IOError: + print("Unable to write to current directory. Please check permissions.\n") + 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!\n") + 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) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/Network_Classification b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Network_Classification new file mode 100644 index 0000000..a7a5513 Binary files /dev/null and b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Network_Classification differ diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/Network_Detection b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Network_Detection new file mode 100644 index 0000000..838b384 Binary files /dev/null and b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Network_Detection differ diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/NodeMapCallback.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/NodeMapCallback.py new file mode 100644 index 0000000..0db4cc7 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/NodeMapCallback.py @@ -0,0 +1,424 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# NodeMapCallback.py shows how to use nodemap callbacks. It relies +# on information provided in the Enumeration, Acquisition, and NodeMapInfo +# examples. As callbacks are very similar to events, it may be a good idea to +# explore this example prior to tackling the events examples. +# +# This example focuses on creating, registering, using, and unregistering +# callbacks. A callback requires a callback class with a callback function signature, +# which allows it to be registered to and access a node. Events follow this same pattern. +# +# Once comfortable with NodeMapCallback, we suggest checking out any of the +# events examples: DeviceEvents, EnumerationEvents, ImageEvents, or Logging. + +import PySpin +import sys + + +class HeightNodeCallback(PySpin.NodeCallback): + """ + This is the first of two callback classes. This callback will be registered to the height node. + Node callbacks must inherit from NodeCallback, and must implement CallbackFunction with the same function signature. + + NOTE: Instances of callback classes must not go out of scope until they are deregistered, otherwise segfaults + will occur. + """ + def __init__(self): + super(HeightNodeCallback, self).__init__() + + def CallbackFunction(self, node): + """ + This function gets called when the height node changes and triggers a callback. + + :param node: Height node. + :type node: INode + :rtype: None + """ + node_height = PySpin.CIntegerPtr(node) + print('Height callback message:\n\tLook! Height changed to %f...\n' % node_height.GetValue()) + + +class GainNodeCallback(PySpin.NodeCallback): + """ + This is the second callback class, registered to the gain node. + """ + def __init__(self): + super(GainNodeCallback, self).__init__() + + def CallbackFunction(self, node): + """ + This function gets called when the gain node changes and triggers a callback. + + :param node: Gain node. + :type node: INode + :rtype: None + """ + node_gain = PySpin.CFloatPtr(node) + print('Gain callback message:\n\tLook! Gain changed to %f...\n' % node_gain.GetValue()) + + +def configure_callbacks(nodemap): + """ + This function sets up the example by disabling automatic gain, creating the callbacks, and registering them to + their specific nodes. + + :param nodemap: Device nodemap. + :type nodemap: INodeMap + :returns: tuple (result, callback_height, callback_gain) + WHERE + result is True if successful, False otherwise + callback_height is the HeightNodeCallback instance registered to the height node + callback_gain is the GainNodeCallback instance registered to the gain node + :rtype: (bool, HeightNodeCallback, GainNodeCallback) + """ + print('\n*** CONFIGURING CALLBACKS ***\n') + try: + result = True + + # Turn off automatic gain + # + # *** NOTES *** + # Automatic gain prevents the manual configuration of gain and needs to + # be turned off for this example. + # + # *** LATER *** + # Automatic exposure is turned off 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.IsAvailable(node_gain_auto) or not PySpin.IsWritable(node_gain_auto): + print('Unable to disable automatic gain (node retrieval). Aborting...') + return False + + node_gain_auto_off = PySpin.CEnumEntryPtr(node_gain_auto.GetEntryByName('Off')) + if not PySpin.IsAvailable(node_gain_auto_off) or not PySpin.IsReadable(node_gain_auto_off): + print('Unable to disable automatic gain (enum entry retrieval). Aborting...') + return False + + node_gain_auto.SetIntValue(node_gain_auto_off.GetValue()) + print('Automatic gain disabled...') + + # Register callback to height node + # + # *** NOTES *** + # Callbacks need to be registered to nodes, which should be writable + # if the callback is to ever be triggered. Also ensure that the callback + # instance does not go out of scope, as it will get garbage-collected + # and a segfault will result once the callback actually occurs. + # + # *** LATER *** + # Each callback needs to be unregistered individually before releasing + # the system or an exception will be thrown. + node_height = PySpin.CIntegerPtr(nodemap.GetNode('Height')) + if not PySpin.IsAvailable(node_height) or not PySpin.IsWritable(node_height): + print('Unable to retrieve height. Aborting...\n') + return False + + print('Height ready...') + + callback_height = HeightNodeCallback() + PySpin.RegisterNodeCallback(node_height.GetNode(), callback_height) + + print('Height callback registered...') + + # Register callback to gain node + # + # *** NOTES *** + # Depending on the specific goal of the function, it can be important + # to notice the node type that a callback is registered to. Notice in + # the callback functions above that the callback registered to height + # casts its node as an integer whereas the callback registered to gain + # casts as a float. + # + # *** LATER *** + # Each callback needs to be unregistered individually before releasing + # the system or an exception will be thrown. + node_gain = PySpin.CFloatPtr(nodemap.GetNode('Gain')) + if not PySpin.IsAvailable(node_gain) or not PySpin.IsWritable(node_gain): + print('Unable to retrieve gain. Aborting...\n') + return False + + print('Gain ready...') + + callback_gain = GainNodeCallback() + PySpin.RegisterNodeCallback(node_gain.GetNode(), callback_gain) + print('Gain callback registered...\n') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result, callback_height, callback_gain + + +def change_height_and_gain(nodemap): + """ + This function demonstrates the triggering of the nodemap callbacks. First it + changes height, which executes the callback registered to the height node, and + then it changes gain, which executes the callback registered to the gain node. + + :param nodemap: Device nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n***CHANGE HEIGHT & GAIN ***\n') + + try: + result = True + + # Change height to trigger height callback + # + # *** NOTES *** + # Notice that changing the height only triggers the callback function + # registered to the height node. + node_height = PySpin.CIntegerPtr(nodemap.GetNode('Height')) + if not PySpin.IsAvailable(node_height) or not PySpin.IsWritable(node_height) \ + or node_height.GetInc() == 0 or node_height.GetMax() == 0: + + print('Unable to retrieve height. Aborting...') + return False + + height_to_set = node_height.GetMax() + + print('Regular function message:\n\tHeight about to be changed to %i...\n' % height_to_set) + + node_height.SetValue(height_to_set) + + # Change gain to trigger gain callback + # + # *** NOTES *** + # The same is true of changing the gain node; changing a node will + # only ever trigger the callback function (or functions) currently + # registered to it. + node_gain = PySpin.CFloatPtr(nodemap.GetNode('Gain')) + if not PySpin.IsAvailable(node_gain) or not PySpin.IsWritable(node_gain) or node_gain.GetMax() == 0: + print('Unable to retrieve gain...') + return False + + gain_to_set = node_gain.GetMax() / 2.0 + + print('Regular function message:\n\tGain about to be changed to %f...\n' % gain_to_set) + node_gain.SetValue(gain_to_set) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def reset_callbacks(nodemap, callback_height, callback_gain): + """ + This function cleans up the example by deregistering the callbacks and + turning automatic gain back on. + + :param nodemap: Device nodemap. + :param callback_height: Height node callback instance to deregister. + :param callback_gain: Gain node callback instance to deregister. + :type nodemap: INodeMap + :type callback_height: HeightNodeCallback + :type callback_gain: GainNodeCallback + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Deregister callbacks + # + # *** NOTES *** + # It is important to deregister each callback function from each node + # that it is registered to. + PySpin.DeregisterNodeCallback(callback_height) + PySpin.DeregisterNodeCallback(callback_gain) + + print('Callbacks deregistered...') + + # Turn automatic gain back on + # + # *** NOTES *** + # Automatic gain is turned back on in order to restore the camera to + # its default state. + node_gain_auto = PySpin.CEnumerationPtr(nodemap.GetNode('GainAuto')) + if not PySpin.IsAvailable(node_gain_auto) or not PySpin.IsWritable(node_gain_auto): + print('Unable to enable automatic gain (node retrieval). Aborting...') + return False + + node_gain_auto_continuous = PySpin.CEnumEntryPtr(node_gain_auto.GetEntryByName('Continuous')) + if not PySpin.IsAvailable(node_gain_auto_continuous) or not PySpin.IsReadable(node_gain_auto_continuous): + print('Unable to enable automatic gain (enum entry retrieval). Aborting...') + return False + + node_gain_auto.SetIntValue(node_gain_auto_continuous.GetValue()) + print('Automatic gain 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 setup and 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 callbacks + err, callback_height, callback_gain = configure_callbacks(nodemap) + if not err: + return err + + # Change height and gain to trigger callbacks + result &= change_height_and_gain(nodemap) + + # Reset callbacks + result &= reset_callbacks(nodemap, callback_height, callback_gain) + + # Deinitialize camera + cam.DeInit() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return 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 instance + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + return result + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/NodeMapInfo.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/NodeMapInfo.py new file mode 100644 index 0000000..c8224cc --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/NodeMapInfo.py @@ -0,0 +1,576 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# NodeMapInfo.py shows how to retrieve node map information. It relies +# on information provided in the Enumeration example. Also, check out the +# Acquisition and ExceptionHandling examples if you haven't already. +# Acquisition demonstrates image acquisition while ExceptionHandling shows the +# handling of standard and Spinnaker exceptions. +# +# This example explores retrieving information from all major node types on the +# camera. This includes string, integer, float, boolean, command, enumeration, +# category, and value types. Looping through multiple child nodes is also +# covered. A few node types are not covered - base, port, and register - as +# they are not fundamental. The final node type - enumeration entry - is +# explored only in terms of its parent node type - enumeration. +# +# Once comfortable with NodeMapInfo, we suggest checking out ImageFormatControl +# and Exposure. ImageFormatControl explores customizing image settings on a +# camera while Exposure introduces the standard structure of configuring a +# device, acquiring some images, and then returning the device to a default +# state. + +import PySpin +import sys + +# Defines max number of characters that will be printed out for any node information +MAX_CHARS = 35 + + +class ReadType: + """ + Use the following constants to determine whether nodes are read + as Value nodes or their individual types. + """ + VALUE = 0, + INDIVIDUAL = 1 + +CHOSEN_READ = ReadType.INDIVIDUAL + + +def print_with_indent(level, text): + """ + Helper function for printing a string prefix with a specifc number of indents. + :param level: Number of indents to generate + :type level: int + :param text: String to print after indent + :type text: str + """ + ind = '' + for i in range(level): + ind += ' ' + print('%s%s' % (ind, text)) + + +def print_value_node(node, level): + """ + Retrieves and prints the display name and value of all node types as value nodes. + A value node is a general node type that allows for the reading and writing of any node type as a string. + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create value node + node_value = PySpin.CValuePtr(node) + + # Retrieve display name + # + # *** NOTES *** + # A node's 'display name' is generally more appropriate for output and + # user interaction whereas its 'name' is what the camera understands. + # Generally, its name is the same as its display name but without + # spaces - for instance, the name of the node that houses a camera's + # serial number is 'DeviceSerialNumber' while its display name is + # 'Device Serial Number'. + display_name = node_value.GetDisplayName() + + # Retrieve value of any node type as string + # + # *** NOTES *** + # Because value nodes return any node type as a string, it can be much + # easier to deal with nodes as value nodes rather than their actual + # individual types. + value = node_value.ToString() + + # Cap length at MAX_CHARS + value = value[:MAX_CHARS] + '...' if len(value) > MAX_CHARS else value + + # Print value + print_with_indent(level, '%s: %s' % (display_name, value)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_string_node(node, level): + """ + Retrieves and prints the display name and value of a string node. + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create string node + node_string = PySpin.CStringPtr(node) + + # Retrieve string node value + # + # *** NOTES *** + # Functions in Spinnaker C++ that use gcstring types + # are substituted with Python strings in PySpin. + # The only exception is shown in the DeviceEvents example, where + # the callback function still uses a wrapped gcstring type. + display_name = node_string.GetDisplayName() + + # Ensure that the value length is not excessive for printing + value = node_string.GetValue() + value = value[:MAX_CHARS] + '...' if len(value) > MAX_CHARS else value + + # Print value; 'level' determines the indentation level of output + print_with_indent(level, '%s: %s' % (display_name, value)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_integer_node(node, level): + """ + Retrieves and prints the display name and value of an integer node. + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create integer node + node_integer = PySpin.CIntegerPtr(node) + + # Get display name + display_name = node_integer.GetDisplayName() + + # Retrieve integer node value + # + # *** NOTES *** + # All node types except base nodes have a ToString() + # method which returns a value as a string. + value = node_integer.GetValue() + + # Print value + print_with_indent(level, '%s: %s' % (display_name, value)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_float_node(node, level): + """ + Retrieves and prints the display name and value of a float node. + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create float node + node_float = PySpin.CFloatPtr(node) + + # Get display name + display_name = node_float.GetDisplayName() + + # Retrieve float value + value = node_float.GetValue() + + # Print value + print_with_indent(level, '%s: %s' % (display_name, value)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_boolean_node(node, level): + """ + Retrieves and prints the display name and value of a Boolean node. + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create Boolean node + node_boolean = PySpin.CBooleanPtr(node) + + # Get display name + display_name = node_boolean.GetDisplayName() + + # Retrieve Boolean value + value = node_boolean.GetValue() + + # Print Boolean value + # NOTE: In Python a Boolean will be printed as "True" or "False". + print_with_indent(level, '%s: %s' % (display_name, value)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_command_node(node, level): + """ + This function retrieves and prints the display name and tooltip of a command + node, limiting the number of printed characters to a macro-defined maximum. + The tooltip is printed below because command nodes do not have an intelligible + value. + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create command node + node_command = PySpin.CCommandPtr(node) + + # Get display name + display_name = node_command.GetDisplayName() + + # Retrieve tooltip + # + # *** NOTES *** + # All node types have a tooltip available. Tooltips provide useful + # information about nodes. Command nodes do not have a method to + # retrieve values as their is no intelligible value to retrieve. + tooltip = node_command.GetToolTip() + + # Ensure that the value length is not excessive for printing + tooltip = tooltip[:MAX_CHARS] + '...' if len(tooltip) > MAX_CHARS else tooltip + + # Print display name and tooltip + print_with_indent(level, '%s: %s' % (display_name, tooltip)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_enumeration_node_and_current_entry(node, level): + """ + This function retrieves and prints the display names of an enumeration node + and its current entry (which is actually housed in another node unto itself). + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create enumeration node + node_enumeration = PySpin.CEnumerationPtr(node) + + # Retrieve current entry as enumeration node + # + # *** NOTES *** + # Enumeration nodes have three methods to differentiate between: first, + # GetIntValue() returns the integer value of the current entry node; + # second, GetCurrentEntry() returns the entry node itself; and third, + # ToString() returns the symbolic of the current entry. + node_enum_entry = PySpin.CEnumEntryPtr(node_enumeration.GetCurrentEntry()) + + # Get display name + display_name = node_enumeration.GetDisplayName() + + # Retrieve current symbolic + # + # *** NOTES *** + # Rather than retrieving the current entry node and then retrieving its + # symbolic, this could have been taken care of in one step by using the + # enumeration node's ToString() method. + entry_symbolic = node_enum_entry.GetSymbolic() + + # Print current entry symbolic + print_with_indent(level, '%s: %s' % (display_name, entry_symbolic)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_category_node_and_all_features(node, level): + """ + This function retrieves and prints out the display name of a category node + before printing all child nodes. Child nodes that are also category nodes are + printed recursively. + + :param node: Category node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create category node + node_category = PySpin.CCategoryPtr(node) + + # Get and print display name + display_name = node_category.GetDisplayName() + print_with_indent(level, display_name) + + # Retrieve and iterate through all children + # + # *** NOTES *** + # The two nodes that typically have children are category nodes and + # enumeration nodes. Throughout the examples, the children of category nodes + # are referred to as features while the children of enumeration nodes are + # referred to as entries. Keep in mind that enumeration nodes can be cast as + # category nodes, but category nodes cannot be cast as enumerations. + for node_feature in node_category.GetFeatures(): + + # Ensure node is available and readable + if not PySpin.IsAvailable(node_feature) or not PySpin.IsReadable(node_feature): + continue + + # Category nodes must be dealt with separately in order to retrieve subnodes recursively. + if node_feature.GetPrincipalInterfaceType() == PySpin.intfICategory: + result &= print_category_node_and_all_features(node_feature, level + 1) + + # Cast all non-category nodes as value nodes + # + # *** NOTES *** + # If dealing with a variety of node types and their values, it may be + # simpler to cast them as value nodes rather than as their individual types. + # However, with this increased ease-of-use, functionality is sacrificed. + elif CHOSEN_READ == ReadType.VALUE: + result &= print_value_node(node_feature, level + 1) + + # Cast all non-category nodes as actual types + elif CHOSEN_READ == ReadType.INDIVIDUAL: + if node_feature.GetPrincipalInterfaceType() == PySpin.intfIString: + result &= print_string_node(node_feature, level + 1) + elif node_feature.GetPrincipalInterfaceType() == PySpin.intfIInteger: + result &= print_integer_node(node_feature, level + 1) + elif node_feature.GetPrincipalInterfaceType() == PySpin.intfIFloat: + result &= print_float_node(node_feature, level + 1) + elif node_feature.GetPrincipalInterfaceType() == PySpin.intfIBoolean: + result &= print_boolean_node(node_feature, level + 1) + elif node_feature.GetPrincipalInterfaceType() == PySpin.intfICommand: + result &= print_command_node(node_feature, level + 1) + elif node_feature.GetPrincipalInterfaceType() == PySpin.intfIEnumeration: + result &= print_enumeration_node_and_current_entry(node_feature, level + 1) + + print('') + + 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. First nodes from the TL + device and TL stream nodemaps are retrieved and printed. Following this, + the camera is initialized and then nodes from the GenICam nodemap are + retrieved and printed. + + :param cam: Camera to get nodemaps from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + level = 0 + + # Retrieve TL device nodemap + # + # *** NOTES *** + # The TL device nodemap is available on the transport layer. As such, + # camera initialization is unnecessary. It provides mostly immutable + # information fundamental to the camera such as the serial number, + # vendor, and model. + print('\n*** PRINTING TRANSPORT LAYER DEVICE NODEMAP *** \n') + + nodemap_gentl = cam.GetTLDeviceNodeMap() + + result &= print_category_node_and_all_features(nodemap_gentl.GetNode('Root'), level) + + # Retrieve TL stream nodemap + # + # *** NOTES *** + # The TL stream nodemap is also available on the transport layer. Camera + # initialization is again unnecessary. As you can probably guess, it + # provides information on the camera's streaming performance at any + # given moment. Having this information available on the transport layer + # allows the information to be retrieved without affecting camera performance. + print('*** PRINTING TL STREAM NODEMAP ***\n') + + nodemap_tlstream = cam.GetTLStreamNodeMap() + + result &= print_category_node_and_all_features(nodemap_tlstream.GetNode('Root'), level) + + # Initialize camera + # + # *** NOTES *** + # The camera becomes connected upon initialization. This provides + # access to configurable options and additional information, accessible + # through the GenICam nodemap. + # + # *** LATER *** + # Cameras should be deinitialized when no longer needed. + print('*** PRINTING GENICAM NODEMAP ***\n') + + cam.Init() + + # Retrieve GenICam nodemap + # + # *** NOTES *** + # The GenICam nodemap is the primary gateway to customizing + # and configuring the camera to suit your needs. Configuration options + # such as image height and width, trigger mode enabling and disabling, + # and the sequencer are found on this nodemap. + nodemap_applayer = cam.GetNodeMap() + + result &= print_category_node_and_all_features(nodemap_applayer.GetNode('Root'), level) + + # Deinitialize camera + # + # *** NOTES *** + # Camera deinitialization helps ensure that devices clean up properly + # and do not need to be power-cycled to maintain integrity. + cam.DeInit() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return True + + +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 instance + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + return result + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/NodeMapInfo_QuickSpin.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/NodeMapInfo_QuickSpin.py new file mode 100644 index 0000000..3381bb6 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/NodeMapInfo_QuickSpin.py @@ -0,0 +1,359 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# NodeMapInfo_QuickSpin.py shows how to interact with nodes +# using the QuickSpin API. QuickSpin is a subset of the Spinnaker library +# that allows for simpler node access and control. +# +# This example demonstrates the retrieval of information from both the +# transport layer and the camera. Because the focus of this example is node +# access, which is where QuickSpin and regular Spinnaker differ, this +# example differs from NodeMapInfo quite a bit. +# +# 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 + + +def print_transport_layer_device_info(cam): + """ + Prints device information from the transport layer. + + *** NOTES *** + In QuickSpin, accessing device information on the transport layer is + accomplished via a camera's TLDevice property. The TLDevice property + houses nodes related to general device information such as the three + demonstrated below, device access status, XML and GUI paths and + locations, and GEV information to name a few. The TLDevice property + allows access to nodes that would generally be retrieved through the + TL device nodemap in full Spinnaker. + + Notice that each node is checked for availability and readability + prior to value retrieval. Checking for availability and readability + (or writability when applicable) whenever a node is accessed is + important in terms of error handling. If a node retrieval error + occurs but remains unhandled, an exception is thrown. + + :param cam: Camera to get information from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Print device serial number + if cam.TLDevice.DeviceSerialNumber.GetAccessMode() == PySpin.RO: + print('Device serial number: %s' % cam.TLDevice.DeviceSerialNumber.ToString()) + + else: + print('Device serial number: unavailable') + result = False + + # Print device vendor name + # + # *** NOTE *** + # To check node readability/writability, you can either + # compare its access mode with RO, RW, etc. or you can use + # the IsReadable/IsWritable functions on the node. + if PySpin.IsReadable(cam.TLDevice.DeviceVendorName): + print('Device vendor name: %s' % cam.TLDevice.DeviceVendorName.ToString()) + else: + print('Device vendor name: unavailable') + result = False + + # Print device display name + if PySpin.IsReadable(cam.TLDevice.DeviceDisplayName): + print('Device display name: %s' % cam.TLDevice.DeviceDisplayName.ToString()) + else: + print('Device display name: unavailable') + result = False + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_transport_layer_stream_info(cam): + """ + Prints stream information from transport layer. + + *** NOTES *** + In QuickSpin, accessing stream information on the transport layer is + accomplished via a camera's TLStream property. The TLStream property + houses nodes related to streaming such as the two demonstrated below, + buffer information, and GEV packet information to name a few. The + TLStream property allows access to nodes that would generally be + retrieved through the TL stream nodemap in full Spinnaker. + + :param cam: Camera to get information from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Print stream ID + if cam.TLStream.StreamID.GetAccessMode() == PySpin.RO: + print('Stream ID: %s' % cam.TLStream.StreamID.ToString()) + else: + print('Stream ID: unavailable') + result = False + + # Print stream type + if PySpin.IsReadable(cam.TLStream.StreamType): + print('Stream type: %s' % cam.TLStream.StreamType.ToString()) + else: + print('Stream type: unavailable') + result = False + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_transport_layer_interface_info(interface): + """ + Prints stream information from the transport layer. + + *** NOTES *** + In QuickSpin, accessing interface information is accomplished via an + interface's TLInterface property. The TLInterface property houses + nodes that hold information about the interface such as the three + demonstrated below, other general interface information, and + GEV addressing information. The TLInterface property allows access to + nodes that would generally be retrieved through the interface nodemap + in full Spinnaker. + + Interface nodes should also always be checked for availability and + readability (or writability when applicable). If a node retrieval + error occurs but remains unhandled, an exception is thrown. + + :param interface: Interface to get information from. + :type interface: InterfacePtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Print interface display name + if interface.TLInterface.InterfaceDisplayName.GetAccessMode() == PySpin.RO: + print('Interface display name: %s' % interface.TLInterface.InterfaceDisplayName.ToString()) + else: + print('Interface display name: unavailable') + result = False + + # Print interface ID + if interface.TLInterface.InterfaceID.GetAccessMode() == PySpin.RO: + print('Interface ID: %s' % interface.TLInterface.InterfaceID.ToString()) + else: + print('Interface ID: unavailable') + result = False + + # Print interface type + if PySpin.IsReadable(interface.TLInterface.InterfaceType.GetAccessMode()): + print('Interface type: %s' % interface.TLInterface.InterfaceType.ToString()) + else: + print('Interface type: unavailable') + result = False + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_genicam_device_info(cam): + """ + Prints device information from the camera. + + *** NOTES *** + Most camera interaction happens through GenICam nodes. The + advantages of these nodes is that there is a lot more of them, they + allow for a much deeper level of interaction with a camera, and no + intermediate property (i.e. TLDevice or TLStream) is required. The + disadvantage is that they require initialization. + + :param cam: Camera to get information from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Print exposure time + if cam.ExposureTime.GetAccessMode() == PySpin.RO or cam.ExposureTime.GetAccessMode() == PySpin.RW: + print('Exposure time: %s' % cam.ExposureTime.ToString()) + else: + print('Exposure time: unavailable') + result = False + + # Print black level + if PySpin.IsReadable(cam.BlackLevel): + print('Black level: %s' % cam.BlackLevel.ToString()) + else: + print('Black level: unavailable') + result = False + + # Print height + if PySpin.IsReadable(cam.Height): + print('Height: %s' % cam.Height.ToString()) + else: + print('Height: unavailable') + result = False + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def main(): + """ + Example entry point; this function prints transport layer information from + each interface and transport and GenICam information from each camera. + + :return: True if successful, False otherwise. + :rtype: bool + """ + result = True + + # Retrieve singleton reference to system object + sys = PySpin.System.GetInstance() + + # Get current library version + version = sys.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 = sys.GetCameras() + + num_cams = cam_list.GetSize() + + print('Number of cameras detected: %i \n' % num_cams) + + # Finish if there are no cameras + if num_cams == 0: + # Clear camera list before releasing system + cam_list.Clear() + + # Release system instance + sys.ReleaseInstance() + + print('Not enough cameras!') + input('Done! Press Enter to exit...') + return False + + # Retrieve list of interfaces from the system + iface_list = sys.GetInterfaces() + + num_ifaces = iface_list.GetSize() + + print('Number of interfaces detected: %i \n' % num_ifaces) + + # Print information on each interface + # + # *** NOTES *** + # All USB 3 Vision and GigE Vision interfaces should enumerate for + # Spinnaker. + print('\n*** PRINTING INTERFACE INFORMATION ***\n') + + for iface in iface_list: + result &= print_transport_layer_interface_info(iface) + + # Release reference to interface + # 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 iface + + # Print general device information on each camera from transport layer + # + # *** NOTES *** + # Transport layer nodes do not require initialization in order to interact + # with them. + print('\n*** PRINTING TRANSPORT LAYER DEVICE INFORMATION ***\n') + + for cam in cam_list: + result &= print_transport_layer_device_info(cam) + + # Print streaming information on each camera from transport layer + # + # *** NOTES *** + # Again, initialization is not required to print information from the + # transport layer; this is equally true of streaming information. + print('\n*** PRINTING TRANSPORT LAYER STREAMING INFORMATION ***\n') + + for cam in cam_list: + result &= print_transport_layer_stream_info(cam) + + # Print device information on each camera from GenICam nodemap + # + # *** NOTES *** + # GenICam nodes require initialization in order to interact with + # them; as such, this loop initializes the camera, prints some information + # from the GenICam nodemap, and then deinitializes it. If the camera were + # not initialized, node availability would fail. + print('\n*** PRINTING GENICAM INFORMATION ***\n') + + for cam in cam_list: + # Initialize camera + cam.Init() + + # Print info + result &= print_genicam_device_info(cam) + + # Deinitialize camera + cam.DeInit() + + # 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() + + # Clear interface list before releasing system + iface_list.Clear() + + # Release system instance + sys.ReleaseInstance() + + input('\nDone! Press Enter to exit...') + return result + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/SaveToAvi.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/SaveToAvi.py new file mode 100644 index 0000000..1f79203 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/SaveToAvi.py @@ -0,0 +1,378 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# SaveToAvi.py shows how to create an AVI video from a vector of +# images. It relies on information provided in the Enumeration, Acquisition, +# and NodeMapInfo examples. +# +# This example introduces the SpinVideo class, which is used to quickly and +# easily create various types of AVI videos. It demonstrates the creation of +# three types: uncompressed, MJPG, and H264. + +import PySpin +import sys + + +class AviType: + """'Enum' to select AVI video type to be created and saved""" + UNCOMPRESSED = 0 + MJPG = 1 + H264 = 2 + +chosenAviType = AviType.UNCOMPRESSED # change me! +NUM_IMAGES = 10 # number of images to use in AVI file + + +def save_list_to_avi(nodemap, nodemap_tldevice, images): + """ + This function prepares, saves, and cleans up an AVI video from a vector of images. + + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :param images: List of images to save to an AVI video. + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :type images: list of ImagePtr + :return: True if successful, False otherwise. + :rtype: bool + """ + print('*** CREATING VIDEO ***') + + try: + result = True + + # Retrieve device serial number for filename + device_serial_number = '' + node_serial = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + + if PySpin.IsAvailable(node_serial) and PySpin.IsReadable(node_serial): + device_serial_number = node_serial.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Get the current frame rate; acquisition frame rate recorded in hertz + # + # *** NOTES *** + # The video frame rate can be set to anything; however, in order to + # have videos play in real-time, the acquisition frame rate can be + # retrieved from the camera. + + node_acquisition_framerate = PySpin.CFloatPtr(nodemap.GetNode('AcquisitionFrameRate')) + + if not PySpin.IsAvailable(node_acquisition_framerate) and not PySpin.IsReadable(node_acquisition_framerate): + print('Unable to retrieve frame rate. Aborting...') + return False + + framerate_to_set = node_acquisition_framerate.GetValue() + + print('Frame rate to be set to %d...' % framerate_to_set) + + # Select option and open AVI filetype with unique filename + # + # *** NOTES *** + # Depending on the filetype, a number of settings need to be set in + # an object called an option. An uncompressed option only needs to + # have the video frame rate set whereas videos with MJPG or H264 + # compressions should have more values set. + # + # Once the desired option object is configured, open the AVI file + # with the option in order to create the image file. + # + # Note that the filename does not need to be appended to the + # name of the file. This is because the AVI recorder object takes care + # of the file extension automatically. + # + # *** LATER *** + # Once all images have been added, it is important to close the file - + # this is similar to many other standard file streams. + + avi_recorder = PySpin.SpinVideo() + + if chosenAviType == AviType.UNCOMPRESSED: + avi_filename = 'SaveToAvi-Uncompressed-%s' % device_serial_number + + option = PySpin.AVIOption() + option.frameRate = framerate_to_set + + elif chosenAviType == AviType.MJPG: + avi_filename = 'SaveToAvi-MJPG-%s' % device_serial_number + + option = PySpin.MJPGOption() + option.frameRate = framerate_to_set + option.quality = 75 + + elif chosenAviType == AviType.H264: + avi_filename = 'SaveToAvi-H264-%s' % device_serial_number + + option = PySpin.H264Option() + option.frameRate = framerate_to_set + option.bitrate = 1000000 + option.height = images[0].GetHeight() + option.width = images[0].GetWidth() + + else: + print('Error: Unknown AviType. Aborting...') + return False + + avi_recorder.Open(avi_filename, option) + + # Construct and save AVI video + # + # *** NOTES *** + # Although the video file has been opened, images must be individually + # appended in order to construct the video. + print('Appending %d images to AVI file: %s.avi...' % (len(images), avi_filename)) + + for i in range(len(images)): + avi_recorder.Append(images[i]) + print('Appended image %d...' % i) + + # Close AVI file + # + # *** NOTES *** + # Once all images have been appended, it is important to close the + # AVI file. Notice that once an AVI file has been closed, no more + # images can be added. + + avi_recorder.Close() + print('Video saved at %s.avi' % avi_filename) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return 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 + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** 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 acquire_images(cam, nodemap): + """ + This function acquires 10 images from a device, stores them in a list, and returns the list. + please see the Acquisition example for more in-depth comments on acquiring images. + + :param cam: Camera to acquire images from. + :param nodemap: Device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :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.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or not PySpin.IsReadable(node_acquisition_mode_continuous): + print('Unable to set acquisition mode to continuous (entry retrieval). Aborting...') + return False + + acquisition_mode_continuous = node_acquisition_mode_continuous.GetValue() + + node_acquisition_mode.SetIntValue(acquisition_mode_continuous) + + print('Acquisition mode set to continuous...') + + # Begin acquiring images + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve, convert, and save images + images = list() + + for i in range(NUM_IMAGES): + try: + # 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; height and width recorded in pixels + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed Image %d, width = %d, height = %d' % (i, width, height)) + + # Convert image to mono 8 and append to list + images.append(image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR)) + + # Release image + image_result.Release() + print('') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + # End acquisition + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result, images + + +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 example 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() + + # Acquire list of images + err, images = acquire_images(cam, nodemap) + if err < 0: + return err + + result &= save_list_to_avi(nodemap, nodemap_tldevice, images) + + # 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:', 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 instance + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + return result + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/Sequencer.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Sequencer.py new file mode 100644 index 0000000..23035c7 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Sequencer.py @@ -0,0 +1,873 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# 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. + +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.IsAvailable(node_sequencer_configuration_valid) \ + or 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.IsAvailable(sequencer_configuration_valid_yes) \ + or 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.IsAvailable(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.IsAvailable(sequencer_mode_off) or 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.IsAvailable(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.IsAvailable(exposure_auto_off) or 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.IsAvailable(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.IsAvailable(gain_auto_off) or 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.IsAvailable(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.IsAvailable(sequencer_configuration_mode_on)\ + or 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.IsAvailable(node_sequencer_set_selector) or 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.IsAvailable(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.IsAvailable(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.IsAvailable(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.IsAvailable(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.IsAvailable(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.IsAvailable(sequencer_trigger_source_frame_start) or \ + 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.IsAvailable(node_sequencer_set_next) or 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.IsAvailable(node_sequencer_set_save) or 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.IsAvailable(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.IsAvailable(sequencer_configuration_mode_off)\ + or 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.IsAvailable(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.IsAvailable(sequencer_mode_on) or 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.IsAvailable(node_sequencer_configuration_valid) \ + or 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.IsAvailable(sequencer_configuration_valid_yes) \ + or 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.IsAvailable(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.IsAvailable(sequencer_mode_off) or 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.IsAvailable(node_exposure_auto) and PySpin.IsWritable(node_exposure_auto): + exposure_auto_continuous = node_exposure_auto.GetEntryByName('Continuous') + if PySpin.IsAvailable(exposure_auto_continuous) and 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.IsAvailable(node_gain_auto) and PySpin.IsWritable(node_gain_auto): + gain_auto_continuous = node_exposure_auto.GetEntryByName('Continuous') + if PySpin.IsAvailable(gain_auto_continuous) and 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.IsAvailable(node_device_information) and 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 available.') + + 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.IsAvailable(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.IsAvailable(node_acquisition_mode_continuous) or \ + 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.IsAvailable(node_device_serial_number) and 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 + 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 = image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + # 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.IsAvailable(node_width) or 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.IsAvailable(node_height) or 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.IsAvailable(node_exposure_time) or 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.IsAvailable(node_exposure_time) or 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) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/SpinUpdate.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/SpinUpdate.py new file mode 100644 index 0000000..409fb80 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/SpinUpdate.py @@ -0,0 +1,89 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# SpinUpdate.py is a sample firmware updater application that takes in +# command line arguments. The example also demonstrates usage of callback +# functions to keep track of current update progress. +# +# Run with arguments in format (no quotes): "-R -P -UU " + +import PySpin +import sys + + +last_action = '' + + +def progress_callback(action, address, global_percent, curr_percent): + """ + Example progress callback function. + NOTE: This function must take exactly 4 arguments, + otherwise the update process will hang/crash! + + :param action: Current action being done in firmware update (as a byte string). + :param address: Address in camera being written to. + :param global_percent: Global completion percentage of update. + :param curr_percent: Completion percentage of current action. + :type action: str + :type address: int + :type global_percent: int + :type curr_percent: int + :rtype: int + """ + global last_action + if action != last_action: + # Prints action only if changed from previous one + print('Action: %s' % action) + last_action = action + + return 1 + + +def message_callback(message): + """ + Example message callback function. + NOTE: This function must take exactly 1 argument, + otherwise the update process will hang/crash! + + :param message: Message from updator (as a byte string). + :type message: str + :rtype: None + """ + print('Message: %s' % message) + + return 1 + + +def main(): + # Register callbacks + PySpin.SetProgressCallback(progress_callback) + PySpin.SetMessageCallback(message_callback) + + # Example usage for firmware update: + # Use either UpdateFirmware() or UpdateFirmwareConsole(): + # + # cmd = "-R3932019 C:\\firmware\\bfly2_u3_python1300.zim" # Add -P to argument list for callbacks + # return UpdateFirmware(cmd); + + return PySpin.UpdateFirmwareConsole(sys.argv) # uses command line args + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/Trigger-20343286-0.jpg b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Trigger-20343286-0.jpg new file mode 100644 index 0000000..1a24b00 Binary files /dev/null and b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Trigger-20343286-0.jpg differ diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/Trigger-20343286-1.jpg b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Trigger-20343286-1.jpg new file mode 100644 index 0000000..8869161 Binary files /dev/null and b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Trigger-20343286-1.jpg differ diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/Trigger-20343286-2.jpg b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Trigger-20343286-2.jpg new file mode 100644 index 0000000..9e72433 Binary files /dev/null and b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Trigger-20343286-2.jpg differ diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/Trigger.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Trigger.py new file mode 100644 index 0000000..aac40ff --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Trigger.py @@ -0,0 +1,516 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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.py shows how to trigger the camera. 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 they are somewhat shorter and simpler, either +# provides a strong introduction to camera customization. +# +# This example shows the process of configuring, using, and cleaning up a +# camera for use with both a software and a hardware trigger. + +import os +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 + set to off in order to select the trigger source. Once the trigger source + has been selected, trigger mode is then enabled, which has the camera + capture only a single image upon the execution of the chosen trigger. + + :param cam: Camera to configure trigger for. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + result = True + + print('*** CONFIGURING TRIGGER ***\n') + + if CHOSEN_TRIGGER == TriggerType.SOFTWARE: + print('Software trigger chosen ...') + elif CHOSEN_TRIGGER == TriggerType.HARDWARE: + print('Hardware trigger chose ...') + + try: + # Ensure trigger mode off + # The trigger must be disabled in order to configure whether the source + # is software or hardware. + nodemap = cam.GetNodeMap() + node_trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerMode')) + if not PySpin.IsAvailable(node_trigger_mode) or not PySpin.IsReadable(node_trigger_mode): + print('Unable to disable trigger mode (node retrieval). Aborting...') + return False + + node_trigger_mode_off = node_trigger_mode.GetEntryByName('Off') + if not PySpin.IsAvailable(node_trigger_mode_off) or not PySpin.IsReadable(node_trigger_mode_off): + print('Unable to disable trigger mode (enum entry retrieval). Aborting...') + return False + + node_trigger_mode.SetIntValue(node_trigger_mode_off.GetValue()) + + 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. + node_trigger_selector= PySpin.CEnumerationPtr(nodemap.GetNode('TriggerSelector')) + if not PySpin.IsAvailable(node_trigger_selector) or not PySpin.IsWritable(node_trigger_selector): + print('Unable to get trigger selector (node retrieval). Aborting...') + return False + + node_trigger_selector_framestart = node_trigger_selector.GetEntryByName('FrameStart') + if not PySpin.IsAvailable(node_trigger_selector_framestart) or not PySpin.IsReadable( + node_trigger_selector_framestart): + print('Unable to set trigger selector (enum entry retrieval). Aborting...') + return False + node_trigger_selector.SetIntValue(node_trigger_selector_framestart.GetValue()) + + 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. + node_trigger_source = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerSource')) + if not PySpin.IsAvailable(node_trigger_source) or not PySpin.IsWritable(node_trigger_source): + print('Unable to get trigger source (node retrieval). Aborting...') + return False + + if CHOSEN_TRIGGER == TriggerType.SOFTWARE: + node_trigger_source_software = node_trigger_source.GetEntryByName('Software') + if not PySpin.IsAvailable(node_trigger_source_software) or not PySpin.IsReadable( + node_trigger_source_software): + print('Unable to set trigger source (enum entry retrieval). Aborting...') + return False + node_trigger_source.SetIntValue(node_trigger_source_software.GetValue()) + print('Trigger source set to software...') + + elif CHOSEN_TRIGGER == TriggerType.HARDWARE: + node_trigger_source_hardware = node_trigger_source.GetEntryByName('Line0') + if not PySpin.IsAvailable(node_trigger_source_hardware) or not PySpin.IsReadable( + node_trigger_source_hardware): + print('Unable to set trigger source (enum entry retrieval). Aborting...') + return False + node_trigger_source.SetIntValue(node_trigger_source_hardware.GetValue()) + 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. + node_trigger_mode_on = node_trigger_mode.GetEntryByName('On') + if not PySpin.IsAvailable(node_trigger_mode_on) or not PySpin.IsReadable(node_trigger_mode_on): + print('Unable to enable trigger mode (enum entry retrieval). Aborting...') + return False + + node_trigger_mode.SetIntValue(node_trigger_mode_on.GetValue()) + 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(nodemap, cam): + """ + This function acquires an image by executing the trigger node. + + :param cam: Camera to acquire images from. + :param nodemap: Device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :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 + node_softwaretrigger_cmd = PySpin.CCommandPtr(nodemap.GetNode('TriggerSoftware')) + if not PySpin.IsAvailable(node_softwaretrigger_cmd) or not PySpin.IsWritable(node_softwaretrigger_cmd): + print('Unable to execute trigger. Aborting...') + return False + + node_softwaretrigger_cmd.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, nodemap, nodemap_tldevice): + """ + 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. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** IMAGE ACQUISITION ***\n') + try: + result = True + + # Set acquisition mode to continuous + # In order to access the node entries, they have to be casted to a pointer type (CEnumerationPtr here) + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.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(nodemap, 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; height and width recorded in pixels + # + # *** NOTES *** + # Images have quite a bit of available metadata including + # things such as CRC, image status, and offset values, to + # name a few. + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed Image %d, width = %d, height = %d' % (i, width, height)) + + # Convert image to mono 8 + # + # *** NOTES *** + # Images can be converted between pixel formats by using + # the appropriate enumeration value. Unlike the original + # image, the converted one does not need to be released as + # it does not affect the camera buffer. + # + # When converting images, color processing algorithm is an + # optional parameter. + 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 + # + # *** NOTES *** + # The standard practice of the examples is to use device + # serial numbers to keep images of one device from + # overwriting those of another. + image_converted.Save(filename) + print('Image saved at %s\n' % filename) + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def reset_trigger(nodemap): + """ + This function returns the camera to a normal state by turning off trigger mode. + + :param nodemap: Transport layer device nodemap. + :type nodemap: INodeMap + :returns: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + node_trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerMode')) + if not PySpin.IsAvailable(node_trigger_mode) or not PySpin.IsReadable(node_trigger_mode): + print('Unable to disable trigger mode (node retrieval). Aborting...') + return False + + node_trigger_mode_off = node_trigger_mode.GetEntryByName('Off') + if not PySpin.IsAvailable(node_trigger_mode_off) or not PySpin.IsReadable(node_trigger_mode_off): + print('Unable to disable trigger mode (enum entry retrieval). Aborting...') + return False + + node_trigger_mode.SetIntValue(node_trigger_mode_off.GetValue()) + + 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, nodemap, nodemap_tldevice) + + # Reset trigger + result &= reset_trigger(nodemap) + + # 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 + """ + + # 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: %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) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/Examples/Trigger_QuickSpin.py b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Trigger_QuickSpin.py new file mode 100644 index 0000000..a1eb67e --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/Examples/Trigger_QuickSpin.py @@ -0,0 +1,419 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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') + + 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.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 + 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 + 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!') + 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) diff --git a/FLIR/FLIRcodev4.0/Spinnaker/README.txt b/FLIR/FLIRcodev4.0/Spinnaker/README.txt new file mode 100644 index 0000000..42057f3 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/README.txt @@ -0,0 +1,342 @@ +============================================================================= +Copyright (c) 2001-2019 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. +============================================================================= + +============================================================================= +== +== README +== +============================================================================= + +PySpin is a wrapper for FLIR Integrated Imaging Solutions' Spinnaker library. + +FLIR Integrated Imaging Solutions' website is located at https://www.flir.com/iis/machine-vision + +The PySpin Python extension provides a common software interface +to control and acquire images from FLIR USB 3.0, GigE, +and USB 2.0 cameras using the same API under 32- or 64-bit Windows. + +============================================================================= +TABLE OF CONTENTS +============================================================================= +1. INSTALLATION +1.1 INSTALLATION ON WINDOWS +1.2 INSTALLATION ON LINUX +1.3 INSTALLATION ON MACOS +2. API DIFFERENCES +3. REMOVE PYSPIN + +============================================================================= +1. INSTALLATION +============================================================================= + +----------------------------------------------------------------------------- +1.1 WINDOWS +----------------------------------------------------------------------------- + +1. Install Python. Currently we support Python 2.7, 3.5, 3.6, and 3.7. To + download Python, visit https://www.python.org/downloads/. Note that the + Python website defaults to 32-bit interpreters, so if you want a 64-bit + version of Python you have to click into the specific release version. + +2. (Optional) Set the PATH environment variable for your Python installation. + This may have been done automatically as part of installation, but to do + this manually you have to open Environment Variables through the following: + + My Computer > Properties > Advanced System Settings > Environment Variables + + Add your Python installation location to your PATH variable. For example, + if you installed Python at C:\Python37\, you would add the following entry + to the PATH variable: + + C:\Python37\ + +3. Configure your Python installation. From a command line, run the following + commands to update and install dependencies for your associated Python version: + + -m ensurepip + -m pip install --upgrade pip numpy matplotlib + + NumPy is a requirement for PySpin and needs to be at least version 1.15 or + above. Matplotlib is not required for the library itself but is used in some + of our examples to highlight possible usages of PySpin. For better support of + matplotlib output image file formats, Pillow is suggested to be installed. + Note: some versions of Pillow might NOT support some Python versions. + + The full list of supported Pillow versions given a Python version can be found here: + https://pillow.readthedocs.io/en/stable/installation.html#notes + + For example, with Python 3.7, install a supported Pillow using the following command: + + ex. py -3.7 -m pip install Pillow==5.2.0 + + Older installations of Python 2.7 do NOT come with enum34, which is required by + the Inference.py Python2 example. Install enum34 for Python 2.7 using the following command: + + py -2.7 -m pip install enum34 + +4. To ensure prerequisites such as drivers and Visual Studio redistributables + are installed on the system, run the Spinnaker SDK installer that corresponds + with the PySpin version number. For example, if installing PySpin 1.8.0.0, + install Spinnaker 1.8.0.0 beforehand, selecting only the Visual Studio + runtimes and drivers. + +5. Run the following command to install PySpin to your associated Python version. + This command assumes you have your PATH variable set correctly for Python: + + -m pip install spinnaker_python-1.x.x.x-cp37-cp37m-win_amd64.whl + + Ensure that the wheel downloaded matches the Python version you are installing to! + +After installation, PySpin examples can be ran directly from the command prompt. +For example, if PySpin is installed for Python 3.7, run a preinstalled example +using the following: + + ex. py -3.7 Examples\Python3\Acquisition.py + +----------------------------------------------------------------------------- +1.2 LINUX +----------------------------------------------------------------------------- + +1. Check that pip is available for your respective Python versions + by running the following command: + + sudo apt-get install python-pip python3-pip + +2. Install library dependencies for PySpin: numpy and matplotlib. NumPy is a + requirement for PySpin and needs to be at least version 1.15 or above. + Matplotlib is not required for the library itself but is used in some of + our examples to highlight possible usages of PySpin. Install these + dependencies by running one of the following commands. + + - Install for Python 2.7, user only: + python -m pip install --upgrade --user numpy matplotlib + + - Install for Python 2.7, site wide: + sudo python -m pip install --upgrade numpy matplotlib + + - Install for Python 3.5, user only (16.04 only): + python3.5 -m pip install --upgrade --user numpy matplotlib + + - Install for Python 3.5, site wide (16.04 only): + sudo python3.5 -m pip install --upgrade numpy matplotlib + + - Install for Python 3.6, user only: + python3.6 -m pip install --upgrade --user numpy matplotlib + + - Install for Python 3.6, site wide: + sudo python3.6 -m pip install --upgrade numpy matplotlib + + - Install for Python 3.7, user only: + python3.7 -m pip install --upgrade --user numpy matplotlib + + - Install for Python 3.7, site wide: + sudo python3.7 -m pip install --upgrade numpy matplotlib + + For better support of matplotlib output image file formats, Pillow is suggested to be installed. + Note: some versions of Pillow might NOT support some Python versions. + + The full list of supported Pillow versions given a Python version can be found here: + https://pillow.readthedocs.io/en/stable/installation.html#notes + + For example, with Python 3.7, install a supported Pillow using the following command: + + ex. python3.7 -m pip install Pillow==5.2.0 + + Older installations of Python 2.7 do NOT come with enum34, which is required by + the Inference.py Python2 example. Install enum34 for Python 2.7 using the following command: + + python2.7 -m pip install enum34 + +3. Ensure that the corresponding version of the Spinnaker SDK Debian packages + and their prerequisites are installed beforehand + (ex. install the 1.21.0.61 packages if the wheel version is also 1.21.0.61) + +4. Install wheel for specific Python version. This can be installed site-wide + for all users or for a specific user. + + - Python 2.7, site wide: + sudo python -m pip install spinnaker_python-1.x.x.x-cp27-cp27mu-linux_x86_64.whl + + - Python 2.7, user only: + python -m pip install --user spinnaker_python-1.x.x.x-cp27-cp27mu-linux_x86_64.whl + + - Python 3.5, site wide (16.04 only): + sudo python3.5 -m pip install spinnaker_python-1.x.x.x-cp35-cp35m-linux_x86_64.whl + + - Python 3.5, user only (16.04 only): + python3.5 -m pip install --user spinnaker_python-1.x.x.x-cp35-cp35m-linux_x86_64.whl + + - Python 3.6, site wide: + sudo python3.6 -m pip install spinnaker_python-1.x.x.x-cp36-cp36m-linux_x86_64.whl + + - Python 3.6, user only: + python3.6 -m pip install --user spinnaker_python-1.x.x.x-cp36-cp36m-linux_x86_64.whl + + - Python 3.7, site wide: + sudo python3.7 -m pip install spinnaker_python-1.x.x.x-cp37-cp37m-linux_x86_64.whl + + - Python 3.7, user only: + python3.7 -m pip install --user spinnaker_python-1.x.x.x-cp37-cp37m-linux_x86_64.whl + +5. The examples are located in the Examples folder of the extracted tarball. Run with: + ex. python3.7 Examples/Python3/DeviceEvents.py + +----------------------------------------------------------------------------- +1.3 MACOS +----------------------------------------------------------------------------- + +1. Check that Python is installed. MacOS comes with Python 2.7 installed, + but it may be an older build of Python. Up-to-date Python packages + can be downloaded from https://www.python.org/downloads. + +2. Update pip for Python. Run the following command for your version of Python: + + sudo -m ensurepip + + This will install a version of pip and allow you to update or install new wheels. + +3. Install library dependencies for PySpin: numpy and matplotlib. NumPy is a + requirement for PySpin and needs to be at least version 1.15 or above. + Matplotlib is not required for the library itself but is used in some of + our examples to highlight possible usages of PySpin. Install these + dependencies by running one of the following commands. + + - Install for Python 2.7, user only: + python -m pip install --upgrade --user numpy matplotlib + + - Install for Python 2.7, site wide: + sudo python -m pip install --upgrade numpy matplotlib + + - Install for Python 3.6, user only: + python3.6 -m pip install --upgrade --user numpy matplotlib + + - Install for Python 3.6, site wide: + sudo python3.6 -m pip install --upgrade numpy matplotlib + + - Install for Python 3.7, user only: + python3.7 -m pip install --upgrade --user numpy matplotlib + + - Install for Python 3.7, site wide: + sudo python3.7 -m pip install --upgrade numpy matplotlib + + For better support of matplotlib output image file formats, Pillow is suggested to be installed. + Note: some versions of Pillow might NOT support some Python versions. + + The full list of supported Pillow versions given a Python version can be found here: + https://pillow.readthedocs.io/en/stable/installation.html#notes + + For example, with Python 3.7, install a supported Pillow using the following command: + + ex. python3.7 -m pip install Pillow==5.2.0 + + Older installations of Python 2.7 do NOT come with enum34, which is required by + the Inference.py Python2 example. Install enum34 for Python 2.7 using the following command: + + python2.7 -m pip install enum34 + +4. Ensure that the corresponding version of the Spinnaker SDK MacOS packages + and their prerequisites are installed beforehand. + (ex. install 1.21.0.61 packages if the wheel version is also 1.21.0.61) + +5. Install the PySpin wheel for specific Python version. + ex. sudo python3.7 -m pip install spinnaker_python-1.x.x.x-cp37-cp37mu-macos_x86_x64.whl" for 64-bit Python 3.7 + +6. The examples are located in the Examples folder of the extracted tarball. Run with: + ex. python3.7 Examples/Python3/DeviceEvents.py + +============================================================================= +2. API DIFFERENCES +============================================================================= + +Except for the changes listed below, most function names are exactly the same +as the C++ API. See examples for PySpin usage! + +- All methods of SpinnakerException no longer exist, please replace all + usages of SpinnakerException with any of the following attributes: + message: Normal exception message. + fullmessage: Exception message including line, file, function, + build date, and time (from C++ library). + errorcode: Integer error code of the exception. + The SpinnakerException instance itself can be printed, as it derives from + the BaseException class and has a default __str__ representation. + See examples for usage. + +- Image creation using NumPy arrays (although the int type of the array must be uint8) + +- The majority of headers from the C++ API have been wrapped, with the exception of: + - Headers with "Adapter" or "Port" in the name + - NodeMapRef.h, NodeMapFactory.h + - Synch.h, GCSynch.h, Counter.h, filestream.h + +- INode and IValue types (esp. returned from GetNode()) have to + be initialized to their respective pointer types + (ex. CFloatPtr, CEnumerationPtr) to access their functions + +- CameraPtr, CameraList, InterfacePtr, InterfaceList, and SystemPtr + have to be manually released and/or deleted before program exit (use del operator) + - See EnumerationEvents example + +- Image.GetData() returns a 1-D NumPy array of integers, the int type + depends on the pixel format of the image + +- Image.GetNDArray() returns a 2 or 3-D NumPy array of integers, only for select + image formats. This can be used in libraries such as PIL and/or OpenCV. + +- Node callbacks take in a callback class instead of a function pointer + - Register is now RegisterNodeCallback, Deregister is now DeregisterNodeCallback + - See NodeMapCallback example for more details + +- IImage.CalculateChannelStatistics(StatisticsChannel channel) returns + a ChannelStatistics object representing stats for the given channel + in the image. These stats are properties within the ChannelStatistics object, + Please see the docstring for details. This replaces ImageStatistics! + +- Pass-by-reference functions now return the type and take in void + - GetFeatures() returns a Python list of IValue, instead of taking + in a FeatureList_t reference + - GetChildren() returns a Python list of INode, instead of taking + in a NodeList_t reference + - Same with GetEntries(), GetNodes() + - GetPropertyNames() returns a Python list of str, + instead of taking in a gcstring_vector reference + - See DeviceEvents example for usage + +- Methods Get() and Set() for IRegister and register nodes use NumPy arrays + - Get() takes in the length of the register to read and two optional + bools, returns a NumPy array + - Set() takes in a single NumPy array + +============================================================================= +3. REMOVE PYSPIN +============================================================================= + +Removing or updating PySpin is similar to removing or updating other wheels. + +For Windows, if you need to remove PySpin, the following command needs to be +run from an administrator command prompt to remove your associated Python version: + + -m pip uninstall spinnaker-python + +For Linux or MacOS, if you need to remove PySpin from a user-specific install, run +the following command to remove your associated Python version: + + -m pip uninstall spinnaker-python + +For Linux or MacOS, if you need to remove PySpin from a site-wide install the +following command needs to be run as sudo to remove your associated Python version: + +sudo -m pip uninstall spinnaker-python \ No newline at end of file diff --git a/FLIR/FLIRcodev4.0/Spinnaker/docs/PySpinDoc.chm b/FLIR/FLIRcodev4.0/Spinnaker/docs/PySpinDoc.chm new file mode 100644 index 0000000..4e69f95 Binary files /dev/null and b/FLIR/FLIRcodev4.0/Spinnaker/docs/PySpinDoc.chm differ diff --git a/FLIR/FLIRcodev4.0/Spinnaker/docs/PySpinDoc.pdf b/FLIR/FLIRcodev4.0/Spinnaker/docs/PySpinDoc.pdf new file mode 100644 index 0000000..5b2a889 Binary files /dev/null and b/FLIR/FLIRcodev4.0/Spinnaker/docs/PySpinDoc.pdf differ diff --git a/FLIR/FLIRcodev4.0/Spinnaker/licenses/FFmpeg_compliance_doc.txt b/FLIR/FLIRcodev4.0/Spinnaker/licenses/FFmpeg_compliance_doc.txt new file mode 100644 index 0000000..7b06e29 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Spinnaker/licenses/FFmpeg_compliance_doc.txt @@ -0,0 +1,2 @@ +This software uses code of FFmpeg http://ffmpeg.org licensed under the LGPL v2.1 (http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html). +The FFmpeg code can be found online at https://github.com/FFmpeg/FFmpeg/tree/5156578d1f486163d5b83f1d63246cd23d107933. \ No newline at end of file diff --git a/FLIR/FLIRcodev4.0/Spinnaker/licenses/Spinnaker-Open-Source-Licenses.pdf b/FLIR/FLIRcodev4.0/Spinnaker/licenses/Spinnaker-Open-Source-Licenses.pdf new file mode 100644 index 0000000..55a8894 Binary files /dev/null and b/FLIR/FLIRcodev4.0/Spinnaker/licenses/Spinnaker-Open-Source-Licenses.pdf differ diff --git a/FLIR/FLIRcodev4.0/Spinnaker/spinnaker_python-2.0.0.146-cp38-cp38-win_amd64.whl b/FLIR/FLIRcodev4.0/Spinnaker/spinnaker_python-2.0.0.146-cp38-cp38-win_amd64.whl new file mode 100644 index 0000000..bd0497a Binary files /dev/null and b/FLIR/FLIRcodev4.0/Spinnaker/spinnaker_python-2.0.0.146-cp38-cp38-win_amd64.whl differ diff --git a/FLIR/FLIRcodev4.0/Trigger_QuickSpin.py b/FLIR/FLIRcodev4.0/Trigger_QuickSpin.py new file mode 100644 index 0000000..9a33cb4 --- /dev/null +++ b/FLIR/FLIRcodev4.0/Trigger_QuickSpin.py @@ -0,0 +1,422 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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 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.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 + 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 + 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!') + 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) diff --git a/FLIR/FLIRcodev4.0/build/lib/flir/__init__.py b/FLIR/FLIRcodev4.0/build/lib/flir/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/FLIR/FLIRcodev4.0/build/lib/flir/aqctl_flir.py b/FLIR/FLIRcodev4.0/build/lib/flir/aqctl_flir.py new file mode 100644 index 0000000..edc43e6 --- /dev/null +++ b/FLIR/FLIRcodev4.0/build/lib/flir/aqctl_flir.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 + +# Written by Joe Britton, 2015 + +import argparse +import logging +import sys +import os +import asyncio + +from GitHub.Instruments.FLIR.FLIRcodev40.flir.driver import FLIR +from flir.driver import TriggerType +from sipyco.pc_rpc import simple_server_loop +from sipyco import common_args + + +logger = logging.getLogger(__name__) + + +def get_argparser(): + parser = argparse.ArgumentParser( + description="ARTIQ controller for the FLIR camera") + common_args.simple_network_args(parser, 3200) + parser.add_argument( + "-d", "--device", default=None, + help="serial port.") + parser.add_argument( + "--softtrig", default=False, action="store_true", + help="Sets trigger to software. Default is hardware") + parser.add_argument( + "--num", default=1, + help="Sets number of images. Default is hardware") + parser.add_argument( + "--simulation", action="store_true", + help="Put the driver in simulation mode, even if --device is used.") + common_args.verbosity_args(parser) + return parser + + +def main(): + args = get_argparser().parse_args() + common_args.init_logger_from_args(args) + if os.name == "nt": + asyncio.set_event_loop(asyncio.ProactorEventLoop()) + # if args.device is None: + # print("Starting in Simulation mode...") + # dev = FLIR(args.device if not args.simulation else None) + + print("Software trigger is:",args.softtrig) + triggerset=TriggerType(args.softtrig) + dev = FLIR() + #asyncio.get_event_loop().run_until_complete(dev.setup()) + try: + print("Startup on port",args.port,"successful...") + simple_server_loop( + {"flir": dev}, common_args.bind_address_from_args(args), args.port) + finally: + dev.close() +if __name__ == "__main__": + main() diff --git a/FLIR/FLIRcodev4.0/build/lib/flir/driver(backup).py b/FLIR/FLIRcodev4.0/build/lib/flir/driver(backup).py new file mode 100644 index 0000000..f6295b4 --- /dev/null +++ b/FLIR/FLIRcodev4.0/build/lib/flir/driver(backup).py @@ -0,0 +1,535 @@ +# Written by Joe Britton, 2015 + +import math +import logging +import asyncio +import asyncserial + +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +class TriggerType: + SOFTWARE = 1 + HARDWARE = 2 + +CHOSEN_TRIGGER = TriggerType.SOFTWARE + + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + pass + + +class FLIR: + """Driver for FLIR camera """ + + error_codes = { + "?0": "Unrecognized Command", + "?1": "Bad Frequency", + "?2": "Bad AM Command", + "?3": "Input line too long", + "?4": "Bad Phase", + "?5": "Bad Time", + "?6": "Bad Mode", + "?7": "Bad Amp", + "?8": "Bad Constant", + "?f": "Bad Byte" + } + + def __init__(self, serial_dev): + if serial_dev is None: + self.simulation = True + else: + self.simulation = False + self.port = asyncserial.AsyncSerial( + serial_dev, + baudrate=19200, + bytesize=8, + parity="N", + stopbits=1, + xonxoff=0) + + async def _ser_readline(self): + c = await self.port.read(1) + print(c) + r = c + while c != b"\n": + c = await self.port.read(1) + r += c + return r + + async def _ser_send(self, cmd, get_response=True): + """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + if self.simulation: + logger.info("simulation _ser_send(\"%s\")", cmd) + else: + logger.debug("_ser_send(\"%s\")", cmd) + self.port.ser.reset_input_buffer() + await self.port.write((cmd + "\r\n").encode()) + if get_response: + result = (await self._ser_readline()).rstrip().decode() + logger.debug("got response from device: %s", result) + if result != "OK": + errstr = self.error_codes.get(result, "Unrecognized reply") + s = "Erroneous reply from device: {ec}, {ecs}".format( + ec=result, ecs=errstr) + raise ValueError(s) + else: + pass + + async def setup(self): + """Initial setup of FLIR.""" + await self._ser_send("E d", get_response=False) + + + def close(self): + """Close the serial hardware port.""" + if not self.simulation: + self.port.close() + + async def ping(self): + try: + stat = await self.get_status() + except asyncio.CancelledError: + raise + except: + return False + # check that version number matches is "21" + if stat[4][20:] == "21": + logger.debug("ping successful") + return True + else: + return False + + + 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.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 + 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 + 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 + """ + print("393-postfunction") + try: + print("395") + result = True + err = False + print("398") + # Retrieve TL device nodemap and print device information + nodemap_tldevice = cam.GetTLDeviceNodeMap() + print("401") + result &= print_device_info(nodemap_tldevice) + print("403") + # Initialize camera + cam.Init() + print("406") + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + print("409") + # Configure trigger + if configure_trigger(cam) is False: + return False + print("413") + # Acquire images + result &= grab_next_image_by_trigger(cam) #acquire_images(cam) THIS IS WHAT I CHANGED TO TRY TO GRAB ONLY ONE IMAGE AT A TIME! + print("416") + # Reset trigger + result &= reset_trigger(cam) + print("419") + # Deinitialize camera + cam.DeInit() + print("422") + except PySpin.SpinnakerException as ex: + print("424-exception") + print('Error: %s' % ex) + result = False + + + return result + + + def picture(cam): + """ + Run this code to take a single triggered picture! + + :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!') + print("Closing camera instance...") #input('Done! Press Enter to exit...') + return False + print(cam) + # Run example on each camera + for i, cam in enumerate(cam_list): + + print('Running example for camera %d...' % i) + + print("472-prefunction") + 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() + + print("Closing camera instance...") #input('Done! Press Enter to exit...') + return result + + + # if __name__ == '__picture__': + # if picture(): + # sys.exit(0) + # else: + # sys.exit(1) + + + + +############################################################ + + + + + + # async def reset(self): + # """Hardware reset of FLIR.""" + # await self._ser_send("R", get_response=False) + # await asyncio.sleep(1) + # await self.setup() + + # async def setup(self): + # """Initial setup of FLIR.""" + + # await self._ser_send("E d", get_response=False) + + # async def get_status(self): + # if self.simulation: + # return ["00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "80 BC0000 0000 0102 21"] + # else: + # self.port.ser.reset_input_buffer() + # result = [] + # await self.port.write(("QUE" + "\r\n").encode()) + # for i in range(5): + # m = (await self._ser_readline()).rstrip().decode() + # result.append(m) + # logger.debug("got device status: %s", result) + # return result + + \ No newline at end of file diff --git a/FLIR/FLIRcodev4.0/build/lib/flir/driver(backup_old).py b/FLIR/FLIRcodev4.0/build/lib/flir/driver(backup_old).py new file mode 100644 index 0000000..f6295b4 --- /dev/null +++ b/FLIR/FLIRcodev4.0/build/lib/flir/driver(backup_old).py @@ -0,0 +1,535 @@ +# Written by Joe Britton, 2015 + +import math +import logging +import asyncio +import asyncserial + +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +class TriggerType: + SOFTWARE = 1 + HARDWARE = 2 + +CHOSEN_TRIGGER = TriggerType.SOFTWARE + + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + pass + + +class FLIR: + """Driver for FLIR camera """ + + error_codes = { + "?0": "Unrecognized Command", + "?1": "Bad Frequency", + "?2": "Bad AM Command", + "?3": "Input line too long", + "?4": "Bad Phase", + "?5": "Bad Time", + "?6": "Bad Mode", + "?7": "Bad Amp", + "?8": "Bad Constant", + "?f": "Bad Byte" + } + + def __init__(self, serial_dev): + if serial_dev is None: + self.simulation = True + else: + self.simulation = False + self.port = asyncserial.AsyncSerial( + serial_dev, + baudrate=19200, + bytesize=8, + parity="N", + stopbits=1, + xonxoff=0) + + async def _ser_readline(self): + c = await self.port.read(1) + print(c) + r = c + while c != b"\n": + c = await self.port.read(1) + r += c + return r + + async def _ser_send(self, cmd, get_response=True): + """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + if self.simulation: + logger.info("simulation _ser_send(\"%s\")", cmd) + else: + logger.debug("_ser_send(\"%s\")", cmd) + self.port.ser.reset_input_buffer() + await self.port.write((cmd + "\r\n").encode()) + if get_response: + result = (await self._ser_readline()).rstrip().decode() + logger.debug("got response from device: %s", result) + if result != "OK": + errstr = self.error_codes.get(result, "Unrecognized reply") + s = "Erroneous reply from device: {ec}, {ecs}".format( + ec=result, ecs=errstr) + raise ValueError(s) + else: + pass + + async def setup(self): + """Initial setup of FLIR.""" + await self._ser_send("E d", get_response=False) + + + def close(self): + """Close the serial hardware port.""" + if not self.simulation: + self.port.close() + + async def ping(self): + try: + stat = await self.get_status() + except asyncio.CancelledError: + raise + except: + return False + # check that version number matches is "21" + if stat[4][20:] == "21": + logger.debug("ping successful") + return True + else: + return False + + + 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.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 + 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 + 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 + """ + print("393-postfunction") + try: + print("395") + result = True + err = False + print("398") + # Retrieve TL device nodemap and print device information + nodemap_tldevice = cam.GetTLDeviceNodeMap() + print("401") + result &= print_device_info(nodemap_tldevice) + print("403") + # Initialize camera + cam.Init() + print("406") + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + print("409") + # Configure trigger + if configure_trigger(cam) is False: + return False + print("413") + # Acquire images + result &= grab_next_image_by_trigger(cam) #acquire_images(cam) THIS IS WHAT I CHANGED TO TRY TO GRAB ONLY ONE IMAGE AT A TIME! + print("416") + # Reset trigger + result &= reset_trigger(cam) + print("419") + # Deinitialize camera + cam.DeInit() + print("422") + except PySpin.SpinnakerException as ex: + print("424-exception") + print('Error: %s' % ex) + result = False + + + return result + + + def picture(cam): + """ + Run this code to take a single triggered picture! + + :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!') + print("Closing camera instance...") #input('Done! Press Enter to exit...') + return False + print(cam) + # Run example on each camera + for i, cam in enumerate(cam_list): + + print('Running example for camera %d...' % i) + + print("472-prefunction") + 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() + + print("Closing camera instance...") #input('Done! Press Enter to exit...') + return result + + + # if __name__ == '__picture__': + # if picture(): + # sys.exit(0) + # else: + # sys.exit(1) + + + + +############################################################ + + + + + + # async def reset(self): + # """Hardware reset of FLIR.""" + # await self._ser_send("R", get_response=False) + # await asyncio.sleep(1) + # await self.setup() + + # async def setup(self): + # """Initial setup of FLIR.""" + + # await self._ser_send("E d", get_response=False) + + # async def get_status(self): + # if self.simulation: + # return ["00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "80 BC0000 0000 0102 21"] + # else: + # self.port.ser.reset_input_buffer() + # result = [] + # await self.port.write(("QUE" + "\r\n").encode()) + # for i in range(5): + # m = (await self._ser_readline()).rstrip().decode() + # result.append(m) + # logger.debug("got device status: %s", result) + # return result + + \ No newline at end of file diff --git a/FLIR/FLIRcodev4.0/build/lib/flir/driver(complex).py b/FLIR/FLIRcodev4.0/build/lib/flir/driver(complex).py new file mode 100644 index 0000000..b4167c8 --- /dev/null +++ b/FLIR/FLIRcodev4.0/build/lib/flir/driver(complex).py @@ -0,0 +1,202 @@ +# Written by Joe Britton, 2015 + +import math +import logging +import asyncio +import asyncserial + + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + print("Exception Error :(") + pass + + +class FLIR: + """Driver for Novatech 409B 4-channel DDS. + + All output channels are in range [0, 1, 2, 3]. + All frequencies are in Hz. + All phases are in turns. + All amplitudes are in volts. + """ + + error_codes = { + "?0": "Unrecognized Command", + "?1": "Bad Frequency", + "?2": "Bad AM Command", + "?3": "Input line too long", + "?4": "Bad Phase", + "?5": "Bad Time", + "?6": "Bad Mode", + "?7": "Bad Amp", + "?8": "Bad Constant", + "?f": "Bad Byte" + } + + def __init__(self, serial_dev): + if serial_dev is None: + self.simulation = True + else: + self.simulation = False + self.port = asyncserial.AsyncSerial( + serial_dev, + baudrate=19200, + bytesize=8, + parity="N", + stopbits=1, + xonxoff=0) + + def close(self): + """Close the serial port.""" + if not self.simulation: + self.port.close() + + async def _ser_readline(self): + c = await self.port.read(1) + print(c) + r = c + while c != b"\n": + c = await self.port.read(1) + r += c + return r + + async def _ser_send(self, cmd, get_response=True): + """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + if self.simulation: + logger.info("simulation _ser_send(\"%s\")", cmd) + else: + logger.debug("_ser_send(\"%s\")", cmd) + self.port.ser.reset_input_buffer() + await self.port.write((cmd + "\r\n").encode()) + if get_response: + result = (await self._ser_readline()).rstrip().decode() + logger.debug("got response from device: %s", result) + if result != "OK": + errstr = self.error_codes.get(result, "Unrecognized reply") + s = "Erroneous reply from device: {ec}, {ecs}".format( + ec=result, ecs=errstr) + raise ValueError(s) + else: + pass + + async def reset(self): + """Hardware reset of 409B.""" + await self._ser_send("R", get_response=False) + await asyncio.sleep(1) + await self.setup() + + async def setup(self): + """Initial setup of 409B.""" + + # Setup the Novatech 409B with the following defaults: + # * command echo off ("E d") + # * external clock ("") 10 MHz sinusoid -1 to +7 dBm + print("setup is working") + await self._ser_send("E d", get_response=False) + await self.set_phase_continuous(True) + await self.set_simultaneous_update(False) + + async def save_state_to_eeprom(self): + """Save current state to EEPROM.""" + await self._ser_send("S") + + async def set_phase_continuous(self, is_continuous): + """Toggle phase continuous mode. + + Sends the "M n" command. This turns off the automatic + clearing of the phase register. In this mode, the phase + register is left intact when a command is performed. + Use this mode if you want frequency changes to remain + phase synchronous, with no phase discontinuities. + + :param is_continuous: True or False + """ + if is_continuous: + await self._ser_send("M n") + else: + await self._ser_send("M a") + + async def set_simultaneous_update(self, simultaneous): + """Set simultaneous update mode. + + Sends the "I m" command. In this mode an update + pulse will not be sent to the DDS chip until + an "I p" command is sent. This is useful when it is + important to change all the outputs to new values + simultaneously. + """ + if simultaneous: + await self._ser_send("I m") + else: + await self._ser_send("I a") + + async def do_simultaneous_update(self): + """Apply update in simultaneous update mode.""" + await self._ser_send("I p") + + async def set_freq(self, ch_no, freq): + """Set frequency of one channel.""" + # Novatech expects MHz + await self._ser_send("F{:d} {:f}".format(ch_no, freq/1e6)) + + async def set_phase(self, ch_no, phase): + """Set phase of one channel.""" + # phase word is required by device + # N is an integer from 0 to 16383. Phase is set to + # N*360/16384 deg; in ARTIQ represent phase in cycles [0, 1] + phase_word = round(phase*16383) + cmd = "P{:d} {:d}".format(ch_no, phase_word) + await self._ser_send(cmd) + + async def set_gain(self, ch_no, volts): + """Set amplitude of one channel.""" + + # due to error in Novatech it doesn't generate an error for + # dac_value>1024, so need to trap. + dac_value = int(math.floor(volts/0.51*1024)) + if dac_value < 0 or dac_value > 1023: + s = "Amplitude out of range {v}".format(v=volts) + raise ValueError(s) + + s = "V{:d} {:d}".format(ch_no, dac_value) + await self._ser_send(s) + + async def get_status(self): + if self.simulation: + return ["00989680 2000 01F5 0000 00000000 00000000 000301", + "00989680 2000 01F5 0000 00000000 00000000 000301", + "00989680 2000 01F5 0000 00000000 00000000 000301", + "00989680 2000 01F5 0000 00000000 00000000 000301", + "80 BC0000 0000 0102 21"] + else: + self.port.ser.reset_input_buffer() + result = [] + await self.port.write(("QUE" + "\r\n").encode()) + for i in range(5): + m = (await self._ser_readline()).rstrip().decode() + result.append(m) + logger.debug("got device status: %s", result) + return result + + async def ping(self): + try: + stat = await self.get_status() + except asyncio.CancelledError: + raise + except: + return False + # check that version number matches is "21" + if stat[4][20:] == "21": + logger.debug("ping successful") + return True + else: + return False diff --git a/FLIR/FLIRcodev4.0/build/lib/flir/driver(old).py b/FLIR/FLIRcodev4.0/build/lib/flir/driver(old).py new file mode 100644 index 0000000..f7b83d4 --- /dev/null +++ b/FLIR/FLIRcodev4.0/build/lib/flir/driver(old).py @@ -0,0 +1,715 @@ +import math +import logging +import asyncio +import asyncserial +import os +import matplotlib.pyplot as plt +import keyboard +import time +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + +global continue_recording +continue_recording = True + +global trigtype +SOFTWARE = 1 +HARDWARE = 2 +trigtype=SOFTWARE +class TriggerType(): + def __init__(self, softtrig): + global trigtype + if softtrig is True: + trigtype=SOFTWARE + else: + trigtype=HARDWARE + +CHOSEN_TRIGGER = trigtype + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + pass + + +class FLIR: + """Driver for FLIR camera """ + def __init__(self,num): + serial_dev = None + cam=0 + cam_list=0 + self.cameras=0 + result = True + self.num=num + system = PySpin.System.GetInstance() + version = system.GetLibraryVersion() + print('Library version: %d.%d.%d.%d' % (version.major, version.minor, version.type, version.build)) + cam_list = system.GetCameras() + self.system = system + self.cam_list = cam_list + self.cam=cam_list[0] + + num_cameras = cam_list.GetSize() + print('Number of cameras detected: %d' % num_cameras) + if num_cameras == 0: + cam_list.Clear() + system.ReleaseInstance() + print('Not enough cameras!') + print("Closing camera instance...") + return False + for i, cam in enumerate(cam_list): + print('Defining camera %d...' % i) + + self.nodemap_tldevice = cam.GetTLDeviceNodeMap() + result &= self.print_device_info(self.nodemap_tldevice) + cam.Init() + self.nodemap = cam.GetNodeMap() + + print("Going back to server now...") + + + + + + + # def picture(self): + # """ + # Run this code to take a single triggered picture! + + # :return: True if successful, False otherwise. + # :rtype: bool + # """ + # result = True + # print(self.cam) + # result &= self.run_single_camera(self.cam) + # for i, cam in enumerate(cam_list): + + # print('Running example for camera %d...' % i) + + # print("472-prefunction") + # result &= run_single_camera(cam) + # print('Camera %d example complete... \n' % i) + # return result + + def picture(self):#run_single_camera(self): + """ + 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 + cam=self.cam + cam.BeginAcquisition() + image_result = cam.GetNextImage(1000) + # Configure trigger + if self.configure_trigger(cam) is False: + return False + + # Acquire images + result &= self.grab_next_image_by_trigger(cam) #acquire_images(cam) THIS IS WHAT I CHANGED TO TRY TO GRAB ONLY ONE IMAGE AT A TIME! + + + 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 + filename = 'Trigger-%d.jpg' % i + + + # Save image + image_converted.Save(filename) + + print('Image saved at %s\n' % filename) + + # Release image + image_result.Release() + # Reset trigger + result &= self.reset_trigger(cam) + cam.EndAcquisition() + cam.EndAcquisition() + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + + return result + + async def _ser_readline(self): + c = await self.port.read(1) + print(c) + r = c + while c != b"\n": + c = await self.port.read(1) + r += c + return r + + async def _ser_send(self, cmd, get_response=True): + """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + if self.simulation: + logger.info("simulation _ser_send(\"%s\")", cmd) + else: + logger.debug("_ser_send(\"%s\")", cmd) + self.port.ser.reset_input_buffer() + await self.port.write((cmd + "\r\n").encode()) + if get_response: + result = (await self._ser_readline()).rstrip().decode() + logger.debug("got response from device: %s", result) + if result != "OK": + errstr = self.error_codes.get(result, "Unrecognized reply") + s = "Erroneous reply from device: {ec}, {ecs}".format( + ec=result, ecs=errstr) + raise ValueError(s) + else: + pass + + async def setup(self): + """Initial setup of FLIR.""" + await self._ser_send("E d", get_response=False) + + + def close(self): + """Close the serial hardware port.""" + # Deinitialize camera + self.cam.DeInit() + del self.cam + self.system.ReleaseInstance() + self.cam_list.Clear() + print("Closing camera instance...") #input('Done! Press Enter to exit...') + # if not self.simulation: + # self.port.close() + + async def ping(self): + try: + stat = await self.get_status() + except asyncio.CancelledError: + raise + except: + return False + # check that version number matches is "21" + if stat[4][20:] == "21": + logger.debug("ping successful") + return True + else: + return False + + + def configure_trigger(self,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 == SOFTWARE: + print('Software trigger chosen...') + elif CHOSEN_TRIGGER == 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.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 == SOFTWARE: + cam.TriggerSource.SetValue(PySpin.TriggerSource_Software) + print('Trigger source set to software...') + elif CHOSEN_TRIGGER == 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(self,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 == 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 == 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(self): + """ + 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 + """ + cam=self.cam + NUM_IMAGES=self.num + 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 &= self.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(self): + # Deinitialize camera + self.cam.DeInit() + + self.cam.Init() + + + def reset_trigger(self,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(self,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 handle_close(self,evt): + """ + This function will close the GUI when close event happens. + + :param evt: Event that occurs when the figure closes. + :type evt: Event + """ + + global continue_recording + continue_recording = False + + def display(self): + """ + This function continuously acquires images from a device and display them in a GUI. + + :param cam: Camera to acquire images from. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + global continue_recording + + cam=self.cam + nodemap=self.nodemap + nodemap_tldevice=self.nodemap_tldevice + sNodemap = cam.GetTLStreamNodeMap() + + # Change bufferhandling mode to NewestOnly + node_bufferhandling_mode = PySpin.CEnumerationPtr(sNodemap.GetNode('StreamBufferHandlingMode')) + if not PySpin.IsAvailable(node_bufferhandling_mode) or not PySpin.IsWritable(node_bufferhandling_mode): + print('Unable to set stream buffer handling mode.. Aborting...') + return False + + # Retrieve entry node from enumeration node + node_newestonly = node_bufferhandling_mode.GetEntryByName('NewestOnly') + if not PySpin.IsAvailable(node_newestonly) or not PySpin.IsReadable(node_newestonly): + print('Unable to set stream buffer handling mode.. Aborting...') + return False + + # Retrieve integer value from entry node + node_newestonly_mode = node_newestonly.GetValue() + + # Set integer value from entry node as new value of enumeration node + node_bufferhandling_mode.SetIntValue(node_newestonly_mode) + + print('*** IMAGE ACQUISITION ***\n') + try: + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # What happens when the camera begins acquiring images depends on the + # acquisition mode. Single frame captures only a single image, multi + # frame catures a set number of images, and continuous captures a + # continuous stream of images. + # + # *** LATER *** + # Image acquisition must be ended when no more images are needed. + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve device serial number for filename + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Close program + print('Press enter to close the program..') + + # Figure(1) is default so you can omit this line. Figure(0) will create a new window every time program hits this line + fig = plt.figure(1) + + # Close the GUI when close event happens + fig.canvas.mpl_connect('close_event', self.handle_close) + + # Retrieve and display images + while(continue_recording): + try: + + # Retrieve next received image + # + # *** NOTES *** + # Capturing an image houses images on the camera buffer. Trying + # to capture an image that does not exist will hang the camera. + # + # *** LATER *** + # Once an image from the buffer is saved and/or no longer + # needed, the image must be released in order to keep the + # buffer from filling up. + + image_result = cam.GetNextImage(1000) + + # Ensure image completion + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + + else: + + # Getting the image data as a numpy array + image_data = image_result.GetNDArray() + + # Draws an image on the current figure + plt.imshow(image_data, cmap='gray') + + # Interval in plt.pause(interval) determines how fast the images are displayed in a GUI + # Interval is in seconds. + plt.pause(0.001) + + # Clear current reference of a figure. This will improve display speed significantly + plt.clf() + + # If user presses enter, close the program + if keyboard.is_pressed('ENTER'): + print('Program is closing...') + + # Close figure + plt.close('all') + input('Done! Press Enter to exit...') + continue_recording=False + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return True + + + + + + + + + +############################################################ + + + + + + # async def reset(self): + # """Hardware reset of FLIR.""" + # await self._ser_send("R", get_response=False) + # await asyncio.sleep(1) + # await self.setup() + + # async def setup(self): + # """Initial setup of FLIR.""" + + # await self._ser_send("E d", get_response=False) + + # async def get_status(self): + # if self.simulation: + # return ["00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "80 BC0000 0000 0102 21"] + # else: + # self.port.ser.reset_input_buffer() + # result = [] + # await self.port.write(("QUE" + "\r\n").encode()) + # for i in range(5): + # m = (await self._ser_readline()).rstrip().decode() + # result.append(m) + # logger.debug("got device status: %s", result) + # return result + + \ No newline at end of file diff --git a/FLIR/FLIRcodev4.0/build/lib/flir/driver.py b/FLIR/FLIRcodev4.0/build/lib/flir/driver.py new file mode 100644 index 0000000..df94acd --- /dev/null +++ b/FLIR/FLIRcodev4.0/build/lib/flir/driver.py @@ -0,0 +1,179 @@ +import math +import logging +import asyncio +import asyncserial +import os +import matplotlib.pyplot as plt +import keyboard +import time +import PySpin +import sys +import time + +NUM_IMAGES = 10 # number of images to grab + +global continue_recording +continue_recording = True + +global trigtype +SOFTWARE = 1 +HARDWARE = 2 +trigtype=SOFTWARE +class TriggerType(): + def __init__(self, softtrig): + global trigtype + if softtrig is True: + trigtype=SOFTWARE + else: + trigtype=HARDWARE + +CHOSEN_TRIGGER = trigtype + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + pass + + +class FLIR: + """Driver for FLIR camera """ + def __init__(self): + try: + # Set camera serial numbers + serial_1 = '20343286' + ##### serial_2 = '16276941' + + # Get system + self.system = PySpin.System.GetInstance() + + # Get camera list + self.cam_list = self.system.GetCameras() + + # Get cameras by serial + self.cam_1 = self.cam_list.GetBySerial(serial_1) + ##### cam_2 = cam_list.GetBySerial(serial_2) + + # Initialize cameras + self.cam_1.Init() + ##### cam_2.Init() + + # Set acquisition mode to acquire a single frame, this ensures acquired images are sync'd since camera 2 and 3 are setup to be triggered + self.cam_1.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) + ##### cam_2.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) + + + #This takes an image quickly. The first image is always corrupt for whatever reason. This picture is not saved. + self.cam_1.TriggerMode.SetValue(PySpin.TriggerMode_Off) + self.cam_1.TriggerMode.SetValue(PySpin.TriggerMode_On) + self.cam_1.BeginAcquisition() + self.cam_1.EndAcquisition() + + ## Set up primary camera trigger + # self.cam_1.LineSelector.SetValue(PySpin.LineSelector_Line2) + # self.cam_1.V3_3Enable.SetValue(True) + + print("Initialization successful...") + except: + print("Error in __init__()") + + def await_trigger(self): + try: + self.cam_1.TriggerMode.SetValue(PySpin.TriggerMode_Off) + #self.cam_1.TriggerSource.SetValue(PySpin.TriggerSource_Line3) + #self.cam_1.TriggerOverlap.SetValue(PySpin.TriggerOverlap_ReadOut) + self.cam_1.TriggerMode.SetValue(PySpin.TriggerMode_On) + + # Set up secondary camera trigger + ##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_Off) + ##### cam_2.TriggerSource.SetValue(PySpin.TriggerSource_Line3) + ##### cam_2.TriggerOverlap.SetValue(PySpin.TriggerOverlap_ReadOut) + ##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_On) + + # Start acquisition; note that secondary cameras have to be started first so acquisition of primary camera triggers secondary cameras. + ##### cam_2.BeginAcquisition() + self.cam_1.BeginAcquisition() + + print("Awaiting trigger...") + + self.postpicture() + except: + print("Error in await_trigger()") + + def postpicture(self): + try: + # Acquire images + self.image_1 = self.cam_1.GetNextImage() + ##### image_2 = cam_2.GetNextImage() + + # Ensure image completion + if self.image_1.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + + else: + + # Save images + filename = 'Image_H%s_M%d_S%g.png' % (int(time.strftime("%H", time.localtime())), int(time.strftime("%M", time.localtime())),int(time.strftime("%S", time.localtime()))) + self.image_1.Save(filename) + ##### image_2.Save('cam_2.png') + + # Release images + self.image_1.Release() + ##### image_2.Release() + + # end acquisition + self.cam_1.EndAcquisition() + ##### cam_2.EndAcquisition() + print("Picture Successfully taken at: ",time.strftime("%d %b %Y %H:%M:%S", time.localtime())) + except: + print("Error in postpicture()") + + def reset(self): + self.cam_1.DeInit() + self.cam_1.EndAcquisition() + del self.cam + self.cam_list.Clear() + PySpin.System.CloseInstance() + + + + ##################################################################### + # async def _ser_readline(self): + # c = await self.port.read(1) + # print(c) + # r = c + # while c != b"\n": + # c = await self.port.read(1) + # r += c + # return r + + # async def _ser_send(self, cmd, get_response=True): + # """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + # if self.simulation: + # logger.info("simulation _ser_send(\"%s\")", cmd) + # else: + # logger.debug("_ser_send(\"%s\")", cmd) + # self.port.ser.reset_input_buffer() + # await self.port.write((cmd + "\r\n").encode()) + # if get_response: + # result = (await self._ser_readline()).rstrip().decode() + # logger.debug("got response from device: %s", result) + # if result != "OK": + # errstr = self.error_codes.get(result, "Unrecognized reply") + # s = "Erroneous reply from device: {ec}, {ecs}".format( + # ec=result, ecs=errstr) + # raise ValueError(s) + # else: + # pass + + # async def setup(self): + # """Initial setup of FLIR.""" + # await self._ser_send("E d", get_response=False) + + \ No newline at end of file diff --git a/FLIR/FLIRcodev4.0/build/lib/flir/examplev1.py b/FLIR/FLIRcodev4.0/build/lib/flir/examplev1.py new file mode 100644 index 0000000..b1a4896 --- /dev/null +++ b/FLIR/FLIRcodev4.0/build/lib/flir/examplev1.py @@ -0,0 +1,53 @@ +import PySpin + +# Set camera serial numbers +serial_1 = '20343286' +##### serial_2 = '16276941' + +# Get system +system = PySpin.System.GetInstance() + +# Get camera list +cam_list = system.GetCameras() + +# Get cameras by serial +cam_1 = cam_list.GetBySerial(serial_1) +##### cam_2 = cam_list.GetBySerial(serial_2) + +# Initialize cameras +cam_1.Init() +##### cam_2.Init() + +# Set up primary camera trigger +cam_1.LineSelector.SetValue(PySpin.LineSelector_Line2) +cam_1.V3_3Enable.SetValue(True) + +# Set up secondary camera trigger +##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_Off) +##### cam_2.TriggerSource.SetValue(PySpin.TriggerSource_Line3) +##### cam_2.TriggerOverlap.SetValue(PySpin.TriggerOverlap_ReadOut) +##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_On) + +# Set acquisition mode to acquire a single frame, this ensures acquired images are sync'd since camera 2 and 3 are setup to be triggered +cam_1.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) +##### cam_2.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) + +# Start acquisition; note that secondary cameras have to be started first so acquisition of primary camera triggers secondary cameras. +##### cam_2.BeginAcquisition() +cam_1.BeginAcquisition() + +# Acquire images +image_1 = cam_1.GetNextImage() +##### image_2 = cam_2.GetNextImage() + +# Save images +image_1.Save('cam_1.png') +##### image_2.Save('cam_2.png') + +# Release images +image_1.Release() +##### image_2.Release() + +# end acquisition +cam_1.EndAcquisition() +##### cam_2.EndAcquisition() \ No newline at end of file diff --git a/FLIR/FLIRcodev4.0/build/lib/flir/examplev2.py b/FLIR/FLIRcodev4.0/build/lib/flir/examplev2.py new file mode 100644 index 0000000..cc3d3ad --- /dev/null +++ b/FLIR/FLIRcodev4.0/build/lib/flir/examplev2.py @@ -0,0 +1,64 @@ +import math +import logging +import asyncio +import asyncserial + +import PySpin +import sys + + +def __init__(): + # Set camera serial numbers + serial_1 = '20343286' + ##### serial_2 = '16276941' + + # Get system + system = PySpin.System.GetInstance() + + # Get camera list + cam_list = system.GetCameras() + + # Get cameras by serial + cam_1 = cam_list.GetBySerial(serial_1) + ##### cam_2 = cam_list.GetBySerial(serial_2) + + # Initialize cameras + cam_1.Init() + ##### cam_2.Init() + + # Set up primary camera trigger + cam_1.LineSelector.SetValue(PySpin.LineSelector_Line2) + cam_1.V3_3Enable.SetValue(True) + + # Set acquisition mode to acquire a single frame, this ensures acquired images are sync'd since camera 2 and 3 are setup to be triggered + cam_1.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) + ##### cam_2.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) + +def await_trigger(): + + # Set up secondary camera trigger + ##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_Off) + ##### cam_2.TriggerSource.SetValue(PySpin.TriggerSource_Line3) + ##### cam_2.TriggerOverlap.SetValue(PySpin.TriggerOverlap_ReadOut) + ##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_On) + + # Start acquisition; note that secondary cameras have to be started first so acquisition of primary camera triggers secondary cameras. + ##### cam_2.BeginAcquisition() + cam_1.BeginAcquisition() + +def postpicture(): + # Acquire images + image_1 = cam_1.GetNextImage() + ##### image_2 = cam_2.GetNextImage() + + # Save images + image_1.Save('cam_1.png') + ##### image_2.Save('cam_2.png') + + # Release images + image_1.Release() + ##### image_2.Release() + + # end acquisition + cam_1.EndAcquisition() + ##### cam_2.EndAcquisition() \ No newline at end of file diff --git a/FLIR/FLIRcodev4.0/dist/flir-0.0.0-py3.5.egg b/FLIR/FLIRcodev4.0/dist/flir-0.0.0-py3.5.egg new file mode 100644 index 0000000..82bb8da Binary files /dev/null and b/FLIR/FLIRcodev4.0/dist/flir-0.0.0-py3.5.egg differ diff --git a/FLIR/FLIRcodev4.0/dist/flir-0.0.0-py3.7.egg b/FLIR/FLIRcodev4.0/dist/flir-0.0.0-py3.7.egg new file mode 100644 index 0000000..e41e83d Binary files /dev/null and b/FLIR/FLIRcodev4.0/dist/flir-0.0.0-py3.7.egg differ diff --git a/FLIR/FLIRcodev4.0/dist/flir-0.0.0-py3.8.egg b/FLIR/FLIRcodev4.0/dist/flir-0.0.0-py3.8.egg new file mode 100644 index 0000000..7bbdd8f Binary files /dev/null and b/FLIR/FLIRcodev4.0/dist/flir-0.0.0-py3.8.egg differ diff --git a/FLIR/FLIRcodev4.0/doc/Makefile b/FLIR/FLIRcodev4.0/doc/Makefile new file mode 100644 index 0000000..298ea9e --- /dev/null +++ b/FLIR/FLIRcodev4.0/doc/Makefile @@ -0,0 +1,19 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/FLIR/FLIRcodev4.0/doc/conf.py b/FLIR/FLIRcodev4.0/doc/conf.py new file mode 100644 index 0000000..6cdd72e --- /dev/null +++ b/FLIR/FLIRcodev4.0/doc/conf.py @@ -0,0 +1,176 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config + + +import os +import sys +from unittest.mock import Mock + +sys.path.insert(0, os.path.abspath('..')) + +mock_modules = ["asyncserial"] + +for module in mock_modules: + sys.modules[module] = Mock() + +# -- Project information ----------------------------------------------------- + +project = 'FLIR' +copyright = '2019, M-Labs' +author = 'M-Labs' + +# The short X.Y version +version = '1.0' +# The full version, including alpha/beta/rc tags +release = '1.0' + + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinxarg.ext' +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = None + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'FLIRdoc' + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'FLIR.tex', 'FLIR Documentation', + 'M-Labs', 'manual'), +] + + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'flir', 'FLIR Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'FLIR', 'FLIR Documentation', + author, 'FLIR', 'One line description of project.', + 'Miscellaneous'), +] + + +# -- Options for Epub output ------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +# +# epub_identifier = '' + +# A unique identification for the text. +# +# epub_uid = '' + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] diff --git a/FLIR/FLIRcodev4.0/doc/index.rst b/FLIR/FLIRcodev4.0/doc/index.rst new file mode 100644 index 0000000..a92b827 --- /dev/null +++ b/FLIR/FLIRcodev4.0/doc/index.rst @@ -0,0 +1,24 @@ +Welcome to Novatech409B's documentation! +======================================== + +API +--- + +.. automodule:: flir.driver + :members: + + +ARTIQ controller +---------------- + +.. argparse:: + :ref: flir.aqctl_flir.get_argparser + :prog: aqctl_flir + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/FLIR/FLIRcodev4.0/flir.egg-info/PKG-INFO b/FLIR/FLIRcodev4.0/flir.egg-info/PKG-INFO new file mode 100644 index 0000000..bfed401 --- /dev/null +++ b/FLIR/FLIRcodev4.0/flir.egg-info/PKG-INFO @@ -0,0 +1,10 @@ +Metadata-Version: 1.0 +Name: flir +Version: 0.0.0 +Summary: UNKNOWN +Home-page: UNKNOWN +Author: UNKNOWN +Author-email: UNKNOWN +License: UNKNOWN +Description: UNKNOWN +Platform: UNKNOWN diff --git a/FLIR/FLIRcodev4.0/flir.egg-info/SOURCES.txt b/FLIR/FLIRcodev4.0/flir.egg-info/SOURCES.txt new file mode 100644 index 0000000..6a7d17b --- /dev/null +++ b/FLIR/FLIRcodev4.0/flir.egg-info/SOURCES.txt @@ -0,0 +1,13 @@ +setup.py +flir/__init__.py +flir/aqctl_flir.py +flir/driver(backup_old).py +flir/driver(old).py +flir/driver.py +flir/examplev1.py +flir/examplev2.py +flir.egg-info/PKG-INFO +flir.egg-info/SOURCES.txt +flir.egg-info/dependency_links.txt +flir.egg-info/entry_points.txt +flir.egg-info/top_level.txt \ No newline at end of file diff --git a/FLIR/FLIRcodev4.0/flir.egg-info/dependency_links.txt b/FLIR/FLIRcodev4.0/flir.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/FLIR/FLIRcodev4.0/flir.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/FLIR/FLIRcodev4.0/flir.egg-info/entry_points.txt b/FLIR/FLIRcodev4.0/flir.egg-info/entry_points.txt new file mode 100644 index 0000000..62c21bb --- /dev/null +++ b/FLIR/FLIRcodev4.0/flir.egg-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +aqctl_flir = flir.aqctl_flir:main + diff --git a/FLIR/FLIRcodev4.0/flir.egg-info/top_level.txt b/FLIR/FLIRcodev4.0/flir.egg-info/top_level.txt new file mode 100644 index 0000000..c523cfe --- /dev/null +++ b/FLIR/FLIRcodev4.0/flir.egg-info/top_level.txt @@ -0,0 +1 @@ +flir diff --git a/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S12.png b/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S12.png new file mode 100644 index 0000000..c975b32 Binary files /dev/null and b/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S12.png differ diff --git a/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S42.png b/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S42.png new file mode 100644 index 0000000..c7ebf49 Binary files /dev/null and b/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S42.png differ diff --git a/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S43.png b/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S43.png new file mode 100644 index 0000000..d45ae94 Binary files /dev/null and b/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S43.png differ diff --git a/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S44.png b/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S44.png new file mode 100644 index 0000000..8b4f542 Binary files /dev/null and b/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S44.png differ diff --git a/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S45.png b/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S45.png new file mode 100644 index 0000000..f662ccc Binary files /dev/null and b/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S45.png differ diff --git a/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S46.png b/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S46.png new file mode 100644 index 0000000..feee34c Binary files /dev/null and b/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S46.png differ diff --git a/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S47.png b/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S47.png new file mode 100644 index 0000000..a3cc7dc Binary files /dev/null and b/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S47.png differ diff --git a/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S48.png b/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S48.png new file mode 100644 index 0000000..ca2e9bd Binary files /dev/null and b/FLIR/FLIRcodev4.0/flir/Image_H15_M19_S48.png differ diff --git a/FLIR/FLIRcodev4.0/flir/__init__.py b/FLIR/FLIRcodev4.0/flir/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/FLIR/FLIRcodev4.0/flir/__pycache__/driver.cpython-37.pyc b/FLIR/FLIRcodev4.0/flir/__pycache__/driver.cpython-37.pyc new file mode 100644 index 0000000..d0f4f64 Binary files /dev/null and b/FLIR/FLIRcodev4.0/flir/__pycache__/driver.cpython-37.pyc differ diff --git a/FLIR/FLIRcodev4.0/flir/__pycache__/driver.cpython-38.pyc b/FLIR/FLIRcodev4.0/flir/__pycache__/driver.cpython-38.pyc new file mode 100644 index 0000000..a434172 Binary files /dev/null and b/FLIR/FLIRcodev4.0/flir/__pycache__/driver.cpython-38.pyc differ diff --git a/FLIR/FLIRcodev4.0/flir/__pycache__/examplev2.cpython-37.pyc b/FLIR/FLIRcodev4.0/flir/__pycache__/examplev2.cpython-37.pyc new file mode 100644 index 0000000..9ee1b6c Binary files /dev/null and b/FLIR/FLIRcodev4.0/flir/__pycache__/examplev2.cpython-37.pyc differ diff --git a/FLIR/FLIRcodev4.0/flir/aqctl_flir.py b/FLIR/FLIRcodev4.0/flir/aqctl_flir.py new file mode 100644 index 0000000..edc43e6 --- /dev/null +++ b/FLIR/FLIRcodev4.0/flir/aqctl_flir.py @@ -0,0 +1,60 @@ +#!/usr/bin/env python3 + +# Written by Joe Britton, 2015 + +import argparse +import logging +import sys +import os +import asyncio + +from GitHub.Instruments.FLIR.FLIRcodev40.flir.driver import FLIR +from flir.driver import TriggerType +from sipyco.pc_rpc import simple_server_loop +from sipyco import common_args + + +logger = logging.getLogger(__name__) + + +def get_argparser(): + parser = argparse.ArgumentParser( + description="ARTIQ controller for the FLIR camera") + common_args.simple_network_args(parser, 3200) + parser.add_argument( + "-d", "--device", default=None, + help="serial port.") + parser.add_argument( + "--softtrig", default=False, action="store_true", + help="Sets trigger to software. Default is hardware") + parser.add_argument( + "--num", default=1, + help="Sets number of images. Default is hardware") + parser.add_argument( + "--simulation", action="store_true", + help="Put the driver in simulation mode, even if --device is used.") + common_args.verbosity_args(parser) + return parser + + +def main(): + args = get_argparser().parse_args() + common_args.init_logger_from_args(args) + if os.name == "nt": + asyncio.set_event_loop(asyncio.ProactorEventLoop()) + # if args.device is None: + # print("Starting in Simulation mode...") + # dev = FLIR(args.device if not args.simulation else None) + + print("Software trigger is:",args.softtrig) + triggerset=TriggerType(args.softtrig) + dev = FLIR() + #asyncio.get_event_loop().run_until_complete(dev.setup()) + try: + print("Startup on port",args.port,"successful...") + simple_server_loop( + {"flir": dev}, common_args.bind_address_from_args(args), args.port) + finally: + dev.close() +if __name__ == "__main__": + main() diff --git a/FLIR/FLIRcodev4.0/flir/driver(backup_old).py b/FLIR/FLIRcodev4.0/flir/driver(backup_old).py new file mode 100644 index 0000000..f6295b4 --- /dev/null +++ b/FLIR/FLIRcodev4.0/flir/driver(backup_old).py @@ -0,0 +1,535 @@ +# Written by Joe Britton, 2015 + +import math +import logging +import asyncio +import asyncserial + +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +class TriggerType: + SOFTWARE = 1 + HARDWARE = 2 + +CHOSEN_TRIGGER = TriggerType.SOFTWARE + + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + pass + + +class FLIR: + """Driver for FLIR camera """ + + error_codes = { + "?0": "Unrecognized Command", + "?1": "Bad Frequency", + "?2": "Bad AM Command", + "?3": "Input line too long", + "?4": "Bad Phase", + "?5": "Bad Time", + "?6": "Bad Mode", + "?7": "Bad Amp", + "?8": "Bad Constant", + "?f": "Bad Byte" + } + + def __init__(self, serial_dev): + if serial_dev is None: + self.simulation = True + else: + self.simulation = False + self.port = asyncserial.AsyncSerial( + serial_dev, + baudrate=19200, + bytesize=8, + parity="N", + stopbits=1, + xonxoff=0) + + async def _ser_readline(self): + c = await self.port.read(1) + print(c) + r = c + while c != b"\n": + c = await self.port.read(1) + r += c + return r + + async def _ser_send(self, cmd, get_response=True): + """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + if self.simulation: + logger.info("simulation _ser_send(\"%s\")", cmd) + else: + logger.debug("_ser_send(\"%s\")", cmd) + self.port.ser.reset_input_buffer() + await self.port.write((cmd + "\r\n").encode()) + if get_response: + result = (await self._ser_readline()).rstrip().decode() + logger.debug("got response from device: %s", result) + if result != "OK": + errstr = self.error_codes.get(result, "Unrecognized reply") + s = "Erroneous reply from device: {ec}, {ecs}".format( + ec=result, ecs=errstr) + raise ValueError(s) + else: + pass + + async def setup(self): + """Initial setup of FLIR.""" + await self._ser_send("E d", get_response=False) + + + def close(self): + """Close the serial hardware port.""" + if not self.simulation: + self.port.close() + + async def ping(self): + try: + stat = await self.get_status() + except asyncio.CancelledError: + raise + except: + return False + # check that version number matches is "21" + if stat[4][20:] == "21": + logger.debug("ping successful") + return True + else: + return False + + + 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.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 + 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 + 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 + """ + print("393-postfunction") + try: + print("395") + result = True + err = False + print("398") + # Retrieve TL device nodemap and print device information + nodemap_tldevice = cam.GetTLDeviceNodeMap() + print("401") + result &= print_device_info(nodemap_tldevice) + print("403") + # Initialize camera + cam.Init() + print("406") + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + print("409") + # Configure trigger + if configure_trigger(cam) is False: + return False + print("413") + # Acquire images + result &= grab_next_image_by_trigger(cam) #acquire_images(cam) THIS IS WHAT I CHANGED TO TRY TO GRAB ONLY ONE IMAGE AT A TIME! + print("416") + # Reset trigger + result &= reset_trigger(cam) + print("419") + # Deinitialize camera + cam.DeInit() + print("422") + except PySpin.SpinnakerException as ex: + print("424-exception") + print('Error: %s' % ex) + result = False + + + return result + + + def picture(cam): + """ + Run this code to take a single triggered picture! + + :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!') + print("Closing camera instance...") #input('Done! Press Enter to exit...') + return False + print(cam) + # Run example on each camera + for i, cam in enumerate(cam_list): + + print('Running example for camera %d...' % i) + + print("472-prefunction") + 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() + + print("Closing camera instance...") #input('Done! Press Enter to exit...') + return result + + + # if __name__ == '__picture__': + # if picture(): + # sys.exit(0) + # else: + # sys.exit(1) + + + + +############################################################ + + + + + + # async def reset(self): + # """Hardware reset of FLIR.""" + # await self._ser_send("R", get_response=False) + # await asyncio.sleep(1) + # await self.setup() + + # async def setup(self): + # """Initial setup of FLIR.""" + + # await self._ser_send("E d", get_response=False) + + # async def get_status(self): + # if self.simulation: + # return ["00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "80 BC0000 0000 0102 21"] + # else: + # self.port.ser.reset_input_buffer() + # result = [] + # await self.port.write(("QUE" + "\r\n").encode()) + # for i in range(5): + # m = (await self._ser_readline()).rstrip().decode() + # result.append(m) + # logger.debug("got device status: %s", result) + # return result + + \ No newline at end of file diff --git a/FLIR/FLIRcodev4.0/flir/driver(old).py b/FLIR/FLIRcodev4.0/flir/driver(old).py new file mode 100644 index 0000000..f7b83d4 --- /dev/null +++ b/FLIR/FLIRcodev4.0/flir/driver(old).py @@ -0,0 +1,715 @@ +import math +import logging +import asyncio +import asyncserial +import os +import matplotlib.pyplot as plt +import keyboard +import time +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + +global continue_recording +continue_recording = True + +global trigtype +SOFTWARE = 1 +HARDWARE = 2 +trigtype=SOFTWARE +class TriggerType(): + def __init__(self, softtrig): + global trigtype + if softtrig is True: + trigtype=SOFTWARE + else: + trigtype=HARDWARE + +CHOSEN_TRIGGER = trigtype + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + pass + + +class FLIR: + """Driver for FLIR camera """ + def __init__(self,num): + serial_dev = None + cam=0 + cam_list=0 + self.cameras=0 + result = True + self.num=num + system = PySpin.System.GetInstance() + version = system.GetLibraryVersion() + print('Library version: %d.%d.%d.%d' % (version.major, version.minor, version.type, version.build)) + cam_list = system.GetCameras() + self.system = system + self.cam_list = cam_list + self.cam=cam_list[0] + + num_cameras = cam_list.GetSize() + print('Number of cameras detected: %d' % num_cameras) + if num_cameras == 0: + cam_list.Clear() + system.ReleaseInstance() + print('Not enough cameras!') + print("Closing camera instance...") + return False + for i, cam in enumerate(cam_list): + print('Defining camera %d...' % i) + + self.nodemap_tldevice = cam.GetTLDeviceNodeMap() + result &= self.print_device_info(self.nodemap_tldevice) + cam.Init() + self.nodemap = cam.GetNodeMap() + + print("Going back to server now...") + + + + + + + # def picture(self): + # """ + # Run this code to take a single triggered picture! + + # :return: True if successful, False otherwise. + # :rtype: bool + # """ + # result = True + # print(self.cam) + # result &= self.run_single_camera(self.cam) + # for i, cam in enumerate(cam_list): + + # print('Running example for camera %d...' % i) + + # print("472-prefunction") + # result &= run_single_camera(cam) + # print('Camera %d example complete... \n' % i) + # return result + + def picture(self):#run_single_camera(self): + """ + 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 + cam=self.cam + cam.BeginAcquisition() + image_result = cam.GetNextImage(1000) + # Configure trigger + if self.configure_trigger(cam) is False: + return False + + # Acquire images + result &= self.grab_next_image_by_trigger(cam) #acquire_images(cam) THIS IS WHAT I CHANGED TO TRY TO GRAB ONLY ONE IMAGE AT A TIME! + + + 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 + filename = 'Trigger-%d.jpg' % i + + + # Save image + image_converted.Save(filename) + + print('Image saved at %s\n' % filename) + + # Release image + image_result.Release() + # Reset trigger + result &= self.reset_trigger(cam) + cam.EndAcquisition() + cam.EndAcquisition() + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + + return result + + async def _ser_readline(self): + c = await self.port.read(1) + print(c) + r = c + while c != b"\n": + c = await self.port.read(1) + r += c + return r + + async def _ser_send(self, cmd, get_response=True): + """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + if self.simulation: + logger.info("simulation _ser_send(\"%s\")", cmd) + else: + logger.debug("_ser_send(\"%s\")", cmd) + self.port.ser.reset_input_buffer() + await self.port.write((cmd + "\r\n").encode()) + if get_response: + result = (await self._ser_readline()).rstrip().decode() + logger.debug("got response from device: %s", result) + if result != "OK": + errstr = self.error_codes.get(result, "Unrecognized reply") + s = "Erroneous reply from device: {ec}, {ecs}".format( + ec=result, ecs=errstr) + raise ValueError(s) + else: + pass + + async def setup(self): + """Initial setup of FLIR.""" + await self._ser_send("E d", get_response=False) + + + def close(self): + """Close the serial hardware port.""" + # Deinitialize camera + self.cam.DeInit() + del self.cam + self.system.ReleaseInstance() + self.cam_list.Clear() + print("Closing camera instance...") #input('Done! Press Enter to exit...') + # if not self.simulation: + # self.port.close() + + async def ping(self): + try: + stat = await self.get_status() + except asyncio.CancelledError: + raise + except: + return False + # check that version number matches is "21" + if stat[4][20:] == "21": + logger.debug("ping successful") + return True + else: + return False + + + def configure_trigger(self,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 == SOFTWARE: + print('Software trigger chosen...') + elif CHOSEN_TRIGGER == 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.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 == SOFTWARE: + cam.TriggerSource.SetValue(PySpin.TriggerSource_Software) + print('Trigger source set to software...') + elif CHOSEN_TRIGGER == 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(self,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 == 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 == 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(self): + """ + 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 + """ + cam=self.cam + NUM_IMAGES=self.num + 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 &= self.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(self): + # Deinitialize camera + self.cam.DeInit() + + self.cam.Init() + + + def reset_trigger(self,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(self,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 handle_close(self,evt): + """ + This function will close the GUI when close event happens. + + :param evt: Event that occurs when the figure closes. + :type evt: Event + """ + + global continue_recording + continue_recording = False + + def display(self): + """ + This function continuously acquires images from a device and display them in a GUI. + + :param cam: Camera to acquire images from. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + global continue_recording + + cam=self.cam + nodemap=self.nodemap + nodemap_tldevice=self.nodemap_tldevice + sNodemap = cam.GetTLStreamNodeMap() + + # Change bufferhandling mode to NewestOnly + node_bufferhandling_mode = PySpin.CEnumerationPtr(sNodemap.GetNode('StreamBufferHandlingMode')) + if not PySpin.IsAvailable(node_bufferhandling_mode) or not PySpin.IsWritable(node_bufferhandling_mode): + print('Unable to set stream buffer handling mode.. Aborting...') + return False + + # Retrieve entry node from enumeration node + node_newestonly = node_bufferhandling_mode.GetEntryByName('NewestOnly') + if not PySpin.IsAvailable(node_newestonly) or not PySpin.IsReadable(node_newestonly): + print('Unable to set stream buffer handling mode.. Aborting...') + return False + + # Retrieve integer value from entry node + node_newestonly_mode = node_newestonly.GetValue() + + # Set integer value from entry node as new value of enumeration node + node_bufferhandling_mode.SetIntValue(node_newestonly_mode) + + print('*** IMAGE ACQUISITION ***\n') + try: + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # What happens when the camera begins acquiring images depends on the + # acquisition mode. Single frame captures only a single image, multi + # frame catures a set number of images, and continuous captures a + # continuous stream of images. + # + # *** LATER *** + # Image acquisition must be ended when no more images are needed. + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve device serial number for filename + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Close program + print('Press enter to close the program..') + + # Figure(1) is default so you can omit this line. Figure(0) will create a new window every time program hits this line + fig = plt.figure(1) + + # Close the GUI when close event happens + fig.canvas.mpl_connect('close_event', self.handle_close) + + # Retrieve and display images + while(continue_recording): + try: + + # Retrieve next received image + # + # *** NOTES *** + # Capturing an image houses images on the camera buffer. Trying + # to capture an image that does not exist will hang the camera. + # + # *** LATER *** + # Once an image from the buffer is saved and/or no longer + # needed, the image must be released in order to keep the + # buffer from filling up. + + image_result = cam.GetNextImage(1000) + + # Ensure image completion + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + + else: + + # Getting the image data as a numpy array + image_data = image_result.GetNDArray() + + # Draws an image on the current figure + plt.imshow(image_data, cmap='gray') + + # Interval in plt.pause(interval) determines how fast the images are displayed in a GUI + # Interval is in seconds. + plt.pause(0.001) + + # Clear current reference of a figure. This will improve display speed significantly + plt.clf() + + # If user presses enter, close the program + if keyboard.is_pressed('ENTER'): + print('Program is closing...') + + # Close figure + plt.close('all') + input('Done! Press Enter to exit...') + continue_recording=False + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return True + + + + + + + + + +############################################################ + + + + + + # async def reset(self): + # """Hardware reset of FLIR.""" + # await self._ser_send("R", get_response=False) + # await asyncio.sleep(1) + # await self.setup() + + # async def setup(self): + # """Initial setup of FLIR.""" + + # await self._ser_send("E d", get_response=False) + + # async def get_status(self): + # if self.simulation: + # return ["00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "80 BC0000 0000 0102 21"] + # else: + # self.port.ser.reset_input_buffer() + # result = [] + # await self.port.write(("QUE" + "\r\n").encode()) + # for i in range(5): + # m = (await self._ser_readline()).rstrip().decode() + # result.append(m) + # logger.debug("got device status: %s", result) + # return result + + \ No newline at end of file diff --git a/FLIR/FLIRcodev4.0/flir/driver.py b/FLIR/FLIRcodev4.0/flir/driver.py new file mode 100644 index 0000000..df94acd --- /dev/null +++ b/FLIR/FLIRcodev4.0/flir/driver.py @@ -0,0 +1,179 @@ +import math +import logging +import asyncio +import asyncserial +import os +import matplotlib.pyplot as plt +import keyboard +import time +import PySpin +import sys +import time + +NUM_IMAGES = 10 # number of images to grab + +global continue_recording +continue_recording = True + +global trigtype +SOFTWARE = 1 +HARDWARE = 2 +trigtype=SOFTWARE +class TriggerType(): + def __init__(self, softtrig): + global trigtype + if softtrig is True: + trigtype=SOFTWARE + else: + trigtype=HARDWARE + +CHOSEN_TRIGGER = trigtype + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + pass + + +class FLIR: + """Driver for FLIR camera """ + def __init__(self): + try: + # Set camera serial numbers + serial_1 = '20343286' + ##### serial_2 = '16276941' + + # Get system + self.system = PySpin.System.GetInstance() + + # Get camera list + self.cam_list = self.system.GetCameras() + + # Get cameras by serial + self.cam_1 = self.cam_list.GetBySerial(serial_1) + ##### cam_2 = cam_list.GetBySerial(serial_2) + + # Initialize cameras + self.cam_1.Init() + ##### cam_2.Init() + + # Set acquisition mode to acquire a single frame, this ensures acquired images are sync'd since camera 2 and 3 are setup to be triggered + self.cam_1.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) + ##### cam_2.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) + + + #This takes an image quickly. The first image is always corrupt for whatever reason. This picture is not saved. + self.cam_1.TriggerMode.SetValue(PySpin.TriggerMode_Off) + self.cam_1.TriggerMode.SetValue(PySpin.TriggerMode_On) + self.cam_1.BeginAcquisition() + self.cam_1.EndAcquisition() + + ## Set up primary camera trigger + # self.cam_1.LineSelector.SetValue(PySpin.LineSelector_Line2) + # self.cam_1.V3_3Enable.SetValue(True) + + print("Initialization successful...") + except: + print("Error in __init__()") + + def await_trigger(self): + try: + self.cam_1.TriggerMode.SetValue(PySpin.TriggerMode_Off) + #self.cam_1.TriggerSource.SetValue(PySpin.TriggerSource_Line3) + #self.cam_1.TriggerOverlap.SetValue(PySpin.TriggerOverlap_ReadOut) + self.cam_1.TriggerMode.SetValue(PySpin.TriggerMode_On) + + # Set up secondary camera trigger + ##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_Off) + ##### cam_2.TriggerSource.SetValue(PySpin.TriggerSource_Line3) + ##### cam_2.TriggerOverlap.SetValue(PySpin.TriggerOverlap_ReadOut) + ##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_On) + + # Start acquisition; note that secondary cameras have to be started first so acquisition of primary camera triggers secondary cameras. + ##### cam_2.BeginAcquisition() + self.cam_1.BeginAcquisition() + + print("Awaiting trigger...") + + self.postpicture() + except: + print("Error in await_trigger()") + + def postpicture(self): + try: + # Acquire images + self.image_1 = self.cam_1.GetNextImage() + ##### image_2 = cam_2.GetNextImage() + + # Ensure image completion + if self.image_1.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + + else: + + # Save images + filename = 'Image_H%s_M%d_S%g.png' % (int(time.strftime("%H", time.localtime())), int(time.strftime("%M", time.localtime())),int(time.strftime("%S", time.localtime()))) + self.image_1.Save(filename) + ##### image_2.Save('cam_2.png') + + # Release images + self.image_1.Release() + ##### image_2.Release() + + # end acquisition + self.cam_1.EndAcquisition() + ##### cam_2.EndAcquisition() + print("Picture Successfully taken at: ",time.strftime("%d %b %Y %H:%M:%S", time.localtime())) + except: + print("Error in postpicture()") + + def reset(self): + self.cam_1.DeInit() + self.cam_1.EndAcquisition() + del self.cam + self.cam_list.Clear() + PySpin.System.CloseInstance() + + + + ##################################################################### + # async def _ser_readline(self): + # c = await self.port.read(1) + # print(c) + # r = c + # while c != b"\n": + # c = await self.port.read(1) + # r += c + # return r + + # async def _ser_send(self, cmd, get_response=True): + # """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + # if self.simulation: + # logger.info("simulation _ser_send(\"%s\")", cmd) + # else: + # logger.debug("_ser_send(\"%s\")", cmd) + # self.port.ser.reset_input_buffer() + # await self.port.write((cmd + "\r\n").encode()) + # if get_response: + # result = (await self._ser_readline()).rstrip().decode() + # logger.debug("got response from device: %s", result) + # if result != "OK": + # errstr = self.error_codes.get(result, "Unrecognized reply") + # s = "Erroneous reply from device: {ec}, {ecs}".format( + # ec=result, ecs=errstr) + # raise ValueError(s) + # else: + # pass + + # async def setup(self): + # """Initial setup of FLIR.""" + # await self._ser_send("E d", get_response=False) + + \ No newline at end of file diff --git a/FLIR/FLIRcodev4.0/flir/examplev1.py b/FLIR/FLIRcodev4.0/flir/examplev1.py new file mode 100644 index 0000000..b1a4896 --- /dev/null +++ b/FLIR/FLIRcodev4.0/flir/examplev1.py @@ -0,0 +1,53 @@ +import PySpin + +# Set camera serial numbers +serial_1 = '20343286' +##### serial_2 = '16276941' + +# Get system +system = PySpin.System.GetInstance() + +# Get camera list +cam_list = system.GetCameras() + +# Get cameras by serial +cam_1 = cam_list.GetBySerial(serial_1) +##### cam_2 = cam_list.GetBySerial(serial_2) + +# Initialize cameras +cam_1.Init() +##### cam_2.Init() + +# Set up primary camera trigger +cam_1.LineSelector.SetValue(PySpin.LineSelector_Line2) +cam_1.V3_3Enable.SetValue(True) + +# Set up secondary camera trigger +##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_Off) +##### cam_2.TriggerSource.SetValue(PySpin.TriggerSource_Line3) +##### cam_2.TriggerOverlap.SetValue(PySpin.TriggerOverlap_ReadOut) +##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_On) + +# Set acquisition mode to acquire a single frame, this ensures acquired images are sync'd since camera 2 and 3 are setup to be triggered +cam_1.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) +##### cam_2.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) + +# Start acquisition; note that secondary cameras have to be started first so acquisition of primary camera triggers secondary cameras. +##### cam_2.BeginAcquisition() +cam_1.BeginAcquisition() + +# Acquire images +image_1 = cam_1.GetNextImage() +##### image_2 = cam_2.GetNextImage() + +# Save images +image_1.Save('cam_1.png') +##### image_2.Save('cam_2.png') + +# Release images +image_1.Release() +##### image_2.Release() + +# end acquisition +cam_1.EndAcquisition() +##### cam_2.EndAcquisition() \ No newline at end of file diff --git a/FLIR/FLIRcodev4.0/flir/examplev2.py b/FLIR/FLIRcodev4.0/flir/examplev2.py new file mode 100644 index 0000000..cc3d3ad --- /dev/null +++ b/FLIR/FLIRcodev4.0/flir/examplev2.py @@ -0,0 +1,64 @@ +import math +import logging +import asyncio +import asyncserial + +import PySpin +import sys + + +def __init__(): + # Set camera serial numbers + serial_1 = '20343286' + ##### serial_2 = '16276941' + + # Get system + system = PySpin.System.GetInstance() + + # Get camera list + cam_list = system.GetCameras() + + # Get cameras by serial + cam_1 = cam_list.GetBySerial(serial_1) + ##### cam_2 = cam_list.GetBySerial(serial_2) + + # Initialize cameras + cam_1.Init() + ##### cam_2.Init() + + # Set up primary camera trigger + cam_1.LineSelector.SetValue(PySpin.LineSelector_Line2) + cam_1.V3_3Enable.SetValue(True) + + # Set acquisition mode to acquire a single frame, this ensures acquired images are sync'd since camera 2 and 3 are setup to be triggered + cam_1.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) + ##### cam_2.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) + +def await_trigger(): + + # Set up secondary camera trigger + ##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_Off) + ##### cam_2.TriggerSource.SetValue(PySpin.TriggerSource_Line3) + ##### cam_2.TriggerOverlap.SetValue(PySpin.TriggerOverlap_ReadOut) + ##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_On) + + # Start acquisition; note that secondary cameras have to be started first so acquisition of primary camera triggers secondary cameras. + ##### cam_2.BeginAcquisition() + cam_1.BeginAcquisition() + +def postpicture(): + # Acquire images + image_1 = cam_1.GetNextImage() + ##### image_2 = cam_2.GetNextImage() + + # Save images + image_1.Save('cam_1.png') + ##### image_2.Save('cam_2.png') + + # Release images + image_1.Release() + ##### image_2.Release() + + # end acquisition + cam_1.EndAcquisition() + ##### cam_2.EndAcquisition() \ No newline at end of file diff --git a/FLIR/FLIRcodev4.0/readme.txt b/FLIR/FLIRcodev4.0/readme.txt new file mode 100644 index 0000000..6f15efb --- /dev/null +++ b/FLIR/FLIRcodev4.0/readme.txt @@ -0,0 +1,24 @@ +v1.0 was a failure based on the simplistic code of the manual. Scrapped. +v2.0 was a copy-paste of novatech code with all names and unique functions REMOVED +v3.0 is v2.0 but with the addition of the flir camera functions. Methods are working without the camera. Call "sipyco_rpctool ::1 3200 call picture" to get trigger picture. +v3.1 I dont want to ruin v3.0 stability when hardware testing. v3.1 is hardware testing. Camera initialization and parent class problems. +v3.2 Attempt at initializing camera once and passing object to server. + + +Installation: +1. Install Spinnaker with python3.8 +conda install python3.8 +2. In Flircodevx.x directory, run: + +conda install sipyco +conda install asyncserial +python setup.py build +python setup.py install + +3. Change directories to flir and start server with: + +python aqctl_flir.py + +4. In another anaconda window, in the flir directory, take picture with: + +sipyco_rpctool ::1 3200 call picture \ No newline at end of file diff --git a/FLIR/FLIRcodev4.0/setup.py b/FLIR/FLIRcodev4.0/setup.py new file mode 100644 index 0000000..91e6954 --- /dev/null +++ b/FLIR/FLIRcodev4.0/setup.py @@ -0,0 +1,12 @@ +from setuptools import setup, find_packages + +setup( + name="flir", + install_requires=[],#"sipyco", "asyncserial"], #I disabled these because the installs were messed up! + packages=find_packages(), + entry_points={ + "console_scripts": [ + "aqctl_flir = flir.aqctl_flir:main", + ], + }, +) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/AcquireAndDisplay.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/AcquireAndDisplay.py new file mode 100644 index 0000000..2aee556 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/AcquireAndDisplay.py @@ -0,0 +1,313 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# This AcquireAndDisplay.py shows how to get the image data, and then display images in a GUI. +# This example relies on information provided in the ImageChannelStatistics.py example. +# +# This example demonstrates how to display images represented as numpy arrays. +# Currently, this program is limited to single camera use. +# NOTE: keyboard and matplotlib must be installed on Python interpreter prior to running this example. + +import os +import PySpin +import matplotlib.pyplot as plt +import sys +import keyboard +import time + +global continue_recording +continue_recording = True + + +def handle_close(evt): + """ + This function will close the GUI when close event happens. + + :param evt: Event that occurs when the figure closes. + :type evt: Event + """ + + global continue_recording + continue_recording = False + + +def acquire_and_display_images(cam, nodemap, nodemap_tldevice): + """ + This function continuously acquires images from a device and display them in a GUI. + + :param cam: Camera to acquire images from. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + global continue_recording + + sNodemap = cam.GetTLStreamNodeMap() + + # Change bufferhandling mode to NewestOnly + node_bufferhandling_mode = PySpin.CEnumerationPtr(sNodemap.GetNode('StreamBufferHandlingMode')) + if not PySpin.IsAvailable(node_bufferhandling_mode) or not PySpin.IsWritable(node_bufferhandling_mode): + print('Unable to set stream buffer handling mode.. Aborting...') + return False + + # Retrieve entry node from enumeration node + node_newestonly = node_bufferhandling_mode.GetEntryByName('NewestOnly') + if not PySpin.IsAvailable(node_newestonly) or not PySpin.IsReadable(node_newestonly): + print('Unable to set stream buffer handling mode.. Aborting...') + return False + + # Retrieve integer value from entry node + node_newestonly_mode = node_newestonly.GetValue() + + # Set integer value from entry node as new value of enumeration node + node_bufferhandling_mode.SetIntValue(node_newestonly_mode) + + print('*** IMAGE ACQUISITION ***\n') + try: + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # What happens when the camera begins acquiring images depends on the + # acquisition mode. Single frame captures only a single image, multi + # frame catures a set number of images, and continuous captures a + # continuous stream of images. + # + # *** LATER *** + # Image acquisition must be ended when no more images are needed. + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve device serial number for filename + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Close program + print('Press enter to close the program..') + + # Figure(1) is default so you can omit this line. Figure(0) will create a new window every time program hits this line + fig = plt.figure(1) + + # Close the GUI when close event happens + fig.canvas.mpl_connect('close_event', handle_close) + + # Retrieve and display images + while(continue_recording): + try: + + # Retrieve next received image + # + # *** NOTES *** + # Capturing an image houses images on the camera buffer. Trying + # to capture an image that does not exist will hang the camera. + # + # *** LATER *** + # Once an image from the buffer is saved and/or no longer + # needed, the image must be released in order to keep the + # buffer from filling up. + + image_result = cam.GetNextImage(1000) + + # Ensure image completion + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + + else: + + # Getting the image data as a numpy array + image_data = image_result.GetNDArray() + + # Draws an image on the current figure + plt.imshow(image_data, cmap='gray') + + # Interval in plt.pause(interval) determines how fast the images are displayed in a GUI + # Interval is in seconds. + plt.pause(0.001) + + # Clear current reference of a figure. This will improve display speed significantly + plt.clf() + + # If user presses enter, close the program + if keyboard.is_pressed('ENTER'): + print('Program is closing...') + + # Close figure + plt.close('all') + input('Done! Press Enter to exit...') + continue_recording=False + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return True + + +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 + + nodemap_tldevice = cam.GetTLDeviceNodeMap() + + # Initialize camera + cam.Init() + + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + + # Acquire images + result &= acquire_and_display_images(cam, nodemap, nodemap_tldevice) + + # Deinitialize camera + cam.DeInit() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def main(): + """ + Example entry point; notice the volume of data that the logging event handler + prints out on debug despite the fact that very little really happens in this + example. Because of this, it may be better to have the logger set to lower + level in order to provide a more concise, focused log. + + :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) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/Acquisition.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Acquisition.py new file mode 100644 index 0000000..3459923 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Acquisition.py @@ -0,0 +1,372 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# Acquisition.py shows how to acquire images. It relies on +# information provided in the Enumeration example. Also, check out the +# ExceptionHandling and NodeMapInfo examples if you haven't already. +# ExceptionHandling shows the handling of standard and Spinnaker exceptions +# while NodeMapInfo explores retrieving information from various node types. +# +# This example touches on the preparation and cleanup of a camera just before +# and just after the acquisition of images. Image retrieval and conversion, +# grabbing image data, and saving images are all covered as well. +# +# Once comfortable with Acquisition, we suggest checking out +# AcquisitionMultipleCamera, NodeMapCallback, or SaveToAvi. +# AcquisitionMultipleCamera demonstrates simultaneously acquiring images from +# a number of cameras, NodeMapCallback serves as a good introduction to +# programming with callbacks and events, and SaveToAvi exhibits video creation. + +import os +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +def acquire_images(cam, nodemap, nodemap_tldevice): + """ + 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. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** IMAGE ACQUISITION ***\n') + try: + result = True + + # Set acquisition mode to continuous + # + # *** NOTES *** + # Because the example acquires and saves 10 images, setting acquisition + # mode to continuous lets the example finish. If set to single frame + # or multiframe (at a lower number of images), the example would just + # hang. This would happen because the example has been written to + # acquire 10 images while the camera would have been programmed to + # retrieve less than that. + # + # Setting the value of an enumeration node is slightly more complicated + # than other node types. Two nodes must be retrieved: first, the + # enumeration node is retrieved from the nodemap; and second, the entry + # node is retrieved from the enumeration node. The integer value of the + # entry node is then set as the new value of the enumeration node. + # + # Notice that both the enumeration and the entry nodes are checked for + # availability and readability/writability. Enumeration nodes are + # generally readable and writable whereas their entry nodes are only + # ever readable. + # + # Retrieve enumeration node from nodemap + + # In order to access the node entries, they have to be casted to a pointer type (CEnumerationPtr here) + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # What happens when the camera begins acquiring images depends on the + # acquisition mode. Single frame captures only a single image, multi + # frame catures a set number of images, and continuous captures a + # continuous stream of images. Because the example calls for the + # retrieval of 10 images, continuous mode has been set. + # + # *** LATER *** + # Image acquisition must be ended when no more images are needed. + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve device serial number for filename + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Retrieve, convert, and save images + for i in range(NUM_IMAGES): + try: + + # Retrieve next received image + # + # *** NOTES *** + # Capturing an image houses images on the camera buffer. Trying + # to capture an image that does not exist will hang the camera. + # + # *** LATER *** + # Once an image from the buffer is saved and/or no longer + # needed, the image must be released in order to keep the + # buffer from filling up. + image_result = cam.GetNextImage(1000) + + # Ensure image completion + # + # *** NOTES *** + # Images can easily be checked for completion. This should be + # done whenever a complete image is expected or required. + # Further, check image status for a little more insight into + # why an image is incomplete. + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + + else: + + # Print image information; height and width recorded in pixels + # + # *** NOTES *** + # Images have quite a bit of available metadata including + # things such as CRC, image status, and offset values, to + # name a few. + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed Image %d, width = %d, height = %d' % (i, width, height)) + + # Convert image to mono 8 + # + # *** NOTES *** + # Images can be converted between pixel formats by using + # the appropriate enumeration value. Unlike the original + # image, the converted one does not need to be released as + # it does not affect the camera buffer. + # + # When converting images, color processing algorithm is an + # optional parameter. + image_converted = image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + # Create a unique filename + if device_serial_number: + filename = 'Acquisition-%s-%d.jpg' % (device_serial_number, i) + else: # if serial number is empty + filename = 'Acquisition-%d.jpg' % i + + # Save image + # + # *** NOTES *** + # The standard practice of the examples is to use device + # serial numbers to keep images of one device from + # overwriting those of another. + image_converted.Save(filename) + print('Image saved at %s' % filename) + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + print('') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return 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 + + # 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() + + # Acquire images + result &= acquire_images(cam, nodemap, nodemap_tldevice) + + # 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 + """ + + # 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: %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) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/AcquisitionMultipleCamera.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/AcquisitionMultipleCamera.py new file mode 100644 index 0000000..6fd7cc8 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/AcquisitionMultipleCamera.py @@ -0,0 +1,334 @@ +# ============================================================================ +# Copyright (c) 2001-2019 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. +# ============================================================================ +# +# AcquisitionMultipleCamera.py shows how to capture images from +# multiple cameras simultaneously. It relies on information provided in the +# Enumeration, Acquisition, and NodeMapInfo examples. +# +# This example reads similarly to the Acquisition example, +# except that loops are used to allow for simultaneous acquisitions. + +import os +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + +def acquire_images(cam_list): + """ + This function acquires and saves 10 images from each device. + + :param cam_list: List of cameras + :type cam_list: CameraList + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** IMAGE ACQUISITION ***\n') + try: + result = True + + # Prepare each camera to acquire images + # + # *** NOTES *** + # For pseudo-simultaneous streaming, each camera is prepared as if it + # were just one, but in a loop. Notice that cameras are selected with + # an index. We demonstrate pseduo-simultaneous streaming because true + # simultaneous streaming would require multiple process or threads, + # which is too complex for an example. + # + + for i, cam in enumerate(cam_list): + + # Set acquisition mode to continuous + node_acquisition_mode = PySpin.CEnumerationPtr(cam.GetNodeMap().GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (node retrieval; camera %d). Aborting... \n' % i) + return False + + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or not PySpin.IsReadable( + node_acquisition_mode_continuous): + print('Unable to set acquisition mode to continuous (entry \'continuous\' retrieval %d). \ + Aborting... \n' % i) + return False + + acquisition_mode_continuous = node_acquisition_mode_continuous.GetValue() + + node_acquisition_mode.SetIntValue(acquisition_mode_continuous) + + print('Camera %d acquisition mode set to continuous...' % i) + + # Begin acquiring images + cam.BeginAcquisition() + + print('Camera %d started acquiring images...' % i) + + print() + + # Retrieve, convert, and save images for each camera + # + # *** NOTES *** + # In order to work with simultaneous camera streams, nested loops are + # needed. It is important that the inner loop be the one iterating + # through the cameras; otherwise, all images will be grabbed from a + # single camera before grabbing any images from another. + for n in range(NUM_IMAGES): + for i, cam in enumerate(cam_list): + try: + # Retrieve device serial number for filename + node_device_serial_number = PySpin.CStringPtr(cam.GetTLDeviceNodeMap().GetNode('DeviceSerialNumber')) + + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Camera %d serial number set to %s...' % (i, device_serial_number)) + + # Retrieve next received image and ensure image completion + image_result = cam.GetNextImage(1000) + + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ... \n' % image_result.GetImageStatus()) + else: + # Print image information + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Camera %d grabbed image %d, width = %d, height = %d' % (i, n, 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 = 'AcquisitionMultipleCamera-%s-%d.jpg' % (device_serial_number, n) + else: + filename = 'AcquisitionMultipleCamera-%d-%d.jpg' % (i, n) + + # Save image + image_converted.Save(filename) + print('Image saved at %s' % filename) + + # Release image + image_result.Release() + print() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + # End acquisition for each camera + # + # *** NOTES *** + # Notice that what is usually a one-step process is now two steps + # because of the additional step of selecting the camera. It is worth + # repeating that camera selection needs to be done once per loop. + # + # It is possible to interact with cameras through the camera list with + # GetByIndex(); this is an alternative to retrieving cameras as + # CameraPtr objects that can be quick and easy for small tasks. + for cam in cam_list: + + # End acquisition + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def print_device_info(nodemap, cam_num): + """ + 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. + :param cam_num: Camera number. + :type nodemap: INodeMap + :type cam_num: int + :returns: True if successful, False otherwise. + :rtype: bool + """ + + print('Printing device information for camera %d... \n' % cam_num) + + 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.') + print() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + +def run_multiple_cameras(cam_list): + """ + This function acts as the body of the example; please see NodeMapInfo example + for more in-depth comments on setting up cameras. + + :param cam_list: List of cameras + :type cam_list: CameraList + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Retrieve transport layer nodemaps and print device information for + # each camera + # *** NOTES *** + # This example retrieves information from the transport layer nodemap + # twice: once to print device information and once to grab the device + # serial number. Rather than caching the nodem#ap, each nodemap is + # retrieved both times as needed. + print('*** DEVICE INFORMATION ***\n') + + for i, cam in enumerate(cam_list): + + # Retrieve TL device nodemap + nodemap_tldevice = cam.GetTLDeviceNodeMap() + + # Print device information + result &= print_device_info(nodemap_tldevice, i) + + # Initialize each camera + # + # *** NOTES *** + # You may notice that the steps in this function have more loops with + # less steps per loop; this contrasts the AcquireImages() function + # which has less loops but more steps per loop. This is done for + # demonstrative purposes as both work equally well. + # + # *** LATER *** + # Each camera needs to be deinitialized once all images have been + # acquired. + for i, cam in enumerate(cam_list): + + # Initialize camera + cam.Init() + + # Acquire images on all cameras + result &= acquire_images(cam_list) + + # Deinitialize each camera + # + # *** NOTES *** + # Again, each camera must be deinitialized separately by first + # selecting the camera and then deinitializing it. + for cam in cam_list: + + # Deinitialize camera + cam.DeInit() + + # 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 + + 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 + """ + + # 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: %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 all cameras + print('Running example for all cameras...') + + result = run_multiple_cameras(cam_list) + + print('Example complete... \n') + + # 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) \ No newline at end of file diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/BufferHandling.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/BufferHandling.py new file mode 100644 index 0000000..587038f --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/BufferHandling.py @@ -0,0 +1,493 @@ +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= + +# BufferHandling.py shows how the different buffer handling modes work. +# It relies on information provided in the Acquisition and Trigger examples. +# +# Buffer handling determines the ordering at which images are retrieved, and +# what occurs when an image is transmitted while the buffer is full. There are +# four different buffer handling modes available; NewestFirst, NewestOnly, +# OldestFirst and OldestFirstOverwrite. +# +# This example explores retrieving images in a set pattern; triggering the camera +# while not retrieving an image (letting the buffer fill up), and retrieving +# images while not triggering. We cycle through the different buffer handling +# modes to see which images are retrieved, confirming their identites via their +# Frame ID values. + +import os +import PySpin +import time +import sys + +# Total number of buffers +NUM_BUFFERS = 3 +# Number of triggers +NUM_TRIGGERS = 6 +# Total number of loops +NUM_LOOPS = 9 + +def configure_trigger(nodemap): + """ + This function configures the camera to use a trigger. First, trigger mode is + set to off in order to select the trigger source. Once the trigger source + has been selected, trigger mode is then enabled, which has the camera + capture only a single image upon the execution of the trigger. + + :param nodemap: Device nodemap to retrieve images from. + :type nodemap: INodeMap + :return: True if successful, False otherwise + :rtype: bool + """ + try: + result = True + print('\n*** CONFIGURING TRIGGER ***\n') + + # Ensure trigger mode off + # + # *** NOTES *** + # The trigger must be disabled in order to configure the + # trigger source. + trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerMode')) + if not PySpin.IsAvailable(trigger_mode) or not PySpin.IsWritable(trigger_mode): + print('Unable to disable trigger mode (node retrieval). Aborting...\n') + return False + + trigger_mode_off = PySpin.CEnumEntryPtr(trigger_mode.GetEntryByName('Off')) + if not PySpin.IsAvailable(trigger_mode_off) or not PySpin.IsReadable(trigger_mode_off): + print('Unable to disable trigger mode (enum entry retrieval). Aborting...\n') + return False + + trigger_mode.SetIntValue(trigger_mode_off.GetValue()) + print('Trigger mode disabled...') + + # Set trigger source to software + trigger_source = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerSource')) + if not PySpin.IsAvailable(trigger_source) or not PySpin.IsWritable(trigger_source): + print('Unable to set trigger mode (node retrieval). Aborting...') + return False + + trigger_source_software = PySpin.CEnumEntryPtr(trigger_source.GetEntryByName('Software')) + if not PySpin.IsAvailable(trigger_source_software) or not PySpin.IsReadable(trigger_source_software): + print('Unable to set trigger mode (enum entry retrieval). Aborting...') + return False + + trigger_source.SetIntValue(trigger_source_software.GetValue()) + print('Trigger source set to software...') + + # Turn trigger mode on + trigger_mode_on = PySpin.CEnumEntryPtr(trigger_mode.GetEntryByName('On')) + if not PySpin.IsAvailable(trigger_mode_on) or not PySpin.IsReadable(trigger_mode_on): + print('Unable to enable trigger mode (enum entry retrieval). Aborting...\n') + return False + + trigger_mode.SetIntValue(trigger_mode_on.GetValue()) + print('Trigger mode turned back on...') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + +def grab_next_image_by_trigger(nodemap): + """ + This function retrieves a single image using the trigger. In this example, + only a single image is captured and made available for acquisition - as such, + attempting to acquire two images for a single trigger execution would cause + the example to hang. This is different from other examples, whereby a + constant stream of images are being captured and made available for image + acquisition. + + :param nodemap: Device nodemap to retrieve images from. + :type nodemap: INodeMap + :return: True if successful, False otherwise + :rtype: bool + """ + try: + result = True + + # Execute software trigger + software_trigger_command = PySpin.CCommandPtr(nodemap.GetNode('TriggerSoftware')) + if not PySpin.IsAvailable(software_trigger_command) or not PySpin.IsWritable(software_trigger_command): + print('Unable to execute trigger. Aborting...\n') + return False + + software_trigger_command.Execute() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + +def reset_trigger(nodemap): + """ + This function returns the camera to a normal state by turning off trigger mode. + + :param nodemap: Device nodemap to retrieve images from. + :type nodemap: INodeMap + :return: True if successful, False otherwise + :rtype: bool + """ + try: + result = True + + # Turn trigger mode back off + # + # *** NOTES *** + # Once all images have been captured, turn trigger mode back off to + # restore the camera to a clean state. + trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerMode')) + if not PySpin.IsAvailable(trigger_mode) or not PySpin.IsWritable(trigger_mode): + print('Unable to disable trigger mode (node retrieval). Non-fatal error...\n') + return False + + trigger_mode_off = PySpin.CEnumEntryPtr(trigger_mode.GetEntryByName('Off')) + if not PySpin.IsAvailable(trigger_mode_off) or not PySpin.IsReadable(trigger_mode_off): + print('Unable to disable trigger mode (enum entry retrieval). Non-fatal error...\n') + return False + + trigger_mode.SetIntValue(trigger_mode_off.GetValue()) + print('Trigger mode disabled...\n') + + 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 from camera. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + print('\n*** DEVICE INFORMATION ***\n') + + # Retrieve and display Device Information + 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) + result = False + + return result + +def acquire_images(cam, nodemap, nodemap_tldevice): + """ + This function cycles through the four different buffer handling modes. + It saves three images for three of the buffer handling modes + (NewestFirst, OldestFirst, and OldestFirstOverwrite). For NewestOnly, + it saves one image. + + :param cam: Camera instance to grab images from. + :param nodemap: Device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + print('\n*** IMAGE ACQUISITION ***\n') + + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (node retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration mode + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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...') + + # Retrieve device serial number for filename + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Retrieve Stream Parameters device nodemap + s_node_map = cam.GetTLStreamNodeMap() + + # Retrieve Buffer Handling Mode Information + handling_mode = PySpin.CEnumerationPtr(s_node_map.GetNode('StreamBufferHandlingMode')) + if not PySpin.IsAvailable(handling_mode) or not PySpin.IsWritable(handling_mode): + print('Unable to set Buffer Handling mode (node retrieval). Aborting...\n') + return False + + handling_mode_entry = PySpin.CEnumEntryPtr(handling_mode.GetCurrentEntry()) + if not PySpin.IsAvailable(handling_mode_entry) or not PySpin.IsReadable(handling_mode_entry): + print('Unable to set Buffer Handling mode (Entry retrieval). Aborting...\n') + return False + + # Set stream buffer Count Mode to manual + stream_buffer_count_mode = PySpin.CEnumerationPtr(s_node_map.GetNode('StreamBufferCountMode')) + if not PySpin.IsAvailable(stream_buffer_count_mode) or not PySpin.IsWritable(stream_buffer_count_mode): + print('Unable to set Buffer Count Mode (node retrieval). Aborting...\n') + return False + + stream_buffer_count_mode_manual = PySpin.CEnumEntryPtr(stream_buffer_count_mode.GetEntryByName('Manual')) + if not PySpin.IsAvailable(stream_buffer_count_mode_manual) or not PySpin.IsReadable(stream_buffer_count_mode_manual): + print('Unable to set Buffer Count Mode entry (Entry retrieval). Aborting...\n') + return False + + stream_buffer_count_mode.SetIntValue(stream_buffer_count_mode_manual.GetValue()) + print('Stream Buffer Count Mode set to manual...') + + # Retrieve and modify Stream Buffer Count + buffer_count = PySpin.CIntegerPtr(s_node_map.GetNode('StreamBufferCountManual')) + if not PySpin.IsAvailable(buffer_count) or not PySpin.IsWritable(buffer_count): + print('Unable to set Buffer Count (Integer node retrieval). Aborting...\n') + return False + + # Display Buffer Info + print('\nDefault Buffer Handling Mode: %s' % handling_mode_entry.GetDisplayName()) + print('Default Buffer Count: %d' % buffer_count.GetValue()) + print('Maximum Buffer Count: %d' % buffer_count.GetMax()) + + buffer_count.SetValue(NUM_BUFFERS) + + print('Buffer count now set to: %d' % buffer_count.GetValue()) + print('\nCamera will be triggered %d times in a row before %d images will be retrieved' % (NUM_TRIGGERS,(NUM_LOOPS-NUM_TRIGGERS))) + + for x in range (0, 4): + if x == 0: + handling_mode_entry = handling_mode.GetEntryByName('NewestFirst') + handling_mode.SetIntValue(handling_mode_entry.GetValue()) + print('\n\nBuffer Handling Mode has been set to %s' % handling_mode_entry.GetDisplayName()) + elif x == 1: + handling_mode_entry = handling_mode.GetEntryByName('NewestOnly') + handling_mode.SetIntValue(handling_mode_entry.GetValue()) + print('\n\nBuffer Handling Mode has been set to %s' % handling_mode_entry.GetDisplayName()) + elif x == 2: + handling_mode_entry = handling_mode.GetEntryByName('OldestFirst') + handling_mode.SetIntValue(handling_mode_entry.GetValue()) + print('\n\nBuffer Handling Mode has been set to %s' % handling_mode_entry.GetDisplayName()) + elif x == 3: + handling_mode_entry = handling_mode.GetEntryByName('OldestFirstOverwrite') + handling_mode.SetIntValue(handling_mode_entry.GetValue()) + print('\n\nBuffer Handling Mode has been set to %s' % handling_mode_entry.GetDisplayName()) + + # Begin capturing images + cam.BeginAcquisition() + + # Sleep for one second; only necessary when using non-BFS/ORX cameras on startup + if x == 0: + time.sleep(1) + + try: + # Software Trigger the camera then save images + for loop_cnt in range (0, NUM_LOOPS): + if loop_cnt < NUM_TRIGGERS: + # Retrieve the next image from the trigger + result &= grab_next_image_by_trigger(nodemap) + print('\nCamera triggered. No image grabbed') + else: + print('\nNo trigger. Grabbing image %d' %(loop_cnt-NUM_TRIGGERS)) + result_image = cam.GetNextImage(500) + + if result_image.IsIncomplete(): + print('Image incomplete with image status %s ...\n' % result_image.GetImageStatus()) + + if loop_cnt >= NUM_TRIGGERS: + # Retrieve Frame ID + print('Frame ID: %d' % result_image.GetFrameID()) + + # Create a unique filename + if device_serial_number: + filename = '%s-%s-%d.jpg' % (handling_mode_entry.GetSymbolic(),device_serial_number, (loop_cnt-NUM_TRIGGERS)) + else: + filename = '%s-%d.jpg' % (handling_mode_entry.GetSymbolic(),(loop_cnt-NUM_TRIGGERS)) + + # Save image + result_image.Save(filename) + print('Image saved at %s' % filename) + + # Release image + result_image.Release() + + # To control the framerate, have the application pause for 250ms. + time.sleep(0.25) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + if handling_mode_entry.GetSymbolic() == 'NewestOnly': + print('Error should occur when grabbing image 1 with handling mode set to NewestOnly') + result = False + + # End acquisition + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = 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 acquire images from. + :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 chunk data + if configure_trigger(nodemap) is False: + return False + + # Acquire images and display chunk data + result &= acquire_images(cam, nodemap, nodemap_tldevice) + + # Reset trigger + result &= reset_trigger(nodemap) + + # De-initialize 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 + """ + + # 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: %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('\n\nRunning 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) + + + diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/ChunkData.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/ChunkData.py new file mode 100644 index 0000000..4214d69 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/ChunkData.py @@ -0,0 +1,674 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# ChunkData.py shows how to get chunk data on an image, either from +# the nodemap or from the image itself. 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 samples. As they are somewhat shorter and simpler, either +# provides a strong introduction to camera customization. +# +# Chunk data provides information on various traits of an image. This includes +# identifiers such as frame ID, properties such as black level, and more. This +# information can be acquired from either the nodemap or the image itself. +# +# It may be preferable to grab chunk data from each individual image, as it +# can be hard to verify whether data is coming from the correct image when +# using the nodemap. This is because chunk data retrieved from the nodemap is +# only valid for the current image; when GetNextImage() is called, chunk data +# will be updated to that of the new current image. +# + +import os +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +# Use the following class and global variable to select whether +# chunk data is displayed from the image or the nodemap. +class ChunkDataTypes: + IMAGE = 1 + NODEMAP = 2 + + +CHOSEN_CHUNK_DATA_TYPE = ChunkDataTypes.NODEMAP + + +def configure_chunk_data(nodemap): + """ + This function configures the camera to add chunk data to each image. It does + this by enabling each type of chunk data before enabling chunk data mode. + When chunk data is turned on, the data is made available in both the nodemap + and each image. + + :param nodemap: Transport layer device nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise + :rtype: bool + """ + try: + result = True + print('\n*** CONFIGURING CHUNK DATA ***\n') + + # 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. + chunk_mode_active = PySpin.CBooleanPtr(nodemap.GetNode('ChunkModeActive')) + + if PySpin.IsAvailable(chunk_mode_active) and PySpin.IsWritable(chunk_mode_active): + chunk_mode_active.SetValue(True) + + print('Chunk mode activated...') + + # Enable all types of chunk data + # + # *** NOTES *** + # Enabling chunk data requires working with nodes: "ChunkSelector" + # is an enumeration selector node and "ChunkEnable" is a boolean. It + # requires retrieving the selector node (which is of enumeration node + # type), selecting the entry of the chunk data to be enabled, retrieving + # the corresponding boolean, and setting it to be true. + # + # In this example, all chunk data is enabled, so these steps are + # performed in a loop. Once this is complete, chunk mode still needs to + # be activated. + chunk_selector = PySpin.CEnumerationPtr(nodemap.GetNode('ChunkSelector')) + + if not PySpin.IsAvailable(chunk_selector) or not PySpin.IsReadable(chunk_selector): + print('Unable to retrieve chunk selector. Aborting...\n') + return False + + # Retrieve entries + # + # *** NOTES *** + # PySpin handles mass entry retrieval in a different way than the C++ + # API. Instead of taking in a NodeList_t reference, GetEntries() takes + # no parameters and gives us a list of INodes. Since we want these INodes + # to be of type CEnumEntryPtr, we can use a list comprehension to + # transform all of our collected INodes into CEnumEntryPtrs at once. + entries = [PySpin.CEnumEntryPtr(chunk_selector_entry) for chunk_selector_entry in chunk_selector.GetEntries()] + + print('Enabling entries...') + + # Iterate through our list and select each entry node to enable + for chunk_selector_entry in entries: + # Go to next node if problem occurs + if not PySpin.IsAvailable(chunk_selector_entry) or not PySpin.IsReadable(chunk_selector_entry): + continue + + chunk_selector.SetIntValue(chunk_selector_entry.GetValue()) + + chunk_str = '\t {}:'.format(chunk_selector_entry.GetSymbolic()) + + # Retrieve corresponding boolean + chunk_enable = PySpin.CBooleanPtr(nodemap.GetNode('ChunkEnable')) + + # Enable the boolean, thus enabling the corresponding chunk data + if not PySpin.IsAvailable(chunk_enable): + print('{} not available'.format(chunk_str)) + result = False + elif chunk_enable.GetValue() is True: + print('{} enabled'.format(chunk_str)) + elif PySpin.IsWritable(chunk_enable): + chunk_enable.SetValue(True) + print('{} enabled'.format(chunk_str)) + else: + print('{} not writable'.format(chunk_str)) + result = False + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def display_chunk_data_from_nodemap(nodemap): + """ + This function displays all available chunk data by looping through the + chunk data category node on the nodemap. + + :param nodemap: Device nodemap to retrieve images from. + :type nodemap: INodeMap + :return: True if successful, False otherwise + :rtype: bool + """ + print('Printing chunk data from nodemap...') + try: + result = True + # Retrieve chunk data information nodes + # + # *** NOTES *** + # As well as being written into the payload of the image, chunk data is + # accessible on the GenICam nodemap. When chunk data is enabled, it is + # made available from both the image payload and the nodemap. + chunk_data_control = PySpin.CCategoryPtr(nodemap.GetNode('ChunkDataControl')) + if not PySpin.IsAvailable(chunk_data_control) or not PySpin.IsReadable(chunk_data_control): + print('Unable to retrieve chunk data control. Aborting...\n') + return False + + features = chunk_data_control.GetFeatures() + + # Iterate through children + for feature in features: + feature_node = PySpin.CNodePtr(feature) + feature_display_name = '\t{}:'.format(feature_node.GetDisplayName()) + + if not PySpin.IsAvailable(feature_node) or not PySpin.IsReadable(feature_node): + print('{} node not available'.format(feature_display_name)) + result &= False + continue + # Print node type value + # + # *** NOTES *** + # All nodes can be cast as value nodes and have their information + # retrieved as a string using the ToString() method. This is much + # easier than dealing with each individual node type. + else: + feature_value = PySpin.CValuePtr(feature) + print('{} {}'.format(feature_display_name, feature_value.ToString())) + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def display_chunk_data_from_image(image): + """ + This function displays a select amount of chunk data from the image. Unlike + accessing chunk data via the nodemap, there is no way to loop through all + available data. + + :param image: Image to acquire chunk data from + :type image: Image object + :return: True if successful, False otherwise. + :rtype: bool + """ + print('Printing chunk data from image...') + try: + result = True + print(type(image)) + # Retrieve chunk data from image + # + # *** NOTES *** + # When retrieving chunk data from an image, the data is stored in a + # ChunkData object and accessed with getter functions. + chunk_data = image.GetChunkData() + + # Retrieve exposure time (recorded in microseconds) + exposure_time = chunk_data.GetExposureTime() + print('\tExposure time: {}'.format(exposure_time)) + + # Retrieve frame ID + frame_id = chunk_data.GetFrameID() + print('\tFrame ID: {}'.format(frame_id)) + + # Retrieve gain; gain recorded in decibels + gain = chunk_data.GetGain() + print('\tGain: {}'.format(gain)) + + # Retrieve height; height recorded in pixels + height = chunk_data.GetHeight() + print('\tHeight: {}'.format(height)) + + # Retrieve offset X; offset X recorded in pixels + offset_x = chunk_data.GetOffsetX() + print('\tOffset X: {}'.format(offset_x)) + + # Retrieve offset Y; offset Y recorded in pixels + offset_y = chunk_data.GetOffsetY() + print('\tOffset Y: {}'.format(offset_y)) + + # Retrieve sequencer set active + sequencer_set_active = chunk_data.GetSequencerSetActive() + print('\tSequencer set active: {}'.format(sequencer_set_active)) + + # Retrieve timestamp + timestamp = chunk_data.GetTimestamp() + print('\tTimestamp: {}'.format(timestamp)) + + # Retrieve width; width recorded in pixels + width = chunk_data.GetWidth() + print('\tWidth: {}'.format(width)) + + 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 + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('\n*** 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) + result = False + + return result + + +def acquire_images(cam, nodemap, nodemap_tldevice): + """ + 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. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** IMAGE ACQUISTION ***\n') + + try: + result = True + # Set acquisition mode to continuous + # + # *** NOTES *** + # Because the example acquires and saves 10 images, setting acquisition + # mode to continuous lets the example finish. If set to single frame + # or multiframe (at a lower number of images), the example would just + # hang. This would happen because the example has been written to + # acquire 10 images while the camera would have been programmed to + # retrieve less than that. + # + # Setting the value of an enumeration node is slightly more complicated + # than other node types. Two nodes must be retrieved: first, the + # enumeration node is retrieved from the nodemap; and second, the entry + # node is retrieved from the enumeration node. The integer value of the + # entry node is then set as the new value of the enumeration node. + # + # Notice that both the enumeration and the entry nodes are checked for + # availability and readability/writability. Enumeration nodes are + # generally readable and writable whereas their entry nodes are only + # ever readable. + # + # Retrieve enumeration node from nodemap + + # In order to access the node entries, they have to be casted to a pointer type (CEnumerationPtr here) + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (node retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration mode + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # What happens when the camera begins acquiring images depends on the + # acquisition mode. Single frame captures only a single image, multi + # frame captures a set number of images, and continuous captures a + # continuous stream of images. As the example calls for the + # retrieval of 10 images, continuous mode has been set. + # + # *** LATER *** + # Image acquisition must be ended when no more images are needed. + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve device serial number for filename + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Retrieve, convert, and save images + for i in range(NUM_IMAGES): + try: + # Retrieve next received image + # + # *** NOTES *** + # Capturing an image houses images on the camera buffer. Trying + # to capture an image that does not exist will hang the camera. + # + # *** LATER *** + # Once an image from the buffer is saved and/or no longer + # needed, the image must be released in order to keep the + # buffer from filling up. + image_result = cam.GetNextImage(1000) + + # Ensure image completion + # + # *** NOTES *** + # Images can be easily checked for completion. This should be + # done whenever a complete image is expected or required. + # Further, check image status for a little more insight into + # why an image is incomplete. + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + else: + + # Print image information + # + # *** NOTES *** + # Images have quite a bit of available metadata including + # things such as CRC, image status, and offset values, to + # name a few. + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed Image %d, width = %d, height = %d' % (i, width, height)) + + # Convert image to mono 8 + # + # *** NOTES *** + # Images can be converted between pixel formats by using + # the appropriate enumeration value. Unlike the original + # image, the converted one does not need to be released as + # it does not affect the camera buffer. + # + # When converting images, color processing algorithm is an + # optional parameter. + image_converted = image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + # Create a unique filename + if device_serial_number: + filename = 'ChunkData-%s-%d.jpg' % (device_serial_number, i) + else: + filename = 'ChunkData-%d.jpg' % i + + # Save image + # + # *** NOTES *** + # The standard practice of the examples is to use device + # serial numbers to keep images of one device from + # overwriting those of another. + image_converted.Save(filename) + print('Image saved at %s' % filename) + + # Display chunk data + + if CHOSEN_CHUNK_DATA_TYPE == ChunkDataTypes.IMAGE: + result &= display_chunk_data_from_image(image_result) + elif CHOSEN_CHUNK_DATA_TYPE == ChunkDataTypes.NODEMAP: + result = display_chunk_data_from_nodemap(nodemap) + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + print('') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def disable_chunk_data(nodemap): + """ + This function disables each type of chunk data before disabling chunk data mode. + + :param nodemap: Transport layer device nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise + :rtype: bool + """ + try: + result = True + + # Retrieve the selector node + chunk_selector = PySpin.CEnumerationPtr(nodemap.GetNode('ChunkSelector')) + + if not PySpin.IsAvailable(chunk_selector) or not PySpin.IsReadable(chunk_selector): + print('Unable to retrieve chunk selector. Aborting...\n') + return False + + # Retrieve entries + # + # *** NOTES *** + # PySpin handles mass entry retrieval in a different way than the C++ + # API. Instead of taking in a NodeList_t reference, GetEntries() takes + # no parameters and gives us a list of INodes. Since we want these INodes + # to be of type CEnumEntryPtr, we can use a list comprehension to + # transform all of our collected INodes into CEnumEntryPtrs at once. + entries = [PySpin.CEnumEntryPtr(chunk_selector_entry) for chunk_selector_entry in chunk_selector.GetEntries()] + + print('Disabling entries...') + + for chunk_selector_entry in entries: + # Go to next node if problem occurs + if not PySpin.IsAvailable(chunk_selector_entry) or not PySpin.IsReadable(chunk_selector_entry): + continue + + chunk_selector.SetIntValue(chunk_selector_entry.GetValue()) + + chunk_symbolic_form = '\t {}:'.format(chunk_selector_entry.GetSymbolic()) + + # Retrieve corresponding boolean + chunk_enable = PySpin.CBooleanPtr(nodemap.GetNode('ChunkEnable')) + + # Disable the boolean, thus disabling the corresponding chunk data + if not PySpin.IsAvailable(chunk_enable): + print('{} not available'.format(chunk_symbolic_form)) + result = False + elif not chunk_enable.GetValue(): + print('{} disabled'.format(chunk_symbolic_form)) + elif PySpin.IsWritable(chunk_enable): + chunk_enable.SetValue(False) + print('{} disabled'.format(chunk_symbolic_form)) + else: + print('{} not writable'.format(chunk_symbolic_form)) + + # Deactivate Chunk Mode + chunk_mode_active = PySpin.CBooleanPtr(nodemap.GetNode('ChunkModeActive')) + + if not PySpin.IsAvailable(chunk_mode_active) or not PySpin.IsWritable(chunk_mode_active): + print('Unable to deactivate chunk mode. Aborting...\n') + return False + + chunk_mode_active.SetValue(False) + + print('Chunk mode deactivated...') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def run_single_camera(cam): + """ + This function acts as the body of the example; please see NodeMapInfo example + for more in-depth comments on setting up cameras. + + :param cam: Camera to run on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Retrieve TL device nodemap and print device information + nodemap_tldevice = cam.GetTLDeviceNodeMap() + + result &= print_device_info(nodemap_tldevice) + + # Initialize camera + cam.Init() + + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + + # Configure chunk data + if configure_chunk_data(nodemap) is False: + return False + + # Acquire images and display chunk data + result &= acquire_images(cam, nodemap, nodemap_tldevice) + + # Disable chunk data + if disable_chunk_data(nodemap) is False: + return False + + # De-initialize 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 + """ + + # 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: %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) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/CounterAndTimer.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/CounterAndTimer.py new file mode 100644 index 0000000..537d5d4 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/CounterAndTimer.py @@ -0,0 +1,669 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# CounterAndTimer.py shows how to setup a Pulse Width Modulation (PWM) +# signal using counters and timers. The camera will output the PWM signal via +# strobe, and capture images at a rate defined by the PWM signal as well. +# Users should take care to use a PWM signal within the camera's max +# frame rate (by default, the PWM signal is set to 50 Hz). +# +# Counter and Timer functionality is only available for BFS and Oryx Cameras. +# For details on the hardware setup, see our kb article, "Using Counter and +# Timer Control"; https://www.flir.com/support-center/iis/machine-vision/application-note/using-counter-and-timer-control + +import os +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +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: Device nodemap. + :type nodemap: INodeMap + :return: 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) + 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 available.') + + print('') + + except PySpin.SpinnakerException as ex: + print('Error: {}'.format(ex)) + return False + + return result + + +def setup_counter_and_timer(nodemap): + """ + This function configures the camera to setup a Pulse Width Modulation signal using + Counter and Timer functionality. By default, the PWM signal will be set to run at + 50hz, with a duty cycle of 70%. + + :param nodemap: Device nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('Configuring Pulse Width Modulation signal') + + try: + result = True + + # Set Counter Selector to Counter 0 + node_counter_selector = PySpin.CEnumerationPtr(nodemap.GetNode('CounterSelector')) + + # Check to see if camera supports Counter and Timer functionality + if not PySpin.IsAvailable(node_counter_selector): + print('\nCamera does not support Counter and Timer Functionality. Aborting...\n') + return False + + if not PySpin.IsWritable(node_counter_selector): + print('\nUnable to set Counter Selector (enumeration retrieval). Aborting...\n') + return False + + entry_counter_0 = node_counter_selector.GetEntryByName('Counter0') + if not PySpin.IsAvailable(entry_counter_0) or not PySpin.IsReadable(entry_counter_0): + print('\nUnable to set Counter Selector (entry retrieval). Aborting...\n') + return False + + counter_0 = entry_counter_0.GetValue() + + node_counter_selector.SetIntValue(counter_0) + + # Set Counter Event Source to MHzTick + node_counter_event_source = PySpin.CEnumerationPtr(nodemap.GetNode('CounterEventSource')) + if not PySpin.IsAvailable(node_counter_event_source) or not PySpin.IsWritable(node_counter_event_source): + print('\nUnable to set Counter Event Source (enumeration retrieval). Aborting...\n') + return False + + entry_counter_event_source_mhz_tick = node_counter_event_source.GetEntryByName('MHzTick') + if not PySpin.IsAvailable(entry_counter_event_source_mhz_tick) \ + or not PySpin.IsReadable(entry_counter_event_source_mhz_tick): + print('\nUnable to set Counter Event Source (entry retrieval). Aborting...\n') + return False + + counter_event_source_mhz_tick = entry_counter_event_source_mhz_tick.GetValue() + + node_counter_event_source.SetIntValue(counter_event_source_mhz_tick) + + # Set Counter Duration to 14000 + node_counter_duration = PySpin.CIntegerPtr(nodemap.GetNode('CounterDuration')) + if not PySpin.IsAvailable(node_counter_duration) or not PySpin.IsWritable(node_counter_duration): + print('\nUnable to set Counter Duration (integer retrieval). Aborting...\n') + return False + + node_counter_duration.SetValue(14000) + + # Set Counter Delay to 6000 + node_counter_delay = PySpin.CIntegerPtr(nodemap.GetNode('CounterDelay')) + if not PySpin.IsAvailable(node_counter_delay) or not PySpin.IsWritable(node_counter_delay): + print('\nUnable to set Counter Delay (integer retrieval). Aborting...\n') + return False + + node_counter_delay.SetValue(6000) + + # Determine Duty Cycle of PWM signal + duty_cycle = float(node_counter_duration.GetValue()) / (float(node_counter_duration.GetValue() + + node_counter_delay.GetValue())) * 100 + + print('\nThe duty cycle has been set to {}%'.format(duty_cycle)) + + # Determine pulse rate of PWM signal + pulse_rate = 1000000 / float(node_counter_duration.GetValue() + node_counter_delay.GetValue()) + + print('\nThe pulse rate has been set to {} Hz'.format(pulse_rate)) + + # Set Counter Trigger Source to Frame Trigger Wait + node_counter_trigger_source = PySpin.CEnumerationPtr(nodemap.GetNode('CounterTriggerSource')) + if not PySpin.IsAvailable(node_counter_trigger_source) or not PySpin.IsWritable(node_counter_trigger_source): + print('\nUnable to set Counter Trigger Source (enumeration retrieval). Aborting...\n') + return False + + entry_counter_trigger_source_ftw = node_counter_trigger_source.GetEntryByName('FrameTriggerWait') + if not PySpin.IsAvailable(entry_counter_trigger_source_ftw)\ + or not PySpin.IsReadable(entry_counter_trigger_source_ftw): + print('\nUnable to set Counter Trigger Source (entry retrieval). Aborting...\n') + return False + + counter_trigger_source_ftw = entry_counter_trigger_source_ftw.GetValue() + + node_counter_trigger_source.SetIntValue(counter_trigger_source_ftw) + + # Set Counter Trigger Activation to Level High + node_counter_trigger_activation = PySpin.CEnumerationPtr(nodemap.GetNode('CounterTriggerActivation')) + if not PySpin.IsAvailable(node_counter_trigger_activation) or \ + not PySpin.IsWritable(node_counter_trigger_activation): + print('\nUnable to set Counter Trigger Activation (enumeration retrieval). Aborting...\n') + return False + + entry_counter_trigger_source_lh = node_counter_trigger_activation.GetEntryByName('LevelHigh') + if not PySpin.IsAvailable(entry_counter_trigger_source_lh) \ + or not PySpin.IsReadable(entry_counter_trigger_source_lh): + print('\nUnable to set Counter Trigger Activation (entry retrieval). Aborting...\n') + return False + + counter_trigger_level_high = entry_counter_trigger_source_lh.GetValue() + + node_counter_trigger_activation.SetIntValue(counter_trigger_level_high) + + except PySpin.SpinnakerException as ex: + print('Error: {}'.format(ex)) + return False + + return result + + +def configure_digital_io(nodemap): + """ + This function configures the GPIO to output the PWM signal. + + :param nodemap: Device nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('\nConfiguring GPIO strobe output') + + try: + result = True + camera_family_bfs = "BFS" + camera_family_oryx = "ORX" + + # Determine camera family + node_device_name = PySpin.CStringPtr(nodemap.GetNode('DeviceModelName')) + if not PySpin.IsAvailable(node_device_name) or not PySpin.IsReadable(node_device_name): + print('\nUnable to determine camera family. Aborting...\n') + return False + + camera_model = node_device_name.GetValue() + + # Set Line Selector + node_line_selector = PySpin.CEnumerationPtr(nodemap.GetNode('LineSelector')) + if not PySpin.IsAvailable(node_line_selector) or not PySpin.IsWritable(node_line_selector): + print('\nUnable to set Line Selector (enumeration retrieval). Aborting...\n') + return False + + if camera_family_bfs in camera_model: + + entry_line_selector_line_1 = node_line_selector.GetEntryByName('Line1') + if not PySpin.IsAvailable(entry_line_selector_line_1) or not PySpin.IsReadable(entry_line_selector_line_1): + print('\nUnable to set Line Selector (entry retrieval). Aborting...\n') + return False + + line_selector_line_1 = entry_line_selector_line_1.GetValue() + + node_line_selector.SetIntValue(line_selector_line_1) + + elif camera_family_oryx in camera_model: + + entry_line_selector_line_2 = node_line_selector.GetEntryByName('Line2') + if not PySpin.IsAvailable(entry_line_selector_line_2) or not PySpin.IsReadable(entry_line_selector_line_2): + print('\nUnable to set Line Selector (entry retrieval). Aborting...\n') + return False + + line_selector_line_2 = entry_line_selector_line_2.GetValue() + + node_line_selector.SetIntValue(line_selector_line_2) + + # Set Line Mode to output + node_line_mode = PySpin.CEnumerationPtr(nodemap.GetNode('LineMode')) + if not PySpin.IsAvailable(node_line_mode) or not PySpin.IsWritable(node_line_mode): + print('\nUnable to set Line Mode (enumeration retrieval). Aborting...\n') + return False + + entry_line_mode_output = node_line_mode.GetEntryByName('Output') + if not PySpin.IsAvailable(entry_line_mode_output) or not PySpin.IsReadable(entry_line_mode_output): + print('\nUnable to set Line Mode (entry retrieval). Aborting...\n') + return False + + line_mode_output = entry_line_mode_output.GetValue() + + node_line_mode.SetIntValue(line_mode_output) + + # Set Line Source for Selected Line to Counter 0 Active + node_line_source = PySpin.CEnumerationPtr(nodemap.GetNode('LineSource')) + if not PySpin.IsAvailable(node_line_source) or not PySpin.IsWritable(node_line_source): + print('\nUnable to set Line Source (enumeration retrieval). Aborting...\n') + return False + + entry_line_source_counter_0_active = node_line_source.GetEntryByName('Counter0Active') + if not PySpin.IsAvailable(entry_line_source_counter_0_active) \ + or not PySpin.IsReadable(entry_line_source_counter_0_active): + print('\nUnable to set Line Source (entry retrieval). Aborting...\n') + return False + + line_source_counter_0_active = entry_line_source_counter_0_active.GetValue() + + node_line_source.SetIntValue(line_source_counter_0_active) + + if camera_family_bfs in camera_model: + # Change Line Selector to Line 2 and Enable 3.3 Voltage Rail + entry_line_selector_line_2 = node_line_selector.GetEntryByName('Line2') + if not PySpin.IsAvailable(entry_line_selector_line_2) or not PySpin.IsReadable(entry_line_selector_line_2): + print('\nUnable to set Line Selector (entry retrieval). Aborting...\n') + return False + + line_selector_line_2 = entry_line_selector_line_2.GetValue() + + node_line_selector.SetIntValue(line_selector_line_2) + + node_voltage_enable = PySpin.CBooleanPtr(nodemap.GetNode('V3_3Enable')) + if not PySpin.IsAvailable(node_voltage_enable) or not PySpin.IsWritable(node_voltage_enable): + print('\nUnable to set Voltage Enable (boolean retrieval). Aborting...\n') + return False + + node_voltage_enable.SetValue(True) + + except PySpin.SpinnakerException as ex: + print('Error: {}'.format(ex)) + return False + + return result + + +def configure_exposure_and_trigger(nodemap): + """ + This function configures the camera to set a manual exposure value and enables + camera to be triggered by the PWM signal. + + :param nodemap: Device nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('\nConfiguring Exposure and Trigger') + + try: + result = True + + # Turn off auto exposure + node_exposure_auto = PySpin.CEnumerationPtr(nodemap.GetNode('ExposureAuto')) + if not PySpin.IsAvailable(node_exposure_auto) or not PySpin.IsWritable(node_exposure_auto): + print('\nUnable to set Exposure Auto (enumeration retrieval). Aborting...\n') + return False + + entry_exposure_auto_off = node_exposure_auto.GetEntryByName('Off') + if not PySpin.IsAvailable(entry_exposure_auto_off) or not PySpin.IsReadable(entry_exposure_auto_off): + print('\nUnable to set Exposure Auto (entry retrieval). Aborting...\n') + return False + + exposure_auto_off = entry_exposure_auto_off.GetValue() + + node_exposure_auto.SetIntValue(exposure_auto_off) + + # Set Exposure Time to less than 1/50th of a second (5000 us is used as an example) + node_exposure_time = PySpin.CFloatPtr(nodemap.GetNode('ExposureTime')) + if not PySpin.IsAvailable(node_exposure_time) or not PySpin.IsWritable(node_exposure_time): + print('\nUnable to set Exposure Time (float retrieval). Aborting...\n') + return False + + node_exposure_time.SetValue(5000) + + # Ensure trigger mode is off + # + # *** NOTES *** + # The trigger must be disabled in order to configure + node_trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerMode')) + if not PySpin.IsAvailable(node_trigger_mode) or not PySpin.IsWritable(node_trigger_mode): + print('\nUnable to disable trigger mode (node retrieval). Aborting...\n') + return False + + entry_trigger_mode_off = node_trigger_mode.GetEntryByName('Off') + if not PySpin.IsAvailable(entry_trigger_mode_off) or not PySpin.IsReadable(entry_trigger_mode_off): + print('\nUnable to disable trigger mode (enum entry retrieval). Aborting...\n') + return False + + node_trigger_mode.SetIntValue(entry_trigger_mode_off.GetValue()) + + # Set Trigger Source to Counter 0 Start + node_trigger_source = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerSource')) + if not PySpin.IsAvailable(node_trigger_source) or not PySpin.IsWritable(node_trigger_source): + print('\nUnable to set trigger source (enumeration retrieval). Aborting...\n') + return False + + entry_trigger_source_counter_0_start = node_trigger_source.GetEntryByName('Counter0Start') + if not PySpin.IsAvailable(entry_trigger_source_counter_0_start)\ + or not PySpin.IsReadable(entry_trigger_source_counter_0_start): + print('\nUnable to set trigger mode (enum entry retrieval). Aborting...\n') + return False + + node_trigger_source.SetIntValue(entry_trigger_source_counter_0_start.GetValue()) + + # Set Trigger Overlap to Readout + node_trigger_overlap = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerOverlap')) + if not PySpin.IsAvailable(node_trigger_overlap) or not PySpin.IsWritable(node_trigger_overlap): + print('\nUnable to set Trigger Overlap (enumeration retrieval). Aborting...\n') + return False + + entry_trigger_overlap_ro = node_trigger_overlap.GetEntryByName('ReadOut') + if not PySpin.IsAvailable(entry_trigger_overlap_ro) or not PySpin.IsReadable(entry_trigger_overlap_ro): + print('\nUnable to set Trigger Overlap (entry retrieval). Aborting...\n') + return False + + trigger_overlap_ro = entry_trigger_overlap_ro.GetValue() + + node_trigger_overlap.SetIntValue(trigger_overlap_ro) + + # Turn trigger mode on + entry_trigger_mode_on = node_trigger_mode.GetEntryByName('On') + if not PySpin.IsAvailable(entry_trigger_mode_on) or not PySpin.IsReadable(entry_trigger_mode_on): + print('\nUnable to enable trigger mode (enum entry retrieval). Aborting...\n') + return False + + node_trigger_mode.SetIntValue(entry_trigger_mode_on.GetValue()) + + except PySpin.SpinnakerException as ex: + print('Error: {}'.format(ex)) + return False + + return result + + +def acquire_images(cam, nodemap, nodemap_tldevice): + """ + 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. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('\n*** IMAGE ACQUISITION ***\n') + try: + result = True + + # Set acquisition mode to continuous + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enumeration retrieval). Aborting...\n') + return False + + entry_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(entry_acquisition_mode_continuous)\ + or not PySpin.IsReadable(entry_acquisition_mode_continuous): + print('Unable to set acquisition mode to continuous (enum entry retrieval). Aborting...\n') + return False + + acquisition_mode_continuous = entry_acquisition_mode_continuous.GetValue() + + 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.IsAvailable(node_device_serial_number) and 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 + for i in range(NUM_IMAGES): + try: + + # Retrieve next received image and ensure image completion + image_result = cam.GetNextImage(1000) + + if image_result.IsIncomplete(): + print('Image incomplete with image status {} ...'.format(image_result.GetImageStatus())) + + else: + + # Print image information; height and width recorded in pixels + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed image {}, width = {}, height = {}'.format(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 = 'CounterAndTimer-{}-{}.jpg'.format(device_serial_number, i) + else: # if serial number is empty + filename = 'CounterAndTimer-{}.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 reset_trigger(nodemap): + """ + This function returns the camera to a normal state by turning off trigger mode. + + *** NOTES *** + This function turns off trigger mode, but does not change the trigger source. + + :param nodemap: Transport layer device nodemap. + :type nodemap: INodeMap + :returns: True if successful, False otherwise. + :rtype: bool + """ + + try: + result = True + + # Turn trigger mode back off + node_trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerMode')) + if not PySpin.IsAvailable(node_trigger_mode) or not PySpin.IsWritable(node_trigger_mode): + print('Unable to disable trigger mode (node retrieval). Non-fatal error...\n') + + entry_trigger_mode_off = node_trigger_mode.GetEntryByName('Off') + if not PySpin.IsAvailable(entry_trigger_mode_off) or not PySpin.IsReadable(entry_trigger_mode_off): + print('Unable to disable trigger mode (enum entry retrieval). Non-fatal error...\n') + + node_trigger_mode.SetIntValue(entry_trigger_mode_off.GetValue()) + + except PySpin.SpinnakerException as ex: + print('Error: {}'.format(ex)) + return False + + return result + + +def run_single_camera(cam): + """ + This function acts as the body of the example; please see the 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 Counter and Timer setup + result &= setup_counter_and_timer(nodemap) + if not result: + return result + + # Configure DigitalIO (GPIO output) + result &= configure_digital_io(nodemap) + if not result: + return result + + # Configure Exposure and Trigger + result &= configure_exposure_and_trigger(nodemap) + if not result: + return result + + # Acquire images + result &= acquire_images(cam, nodemap, nodemap_tldevice) + + # Reset trigger + result &= reset_trigger(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: {}.{}.{}.{}'.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: {}'.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 {}...'.format(i)) + + result &= run_single_camera(cam) + print('Camera {} example complete... \n'.format(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) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/DeviceEvents.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/DeviceEvents.py new file mode 100644 index 0000000..53ee365 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/DeviceEvents.py @@ -0,0 +1,494 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# =============================================================================*/ +# +# DeviceEvents.py shows how to create a handler to access device +# events. It relies on information provided in the Enumeration, Acquisition, +# and NodeMapInfo examples. +# +# It can also be helpful to familiarize yourself with the NodeMapCallback +# example, as nodemap callbacks follow the same general procedure as events. +# +# Device events can be thought of as camera-related events. This example +# creates a user-defined class, DeviceEventHandler, which allows the user to +# define any properties, parameters, and the event handler itself while DeviceEventHandler, +# the parent class, allows the child class to appropriately interface with +# the Spinnaker SDK. + +import os +import PySpin +import sys + + +class EventType: + """ + 'Enum' for choosing whether to register a event specifically for exposure end events + or universally for all events. + """ + GENERIC = 0 + SPECIFIC = 1 + +CHOSEN_EVENT = EventType.GENERIC # change me! +NUM_IMAGES = 10 # number of images to acquire + + +class DeviceEventHandler(PySpin.DeviceEventHandler): + """ + This class defines the properties, parameters, and the event handler itself. Take a + moment to notice what parts of the class are mandatory, and what have been + added for demonstration purposes. First, any class used to define device + events must inherit from DeviceEventHandler. Second, the method signature of + OnDeviceEvent() must also be consistent. Everything else - including the + constructor, destructor, properties, and body of OnDeviceEvent() - are + particular to the example. + """ + def __init__(self, eventname): + """ + This constructor registers an event name to be used on device events. + + :param eventname: Name of event to register. + :type eventname: str + :rtype: None + """ + super(DeviceEventHandler, self).__init__() + self.event_name = eventname + self.count = 0 + + def OnDeviceEvent(self, eventname): + """ + Callback function when a device event occurs. + Note eventname is a wrapped gcstring, not a Python string, but basic operations such as printing and comparing + with Python strings are supported. + + :param eventname: gcstring representing the name of the occurred event. + :type eventname: gcstring + :rtype: None + """ + if eventname == self.event_name: + self.count += 1 + + # Print information on specified device event + print('\tDevice event %s with ID %i number %i...' % (eventname, + self.GetDeviceEventId(), + self.count)) + else: + # Print no information on non-specified event + print('\tDevice event occurred; not %s; ignoring...' % self.event_name) + + +def configure_device_events(nodemap, cam): + """ + This function configures the example to execute device events by enabling all + types of device events, and then creating and registering a device event handler that + only concerns itself with an end of exposure event. + + :param INodeMap nodemap: Device nodemap. + :param CameraPtr cam: Pointer to camera. + :returns: tuple (result, device_event_handler) + WHERE + result is True if successful, False otherwise + device_event_handler is the event handler + :rtype: (bool, DeviceEventHandler) + """ + print('\n*** CONFIGURING DEVICE EVENTS ***\n') + + try: + result = True + + # Retrieve device event selector + # + # *** NOTES *** + # Each type of device event must be enabled individually. This is done + # by retrieving "EventSelector" (an enumeration node) and then enabling + # the device event on "EventNotification" (another enumeration node). + # + # This example only deals with exposure end events. However, instead of + # only enabling exposure end events with a simpler device event function, + # all device events are enabled while the device event handler deals with + # ensuring that only exposure end events are considered. A more standard + # use-case might be to enable only the events of interest. + node_event_selector = PySpin.CEnumerationPtr(nodemap.GetNode('EventSelector')) + if not PySpin.IsAvailable(node_event_selector) or not PySpin.IsReadable(node_event_selector): + print('Unable to retrieve event selector entries. Aborting...') + return False + + entries = node_event_selector.GetEntries() + print('Enabling event selector entries...') + + # Enable device events + # + # *** NOTES *** + # In order to enable a device event, the event selector and event + # notification nodes (both of type enumeration) must work in unison. + # The desired event must first be selected on the event selector node + # and then enabled on the event notification node. + for entry in entries: + + # Select entry on selector node + node_entry = PySpin.CEnumEntryPtr(entry) + if not PySpin.IsAvailable(node_entry) or not PySpin.IsReadable(node_entry): + + # Skip if node fails + result = False + continue + + node_event_selector.SetIntValue(node_entry.GetValue()) + + # Retrieve event notification node (an enumeration node) + node_event_notification = PySpin.CEnumerationPtr(nodemap.GetNode('EventNotification')) + if not PySpin.IsAvailable(node_event_notification) or not PySpin.IsWritable(node_event_notification): + + # Skip if node fails + result = False + continue + + # Retrieve entry node to enable device event + node_event_notification_on = PySpin.CEnumEntryPtr(node_event_notification.GetEntryByName('On')) + if not PySpin.IsAvailable(node_event_notification_on) or not PySpin.IsReadable(node_event_notification_on): + + # Skip if node fails + result = False + continue + + node_event_notification.SetIntValue(node_event_notification_on.GetValue()) + + print('\t%s: enabled...' % node_entry.GetDisplayName()) + + # Create device event handler + # + # *** NOTES *** + # The class has been designed to take in the name of an event. If all + # events are registered generically, all event types will trigger a + # device event; on the other hand, if an event handler is registered + # specifically, only that event will trigger an event. + device_event_handler = DeviceEventHandler('EventExposureEnd') + + # Register device event handler + # + # *** NOTES *** + # Device event handlers are registered to cameras. If there are multiple + # cameras, each camera must have any device event handlers registered to it + # separately. Note that multiple device event handlers may be registered to a + # single camera. + # + # *** LATER *** + # Device event handlers must be unregistered manually. This must be done prior + # to releasing the system and while the device event handlers are still in + # scope. + if CHOSEN_EVENT == EventType.GENERIC: + + # Device event handlers registered generally will be triggered by any device events. + cam.RegisterEventHandler(device_event_handler) + + print('Device event handler registered generally...') + + elif CHOSEN_EVENT == EventType.SPECIFIC: + + # Device event handlers registered to a specified event will only + # be triggered by the type of event is it registered to. + cam.RegisterEventHandler(device_event_handler, 'EventExposureEnd') + + print('Device event handler registered specifically to EventExposureEnd events...') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result, device_event_handler + + +def reset_device_events(cam, device_event_handler): + """ + This function resets the example by unregistering the device event handler. + + :param cam: Camera to unregister event handler from. + :param device_event_handler: Event handler for this example. + :type cam: CameraPtr + :type device_event_handler: DeviceEventHandler + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Unregister device event handler + # + # *** NOTES *** + # It is important to unregister all device event handlers from all cameras that + # they are registered to. + cam.UnregisterEventHandler(device_event_handler) + + print('Device event handler unregistered...\n') + + 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 + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** 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.message) + return False + + return result + + +def acquire_images(cam, nodemap, nodemap_tldevice): + """ + 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. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** IMAGE ACQUISITION ***\n') + try: + result = True + + # Set acquisition mode to continuous + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...\n') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) \ + or not PySpin.IsReadable(node_acquisition_mode_continuous): + print('Unable to set acquisition mode to continuous (entry retrieval). Aborting...\n') + return False + + acquisition_mode_continuous = node_acquisition_mode_continuous.GetValue() + + 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 + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Retrieve, convert, and save images + for i in range(NUM_IMAGES): + try: + # Retrieve next received image and ensure image completion + image_result = cam.GetNextImage(1000) + + if image_result.IsIncomplete(): + print('Image incomplete with image status %s...' % image_result.GetImageStatus()) + + else: + + # Print image information + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed Image %i, width = %i, height = %i' % (i, width, height)) + + # Convert to mono8 + image_converted = image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + if device_serial_number: + filename = 'DeviceEvents-%s-%i.jpg' % (device_serial_number, i) + else: + filename = 'DeviceEvents-%i.jpg' % i + + # Save image + image_converted.Save(filename) + print('Image saved at %s' % filename) + + # Release image + image_result.Release() + print('') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def 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 setup and 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 device event handlers + err, device_event_handler = configure_device_events(nodemap, cam) + if not err: + return err + + # Acquire images + result &= acquire_images(cam, nodemap, nodemap_tldevice) + + # Reset device event handlers + result &= reset_device_events(cam, device_event_handler) + + # Deinitialize camera + cam.DeInit() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex.message) + 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: %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) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/Enumeration.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Enumeration.py new file mode 100644 index 0000000..489b34a --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Enumeration.py @@ -0,0 +1,272 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# Enumeration.py shows how to enumerate interfaces and cameras. +# Knowing this is mandatory for doing anything with the Spinnaker SDK, and is +# therefore the best place to start learning how to use the SDK. +# +# This example introduces the preparation, use, and cleanup of the system +# object, interface and camera lists, interfaces, and cameras. It also touches +# on retrieving both nodes from nodemaps and information from nodes. +# +# Once comfortable with enumeration, we suggest checking out the Acquisition and/or +# NodeMapInfo examples. Acquisition demonstrates using a camera to acquire images, +# and NodeMapInfo demonstrates retrieving information from various node types. + +import PySpin +import sys + + +def query_interface(interface): + """ + Queries an interface for its cameras and prints out device information. + + :param interface: InterfacePtr + :return: True if successful, False otherwise. + :rtype: bool + """ + + try: + result = True + + # Retrieve TL nodemap from interface + # + # *** NOTES *** + # Each interface has a nodemap that can be retrieved in order to + # access information about the interface itself, any devices + # connected, or addressing information if applicable. + nodemap_interface = interface.GetTLNodeMap() + + # Print interface display name + # + # *** NOTES *** + # Grabbing node information requires first retrieving the node and + # then retrieving its information. There are two things to keep in + # mind. First, a node is distinguished by type, which is related + # to its value's data type. Second, nodes should be checked for + # availability and readability/writability prior to making an + # attempt to read from or write to the node. + # + # Note that for Python, the node retrieved then has to be 'cast' + # to the proper type (CStringPtr in this case) before it can be used. + node_interface_display_name = PySpin.CStringPtr(nodemap_interface.GetNode('InterfaceDisplayName')) + + if PySpin.IsAvailable(node_interface_display_name) and PySpin.IsReadable(node_interface_display_name): + interface_display_name = node_interface_display_name.GetValue() + + print(interface_display_name) + + else: + print('Interface display name not readable') + + # Update list of cameras on the interface + # + # *** NOTES *** + # Updating the cameras on each interface is especially important if + # there has been any device arrivals or removals since the last time + # that UpdateCameras() was called. + interface.UpdateCameras() + + # Retrieve list of cameras from the interface + # + # *** NOTES *** + # Camera lists can be retrieved from an interface or the system object. + # Camera lists retrieved from an interface, such as this one, only + # return cameras attached on that specific interface whereas camera + # lists retrieved from the system will return all cameras on all + # interfaces. + # + # *** LATER *** + # Camera lists must be cleared manually. This must be done prior to + # releasing the system and while the camera list is still in scope. + cam_list = interface.GetCameras() + + # Retrieve number of cameras + num_cams = cam_list.GetSize() + + # Return if no cameras detected + if num_cams == 0: + print('\tNo devices detected.\n') + return result + + # Print device vendor and model name for each camera on the interface + for i, cam in enumerate(cam_list): + + # Retrieve TL device nodemap; please see NodeMapInfo example for + # additional comments on transport layer nodemaps + nodemap_tldevice = cam.GetTLDeviceNodeMap() + + # Print device vendor name and device model name + # + # *** NOTES *** + # Grabbing node information requires first retrieving the node and + # then retrieving its information. There are two things to keep in + # mind. First, a node is distinguished by type, which is related + # to its value's data type. Second, nodes should be checked for + # availability and readability/writability prior to making an + # attempt to read from or write to the node. + node_device_vendor_name = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceVendorName')) + + if PySpin.IsAvailable(node_device_vendor_name) and PySpin.IsReadable(node_device_vendor_name): + device_vendor_name = node_device_vendor_name.ToString() + + node_device_model_name = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceModelName')) + + if PySpin.IsAvailable(node_device_model_name) and PySpin.IsReadable(node_device_model_name): + device_model_name = node_device_model_name.ToString() + + print('\tDevice %i %s %s \n' % (i, device_vendor_name, device_model_name)) + + # 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 losing scope + # + # *** NOTES *** + # Camera lists (and interface lists) must be cleared manually while in + # the same scope that the system is released. However, in cases like this + # where scope is lost, camera lists (and interface lists) will be cleared + # automatically. + cam_list.Clear() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def main(): + """ + Example entry point. + + :return: True if successful, False otherwise. + :rtype: bool + """ + result = True + + # Retrieve singleton reference to system object + # + # *** NOTES *** + # Everything originates with the system object. It is important to notice + # that it has a singleton implementation, so it is impossible to have + # multiple system objects at the same time. Users can only get a smart + # pointer (SystemPtr) to the system instance. + # + # *** LATER *** + # The system object should be cleared prior to program completion. If not + # released explicitly, it will be released automatically when all SystemPtr + # objects that point to the system go out of scope. + 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 interfaces from the system + # + # *** NOTES *** + # Interface lists are retrieved from the system object. + # + # *** LATER *** + # Interface lists must be cleared manually. This must be done prior to + # releasing the system and while the interface list is still in scope. + iface_list = system.GetInterfaces() + + # Get number of interfaces + num_interfaces = iface_list.GetSize() + + print('Number of interfaces detected: %i' % num_interfaces) + + # Retrieve list of cameras from the system + # + # *** NOTES *** + # Camera lists can be retrieved from an interface or the system object. + # Camera lists retrieved from the system, such as this one, return all + # cameras available on the system. + # + # *** LATER *** + # Camera lists must be cleared manually. This must be done prior to + # releasing the system and while the camera list is still in scope. + cam_list = system.GetCameras() + + num_cams = cam_list.GetSize() + + print('Number of cameras detected: %i' % num_cams) + + # Finish if there are no cameras + if num_cams == 0 or num_interfaces == 0: + + # Clear camera list before releasing system + cam_list.Clear() + + # Clear interface list before releasing system + iface_list.Clear() + + # Release system instance + system.ReleaseInstance() + + print('Not enough cameras!') + input('Done! Press Enter to exit...') + return False + + print('\n*** QUERYING INTERFACES ***\n') + + for iface in iface_list: + + # Query interface + result &= query_interface(iface) + + # Release reference to interface + # 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 iface + + # Clear camera list before releasing system + # + # *** NOTES *** + # Camera lists must be cleared manually prior to a system release call. + cam_list.Clear() + + # Clear interface list before releasing system + # + # *** NOTES *** + # Interface lists must be cleared manually prior to a system release call. + iface_list.Clear() + + # Release system instance + # + # *** NOTES *** + # The system should be released, but if it is not, it will do so itself. + # It is often at the release of the system (whether manual or automatic) + # that unreleased resources and still-registered events will throw an + # exception. + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + return result + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/EnumerationEvents.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/EnumerationEvents.py new file mode 100644 index 0000000..79e8187 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/EnumerationEvents.py @@ -0,0 +1,291 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# EnumerationEvents.py explores arrival and removal events on interfaces and the system. +# It relies on information provided in the Enumeration, Acquisition, and NodeMapInfo examples. +# +# It can also be helpful to familiarize yourself with the NodeMapCallback example, +# as nodemap callbacks follow the same general procedure as events, but with a few less steps. +# +# This example creates two user-defined classes: InterfaceEventHandler and SystemEventHandler. +# These child classes allow the user to define properties, parameters, and the event handler itself +# while the parent classes - DeviceArrivalEventHandler, DeviceRemovalEventHandler, and InterfaceEventHandler - +# allow the child classes to interface with Spinnaker. + +import PySpin + +class InterfaceEventHandler(PySpin.InterfaceEventHandler): + """ + This class defines the properties and methods for device arrivals and removals + on an interface. Take special note of the signatures of the OnDeviceArrival() + and OnDeviceRemoval() methods. Also, enumeration event handlers must inherit from + InterfaceEvent whether they are to be registered to the system or an interface. + """ + def __init__(self, iface, iface_num): + """ + Constructor. Note that this sets the interface instance. + + :param iface: Interface instance. + :param iface_num: Interface number. + """ + super(InterfaceEventHandler, self).__init__() + self.interface = iface + self.interface_num = iface_num + + def OnDeviceArrival(self, serial_number): + """ + This method defines the arrival event on an interface. It prints out + the device serial number of the camera arriving and the interface + number. The argument is the serial number of the camera that triggered + the arrival event. + + :param serial_number: gcstring representing the device serial number of arriving camera + :type serial_number: gcstring + :return: None + """ + print('Interface event handler:') + print('\tDevice %i has arrived on interface %i.' % (serial_number, self.interface_num)) + + def OnDeviceRemoval(self, serial_number): + """ + This method defines removal events on an interface. It prints out the + device serial number of the camera being removed and the interface + number. The argument is the serial number of the camera that triggered + the removal event. + + :param serial_number: gcstring representing the device serial number of removed camera + :type serial_number: gcstring + :return: None + """ + print('Interface event handler:') + print('\tDevice %i was removed from interface %i.' % (serial_number, self.interface_num)) + + +class SystemEventHandler(PySpin.InterfaceEventHandler): + """ + In the C++ example, the SystemEventHandler inherits from both DeviceArrivalEventHandler and + DeviceRemovalEventHandler. This doesn't work for this wrapper, as it will only inherit the abstract + method from the first base class listed, so for this example both System and Interface + event handlers inherit from InterfaceEventHandler. + All three event handler types - DeviceArrivalEventHandler, DeviceRemovalEventHandler, and InterfaceEventHandler - can be + registered to interfaces, the system, or both. + """ + def __init__(self, system): + """ + Constructor. This sets the system instance. + + :param system: Instance of the system. + :type system: SystemPtr + :rtype: None + """ + super(SystemEventHandler, self).__init__() + self.system = system + + def OnDeviceArrival(self, serial_number): + """ + This method defines the arrival event on the system. It retrieves the + number of cameras currently connected and prints it out. + + :param serial_number: gcstring representing the serial number of the arriving camera. + :type serial_number: gcstring + :return: None + """ + cam_list = self.system.GetCameras() + count = cam_list.GetSize() + print('System event handler:') + print('\tThere %s %i %s on the system.' % ('is' if count == 1 else 'are', + count, + 'device' if count == 1 else 'devices')) + + def OnDeviceRemoval(self, serial_number): + """ + This method defines the removal event on the system. It does the same + as the system arrival event - it retrieves the number of cameras + currently connected and prints it out. + + :param serial_number: gcstring representing the serial number of the removed camera. + :type serial_number: gcstring + :return: None + """ + cam_list = self.system.GetCameras() + count = cam_list.GetSize() + print('System event handler:') + print('\tThere %s %i %s on the system.' % ('is' if count == 1 else 'are', + count, + 'device' if count == 1 else 'devices')) + + +def check_gev_enabled(system): + """ + This function checks if GEV enumeration is enabled on the system. + + :param system: Current system instance. + :type system: SystemPtr + + """ + + # Retrieve the System TL NodeMap and EnumerateGEVInterfaces node + system_node_map = system.GetTLNodeMap() + node_gev_enumeration = PySpin.CBooleanPtr(system_node_map.GetNode('EnumerateGEVInterfaces')) + + # Ensure the node is valid + if not PySpin.IsAvailable(node_gev_enumeration) or not PySpin.IsReadable(node_gev_enumeration): + print('EnumerateGEVInterfaces node is unavailable or unreadable. Aborting...') + return + + # Check if node is enabled + gev_enabled = node_gev_enumeration.GetValue() + if not gev_enabled: + print('\nWARNING: GEV Enumeration is disabled.') + print('If you intend to use GigE cameras please run the EnableGEVInterfaces shortcut\n' + 'or set EnumerateGEVInterfaces to true and relaunch your application.\n') + return + print('GEV enumeration is enabled. Continuing..') + + +def main(): + """ + Example entry point; please see Enumeration example for more in-depth + comments on preparing and cleaning up the system. + + :rtype: None + """ + # 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)) + + # Check if GEV enumeration is enabled + check_gev_enabled(system) + + # Retrieve list of cameras from the system + cam_list = system.GetCameras() + + num_cams = cam_list.GetSize() + + print('Number of cameras detected: %i' % num_cams) + + # Retrieve list of interfaces from the system + # + # *** NOTES *** + # MacOS interfaces are only registered if they are active. + # For this example to have the desired outcome all devices must be connected + # at the beginning and end of this example in order to register and deregister + # an event handler on each respective interface. + iface_list = system.GetInterfaces() + + num_ifaces = iface_list.GetSize() + + print('Number of interfaces detected: %i' % num_ifaces) + + print('*** CONFIGURING ENUMERATION EVENTS *** \n') + + # Create interface event handler for the system + # + # *** NOTES *** + # The SystemEventHandler has been constructed to accept a system object in + # order to print the number of cameras on the system. + system_event_handler = SystemEventHandler(system) + + # Register interface event handler for the system + # + # *** NOTES *** + # Arrival, removal, and interface event handlers can all be registered to + # interfaces or the system. Do not think that interface event handlers can only be + # registered to an interface. An interface event handler is merely a combination + # of an arrival and a removal event handler. + # + # *** LATER *** + # Arrival, removal, and interface event handlers must all be unregistered manually. + # This must be done prior to releasing the system and while they are still + # in scope. + system.RegisterInterfaceEventHandler(system_event_handler) + + # Create and register interface event handler to each interface + # + # *** NOTES *** + # The process of event handler creation and registration on interfaces is similar + # to the process of event creation and registration on the system. The + # class for interfaces has been constructed to accept an interface and an + # interface number (this is just to separate the interfaces). + # + # *** LATER *** + # Arrival, removal, and interface event handlers must all be unregistered manually. + # This must be done prior to releasing the system and while they are still + # in scope. + interface_events = [] + + for i, iface in enumerate(iface_list): + + # Create interface event handler + iface_event_handler = InterfaceEventHandler(iface, i) + interface_events.append(iface_event_handler) + + # Register interface event handler + iface.RegisterEventHandler(interface_events[i]) + + print('Event handler registered to interface %i ...' % i) + + # Release reference to interface event handler + # 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 iface_event_handler + + # Wait for user to plug in and/or remove camera devices + input('\nReady! Remove/Plug in cameras to test or press Enter to exit...\n') + + # Unregister interface event handler from each interface + # + # *** NOTES *** + # It is important to unregister all arrival, removal, and interface event handlers + # from all interfaces that they may be registered to. + for i, iface in enumerate(iface_list): + iface.UnregisterEventHandler(interface_events[i]) + + # Release reference to interface and interface event handlers + del iface + del interface_events + print('Event handler unregistered from interfaces...') + + # Unregister system event handler from system object + # + # *** NOTES *** + # It is important to unregister all arrival, removal, and interface event handlers + # registered to the system. + system.UnregisterInterfaceEventHandler(system_event_handler) + + # Delete system event handler, which has a system reference + del system_event_handler + print('Event handler unregistered from system...') + + # Clear camera list before releasing system + cam_list.Clear() + + # Clear interface list before releasing system + iface_list.Clear() + + # Release system instance + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + +if __name__ == '__main__': + main() diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/Enumeration_QuickSpin.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Enumeration_QuickSpin.py new file mode 100644 index 0000000..f016f64 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Enumeration_QuickSpin.py @@ -0,0 +1,260 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# Enumeration_QuickSpin.py shows how to enumerate interfaces +# and cameras using the QuickSpin API. QuickSpin is a subset of the Spinnaker +# library that allows for simpler node access and control. This is a great +# example to start learning about QuickSpin. +# +# This example introduces the preparation, use, and cleanup of the system +# object, interface and camera lists, interfaces, and cameras. It also +# touches on retrieving information from pre-fetched nodes using QuickSpin. +# Retrieving node information is the only portion of the example that +# differs from Enumeration. +# +# 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 + + +def query_interface(interface): + """ + Queries an interface for its cameras and prints out device information. + + :param interface: InterfacePtr + :return: True if successful, False otherwise. + :rtype: bool + """ + + try: + result = True + + # Print interface display name + # + # *** NOTES *** + # QuickSpin allows for the retrieval of interface information directly + # from an interface. Because interface information is made available + # on the transport layer, camera initialization is not required. + node_interface_display_name = interface.TLInterface.InterfaceDisplayName + if PySpin.IsAvailable(node_interface_display_name) and PySpin.IsReadable(node_interface_display_name): + + interface_display_name = node_interface_display_name.GetValue() + + print(interface_display_name) + + else: + print('Interface display name not readable') + + # Update list of cameras on the interface + # + # *** NOTES *** + # Updating the cameras on each interface is especially important if + # there has been any device arrivals or removals since the last time + # that UpdateCameras() was called. + interface.UpdateCameras() + + # Retrieve list of cameras from the interface + # + # *** NOTES *** + # Camera lists can be retrieved from an interface or the system object. + # Camera lists retrieved from an interface, such as this one, only + # return cameras attached on that specific interface whereas camera + # lists retrieved from the system will return all cameras on all + # interfaces. + # + # *** LATER *** + # Camera lists must be cleared manually. This must be done prior to + # releasing the system and while the camera list is still in scope. + cam_list = interface.GetCameras() + + # Retrieve number of cameras + num_cams = cam_list.GetSize() + + # Return if no cameras detected + if num_cams == 0: + print('\tNo devices detected.\n') + return True + + # Print device vendor and model name for each camera on the interface + for i, cam in enumerate(cam_list): + + # Print device vendor name and device model name + # + # *** NOTES *** + # In QuickSpin, accessing nodes does not require first retrieving a + # nodemap. Instead, GenICam nodes are made available + # directly through the camera, and transport layer nodes are made + # available through the camera's TLDevice and TLStream properties. + # + # Most camera interaction happens through the GenICam nodemap, which + # requires the device to be initialized. Simpler reads, like the + # ones below, can often be accomplished at the transport layer, + # which does not require initialization; please see + # NodeMapInfo_QuickSpin for additional information on this topic. + # + # Readability/writability should be checked prior to interacting with + # nodes. Readability and writability are ensured by checking the + # access mode or by using the methods + if cam.TLDevice.DeviceVendorName.GetAccessMode() == PySpin.RO: + device_vendor_name = cam.TLDevice.DeviceVendorName.ToString() + + if cam.TLDevice.DeviceModelName.GetAccessMode() == PySpin.RO: + device_model_name = cam.TLDevice.DeviceModelName.GetValue() + + print('\tDevice %i %s %s \n' % (i, device_vendor_name, device_model_name)) + + # 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 losing scope + # + # *** NOTES *** + # Camera lists (and interface lists) must be cleared manually while in + # the same scope that the system is released. However, in cases like this + # where scope is lost, camera lists (and interface lists) will be cleared + cam_list.Clear() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def main(): + """ + Example entry point. + :return: True if successful, False otherwise. + :rtype: bool + """ + result = True + + # Retrieve singleton reference to system object + # + # *** NOTES *** + # Everything originates with the system object. It is important to notice + # that it has a singleton implementation, so it is impossible to have + # multiple system objects at the same time. Users can only get a smart + # pointer (SystemPtr) to the system instance. + # + # *** LATER *** + # The system object should be cleared prior to program completion. If not + # released explicitly, it will be released automatically when all SystemPtr + # objects that point to the system go out of scope. + 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 interfaces from the system + # + # *** NOTES *** + # Interface lists are retrieved from the system object. + # + # *** LATER *** + # Interface lists must be cleared manually. This must be done prior to + # releasing the system and while the interface list is still in scope. + iface_list = system.GetInterfaces() + + # Get number of interfaces + num_ifaces = iface_list.GetSize() + + print('Number of interfaces detected: %i' % num_ifaces) + + # Retrieve list of cameras from the system + # + # *** NOTES *** + # Camera lists can be retrieved from an interface or the system object. + # Camera lists retrieved from the system, such as this one, return all + # cameras available on the system. + # + # *** LATER *** + # Camera lists must be cleared manually. This must be done prior to + # releasing the system and while the camera list is still in scope. + cam_list = system.GetCameras() + + num_cams = cam_list.GetSize() + + print('Number of cameras detected: %i' % num_cams) + + # Finish if there are no cameras + if num_cams == 0 or num_ifaces == 0: + + # Clear camera list before releasing system + cam_list.Clear() + + # Clear interface list before releasing system + iface_list.Clear() + + # Release system instance + system.ReleaseInstance() + + print('Not enough cameras!') + input('Done! Press Enter to exit...') + return False + + print('\n*** QUERYING INTERFACES ***\n') + + for iface in iface_list: + + # Query interface + result &= query_interface(iface) + + # Release reference to interface + # 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 iface + + # Clear camera list before releasing system + # + # *** NOTES *** + # Camera lists must be cleared manually prior to a system release call. + cam_list.Clear() + + # Clear interface list before releasing system + # + # *** NOTES *** + # Interface lists must be cleared manually prior to a system release call. + iface_list.Clear() + + # Release system instance + # + # *** NOTES *** + # The system should be released, but if it is not, it will do so itself. + # It is often at the release of the system (whether manual or automatic) + # that unreleased resources and still registered events will throw an + # exception. + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + return result + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) \ No newline at end of file diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/Exposure_QuickSpin.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Exposure_QuickSpin.py new file mode 100644 index 0000000..af71c34 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Exposure_QuickSpin.py @@ -0,0 +1,369 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# Exposure_QuickSpin.py shows how to customize image exposure time +# using the QuickSpin API. QuickSpin is a subset of the Spinnaker library +# that allows for simpler node access and control. +# +# This example prepares the camera, sets a new exposure time, and restores +# the camera to its default state. Ensuring custom values fall within an +# acceptable range is also touched on. Retrieving and setting information +# is the only portion of the example that differs from Exposure. +# +# 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 = 5 # number of images to save + + +def configure_exposure(cam): + """ + This function configures a custom exposure time. Automatic exposure is turned + off in order to allow for the customization, and then the custom setting is + applied. + + :param cam: Camera to configure exposure for. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** CONFIGURING EXPOSURE ***\n') + + try: + result = True + + # Turn off automatic exposure mode + # + # *** NOTES *** + # Automatic exposure prevents the manual configuration of exposure + # times and needs to be turned off for this example. Enumerations + # representing entry nodes have been added to QuickSpin. This allows + # for the much easier setting of enumeration nodes to new values. + # + # The naming convention of QuickSpin enums is the name of the + # enumeration node followed by an underscore and the symbolic of + # the entry node. Selecting "Off" on the "ExposureAuto" node is + # thus named "ExposureAuto_Off". + # + # *** LATER *** + # Exposure time can be set automatically or manually as needed. This + # example turns automatic exposure off to set it manually and back + # on to return the camera to its default state. + + if cam.ExposureAuto.GetAccessMode() != PySpin.RW: + print('Unable to disable automatic exposure. Aborting...') + return False + + cam.ExposureAuto.SetValue(PySpin.ExposureAuto_Off) + print('Automatic exposure disabled...') + + # Set exposure time manually; exposure time recorded in microseconds + # + # *** NOTES *** + # Notice that the node is checked for availability and writability + # prior to the setting of the node. In QuickSpin, availability and + # writability are ensured by checking the access mode. + # + # Further, it is ensured that the desired exposure time does not exceed + # the maximum. Exposure time is counted in microseconds - this can be + # found out either by retrieving the unit with the GetUnit() method or + # by checking SpinView. + + if cam.ExposureTime.GetAccessMode() != PySpin.RW: + print('Unable to set exposure time. Aborting...') + return False + + # Ensure desired exposure time does not exceed the maximum + exposure_time_to_set = 2000000.0 + exposure_time_to_set = min(cam.ExposureTime.GetMax(), exposure_time_to_set) + cam.ExposureTime.SetValue(exposure_time_to_set) + print('Shutter time set to %s us...\n' % exposure_time_to_set) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def reset_exposure(cam): + """ + This function returns the camera to a normal state by re-enabling automatic exposure. + + :param cam: Camera to reset exposure on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Turn automatic exposure back on + # + # *** NOTES *** + # Automatic exposure is turned on in order to return the camera to its + # default state. + + if cam.ExposureAuto.GetAccessMode() != PySpin.RW: + print('Unable to enable automatic exposure (node retrieval). Non-fatal error...') + return False + + cam.ExposureAuto.SetValue(PySpin.ExposureAuto_Continuous) + + print('Automatic exposure enabled...') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def print_device_info(cam): + """ + 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 cam: Camera to get device information from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** DEVICE INFORMATION ***\n') + + try: + result = True + nodemap = cam.GetTLDeviceNodeMap() + + 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.message) + 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 the acquisition of images. + + :param cam: Camera to acquire images from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + print('*** IMAGE ACQUISITION ***') + + 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 is not None and cam.TLDevice.DeviceSerialNumber.GetAccessMode() == PySpin.RO: + device_serial_number = cam.TLDevice.DeviceSerialNumber.GetValue() + + print('Device serial number retrieved as %s...' % device_serial_number) + + # Get the value of exposure time to set an appropriate timeout for GetNextImage + timeout = 0 + if cam.ExposureTime.GetAccessMode() == PySpin.RW or cam.ExposureTime.GetAccessMode() == PySpin.RO: + # The exposure time is retrieved in µs so it needs to be converted to ms to keep consistency with the unit being used in GetNextImage + timeout = (int)(cam.ExposureTime.GetValue() / 1000 + 1000) + else: + print ('Unable to get exposure time. Aborting...') + return False + + # Retrieve, convert, and save images + for i in range(NUM_IMAGES): + try: + # Retrieve next received image and ensure image completion + # By default, GetNextImage will block indefinitely until an image arrives. + # In this example, the timeout value is set to [exposure time + 1000]ms to ensure that an image has enough time to arrive under normal conditions + image_result = cam.GetNextImage(timeout) + + 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 Mono8 + image_converted = image_result.Convert(PySpin.PixelFormat_Mono8) + + # Create a unique filename + filename = 'ExposureQS-%s-%d.jpg' % (device_serial_number, i) + + # Save image + image_converted.Save(filename) + + print('Image saved at %s' % filename) + + # Release image + image_result.Release() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + # End acquisition + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def run_single_camera(cam): + """ + This function acts as the body of the example; please see NodeMapInfo_QuickSpin example for more + in-depth comments on setting up cameras. + + :param cam: Camera to run example on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + # Initialize camera + cam.Init() + + # Print device info + result = print_device_info(cam) + + # Configure exposure + if not configure_exposure(cam): + return False + + # Acquire images + result &= acquire_images(cam) + + # Reset exposure + result &= reset_exposure(cam) + + # Deinitialize camera + cam.DeInit() + + return result + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + +def main(): + """ + Example entry point; please see Enumeration_QuickSpin 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) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/FileAccess_QuickSpin.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/FileAccess_QuickSpin.py new file mode 100644 index 0000000..f2dae8c --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/FileAccess_QuickSpin.py @@ -0,0 +1,692 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# FileAccess_QuickSpin.py shows shows how to read and write images using camera File Access function. +# +# This example uploads an image to the camera File Access storage and also +# downloads the image from the camera File Access storage and saves it to +# the disk. +# +# It also provides debug message when an additional argument `--verbose` is passed in, +# giving more detailed status of the progress to the users. +# +# Run with arguments in format (no quotes): "--mode --verbose (optional)" +# /d: Download saved image from camera and save it to the working directory. +# /u: Grab an image and store it on camera. +# + +import PySpin +import numpy as np +import os +import argparse +import sys + +parser = argparse.ArgumentParser(formatter_class=argparse.RawTextHelpFormatter) +subparsers = parser.add_subparsers() + +class ImageAcquisitionUtil: + @staticmethod + def check_node_readable(node): + return PySpin.IsAvailable(node) and PySpin.IsReadable(node) + + @staticmethod + def grab_reference_image(cam): + """ + This function first grabs 5 images to stablize the camera, + then it grabs a reference image and returns its pointer. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: Pointer to the reference image + :rtype: ImagePtr + """ + reference_image = PySpin.Image.Create() + + # Start capturing images + cam.BeginAcquisition() + + # Grab a couple of images to stabilize the camera + for image_count in range(5): + try: + result_image = cam.GetNextImage(1000) + if result_image.IsIncomplete(): + print('Imgae incomplete with image status %s' % result_image.GetImageStatus()) + else: + print('Grabbed image %s' %str(image_count) + ', width = %s' % str(result_image.GetWidth())\ + + ', height = %s' % str(result_image.GetHeight())) + reference_image.DeepCopy(result_image) + result_image.Release() + except PySpin.SpinnakerException as ex: + print(ex) + continue + + cam.EndAcquisition() + + return reference_image + +class FileAccess: + @staticmethod + 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 ImageAcquisitionUtil.check_node_readable(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')) + print('') + else: + print('Device control information not available.') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + @staticmethod + def execute_delete_command(cam): + """ + This function executes delete operation on the camera. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + cam.FileOperationSelector.SetValue(PySpin.FileOperationSelector_Delete) + cam.FileOperationExecute.Execute() + + if cam.FileOperationStatus.GetValue() != PySpin.FileOperationStatus_Success: + print('Failed to delete file!') + return False + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return True + + @staticmethod + def open_file_to_write(cam): + """ + This function opens the camera file for writing. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + cam.FileOperationSelector.SetValue(PySpin.FileOperationSelector_Open) + cam.FileOpenMode.SetValue(PySpin.FileOpenMode_Write) + cam.FileOperationExecute.Execute() + + if cam.FileOperationStatus.GetValue() != PySpin.FileOperationStatus_Success: + print('Failed to open file for writing!') + return False + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return True + + @staticmethod + def execute_write_command(cam): + """ + This function executes write command on the camera. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + cam.FileOperationSelector.SetValue(PySpin.FileOperationSelector_Write) + cam.FileOperationExecute.Execute() + + if cam.FileOperationStatus.GetValue() != PySpin.FileOperationStatus_Success: + print('Failed to write to file!') + return False + except PySpin.SpinnakerException as ex: + print('Unexpected exception : %s' % ex) + return False + return True + + @staticmethod + def close_file(cam): + """ + This function closes the file. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + cam.FileOperationSelector.SetValue(PySpin.FileOperationSelector_Close) + cam.FileOperationExecute.Execute() + + if cam.FileOperationStatus.GetValue() != PySpin.FileOperationStatus_Success: + print('Failed to close file!') + return False + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return True + + @staticmethod + def upload_image(cam, verbose=False): + """ + This function first acquires a reference image from the camera, + then it writes the image file to the camera with file selector UserFile1. + + :param cam: Camera used to download file from. + :param verbose: Prints additional details of file download (False by default) + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + success = True + + nodemap_tldevice = cam.GetTLDeviceNodeMap() + FileAccess.print_device_info(nodemap_tldevice) + + cam.Init() + + # Check file selector support + print('Checking file selector support') + if cam.FileSelector.GetAccessMode() == PySpin.NA or cam.FileSelector.GetAccessMode() == PySpin.NI: + print('File selector not supported on device!') + return False + + # Apply small pixel format + if ImageAcquisitionUtil.check_node_readable(cam.PixelFormat.GetEntry(PySpin.PixelFormat_Mono8)): + cam.PixelFormat.SetValue(PySpin.PixelFormat_Mono8) + else: + # Use Bayer8 if Mono8 is not available + cam.PixelFormat.SetValue(PySpin.PixelFormat_BayerGB8) + + # Display camera setup information + print('Width: %s' % cam.Width.GetValue()) + print('Height: %s' % cam.Height.GetValue()) + print('offsetX: %s' % cam.OffsetX.GetValue()) + print('OffsetY: %s' % cam.OffsetY.GetValue()) + print('PixelFormat: %s' % cam.PixelFormat.GetValue()) + + # Grab reference image + try: + reference_image = ImageAcquisitionUtil.grab_reference_image(cam) + except PySpin.SpinnakerException as ex: + cam.DeInit() + del cam + print('Unexpected error grabbing reference image: %s' % ex) + return False + + # Form file path + filename = "DeviceStreamWrite-" + if cam.DeviceSerialNumber.GetAccessMode() == PySpin.RW or cam.DeviceSerialNumber.GetAccessMode() == PySpin.RO: + filename += "%s-" % cam.DeviceSerialNumber.ToString() + filename += ".bmp" + + # Save image + reference_image.Save(filename) + print('Image saved at %s' % filename) + + print('*** UPLOADING IMAGE ***') + + # Perform file stream write + selector_list = cam.FileSelector.GetEntries() + + for entry in selector_list: + # Get current enum entry node + node = PySpin.CEnumEntryPtr(entry) + + if verbose: + print('\nChecking FileSelector EnumEntry - %s' % node.GetSymbolic()) + + # Check file selector entry support + if not node or not ImageAcquisitionUtil.check_node_readable(node): + # Go to next entry node + print('%s not supported!' % node.GetSymbolic()) + continue + + if node.GetSymbolic() == "UserFile1": + # Set file selector + cam.FileSelector.SetIntValue(int(node.GetNumericValue())) + + # Delete file on camera before writing in case camera runs out of space + file_size = cam.FileSize.GetValue() + if file_size > 0: + if not FileAccess.execute_delete_command(cam): + print('Failed to delete file!') + success = False + continue + + # Open file on camera for write + if not FileAccess.open_file_to_write(cam): + print('Failed to open file!') + success = False + continue + + # Attempt to set FileAccessLength to FileAccessBufferNode length to speed up the write + if cam.FileAccessLength.GetValue() < cam.FileAccessBuffer.GetLength(): + try: + cam.FileAccessLength.SetValue(cam.FileAccessBuffer.GetLength()) + except PySpin.SpinnakerException as ex: + print('Unable to set FileAccessLength to FileAccessBuffer length: %s' % ex) + + # Set file access offset to zero if it's not + cam.FileAccessOffset.SetValue(0) + + # Compute number of write operations required + total_bytes_to_write = reference_image.GetBufferSize() + intermediate_buffer_size = cam.FileAccessLength.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.') + return False + + if verbose: + print('') + 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): + offset = index * intermediate_buffer_size + if offset == 0: + continue + sections.append(offset) + + # Get image data and split into equal chunks + image_data = reference_image.GetData() + split_data = np.array_split(image_data, sections) + + for i in range(len(split_data)): + # Setup data to write + tmp_buffer = split_data[i] + + # Write to AccessBufferNode + cam.FileAccessBuffer.Set(tmp_buffer) + + if intermediate_buffer_size > bytes_left_to_write: + # Update FileAccessLength, otherwise garbage data outside the range would be written to device + cam.FileAccessLength.SetValue(bytes_left_to_write) + + # Perform write command + if not FileAccess.execute_write_command(cam): + print('Writing stream failed!') + success = False + break + + # Verify size of bytes written + size_written = cam.FileOperationResult.GetValue() + + # Log current file access offset + if verbose: + print('File Access Offset: %s' % cam.FileAccessOffset.GetValue()) + + # Keep track of total bytes written + total_bytes_written += size_written + if verbose: + print('Bytes written: %s of %s' % (total_bytes_written, total_bytes_to_write)) + + # Keep track of bytes left to write + bytes_left_to_write = total_bytes_to_write - total_bytes_written + + if verbose: + print('Progress: (%s//%s)' % (i, write_iterations)) + else: + print('Progress: %s' % int((i*100 / write_iterations)) + "%") + + print('Writing complete') + + if not FileAccess.close_file(cam): + success = False + + cam.DeInit() + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return success + + @staticmethod + def open_file_to_read(cam): + """ + This function opens the file to read. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + cam.FileOperationSelector.SetValue(PySpin.FileOperationSelector_Open) + cam.FileOpenMode.SetValue(PySpin.FileOpenMode_Read) + cam.FileOperationExecute.Execute() + + if cam.FileOperationStatus.GetValue() != PySpin.FileOperationStatus_Success: + print('Failed to open file for reading!') + return False + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return True + + @staticmethod + def execute_read_command(cam): + """ + This function executes read command on the camera. + + :param cam: Camera used to perform file operation. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + cam.FileOperationSelector.SetValue(PySpin.FileOperationSelector_Read) + cam.FileOperationExecute.Execute() + + if cam.FileOperationStatus.GetValue() != PySpin.FileOperationStatus_Success: + print('Failed to read file!') + return False + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return True + + @staticmethod + def download_image(cam, verbose=False): + """ + This function reads the image file stored in the camera file selector UserFile1, + saving the file to the working directory of this example. + + :param cam: Camera used to download file from. + :param verbose: Prints additional details of file download (False by default) + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + success = True + + nodemap_tldevice = cam.GetTLDeviceNodeMap() + FileAccess.print_device_info(nodemap_tldevice) + + cam.Init() + + # Check file selector support + print('Checking file selector support') + if cam.FileSelector.GetAccessMode() == PySpin.NA or cam.FileSelector.GetAccessMode() == PySpin.NI: + print('File selector not supported on device!') + return False + + print('*** DOWNLOADING IMAGE ***') + + selector_list = cam.FileSelector.GetEntries() + + for entry in selector_list: + node = PySpin.CEnumEntryPtr(entry) + if verbose: + print('\nChecking FileSelector EnumEntry - %s' % node.GetSymbolic()) + + # Check file selector entry support + if not node or not ImageAcquisitionUtil.check_node_readable(node): + # Go to next entry node + print('%s not supported!' % node.GetSymbolic()) + continue + + # Use UserFile1 as the selector in this example. + # Available file selector entries varies across different cameras + if node.GetSymbolic() == "UserFile1": + # Set file selector + cam.FileSelector.SetIntValue(int(node.GetNumericValue())) + + # Get file size + total_bytes_to_read = cam.FileSize.GetValue() + if total_bytes_to_read == 0: + print('%s - No data available to read!' % node.GetSymbolic()) + success = False + continue + + print('Total data to download: %s' % total_bytes_to_read) + + # Open file on camera for reading + if not FileAccess.open_file_to_read(cam): + print('Failed to open file!') + success = False + continue + + # Attempt to set FileAccessLength to FileAccessBufferNode length to speed up the write + if cam.FileAccessLength.GetValue() < cam.FileAccessBuffer.GetLength(): + try: + cam.FileAccessLength.SetValue(cam.FileAccessBuffer.GetLength()) + except PySpin.SpinnakerException as ex: + print('Unable to set FileAccessLength to FileAccessBuffer length: %s' % ex) + + # Set file access offset to zero + cam.FileAccessOffset.SetValue(0) + + # Computer number of read operations required + intermediate_buffer_size = cam.FileAccessLength.GetValue() + read_iterations = (total_bytes_to_read // intermediate_buffer_size) + \ + (0 if ((total_bytes_to_read % intermediate_buffer_size) == 0) else 1) + + if verbose: + print('') + print('Total bytes to read: %s' % total_bytes_to_read) + print('FileAccessLength: %s' % intermediate_buffer_size) + print('Write iterations: %s' % read_iterations) + + print('Fetching image from camera.') + + total_size_read = 0 + size_read = cam.FileOperationResult.GetValue() + image_data = np.array(size_read, dtype=np.uint8) + + for i in range(read_iterations): + if not FileAccess.execute_read_command(cam): + print('Reading stream failed!') + success = False + break + + # Verify size of bytes read + size_read = cam.FileOperationResult.GetValue() + + # Read from buffer Node + buffer_read = cam.FileAccessBuffer.Get(size_read) + if i == 0: + image_data = buffer_read + else: + image_data = np.append(image_data, buffer_read) + + # Keep track of total bytes read + total_size_read += size_read + if verbose: + print('Bytes read: %s of %s' % (total_size_read, total_bytes_to_read)) + print('Progress: (%s//%s)' % (i, read_iterations)) + else: + print('Progress: %s' % int((i*100 / read_iterations)) + "%") + + print('Reading complete') + + if not FileAccess.close_file(cam): + success = False + + # Form file path + filename = "DeviceStreamRead-" + + if cam.DeviceSerialNumber.GetAccessMode() == PySpin.RW or cam.DeviceSerialNumber.GetAccessMode() == PySpin.RO: + filename += "%s-" % cam.DeviceSerialNumber.ToString() + + filename += ".bmp" + + # Image should be captured with Mono8 or Bayer8, it sets camera to correct pixel format + # in order to grab image ROI + if ImageAcquisitionUtil.check_node_readable(cam.PixelFormat.GetEntry(PySpin.PixelFormat_Mono8)): + cam.PixelFormat.SetValue(PySpin.PixelFormat_Mono8) + elif ImageAcquisitionUtil.check_node_readable(cam.PixelFormat.GetEntry(PySpin.PixelFormat_BayerGB8)): + # Use Bayer8 if Mono8 is not available + cam.PixelFormat.SetValue(PySpin.PixelFormat_BayerGB8) + else: + print('Failed to set camera pixel format.') + return False + + width = cam.Width.GetValue() + height = cam.Height.GetValue() + offset_x = cam.OffsetX.GetValue() + offset_y = cam.OffsetY.GetValue() + pixel_format = cam.PixelFormat.GetValue() + + # Form image and save data + print('Width: %s' % width) + print('Height: %s' % height) + print('OffsetX: %s' % offset_x) + print('OffsetY: %s' % offset_y) + print('PixelFormat: %s' % pixel_format) + + # Create image + image = PySpin.Image.Create(width, height, offset_x, offset_y, pixel_format, image_data) + + # Save image + image.Save(filename) + print('Image saved at %s' % filename) + + cam.DeInit() + except PySpin.SpinnakerException as ex: + print('Unexpected exception: %s' % ex) + return False + return success + +def main(): + """ + Example entry point; please see Enumeration.py example for more in-depth + comments on preparing and cleaning up the system with PySpin. + + :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)) + + parser = argparse.ArgumentParser() + parser = subparsers.add_parser('stop', formatter_class=argparse.RawTextHelpFormatter) + + parser.add_argument('--mode', required=True, type=str, + help='/u : Grab an image and store it on camera.\n/d : Download saved image from camera and save it to the working directory.\n') + parser.add_argument('--verbose', default=False, action='store_true', + help='Enable verbose output.') + + args = parser.parse_args() + + cam_list = system.GetCameras() + num_cameras = cam_list.GetSize() + + # This example only works with 1 camera is connected. + 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 + elif num_cameras > 1: + # Clear camera list before releasing system + cam_list.Clear() + + # Release system instance + system.ReleaseInstance() + + print('This example only works when 1 camera is connected.') + input('Done! Press Enter to exit...') + return False + else: + if args.mode == '/u' or args.mode == '/U': + result = FileAccess.upload_image(cam_list[0], args.verbose) + elif args.mode == '/d' or args.mode == '/D': + result = FileAccess.download_image(cam_list[0], args.verbose) + else: + print("Invalid Argument! Use '--help' to learn available arguments.") + input('Done! Press Enter to exit...') + return False + + if not result: + print('File Access failed') + else: + print('File Access is successful!') + + 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) \ No newline at end of file diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/HighDynamicRange.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/HighDynamicRange.py new file mode 100644 index 0000000..da60789 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/HighDynamicRange.py @@ -0,0 +1,302 @@ +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# HighDynamicRange.py +# This example shows how to set High Dynamic Range (HDR) if it is available on the camera. + +import PySpin +import os +import sys + +NUM_IMAGES = 4 # number of images to grab + +K_HDR_SHUTTER1 = 1000 # us +K_HDR_SHUTTER2 = 5000 +K_HDR_SHUTTER3 = 15000 +K_HDR_SHUTTER4 = 30000 + +K_HDR_GAIN1 = 0 # dB +K_HDR_GAIN2 = 5 +K_HDR_GAIN3 = 10 +K_HDR_GAIN4 = 15 + + +def print_device_info(nodemap): + """ + Helper for outputting camera information + + :param nodemap: Transport layer device nodemap. + :type INodeMap + :returns: True if successful, False otherwise. + :rtype: bool + """ + + print('*** DEVICE INFORMATION ***') + + try: + node_device_information = PySpin.CCategoryPtr(nodemap.GetNode('DeviceControl')) + + 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 True + +def check_node_accessibility(node): + """ + Helper for checking GenICam node accessibility + + :param node: GenICam node being checked + :type node: CNodePtr + :return: True if accessible, False otherwise + :rtype: bool + """ + + return PySpin.IsAvailable(node) and (PySpin.IsReadable(node) or PySpin.IsWritable(node)) + +def toggle_hdr_mode(nodemap, hdr_on): + """ + Helper for toggling HDR mode on camera + + :param nodemap: Transport layer device nodemap. + :type: INodeMap + :param hdr_on: True if want to turn hdr mode on, False otherwise. + :type hdr_on: bool + :return: True if successful, False otherwise. + :rtype: bool + """ + + node_hdr_enabled = PySpin.CBooleanPtr(nodemap.GetNode("PGR_HDRModeEnabled")) + + if check_node_accessibility(node_hdr_enabled): + node_hdr_enabled.SetValue(hdr_on) + else: + return False + + print('HDR mode turned to', hdr_on) + + return True + +def initialize_hdr_images(nodemap): + """ + Helper for initializing HDR images + + :param nodemap: Transport layer device nodemap. + :type: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + hdr_image_selector = PySpin.CEnumerationPtr(nodemap.GetNode("PGR_HDRImageSelector")) + hdr_exposure_abs = PySpin.CFloatPtr(nodemap.GetNode("PGR_HDR_ExposureTimeAbs")) + hdr_gain_abs = PySpin.CFloatPtr(nodemap.GetNode("PGR_HDR_GainAbs")) + + if not check_node_accessibility(hdr_image_selector): + return False + if not check_node_accessibility(hdr_exposure_abs): + return False + if not check_node_accessibility(hdr_gain_abs): + return False + + # Configure Image1 + hdr_image_selector.SetIntValue(hdr_image_selector.GetEntryByName("Image1").GetValue()) + hdr_exposure_abs.SetValue(K_HDR_SHUTTER1) + hdr_gain_abs.SetValue(K_HDR_GAIN1) + print('Initialized HDR Image1...') + + # Configure Image2 + hdr_image_selector.SetIntValue(hdr_image_selector.GetEntryByName("Image2").GetValue()) + hdr_exposure_abs.SetValue(K_HDR_SHUTTER2) + hdr_gain_abs.SetValue(K_HDR_GAIN2) + print('Initialized HDR Image2...') + + # Configure Image3 + hdr_image_selector.SetIntValue(hdr_image_selector.GetEntryByName("Image3").GetValue()) + hdr_exposure_abs.SetValue(K_HDR_SHUTTER3) + hdr_gain_abs.SetValue(K_HDR_GAIN3) + print('Initialized HDR Image3...') + + # Configure Image4 + hdr_image_selector.SetIntValue(hdr_image_selector.GetEntryByName("Image4").GetValue()) + hdr_exposure_abs.SetValue(K_HDR_SHUTTER4) + hdr_gain_abs.SetValue(K_HDR_GAIN4) + print('Initialized HDR Image4...') + + return True + +def run_single_camera(cam): + """ + Helper for running example on single camera + + :param cam: Camera to run on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Initialize camera + cam.Init() + + # Get GenICam NodeMap info from camera + nodemap = cam.GetNodeMap() + + # Get camera information through NodeMap + print_device_info(nodemap) + + # Verify whether HDR is supported on this device + node_hdr_enabled = PySpin.CBooleanPtr(nodemap.GetNode("PGR_HDRModeEnabled")) + if not PySpin.IsAvailable(node_hdr_enabled): + print('HDR is not supported! Exiting...') + return True + + # HDR needs to be enabled prior to configure individual HDR images + toggle_hdr_mode(nodemap, True) + + if not initialize_hdr_images(nodemap): + print('Error configuring HDR image! Exiting...') + return False + + # Retrieve Device ID + device_id = cam.GetTLDeviceNodeMap().GetNode("DeviceID") + + # Begin capturing images + print('Starting grabbing images...') + cam.BeginAcquisition() + + for i in range(NUM_IMAGES): + try: + # Retrieve the next received image + raw_image = cam.GetNextImage(1000) + width = raw_image.GetWidth() + height = raw_image.GetHeight() + print('Grabbed image %d, width = %d, height = %d' % (i, width, height)) + + # Convert image to Mono8 + converted_image = raw_image.Convert(PySpin.PixelFormat_Mono8) + + # Create a unique filename + filename = 'HighDynamicRange-%s-%d.jpg' % (device_id, i) + + # Save image + converted_image.Save(filename) + + # Image need to be released after use + raw_image.Release() + + except PySpin.SpinnakerException as ex: + print('Error Retrieving Image: %s' % ex) + result = False + continue + + # End capturing of images + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + print() + + 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: %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 cam in cam_list: + result &= run_single_camera(cam) + + # 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) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/ImageChannelStatistics.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/ImageChannelStatistics.py new file mode 100644 index 0000000..7589b73 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/ImageChannelStatistics.py @@ -0,0 +1,302 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# ImageChannelStatisitcs.py shows how to get the image data and channel statistics, and then saves / displays them. +# This example relies on information provided in the Acquisition examples. +# +# This example demonstrates how to visualize the image histogram using Python, and display an image represented as +# a numpy array. +# +# NOTE: matplotlib must be installed on Python interpreter prior to running this example + +import os +import sys +import PySpin +import matplotlib.pyplot as plt + +NUM_IMAGES = 10 # number of images to grab + + +def acquire_and_display_images(cam, nodemap, nodemap_tldevice): + """ + This function acquires and displays the channel statistics of N images from a device. + + :param cam: Camera to acquire images from. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** IMAGE ACQUISITION ***\n') + try: + result = True + + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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...') + + node_pixel_format = PySpin.CEnumerationPtr(nodemap.GetNode('PixelFormat')) + if not PySpin.IsAvailable(node_pixel_format) or not PySpin.IsWritable(node_pixel_format): + print('Unable to set Pixel Format. Aborting...') + return False + + else: + # Retrieve entry node from enumeration node + node_pixel_format_mono8 = PySpin.CEnumEntryPtr(node_pixel_format.GetEntryByName('Mono8')) + if not PySpin.IsAvailable(node_pixel_format_mono8) or not PySpin.IsReadable(node_pixel_format_mono8): + print('Unable to set Pixel Format to MONO8. Aborting...') + return False + + # Retrieve integer value from entry node + pixel_format_mono8 = node_pixel_format_mono8.GetValue() + + # Set integer value from entry node as new value of enumeration node + node_pixel_format.SetIntValue(pixel_format_mono8) + + print('Pixel Format set to MONO8 ...') + + cam.BeginAcquisition() + + print('Acquiring images...') + + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + plt.ion() + for i in range(NUM_IMAGES): + try: + image_result = cam.GetNextImage(1000) + + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + else: + fig = plt.figure(1) + + try: + image_stats = image_result.CalculateChannelStatistics(PySpin.GREY) + # Getting the image data as a numpy array + image_data = image_result.GetNDArray() + + # Display Statistics + print('SN%s image %d:' % (device_serial_number, i)) + print('\tNumber pixel values : %d' % image_stats.num_pixel_values) + print('\tRange: Min = %d, Max = %d' % (image_stats.range_min, + image_stats.range_max)) + print('\tPixel Value: Min = %d, Max = %d, Mean = %.2f' % (image_stats.pixel_value_min, + image_stats.pixel_value_max, + image_stats.pixel_value_mean)) + + # Using matplotlib, two subplots are created where the top subplot is the histogram and the + # bottom subplot is the image. + # + # Refer to https://matplotlib.org/2.0.2/api/pyplot_api.html#module-matplotlib.pyplot + + # Clear the figure to reuse for next plot + plt.clf() + + # Plot the histogram in the first subplot in a 2 row by 1 column grid + plt.subplot(211) + plt.cla() + plt.plot(image_stats.histogram, label='Grey') + plt.title('SN%s Histogram (%d)' % (device_serial_number, i)) + plt.legend() + + # Plot the image in the second subplot in a 2 row by 1 column grid + plt.subplot(212) + plt.cla() + plt.imshow(image_data, cmap='gray') + + # Show the image + plt.show() + plt.pause(0.01) + + # Create a unique filename + if device_serial_number: + filename = 'ImageChannelStatistics-%s-%d.png' % (device_serial_number, i) + else: # if serial number is empty + filename = 'ImageChannelStatistics-%d.png' % i + + fig.savefig(filename) + print('\tSave to %s' % filename) + print() + + except PySpin.SpinnakerException: + raise + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + + except PySpin.SpinnakerException: + raise + + cam.EndAcquisition() + print('End Acquisition') + + plt.close() + + 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 + + nodemap_tldevice = cam.GetTLDeviceNodeMap() + + #Initialize camera + cam.Init() + + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + + # Acquire images + result &= acquire_and_display_images(cam, nodemap, nodemap_tldevice) + + # Deinitialize camera + cam.DeInit() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + +def main(): + """ + Example entry point; notice the volume of data that the logging event handler + prints out on debug despite the fact that very little really happens in this + example. Because of this, it may be better to have the logger set to lower + level in order to provide a more concise, focused log. + + :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: %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) + diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/ImageEvents.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/ImageEvents.py new file mode 100644 index 0000000..ac85f18 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/ImageEvents.py @@ -0,0 +1,452 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# ImageEvents.py shows how to acquire images using the image event handler. +# It relies on information provided in the Enumeration, Acquisition, +# and NodeMapInfo examples. +# +# It can also be helpful to familiarize yourself with the NodeMapCallback +# example, as nodemap callbacks follow the same general procedure as +# events, but with a few less steps. +# +# This example creates a user-defined class, ImageEventHandler, that inherits +# from the Spinnaker class, ImageEventHandler. ImageEventHandler allows the user to +# define any properties, parameters, and the event handler itself while ImageEvent +# allows the child class to appropriately interface with Spinnaker. + +import os +import sys +import PySpin +from time import sleep + +SLEEP_DURATION = 200 # amount of time for main thread to sleep for (in milliseconds) until _NUM_IMAGES have been saved + + +class ImageEventHandler(PySpin.ImageEventHandler): + """ + This class defines the properties, parameters, and the event handler itself. Take a + moment to notice what parts of the class are mandatory, and what have been + added for demonstration purposes. First, any class used to define image event handlers + must inherit from ImageEventHandler. Second, the method signature of OnImageEvent() + must also be consistent. Everything else - including the constructor, + destructor, properties, body of OnImageEvent(), and other functions - + is particular to the example. + """ + _NUM_IMAGES = 10 + + def __init__(self, cam): + """ + Constructor. Retrieves serial number of given camera and sets image counter to 0. + + :param cam: Camera instance, used to get serial number for unique image filenames. + :type cam: CameraPtr + :rtype: None + """ + super(ImageEventHandler, self).__init__() + + nodemap = cam.GetTLDeviceNodeMap() + + # Retrieve device serial number + node_device_serial_number = PySpin.CStringPtr(nodemap.GetNode('DeviceSerialNumber')) + + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + self._device_serial_number = node_device_serial_number.GetValue() + + # Initialize image counter to 0 + self._image_count = 0 + + # 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 + + def OnImageEvent(self, image): + """ + This method defines an image event. In it, the image that triggered the + event is converted and saved before incrementing the count. Please see + Acquisition example for more in-depth comments on the acquisition + of images. + + :param image: Image from event. + :type image: ImagePtr + :rtype: None + """ + # Save max of _NUM_IMAGES Images + if self._image_count < self._NUM_IMAGES: + print('Image event occurred...') + + # Check if image is incomplete + if image.IsIncomplete(): + print('Image incomplete with image status %i...' % image.GetImageStatus()) + + else: + # Print image info + print('Grabbed image %i, width = %i, height = %i' % (self._image_count, + image.GetWidth(), + image.GetHeight())) + + # Convert to mono8 + image_converted = image.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + # Create unique filename and save image + if self._device_serial_number: + filename = 'ImageEvents-%s-%i.jpg' % (self._device_serial_number, self._image_count) + + else: # if serial number is empty + filename = 'ImageEvents-%i.jpg' % self._image_count + + image_converted.Save(filename) + + print('Image saved at %s\n' % filename) + + # Increment image counter + self._image_count += 1 + + def get_image_count(self): + """ + Getter for image count. + + :return: Number of images saved. + :rtype: int + """ + return self._image_count + + def get_max_images(self): + """ + Getter for maximum images. + + :return: Total number of images to save. + :rtype: int + """ + return self._NUM_IMAGES + + +def configure_image_events(cam): + """ + This function configures the example to execute image events by preparing and + registering an image event. + + :param cam: Camera instance to configure image event. + :return: tuple(result, image_event_handler) + WHERE + result is True if successful, False otherwise + image_event_handler is the event handler + :rtype: (bool, ImageEventHandler) + """ + try: + result = True + + # Create image event handler + # + # *** NOTES *** + # The class has been constructed to accept a camera pointer in order + # to allow the saving of images with the device serial number. + image_event_handler = ImageEventHandler(cam) + + # Register image event handler + # + # *** NOTES *** + # Image events are registered to cameras. If there are multiple + # cameras, each camera must have the image events registered to it + # separately. Also, multiple image events may be registered to a + # single camera. + # + # *** LATER *** + # Image event handlers must be unregistered manually. This must be done prior + # to releasing the system and while the image events are still in + # scope. + cam.RegisterEventHandler(image_event_handler) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result, image_event_handler + + +def wait_for_images(image_event_handler): + """ + This function waits for the appropriate amount of images. Notice that + whereas most examples actively retrieve images, the acquisition of images is + handled passively in this example. + + :param image_event_handler: Image event handler. + :type image_event_handler: ImageEventHandler + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Wait for images + # + # *** NOTES *** + # In order to passively capture images using image event handlers and + # automatic polling, the main thread sleeps in increments of SLEEP_DURATION ms + # until _MAX_IMAGES images have been acquired and saved. + while image_event_handler.get_image_count() < image_event_handler.get_max_images(): + print('\t//\n\t// Sleeping for %i ms. Grabbing images...' % SLEEP_DURATION) + sleep(SLEEP_DURATION / 1000.0) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def reset_image_events(cam, image_event_handler): + """ + This functions resets the example by unregistering the image event handler. + + :param cam: Camera instance. + :param image_event_handler: Image event handler for cam. + :type cam: CameraPtr + :type image_event_handler: ImageEventHandler + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Unregister image event handler + # + # *** NOTES *** + # It is important to unregister all image events from all cameras they are registered to. + # Unlike SystemEventHandler and InterfaceEventHandler in the EnumerationEvents example, + # there is no need to explicitly delete the ImageEventHandler here as it does not store + # an instance of the camera (it gets deleted in the constructor already). + cam.UnregisterEventHandler(image_event_handler) + + print('Image events unregistered...') + + 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 from camera. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + print('*** DEVICE INFORMATION ***') + + 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.message) + result = False + + return result + + +def acquire_images(cam, nodemap, image_event_handler): + """ + This function passively waits for images by calling wait_for_images(). Notice that + this function is much shorter than the acquire_images() function of other examples. + This is because most of the code has been moved to the image event's OnImageEvent() + method. + + :param cam: Camera instance to grab images from. + :param nodemap: Device nodemap. + :param image_event_handler: Image event handler. + :type cam: CameraPtr + :type nodemap: INodeMap + :type image_event_handler: ImageEventHandler + :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.IsAvailable(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.IsAvailable(node_acquisition_mode_continuous) or not PySpin.IsReadable(node_acquisition_mode_continuous): + print('Unable to set acquisition mode to continuous (entry retrieval). Aborting...') + return False + + acquisition_mode_continuous = node_acquisition_mode_continuous.GetValue() + node_acquisition_mode.SetIntValue(acquisition_mode_continuous) + + print('Acquisition mode set to continuous...') + + # Begin acquiring images + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve images using image event handler + wait_for_images(image_event_handler) + + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = 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 acquire images from. + :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 image events + err, image_event_handler = configure_image_events(cam) + if not err: + return err + + # Acquire images using the image event handler + result &= acquire_images(cam, nodemap, image_event_handler) + + # Reset image event handlers + result &= reset_image_events(cam, image_event_handler) + + # 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 additional + comments on the steps in this function. + + :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: %d.%d.%d.%d' % (version.major, version.minor, version.type, version.build)) + + # Retrieve list of cameras from the system + cam_list = system.GetCameras() + + num_cams = cam_list.GetSize() + + print('Number of cameras detected: %i' % num_cams) + + # Finish if there are no cameras + if num_cams == 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 + 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) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/ImageFormatControl.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/ImageFormatControl.py new file mode 100644 index 0000000..e8b19f2 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/ImageFormatControl.py @@ -0,0 +1,501 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# ImageFormatControl.py shows how to apply custom image settings to +# the camera. It relies on information provided in the Enumeration, +# Acquisition, and NodeMapInfo examples. +# +# This example demonstrates setting minimums to offsets, X and Y, and maximums +# to width and height. It also shows the setting of a new pixel format, which +# is an enumeration type node. +# +# Following this, we suggest familiarizing yourself with the Exposure example +# if you haven't already. Exposure is another example on camera customization +# that is shorter and simpler than many of the others. Once comfortable with +# Exposure and ImageFormatControl, we suggest checking out any of the longer, +# more complicated examples related to camera configuration: ChunkData, +# LookupTable, Sequencer, or Trigger. + +import os +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +def configure_custom_image_settings(nodemap): + """ + Configures a number of settings on the camera including offsets X and Y, width, + height, and pixel format. These settings must be applied before BeginAcquisition() + is called; otherwise, they will be read only. Also, it is important to note that + settings are applied immediately. This means if you plan to reduce the width and + move the x offset accordingly, you need to apply such changes in the appropriate order. + + :param nodemap: GenICam nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** CONFIGURING CUSTOM IMAGE SETTINGS *** \n') + + try: + result = True + + # Apply mono 8 pixel format + # + # *** NOTES *** + # Enumeration nodes are slightly more complicated to set than other + # nodes. This is because setting an enumeration node requires working + # with two nodes instead of the usual one. + # + # As such, there are a number of steps to setting an enumeration node: + # retrieve the enumeration node from the nodemap, retrieve the desired + # entry node from the enumeration node, retrieve the integer value from + # the entry node, and set the new value of the enumeration node with + # the integer value from the entry node. + # + # Retrieve the enumeration node from the nodemap + node_pixel_format = PySpin.CEnumerationPtr(nodemap.GetNode('PixelFormat')) + if PySpin.IsAvailable(node_pixel_format) and PySpin.IsWritable(node_pixel_format): + + # Retrieve the desired entry node from the enumeration node + node_pixel_format_mono8 = PySpin.CEnumEntryPtr(node_pixel_format.GetEntryByName('Mono8')) + if PySpin.IsAvailable(node_pixel_format_mono8) and PySpin.IsReadable(node_pixel_format_mono8): + + # Retrieve the integer value from the entry node + pixel_format_mono8 = node_pixel_format_mono8.GetValue() + + # Set integer as new value for enumeration node + node_pixel_format.SetIntValue(pixel_format_mono8) + + print('Pixel format set to %s...' % node_pixel_format.GetCurrentEntry().GetSymbolic()) + + else: + print('Pixel format mono 8 not available...') + + else: + print('Pixel format not available...') + + # Apply minimum to offset X + # + # *** NOTES *** + # Numeric nodes have both a minimum and maximum. A minimum is retrieved + # with the method GetMin(). Sometimes it can be important to check + # minimums to ensure that your desired value is within range. + node_offset_x = PySpin.CIntegerPtr(nodemap.GetNode('OffsetX')) + if PySpin.IsAvailable(node_offset_x) and PySpin.IsWritable(node_offset_x): + + node_offset_x.SetValue(node_offset_x.GetMin()) + print('Offset X set to %i...' % node_offset_x.GetMin()) + + else: + print('Offset X not available...') + + # Apply minimum to offset Y + # + # *** NOTES *** + # It is often desirable to check the increment as well. The increment + # is a number of which a desired value must be a multiple of. Certain + # nodes, such as those corresponding to offsets X and Y, have an + # increment of 1, which basically means that any value within range + # is appropriate. The increment is retrieved with the method GetInc(). + node_offset_y = PySpin.CIntegerPtr(nodemap.GetNode('OffsetY')) + if PySpin.IsAvailable(node_offset_y) and PySpin.IsWritable(node_offset_y): + + node_offset_y.SetValue(node_offset_y.GetMin()) + print('Offset Y set to %i...' % node_offset_y.GetMin()) + + else: + print('Offset Y not available...') + + # Set maximum width + # + # *** NOTES *** + # Other nodes, such as those corresponding to image width and height, + # might have an increment other than 1. In these cases, it can be + # important to check that the desired value is a multiple of the + # increment. However, as these values are being set to the maximum, + # there is no reason to check against the increment. + node_width = PySpin.CIntegerPtr(nodemap.GetNode('Width')) + if PySpin.IsAvailable(node_width) and PySpin.IsWritable(node_width): + + width_to_set = node_width.GetMax() + node_width.SetValue(width_to_set) + print('Width set to %i...' % node_width.GetValue()) + + else: + print('Width not available...') + + # Set maximum height + # + # *** NOTES *** + # A maximum is retrieved with the method GetMax(). A node's minimum and + # maximum should always be a multiple of its increment. + node_height = PySpin.CIntegerPtr(nodemap.GetNode('Height')) + if PySpin.IsAvailable(node_height) and PySpin.IsWritable(node_height): + + height_to_set = node_height.GetMax() + node_height.SetValue(height_to_set) + print('Height set to %i...' % node_height.GetValue()) + + else: + print('Height not available...') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return 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 acquire_images(cam, nodemap, nodemap_tldevice): + """ + 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. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** IMAGE ACQUISITION ***\n') + try: + result = True + + # Set acquisition mode to continuous + # + # *** NOTES *** + # Because the example acquires and saves 10 images, setting acquisition + # mode to continuous lets the example finish. If set to single frame + # or multiframe (at a lower number of images), the example would just + # hang. This would happen because the example has been written to + # acquire 10 images while the camera would have been programmed to + # retrieve less than that. + # + # Setting the value of an enumeration node is slightly more complicated + # than other node types. Two nodes must be retrieved: first, the + # enumeration node is retrieved from the nodemap; and second, the entry + # node is retrieved from the enumeration node. The integer value of the + # entry node is then set as the new value of the enumeration node. + # + # Notice that both the enumeration and the entry nodes are checked for + # availability and readability/writability. Enumeration nodes are + # generally readable and writable whereas their entry nodes are only + # ever readable. + # + # Retrieve enumeration node from nodemap + + # In order to access the node entries, they have to be casted to a pointer type (CEnumerationPtr here) + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # What happens when the camera begins acquiring images depends on the + # acquisition mode. Single frame captures only a single image, multi + # frame catures a set number of images, and continuous captures a + # continuous stream of images. Because the example calls for the + # retrieval of 10 images, continuous mode has been set. + # + # *** LATER *** + # Image acquisition must be ended when no more images are needed. + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve device serial number for filename + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Retrieve, convert, and save images + for i in range(NUM_IMAGES): + try: + + # Retrieve next received image + # + # *** NOTES *** + # Capturing an image houses images on the camera buffer. Trying + # to capture an image that does not exist will hang the camera. + # + # *** LATER *** + # Once an image from the buffer is saved and/or no longer + # needed, the image must be released in order to keep the + # buffer from filling up. + image_result = cam.GetNextImage(1000) + + # Ensure image completion + # + # *** NOTES *** + # Images can easily be checked for completion. This should be + # done whenever a complete image is expected or required. + # Further, check image status for a little more insight into + # why an image is incomplete. + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + + else: + + # Print image information; height and width recorded in pixels + # + # *** NOTES *** + # Images have quite a bit of available metadata including + # things such as CRC, image status, and offset values, to + # name a few. + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed Image %d, width = %d, height = %d' % (i, width, height)) + + # Convert image to mono 8 + # + # *** NOTES *** + # Images can be converted between pixel formats by using + # the appropriate enumeration value. Unlike the original + # image, the converted one does not need to be released as + # it does not affect the camera buffer. + # + # When converting images, color processing algorithm is an + # optional parameter. + image_converted = image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + # Create a unique filename + if device_serial_number: + filename = 'ImageFormatControl-%s-%d.jpg' % (device_serial_number, i) + else: # if serial number is empty + filename = 'ImageFormatControl-%d.jpg' % i + + # Save image + # + # *** NOTES *** + # The standard practice of the examples is to use device + # serial numbers to keep images of one device from + # overwriting those of another. + image_converted.Save(filename) + print('Image saved at %s' % filename) + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + print('') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def run_single_camera(cam): + """ + This function acts as the body of the example; please see NodeMapInfo example + for more in-depth comments on setting up cameras. + + :param cam: Camera to run on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Retrieve TL device nodemap and print device information + nodemap_tldevice = cam.GetTLDeviceNodeMap() + + result &= print_device_info(nodemap_tldevice) + + # Initialize camera + cam.Init() + + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + + # Configure custom image settings + if not configure_custom_image_settings(nodemap): + return False + + # Acquire images + result &= acquire_images(cam, nodemap, nodemap_tldevice) + + # 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 + """ + + # 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: %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) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/ImageFormatControl_QuickSpin.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/ImageFormatControl_QuickSpin.py new file mode 100644 index 0000000..8fba164 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/ImageFormatControl_QuickSpin.py @@ -0,0 +1,358 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# ImageFormatControl_QuickSpin.py shows how to apply custom image +# settings to the camera using the QuickSpin API. QuickSpin is a subset of +# the Spinnaker library that allows for simpler node access and control. +# +# This example demonstrates customizing offsets X and Y, width and height, +# and the pixel format. Ensuring custom values fall within an acceptable +# range is also touched on. Retrieving and setting node values using +# QuickSpin is the only portion of the example that differs from +# ImageFormatControl. +# +# 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 + + +def configure_custom_image_settings(cam): + """ + Configures a number of settings on the camera including offsets X and Y, + width, height, and pixel format. These settings must be applied before + BeginAcquisition() is called; otherwise, those nodes would be read only. + Also, it is important to note that settings are applied immediately. + This means if you plan to reduce the width and move the x offset accordingly, + you need to apply such changes in the appropriate order. + + :param cam: Camera to configure settings on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** CONFIGURING CUSTOM IMAGE SETTINGS ***\n') + + try: + result = True + + # Apply mono 8 pixel format + # + # *** NOTES *** + # In QuickSpin, enumeration nodes are as easy to set as other node + # types. This is because enum values representing each entry node + # are added to the API. + if cam.PixelFormat.GetAccessMode() == PySpin.RW: + cam.PixelFormat.SetValue(PySpin.PixelFormat_Mono8) + print('Pixel format set to %s...' % cam.PixelFormat.GetCurrentEntry().GetSymbolic()) + + else: + print('Pixel format not available...') + result = False + + # Apply minimum to offset X + # + # *** NOTES *** + # Numeric nodes have both a minimum and maximum. A minimum is retrieved + # with the method GetMin(). Sometimes it can be important to check + # minimums to ensure that your desired value is within range. + if cam.OffsetX.GetAccessMode() == PySpin.RW: + cam.OffsetX.SetValue(cam.OffsetX.GetMin()) + print('Offset X set to %d...' % cam.OffsetX.GetValue()) + + else: + print('Offset X not available...') + result = False + + # Apply minimum to offset Y + # + # *** NOTES *** + # It is often desirable to check the increment as well. The increment + # is a number of which a desired value must be a multiple. Certain + # nodes, such as those corresponding to offsets X and Y, have an + # increment of 1, which basically means that any value within range + # is appropriate. The increment is retrieved with the method GetInc(). + if cam.OffsetY.GetAccessMode() == PySpin.RW: + cam.OffsetY.SetValue(cam.OffsetY.GetMin()) + print('Offset Y set to %d...' % cam.OffsetY.GetValue()) + + else: + print('Offset Y not available...') + result = False + + # Set maximum width + # + # *** NOTES *** + # Other nodes, such as those corresponding to image width and height, + # might have an increment other than 1. In these cases, it can be + # important to check that the desired value is a multiple of the + # increment. + # + # This is often the case for width and height nodes. However, because + # these nodes are being set to their maximums, there is no real reason + # to check against the increment. + if cam.Width.GetAccessMode() == PySpin.RW and cam.Width.GetInc() != 0 and cam.Width.GetMax != 0: + cam.Width.SetValue(cam.Width.GetMax()) + print('Width set to %i...' % cam.Width.GetValue()) + + else: + print('Width not available...') + result = False + + # Set maximum height + # + # *** NOTES *** + # A maximum is retrieved with the method GetMax(). A node's minimum and + # maximum should always be a multiple of its increment. + if cam.Height.GetAccessMode() == PySpin.RW and cam.Height.GetInc() != 0 and cam.Height.GetMax != 0: + cam.Height.SetValue(cam.Height.GetMax()) + print('Height set to %i...' % cam.Height.GetValue()) + + else: + print('Height not available...') + result = False + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_device_info(cam): + """ + 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 cam: Camera to get device information from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('\n*** DEVICE INFORMATION ***\n') + + try: + result = True + nodemap = cam.GetTLDeviceNodeMap() + + 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.message) + 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 the acquisition of images. + + :param cam: Camera to acquire images from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** 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 is not None and 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 next received image and ensure image completion + image_result = cam.GetNextImage(1000) + + 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 Mono8 + image_converted = image_result.Convert(PySpin.PixelFormat_Mono8) + + # Create a unique filename + if device_serial_number: + filename = 'ImageFormatControlQS-%s-%d.jpg' % (device_serial_number, i) + else: + filename = 'ImageFormatControlQS-%d.jpg' % i + + # Save image + image_converted.Save(filename) + + print('Image saved at %s' % filename) + + # Release image + image_result.Release() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + # End acquisition + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def run_single_camera(cam): + """ + This function acts as the body of the example; please see NodeMapInfo_QuickSpin example for more + in-depth comments on setting up cameras. + + :param cam: Camera to run example on. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + # Initialize camera + cam.Init() + + # Print device info + result = print_device_info(cam) + + # Configure exposure + if not configure_custom_image_settings(cam): + return False + + # Acquire images + result &= acquire_images(cam) + + # Deinitialize camera + cam.DeInit() + + return result + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + +def main(): + """ + Example entry point; please see Enumeration_QuickSpin 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 + + # Release 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) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/Inference.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Inference.py new file mode 100644 index 0000000..524d8ca --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Inference.py @@ -0,0 +1,1218 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# 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.flir.com/products/firefly-dl/ +# It can also be helpful to familiarize yourself with the Acquisition, +# ChunkData and FileAccess_QuickSpin examples. + +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.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 + +# 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.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.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.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.IsReadable(ptr_file_access_offset) or 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): + try: + ptr_file_operation_selector = PySpin.CEnumerationPtr(nodemap.GetNode("FileOperationSelector")) + if 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 + + ptr_file_operation_selector.SetIntValue(int(ptr_file_operation_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 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.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.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.IsReadable(ptr_file_access_buffer) or 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) + + if intermediate_buffer_size > bytes_left_to_write: + ptr_file_access_length.SetValue(bytes_left_to_write) + + # Perform Write command + if not camera_write_to_file(nodemap): + print('Writing to stream failed. Aborting...') + return False + + # Verify size of bytes written + size_written = ptr_file_access_result.GetValue() + + # 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') + + 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.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.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.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.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.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.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.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.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, convert, and save images + 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) \ No newline at end of file diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/Injected_Image_Classification.raw b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Injected_Image_Classification.raw new file mode 100644 index 0000000..e79db8f Binary files /dev/null and b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Injected_Image_Classification.raw differ diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/Injected_Image_Classification_Daisy.jpg b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Injected_Image_Classification_Daisy.jpg new file mode 100644 index 0000000..128f332 Binary files /dev/null and b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Injected_Image_Classification_Daisy.jpg differ diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/Injected_Image_Detection.raw b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Injected_Image_Detection.raw new file mode 100644 index 0000000..e1c3100 Binary files /dev/null and b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Injected_Image_Detection.raw differ diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/Injected_Image_Detection_Aeroplane.jpg b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Injected_Image_Detection_Aeroplane.jpg new file mode 100644 index 0000000..8e3cefc Binary files /dev/null and b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Injected_Image_Detection_Aeroplane.jpg differ diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/Logging.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Logging.py new file mode 100644 index 0000000..4501a54 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Logging.py @@ -0,0 +1,130 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# Logging.py shows how to create a handler to access logging events. +# It relies on information provided in the Enumeration, Acquisition, and +# NodeMapInfo examples. +# +# It can also be helpful to familiarize yourself with the NodeMapCallback +# example, as nodemap callbacks follow the same general procedure as +# events, but with a few less steps. +# +# This example creates a user-defined class, LoggingEventHandler, that inherits +# from the Spinnaker class, LoggingEventHandler. The child class allows the user to +# define any properties, parameters, and the event handler itself while LoggingEventHandler +# allows the child class to appropriately interface with the Spinnaker SDK. + +import PySpin + + +# Define callback priority threshold; please see documentation for additional +# information on logging level philosophy. +LOGGING_LEVEL = PySpin.LOG_LEVEL_DEBUG # change to any LOG_LEVEL_* constant + + +class LoggingEventHandler(PySpin.LoggingEventHandler): + """ + Although logging events are just as flexible and extensible as other events, + they are generally only used for logging purposes, which is why a number of + helpful functions that provide logging information have been added. Generally, + if the purpose is not logging, one of the other event types is probably more + appropriate. + """ + + def __init__(self): + super(LoggingEventHandler, self).__init__() + + def OnLogEvent(self, logging_event_data): + """ + This function displays readily available logging information. + + :param logging_event_data: Logging data. + :type logging_event_data: LoggingEventData + :rtype: None + """ + print('--------Log Event Received----------') + print('Category: %s' % logging_event_data.GetCategoryName()) + print('Priority Value: %s' % logging_event_data.GetPriority()) + print('Priority Name: %s' % logging_event_data.GetPriorityName()) + print('Timestamp: %s' % logging_event_data.GetTimestamp()) + print('NDC: %s' % logging_event_data.GetNDC()) + print('Thread: %s' % logging_event_data.GetThreadName()) + print('Message: %s' % logging_event_data.GetLogMessage()) + print('------------------------------------\n') + + +def main(): + """ + Example entry point; notice the volume of data that the logging event handler + prints out on debug despite the fact that very little really happens in this + example. Because of this, it may be better to have the logger set to lower + level in order to provide a more concise, focused log. + + :rtype: None + """ + + # 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)) + + # Create and register the logging event handler + # + # *** NOTES *** + # Logging event handlers are registered to the system. Take note that a logging + # event handler is very verbose when the logging level is set to debug. + # + # *** LATER *** + # Logging event handlers must be unregistered manually. This must be done prior to + # releasing the system and while the logging event handlers are still in scope. + logging_event_handler = LoggingEventHandler() + system.RegisterLoggingEventHandler(logging_event_handler) + + # Set callback priority level + # + # *** NOTES *** + # Please see documentation for up-to-date information on the logging + # philosophies of the Spinnaker SDK. + system.SetLoggingEventPriorityLevel(LOGGING_LEVEL) + + # Retrieve list of cameras from the system + cam_list = system.GetCameras() + + num_cams = cam_list.GetSize() + + print('Number of cameras detected: %i' % num_cams) + + # Clear camera list before releasing system + cam_list.Clear() + + # Unregister logging event handler + # + # *** NOTES *** + # It is important to unregister all logging event handlers from the system. + system.UnregisterLoggingEventHandler(logging_event_handler) + + # Release system instance + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + + +if __name__ == '__main__': + main() diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/LookupTable.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/LookupTable.py new file mode 100644 index 0000000..851b6d0 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/LookupTable.py @@ -0,0 +1,440 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= + +# LookupTable.py +# +# LookupTable.py shows how to configure lookup tables on the camera. +# 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 they are somewhat shorter and simpler, either +# provides a strong introduction to camera customization. +# +# Lookup tables allow for the customization and control of individual pixels. +# This can be a very powerful and deeply useful tool; however, because use +# cases are context dependent, this example only explores lookup table +# configuration. + +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_lookup_tables(nodemap): + """ + This function configures lookup tables linearly. This involves selecting the + type of lookup table, finding the appropriate increment calculated from the + maximum value, and enabling lookup tables on the camera. + + :param nodemap: Device nodemap + :type nodemap: INodeMap + :return: returns True if successful, False otherwise + :rtype: bool + """ + result = True + print("***CONFIGURING LOOKUP TABLES***\n") + + # Select lookup table type + # + # ***NOTES *** + # Setting the lookup table selector. It is important to note that this + # does not enable lookup tables. + + try: + lut_selector = PySpin.CEnumerationPtr(nodemap.GetNode("LUTSelector")) + if not PySpin.IsAvailable(lut_selector) or not PySpin.IsWritable(lut_selector): + print_retrieve_node_failure("node", "LUTSelector") + return False + + lut_selector_lut1 = lut_selector.GetEntryByName("LUT1") + if not PySpin.IsAvailable(lut_selector_lut1) or not PySpin.IsReadable(lut_selector_lut1): + print_retrieve_node_failure("entry", "LUTSelector LUT1") + return False + + lut_selector.SetIntValue(lut_selector_lut1.GetValue()) + print("Lookup table selector set to LUT 1...\n") + + # Determine pixel increment and set indexes and values as desired + # + # *** NOTES *** + # To get the pixel increment, the maximum range of the value node must + # first be retrieved. The value node represents an index, so its value + # should be one less than a power of 2 (e.g. 511, 1023, etc.). Add 1 to + # this index to get the maximum range. Divide the maximum range by 512 + # to calculate the pixel increment. + # + # Finally, all values (in the value node) and their corresponding + # indexes (in the index node) need to be set. The goal of this example + # is to set the lookup table linearly. As such, the slope of the values + # should be set according to the increment, but the slope of the + # indexes is inconsequential. + + # Retrieve value node + lut_value = PySpin.CIntegerPtr(nodemap.GetNode("LUTValue")) + if not PySpin.IsAvailable(lut_value) or not PySpin.IsWritable(lut_value): + print_retrieve_node_failure("node", "LUTValue") + return False + + # Retrieve maximum range + max_range = lut_value.GetMax() + 1 + print("\tMaximum Range: {}".format(max_range)) + + # Calculate increment + increment = max_range / 512 + print("\tIncrement: {}".format(increment)) + + # Retrieve index node + lut_index = PySpin.CIntegerPtr(nodemap.GetNode("LUTIndex")) + if not PySpin.IsAvailable(lut_index) or not PySpin.IsWritable(lut_index): + print_retrieve_node_failure("node", "LUTIndex") + return False + + # Set values and indexes + i = 0 + while i < max_range: + lut_index.SetValue(int(i)) + lut_value.SetValue(int(i)) + i += increment + + print("All lookup table values set...\n") + + # Enable lookup tables + # + # *** NOTES *** + # Once lookup tables have been configured, don"t forget to enable them + # with the appropriate node. + # + # *** LATER *** + # Once the images with lookup tables have been collected, turn the + # feature off with the same node. + + lut_enable = PySpin.CBooleanPtr(nodemap.GetNode("LUTEnable")) + if not PySpin.IsAvailable(lut_enable) or not PySpin.IsWritable(lut_enable): + print_retrieve_node_failure("node", "LUTEnable") + return False + + lut_enable.SetValue(True) + print("Lookup tables enabled...\n") + + except PySpin.SpinnakerException as ex: + print("Error: {}".format(ex)) + result = False + + return result + + +def reset_lookup_tables(nodemap): + """ + This function resets the camera by disabling lookup tables. + + :param nodemap: Device nodemap. + :type nodemap: INodeMap + :return: returns True if successful, False otherwise + :rtype: bool + """ + result = True + + # Disable lookup tables + # + # *** NOTES *** + # Turn lookup tables off when they are not needed to reduce overhead + + try: + lut_enable = PySpin.CBooleanPtr(nodemap.GetNode("LUTEnable")) + if not PySpin.IsAvailable(lut_enable) or not PySpin.IsWritable(lut_enable): + print("Unable to disable lookup tables. Non-fatal error...\n") + return False + + lut_enable.SetValue(False) + print("Lookup tables disabled...\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: Device nodemap. + :type nodemap: INodeMap + :return: returns True if successful, False otherwise + :rtype: bool + """ + result = True + print("*** DEVICE INFORMATION ***\n") + + try: + 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) + if PySpin.IsReadable(node_feature): + feature_string = node_feature.ToString() + else: + feature_string = "Node not readable" + + print("{}: {}".format(node_feature.GetName(), feature_string)) + + else: + print("Device control information not available.") + + except PySpin.SpinnakerException as ex: + print("Error: {}".format(ex)) + result = False + + return result + + +def acquire_images(cam, nodemap, nodemap_tl_device): + """ + 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 + :param nodemap: Device nodemap + :param nodemap_tl_device: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tl_device: INodeMap + :return: returns True if successful, False otherwise + :rtype: bool + """ + result = True + print("*** IMAGE ACQUISITION ***\n") + + # Set acquisition mode to continuous + try: + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode("AcquisitionMode")) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print("Unable to set acquisition mode to continuous (node retrieval). Aborting...\n") + return False + + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName("Continuous") + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or \ + not PySpin.IsReadable(node_acquisition_mode_continuous): + print("Unable to set acquisition mode to continuous (entry 'continuous' retrieval). Aborting...\n") + 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...\n") + + # Begin acquiring images + cam.BeginAcquisition() + print("Acquiring images...\n") + + # Retrieve device serial number for filename + device_serial_number = "" + node_device_serial_number = PySpin.CStringPtr(nodemap_tl_device.GetNode("DeviceSerialNumber")) + if PySpin.IsAvailable(node_device_serial_number) and 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 + for i in range(NUM_IMAGES): + try: + + # Retrieve next received image and ensure image completion + image_result = cam.GetNextImage(1000) + + 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 = image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + # Create a unique filename + if device_serial_number: + filename = "LookupTable-{}-{}.jpg".format(device_serial_number, i) + else: # if serial number is empty + filename = "LookupTable-{}.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)) + result = 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 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: returns True if successful, False otherwise + :rtype: bool + """ + result = True + + try: + # Retrieve TL device nodemap and print device information + nodemap_tl_device = cam.GetTLDeviceNodeMap() + + result &= print_device_info(nodemap_tl_device) + + # Initialize camera + cam.Init() + + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + + # Configure lookup tables + result &= configure_lookup_tables(nodemap) + if not result: + return result + + # Acquire images + result &= acquire_images(cam, nodemap, nodemap_tl_device) + + # Reset lookup tables + result &= reset_lookup_tables(nodemap) + + # Deinitialize camera + cam.DeInit() + except PySpin.SpinnakerException as ex: + print("Error: {}".format(ex)) + result = False + + return result + + +def main(): + """ + 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. + + :return: returns True if successful, False otherwise + :rtype: bool + """ + try: + test_file = open("test.txt", "w+") + except IOError: + print("Unable to write to current directory. Please check permissions.\n") + 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!\n") + 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) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/Network_Classification b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Network_Classification new file mode 100644 index 0000000..a7a5513 Binary files /dev/null and b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Network_Classification differ diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/Network_Detection b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Network_Detection new file mode 100644 index 0000000..838b384 Binary files /dev/null and b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Network_Detection differ diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/NodeMapCallback.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/NodeMapCallback.py new file mode 100644 index 0000000..0db4cc7 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/NodeMapCallback.py @@ -0,0 +1,424 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# NodeMapCallback.py shows how to use nodemap callbacks. It relies +# on information provided in the Enumeration, Acquisition, and NodeMapInfo +# examples. As callbacks are very similar to events, it may be a good idea to +# explore this example prior to tackling the events examples. +# +# This example focuses on creating, registering, using, and unregistering +# callbacks. A callback requires a callback class with a callback function signature, +# which allows it to be registered to and access a node. Events follow this same pattern. +# +# Once comfortable with NodeMapCallback, we suggest checking out any of the +# events examples: DeviceEvents, EnumerationEvents, ImageEvents, or Logging. + +import PySpin +import sys + + +class HeightNodeCallback(PySpin.NodeCallback): + """ + This is the first of two callback classes. This callback will be registered to the height node. + Node callbacks must inherit from NodeCallback, and must implement CallbackFunction with the same function signature. + + NOTE: Instances of callback classes must not go out of scope until they are deregistered, otherwise segfaults + will occur. + """ + def __init__(self): + super(HeightNodeCallback, self).__init__() + + def CallbackFunction(self, node): + """ + This function gets called when the height node changes and triggers a callback. + + :param node: Height node. + :type node: INode + :rtype: None + """ + node_height = PySpin.CIntegerPtr(node) + print('Height callback message:\n\tLook! Height changed to %f...\n' % node_height.GetValue()) + + +class GainNodeCallback(PySpin.NodeCallback): + """ + This is the second callback class, registered to the gain node. + """ + def __init__(self): + super(GainNodeCallback, self).__init__() + + def CallbackFunction(self, node): + """ + This function gets called when the gain node changes and triggers a callback. + + :param node: Gain node. + :type node: INode + :rtype: None + """ + node_gain = PySpin.CFloatPtr(node) + print('Gain callback message:\n\tLook! Gain changed to %f...\n' % node_gain.GetValue()) + + +def configure_callbacks(nodemap): + """ + This function sets up the example by disabling automatic gain, creating the callbacks, and registering them to + their specific nodes. + + :param nodemap: Device nodemap. + :type nodemap: INodeMap + :returns: tuple (result, callback_height, callback_gain) + WHERE + result is True if successful, False otherwise + callback_height is the HeightNodeCallback instance registered to the height node + callback_gain is the GainNodeCallback instance registered to the gain node + :rtype: (bool, HeightNodeCallback, GainNodeCallback) + """ + print('\n*** CONFIGURING CALLBACKS ***\n') + try: + result = True + + # Turn off automatic gain + # + # *** NOTES *** + # Automatic gain prevents the manual configuration of gain and needs to + # be turned off for this example. + # + # *** LATER *** + # Automatic exposure is turned off 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.IsAvailable(node_gain_auto) or not PySpin.IsWritable(node_gain_auto): + print('Unable to disable automatic gain (node retrieval). Aborting...') + return False + + node_gain_auto_off = PySpin.CEnumEntryPtr(node_gain_auto.GetEntryByName('Off')) + if not PySpin.IsAvailable(node_gain_auto_off) or not PySpin.IsReadable(node_gain_auto_off): + print('Unable to disable automatic gain (enum entry retrieval). Aborting...') + return False + + node_gain_auto.SetIntValue(node_gain_auto_off.GetValue()) + print('Automatic gain disabled...') + + # Register callback to height node + # + # *** NOTES *** + # Callbacks need to be registered to nodes, which should be writable + # if the callback is to ever be triggered. Also ensure that the callback + # instance does not go out of scope, as it will get garbage-collected + # and a segfault will result once the callback actually occurs. + # + # *** LATER *** + # Each callback needs to be unregistered individually before releasing + # the system or an exception will be thrown. + node_height = PySpin.CIntegerPtr(nodemap.GetNode('Height')) + if not PySpin.IsAvailable(node_height) or not PySpin.IsWritable(node_height): + print('Unable to retrieve height. Aborting...\n') + return False + + print('Height ready...') + + callback_height = HeightNodeCallback() + PySpin.RegisterNodeCallback(node_height.GetNode(), callback_height) + + print('Height callback registered...') + + # Register callback to gain node + # + # *** NOTES *** + # Depending on the specific goal of the function, it can be important + # to notice the node type that a callback is registered to. Notice in + # the callback functions above that the callback registered to height + # casts its node as an integer whereas the callback registered to gain + # casts as a float. + # + # *** LATER *** + # Each callback needs to be unregistered individually before releasing + # the system or an exception will be thrown. + node_gain = PySpin.CFloatPtr(nodemap.GetNode('Gain')) + if not PySpin.IsAvailable(node_gain) or not PySpin.IsWritable(node_gain): + print('Unable to retrieve gain. Aborting...\n') + return False + + print('Gain ready...') + + callback_gain = GainNodeCallback() + PySpin.RegisterNodeCallback(node_gain.GetNode(), callback_gain) + print('Gain callback registered...\n') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result, callback_height, callback_gain + + +def change_height_and_gain(nodemap): + """ + This function demonstrates the triggering of the nodemap callbacks. First it + changes height, which executes the callback registered to the height node, and + then it changes gain, which executes the callback registered to the gain node. + + :param nodemap: Device nodemap. + :type nodemap: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n***CHANGE HEIGHT & GAIN ***\n') + + try: + result = True + + # Change height to trigger height callback + # + # *** NOTES *** + # Notice that changing the height only triggers the callback function + # registered to the height node. + node_height = PySpin.CIntegerPtr(nodemap.GetNode('Height')) + if not PySpin.IsAvailable(node_height) or not PySpin.IsWritable(node_height) \ + or node_height.GetInc() == 0 or node_height.GetMax() == 0: + + print('Unable to retrieve height. Aborting...') + return False + + height_to_set = node_height.GetMax() + + print('Regular function message:\n\tHeight about to be changed to %i...\n' % height_to_set) + + node_height.SetValue(height_to_set) + + # Change gain to trigger gain callback + # + # *** NOTES *** + # The same is true of changing the gain node; changing a node will + # only ever trigger the callback function (or functions) currently + # registered to it. + node_gain = PySpin.CFloatPtr(nodemap.GetNode('Gain')) + if not PySpin.IsAvailable(node_gain) or not PySpin.IsWritable(node_gain) or node_gain.GetMax() == 0: + print('Unable to retrieve gain...') + return False + + gain_to_set = node_gain.GetMax() / 2.0 + + print('Regular function message:\n\tGain about to be changed to %f...\n' % gain_to_set) + node_gain.SetValue(gain_to_set) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result + + +def reset_callbacks(nodemap, callback_height, callback_gain): + """ + This function cleans up the example by deregistering the callbacks and + turning automatic gain back on. + + :param nodemap: Device nodemap. + :param callback_height: Height node callback instance to deregister. + :param callback_gain: Gain node callback instance to deregister. + :type nodemap: INodeMap + :type callback_height: HeightNodeCallback + :type callback_gain: GainNodeCallback + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Deregister callbacks + # + # *** NOTES *** + # It is important to deregister each callback function from each node + # that it is registered to. + PySpin.DeregisterNodeCallback(callback_height) + PySpin.DeregisterNodeCallback(callback_gain) + + print('Callbacks deregistered...') + + # Turn automatic gain back on + # + # *** NOTES *** + # Automatic gain is turned back on in order to restore the camera to + # its default state. + node_gain_auto = PySpin.CEnumerationPtr(nodemap.GetNode('GainAuto')) + if not PySpin.IsAvailable(node_gain_auto) or not PySpin.IsWritable(node_gain_auto): + print('Unable to enable automatic gain (node retrieval). Aborting...') + return False + + node_gain_auto_continuous = PySpin.CEnumEntryPtr(node_gain_auto.GetEntryByName('Continuous')) + if not PySpin.IsAvailable(node_gain_auto_continuous) or not PySpin.IsReadable(node_gain_auto_continuous): + print('Unable to enable automatic gain (enum entry retrieval). Aborting...') + return False + + node_gain_auto.SetIntValue(node_gain_auto_continuous.GetValue()) + print('Automatic gain 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 setup and 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 callbacks + err, callback_height, callback_gain = configure_callbacks(nodemap) + if not err: + return err + + # Change height and gain to trigger callbacks + result &= change_height_and_gain(nodemap) + + # Reset callbacks + result &= reset_callbacks(nodemap, callback_height, callback_gain) + + # Deinitialize camera + cam.DeInit() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return 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 instance + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + return result + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/NodeMapInfo.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/NodeMapInfo.py new file mode 100644 index 0000000..c8224cc --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/NodeMapInfo.py @@ -0,0 +1,576 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# NodeMapInfo.py shows how to retrieve node map information. It relies +# on information provided in the Enumeration example. Also, check out the +# Acquisition and ExceptionHandling examples if you haven't already. +# Acquisition demonstrates image acquisition while ExceptionHandling shows the +# handling of standard and Spinnaker exceptions. +# +# This example explores retrieving information from all major node types on the +# camera. This includes string, integer, float, boolean, command, enumeration, +# category, and value types. Looping through multiple child nodes is also +# covered. A few node types are not covered - base, port, and register - as +# they are not fundamental. The final node type - enumeration entry - is +# explored only in terms of its parent node type - enumeration. +# +# Once comfortable with NodeMapInfo, we suggest checking out ImageFormatControl +# and Exposure. ImageFormatControl explores customizing image settings on a +# camera while Exposure introduces the standard structure of configuring a +# device, acquiring some images, and then returning the device to a default +# state. + +import PySpin +import sys + +# Defines max number of characters that will be printed out for any node information +MAX_CHARS = 35 + + +class ReadType: + """ + Use the following constants to determine whether nodes are read + as Value nodes or their individual types. + """ + VALUE = 0, + INDIVIDUAL = 1 + +CHOSEN_READ = ReadType.INDIVIDUAL + + +def print_with_indent(level, text): + """ + Helper function for printing a string prefix with a specifc number of indents. + :param level: Number of indents to generate + :type level: int + :param text: String to print after indent + :type text: str + """ + ind = '' + for i in range(level): + ind += ' ' + print('%s%s' % (ind, text)) + + +def print_value_node(node, level): + """ + Retrieves and prints the display name and value of all node types as value nodes. + A value node is a general node type that allows for the reading and writing of any node type as a string. + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create value node + node_value = PySpin.CValuePtr(node) + + # Retrieve display name + # + # *** NOTES *** + # A node's 'display name' is generally more appropriate for output and + # user interaction whereas its 'name' is what the camera understands. + # Generally, its name is the same as its display name but without + # spaces - for instance, the name of the node that houses a camera's + # serial number is 'DeviceSerialNumber' while its display name is + # 'Device Serial Number'. + display_name = node_value.GetDisplayName() + + # Retrieve value of any node type as string + # + # *** NOTES *** + # Because value nodes return any node type as a string, it can be much + # easier to deal with nodes as value nodes rather than their actual + # individual types. + value = node_value.ToString() + + # Cap length at MAX_CHARS + value = value[:MAX_CHARS] + '...' if len(value) > MAX_CHARS else value + + # Print value + print_with_indent(level, '%s: %s' % (display_name, value)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_string_node(node, level): + """ + Retrieves and prints the display name and value of a string node. + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create string node + node_string = PySpin.CStringPtr(node) + + # Retrieve string node value + # + # *** NOTES *** + # Functions in Spinnaker C++ that use gcstring types + # are substituted with Python strings in PySpin. + # The only exception is shown in the DeviceEvents example, where + # the callback function still uses a wrapped gcstring type. + display_name = node_string.GetDisplayName() + + # Ensure that the value length is not excessive for printing + value = node_string.GetValue() + value = value[:MAX_CHARS] + '...' if len(value) > MAX_CHARS else value + + # Print value; 'level' determines the indentation level of output + print_with_indent(level, '%s: %s' % (display_name, value)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_integer_node(node, level): + """ + Retrieves and prints the display name and value of an integer node. + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create integer node + node_integer = PySpin.CIntegerPtr(node) + + # Get display name + display_name = node_integer.GetDisplayName() + + # Retrieve integer node value + # + # *** NOTES *** + # All node types except base nodes have a ToString() + # method which returns a value as a string. + value = node_integer.GetValue() + + # Print value + print_with_indent(level, '%s: %s' % (display_name, value)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_float_node(node, level): + """ + Retrieves and prints the display name and value of a float node. + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create float node + node_float = PySpin.CFloatPtr(node) + + # Get display name + display_name = node_float.GetDisplayName() + + # Retrieve float value + value = node_float.GetValue() + + # Print value + print_with_indent(level, '%s: %s' % (display_name, value)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_boolean_node(node, level): + """ + Retrieves and prints the display name and value of a Boolean node. + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create Boolean node + node_boolean = PySpin.CBooleanPtr(node) + + # Get display name + display_name = node_boolean.GetDisplayName() + + # Retrieve Boolean value + value = node_boolean.GetValue() + + # Print Boolean value + # NOTE: In Python a Boolean will be printed as "True" or "False". + print_with_indent(level, '%s: %s' % (display_name, value)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_command_node(node, level): + """ + This function retrieves and prints the display name and tooltip of a command + node, limiting the number of printed characters to a macro-defined maximum. + The tooltip is printed below because command nodes do not have an intelligible + value. + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create command node + node_command = PySpin.CCommandPtr(node) + + # Get display name + display_name = node_command.GetDisplayName() + + # Retrieve tooltip + # + # *** NOTES *** + # All node types have a tooltip available. Tooltips provide useful + # information about nodes. Command nodes do not have a method to + # retrieve values as their is no intelligible value to retrieve. + tooltip = node_command.GetToolTip() + + # Ensure that the value length is not excessive for printing + tooltip = tooltip[:MAX_CHARS] + '...' if len(tooltip) > MAX_CHARS else tooltip + + # Print display name and tooltip + print_with_indent(level, '%s: %s' % (display_name, tooltip)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_enumeration_node_and_current_entry(node, level): + """ + This function retrieves and prints the display names of an enumeration node + and its current entry (which is actually housed in another node unto itself). + + :param node: Node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create enumeration node + node_enumeration = PySpin.CEnumerationPtr(node) + + # Retrieve current entry as enumeration node + # + # *** NOTES *** + # Enumeration nodes have three methods to differentiate between: first, + # GetIntValue() returns the integer value of the current entry node; + # second, GetCurrentEntry() returns the entry node itself; and third, + # ToString() returns the symbolic of the current entry. + node_enum_entry = PySpin.CEnumEntryPtr(node_enumeration.GetCurrentEntry()) + + # Get display name + display_name = node_enumeration.GetDisplayName() + + # Retrieve current symbolic + # + # *** NOTES *** + # Rather than retrieving the current entry node and then retrieving its + # symbolic, this could have been taken care of in one step by using the + # enumeration node's ToString() method. + entry_symbolic = node_enum_entry.GetSymbolic() + + # Print current entry symbolic + print_with_indent(level, '%s: %s' % (display_name, entry_symbolic)) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_category_node_and_all_features(node, level): + """ + This function retrieves and prints out the display name of a category node + before printing all child nodes. Child nodes that are also category nodes are + printed recursively. + + :param node: Category node to get information from. + :type node: INode + :param level: Depth to indent output. + :type level: int + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Create category node + node_category = PySpin.CCategoryPtr(node) + + # Get and print display name + display_name = node_category.GetDisplayName() + print_with_indent(level, display_name) + + # Retrieve and iterate through all children + # + # *** NOTES *** + # The two nodes that typically have children are category nodes and + # enumeration nodes. Throughout the examples, the children of category nodes + # are referred to as features while the children of enumeration nodes are + # referred to as entries. Keep in mind that enumeration nodes can be cast as + # category nodes, but category nodes cannot be cast as enumerations. + for node_feature in node_category.GetFeatures(): + + # Ensure node is available and readable + if not PySpin.IsAvailable(node_feature) or not PySpin.IsReadable(node_feature): + continue + + # Category nodes must be dealt with separately in order to retrieve subnodes recursively. + if node_feature.GetPrincipalInterfaceType() == PySpin.intfICategory: + result &= print_category_node_and_all_features(node_feature, level + 1) + + # Cast all non-category nodes as value nodes + # + # *** NOTES *** + # If dealing with a variety of node types and their values, it may be + # simpler to cast them as value nodes rather than as their individual types. + # However, with this increased ease-of-use, functionality is sacrificed. + elif CHOSEN_READ == ReadType.VALUE: + result &= print_value_node(node_feature, level + 1) + + # Cast all non-category nodes as actual types + elif CHOSEN_READ == ReadType.INDIVIDUAL: + if node_feature.GetPrincipalInterfaceType() == PySpin.intfIString: + result &= print_string_node(node_feature, level + 1) + elif node_feature.GetPrincipalInterfaceType() == PySpin.intfIInteger: + result &= print_integer_node(node_feature, level + 1) + elif node_feature.GetPrincipalInterfaceType() == PySpin.intfIFloat: + result &= print_float_node(node_feature, level + 1) + elif node_feature.GetPrincipalInterfaceType() == PySpin.intfIBoolean: + result &= print_boolean_node(node_feature, level + 1) + elif node_feature.GetPrincipalInterfaceType() == PySpin.intfICommand: + result &= print_command_node(node_feature, level + 1) + elif node_feature.GetPrincipalInterfaceType() == PySpin.intfIEnumeration: + result &= print_enumeration_node_and_current_entry(node_feature, level + 1) + + print('') + + 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. First nodes from the TL + device and TL stream nodemaps are retrieved and printed. Following this, + the camera is initialized and then nodes from the GenICam nodemap are + retrieved and printed. + + :param cam: Camera to get nodemaps from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + level = 0 + + # Retrieve TL device nodemap + # + # *** NOTES *** + # The TL device nodemap is available on the transport layer. As such, + # camera initialization is unnecessary. It provides mostly immutable + # information fundamental to the camera such as the serial number, + # vendor, and model. + print('\n*** PRINTING TRANSPORT LAYER DEVICE NODEMAP *** \n') + + nodemap_gentl = cam.GetTLDeviceNodeMap() + + result &= print_category_node_and_all_features(nodemap_gentl.GetNode('Root'), level) + + # Retrieve TL stream nodemap + # + # *** NOTES *** + # The TL stream nodemap is also available on the transport layer. Camera + # initialization is again unnecessary. As you can probably guess, it + # provides information on the camera's streaming performance at any + # given moment. Having this information available on the transport layer + # allows the information to be retrieved without affecting camera performance. + print('*** PRINTING TL STREAM NODEMAP ***\n') + + nodemap_tlstream = cam.GetTLStreamNodeMap() + + result &= print_category_node_and_all_features(nodemap_tlstream.GetNode('Root'), level) + + # Initialize camera + # + # *** NOTES *** + # The camera becomes connected upon initialization. This provides + # access to configurable options and additional information, accessible + # through the GenICam nodemap. + # + # *** LATER *** + # Cameras should be deinitialized when no longer needed. + print('*** PRINTING GENICAM NODEMAP ***\n') + + cam.Init() + + # Retrieve GenICam nodemap + # + # *** NOTES *** + # The GenICam nodemap is the primary gateway to customizing + # and configuring the camera to suit your needs. Configuration options + # such as image height and width, trigger mode enabling and disabling, + # and the sequencer are found on this nodemap. + nodemap_applayer = cam.GetNodeMap() + + result &= print_category_node_and_all_features(nodemap_applayer.GetNode('Root'), level) + + # Deinitialize camera + # + # *** NOTES *** + # Camera deinitialization helps ensure that devices clean up properly + # and do not need to be power-cycled to maintain integrity. + cam.DeInit() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return True + + +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 instance + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + return result + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/NodeMapInfo_QuickSpin.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/NodeMapInfo_QuickSpin.py new file mode 100644 index 0000000..3381bb6 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/NodeMapInfo_QuickSpin.py @@ -0,0 +1,359 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# NodeMapInfo_QuickSpin.py shows how to interact with nodes +# using the QuickSpin API. QuickSpin is a subset of the Spinnaker library +# that allows for simpler node access and control. +# +# This example demonstrates the retrieval of information from both the +# transport layer and the camera. Because the focus of this example is node +# access, which is where QuickSpin and regular Spinnaker differ, this +# example differs from NodeMapInfo quite a bit. +# +# 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 + + +def print_transport_layer_device_info(cam): + """ + Prints device information from the transport layer. + + *** NOTES *** + In QuickSpin, accessing device information on the transport layer is + accomplished via a camera's TLDevice property. The TLDevice property + houses nodes related to general device information such as the three + demonstrated below, device access status, XML and GUI paths and + locations, and GEV information to name a few. The TLDevice property + allows access to nodes that would generally be retrieved through the + TL device nodemap in full Spinnaker. + + Notice that each node is checked for availability and readability + prior to value retrieval. Checking for availability and readability + (or writability when applicable) whenever a node is accessed is + important in terms of error handling. If a node retrieval error + occurs but remains unhandled, an exception is thrown. + + :param cam: Camera to get information from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Print device serial number + if cam.TLDevice.DeviceSerialNumber.GetAccessMode() == PySpin.RO: + print('Device serial number: %s' % cam.TLDevice.DeviceSerialNumber.ToString()) + + else: + print('Device serial number: unavailable') + result = False + + # Print device vendor name + # + # *** NOTE *** + # To check node readability/writability, you can either + # compare its access mode with RO, RW, etc. or you can use + # the IsReadable/IsWritable functions on the node. + if PySpin.IsReadable(cam.TLDevice.DeviceVendorName): + print('Device vendor name: %s' % cam.TLDevice.DeviceVendorName.ToString()) + else: + print('Device vendor name: unavailable') + result = False + + # Print device display name + if PySpin.IsReadable(cam.TLDevice.DeviceDisplayName): + print('Device display name: %s' % cam.TLDevice.DeviceDisplayName.ToString()) + else: + print('Device display name: unavailable') + result = False + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_transport_layer_stream_info(cam): + """ + Prints stream information from transport layer. + + *** NOTES *** + In QuickSpin, accessing stream information on the transport layer is + accomplished via a camera's TLStream property. The TLStream property + houses nodes related to streaming such as the two demonstrated below, + buffer information, and GEV packet information to name a few. The + TLStream property allows access to nodes that would generally be + retrieved through the TL stream nodemap in full Spinnaker. + + :param cam: Camera to get information from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Print stream ID + if cam.TLStream.StreamID.GetAccessMode() == PySpin.RO: + print('Stream ID: %s' % cam.TLStream.StreamID.ToString()) + else: + print('Stream ID: unavailable') + result = False + + # Print stream type + if PySpin.IsReadable(cam.TLStream.StreamType): + print('Stream type: %s' % cam.TLStream.StreamType.ToString()) + else: + print('Stream type: unavailable') + result = False + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_transport_layer_interface_info(interface): + """ + Prints stream information from the transport layer. + + *** NOTES *** + In QuickSpin, accessing interface information is accomplished via an + interface's TLInterface property. The TLInterface property houses + nodes that hold information about the interface such as the three + demonstrated below, other general interface information, and + GEV addressing information. The TLInterface property allows access to + nodes that would generally be retrieved through the interface nodemap + in full Spinnaker. + + Interface nodes should also always be checked for availability and + readability (or writability when applicable). If a node retrieval + error occurs but remains unhandled, an exception is thrown. + + :param interface: Interface to get information from. + :type interface: InterfacePtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Print interface display name + if interface.TLInterface.InterfaceDisplayName.GetAccessMode() == PySpin.RO: + print('Interface display name: %s' % interface.TLInterface.InterfaceDisplayName.ToString()) + else: + print('Interface display name: unavailable') + result = False + + # Print interface ID + if interface.TLInterface.InterfaceID.GetAccessMode() == PySpin.RO: + print('Interface ID: %s' % interface.TLInterface.InterfaceID.ToString()) + else: + print('Interface ID: unavailable') + result = False + + # Print interface type + if PySpin.IsReadable(interface.TLInterface.InterfaceType.GetAccessMode()): + print('Interface type: %s' % interface.TLInterface.InterfaceType.ToString()) + else: + print('Interface type: unavailable') + result = False + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def print_genicam_device_info(cam): + """ + Prints device information from the camera. + + *** NOTES *** + Most camera interaction happens through GenICam nodes. The + advantages of these nodes is that there is a lot more of them, they + allow for a much deeper level of interaction with a camera, and no + intermediate property (i.e. TLDevice or TLStream) is required. The + disadvantage is that they require initialization. + + :param cam: Camera to get information from. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + + # Print exposure time + if cam.ExposureTime.GetAccessMode() == PySpin.RO or cam.ExposureTime.GetAccessMode() == PySpin.RW: + print('Exposure time: %s' % cam.ExposureTime.ToString()) + else: + print('Exposure time: unavailable') + result = False + + # Print black level + if PySpin.IsReadable(cam.BlackLevel): + print('Black level: %s' % cam.BlackLevel.ToString()) + else: + print('Black level: unavailable') + result = False + + # Print height + if PySpin.IsReadable(cam.Height): + print('Height: %s' % cam.Height.ToString()) + else: + print('Height: unavailable') + result = False + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def main(): + """ + Example entry point; this function prints transport layer information from + each interface and transport and GenICam information from each camera. + + :return: True if successful, False otherwise. + :rtype: bool + """ + result = True + + # Retrieve singleton reference to system object + sys = PySpin.System.GetInstance() + + # Get current library version + version = sys.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 = sys.GetCameras() + + num_cams = cam_list.GetSize() + + print('Number of cameras detected: %i \n' % num_cams) + + # Finish if there are no cameras + if num_cams == 0: + # Clear camera list before releasing system + cam_list.Clear() + + # Release system instance + sys.ReleaseInstance() + + print('Not enough cameras!') + input('Done! Press Enter to exit...') + return False + + # Retrieve list of interfaces from the system + iface_list = sys.GetInterfaces() + + num_ifaces = iface_list.GetSize() + + print('Number of interfaces detected: %i \n' % num_ifaces) + + # Print information on each interface + # + # *** NOTES *** + # All USB 3 Vision and GigE Vision interfaces should enumerate for + # Spinnaker. + print('\n*** PRINTING INTERFACE INFORMATION ***\n') + + for iface in iface_list: + result &= print_transport_layer_interface_info(iface) + + # Release reference to interface + # 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 iface + + # Print general device information on each camera from transport layer + # + # *** NOTES *** + # Transport layer nodes do not require initialization in order to interact + # with them. + print('\n*** PRINTING TRANSPORT LAYER DEVICE INFORMATION ***\n') + + for cam in cam_list: + result &= print_transport_layer_device_info(cam) + + # Print streaming information on each camera from transport layer + # + # *** NOTES *** + # Again, initialization is not required to print information from the + # transport layer; this is equally true of streaming information. + print('\n*** PRINTING TRANSPORT LAYER STREAMING INFORMATION ***\n') + + for cam in cam_list: + result &= print_transport_layer_stream_info(cam) + + # Print device information on each camera from GenICam nodemap + # + # *** NOTES *** + # GenICam nodes require initialization in order to interact with + # them; as such, this loop initializes the camera, prints some information + # from the GenICam nodemap, and then deinitializes it. If the camera were + # not initialized, node availability would fail. + print('\n*** PRINTING GENICAM INFORMATION ***\n') + + for cam in cam_list: + # Initialize camera + cam.Init() + + # Print info + result &= print_genicam_device_info(cam) + + # Deinitialize camera + cam.DeInit() + + # 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() + + # Clear interface list before releasing system + iface_list.Clear() + + # Release system instance + sys.ReleaseInstance() + + input('\nDone! Press Enter to exit...') + return result + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/SaveToAvi.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/SaveToAvi.py new file mode 100644 index 0000000..1f79203 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/SaveToAvi.py @@ -0,0 +1,378 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# SaveToAvi.py shows how to create an AVI video from a vector of +# images. It relies on information provided in the Enumeration, Acquisition, +# and NodeMapInfo examples. +# +# This example introduces the SpinVideo class, which is used to quickly and +# easily create various types of AVI videos. It demonstrates the creation of +# three types: uncompressed, MJPG, and H264. + +import PySpin +import sys + + +class AviType: + """'Enum' to select AVI video type to be created and saved""" + UNCOMPRESSED = 0 + MJPG = 1 + H264 = 2 + +chosenAviType = AviType.UNCOMPRESSED # change me! +NUM_IMAGES = 10 # number of images to use in AVI file + + +def save_list_to_avi(nodemap, nodemap_tldevice, images): + """ + This function prepares, saves, and cleans up an AVI video from a vector of images. + + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :param images: List of images to save to an AVI video. + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :type images: list of ImagePtr + :return: True if successful, False otherwise. + :rtype: bool + """ + print('*** CREATING VIDEO ***') + + try: + result = True + + # Retrieve device serial number for filename + device_serial_number = '' + node_serial = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + + if PySpin.IsAvailable(node_serial) and PySpin.IsReadable(node_serial): + device_serial_number = node_serial.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Get the current frame rate; acquisition frame rate recorded in hertz + # + # *** NOTES *** + # The video frame rate can be set to anything; however, in order to + # have videos play in real-time, the acquisition frame rate can be + # retrieved from the camera. + + node_acquisition_framerate = PySpin.CFloatPtr(nodemap.GetNode('AcquisitionFrameRate')) + + if not PySpin.IsAvailable(node_acquisition_framerate) and not PySpin.IsReadable(node_acquisition_framerate): + print('Unable to retrieve frame rate. Aborting...') + return False + + framerate_to_set = node_acquisition_framerate.GetValue() + + print('Frame rate to be set to %d...' % framerate_to_set) + + # Select option and open AVI filetype with unique filename + # + # *** NOTES *** + # Depending on the filetype, a number of settings need to be set in + # an object called an option. An uncompressed option only needs to + # have the video frame rate set whereas videos with MJPG or H264 + # compressions should have more values set. + # + # Once the desired option object is configured, open the AVI file + # with the option in order to create the image file. + # + # Note that the filename does not need to be appended to the + # name of the file. This is because the AVI recorder object takes care + # of the file extension automatically. + # + # *** LATER *** + # Once all images have been added, it is important to close the file - + # this is similar to many other standard file streams. + + avi_recorder = PySpin.SpinVideo() + + if chosenAviType == AviType.UNCOMPRESSED: + avi_filename = 'SaveToAvi-Uncompressed-%s' % device_serial_number + + option = PySpin.AVIOption() + option.frameRate = framerate_to_set + + elif chosenAviType == AviType.MJPG: + avi_filename = 'SaveToAvi-MJPG-%s' % device_serial_number + + option = PySpin.MJPGOption() + option.frameRate = framerate_to_set + option.quality = 75 + + elif chosenAviType == AviType.H264: + avi_filename = 'SaveToAvi-H264-%s' % device_serial_number + + option = PySpin.H264Option() + option.frameRate = framerate_to_set + option.bitrate = 1000000 + option.height = images[0].GetHeight() + option.width = images[0].GetWidth() + + else: + print('Error: Unknown AviType. Aborting...') + return False + + avi_recorder.Open(avi_filename, option) + + # Construct and save AVI video + # + # *** NOTES *** + # Although the video file has been opened, images must be individually + # appended in order to construct the video. + print('Appending %d images to AVI file: %s.avi...' % (len(images), avi_filename)) + + for i in range(len(images)): + avi_recorder.Append(images[i]) + print('Appended image %d...' % i) + + # Close AVI file + # + # *** NOTES *** + # Once all images have been appended, it is important to close the + # AVI file. Notice that once an AVI file has been closed, no more + # images can be added. + + avi_recorder.Close() + print('Video saved at %s.avi' % avi_filename) + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return 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 + :return: True if successful, False otherwise. + :rtype: bool + """ + print('\n*** 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 acquire_images(cam, nodemap): + """ + This function acquires 10 images from a device, stores them in a list, and returns the list. + please see the Acquisition example for more in-depth comments on acquiring images. + + :param cam: Camera to acquire images from. + :param nodemap: Device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :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.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or not PySpin.IsReadable(node_acquisition_mode_continuous): + print('Unable to set acquisition mode to continuous (entry retrieval). Aborting...') + return False + + acquisition_mode_continuous = node_acquisition_mode_continuous.GetValue() + + node_acquisition_mode.SetIntValue(acquisition_mode_continuous) + + print('Acquisition mode set to continuous...') + + # Begin acquiring images + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve, convert, and save images + images = list() + + for i in range(NUM_IMAGES): + try: + # 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; height and width recorded in pixels + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed Image %d, width = %d, height = %d' % (i, width, height)) + + # Convert image to mono 8 and append to list + images.append(image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR)) + + # Release image + image_result.Release() + print('') + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + # End acquisition + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + return result, images + + +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 example 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() + + # Acquire list of images + err, images = acquire_images(cam, nodemap) + if err < 0: + return err + + result &= save_list_to_avi(nodemap, nodemap_tldevice, images) + + # 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:', 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 instance + system.ReleaseInstance() + + input('Done! Press Enter to exit...') + return result + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/Sequencer.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Sequencer.py new file mode 100644 index 0000000..23035c7 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Sequencer.py @@ -0,0 +1,873 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# 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. + +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.IsAvailable(node_sequencer_configuration_valid) \ + or 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.IsAvailable(sequencer_configuration_valid_yes) \ + or 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.IsAvailable(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.IsAvailable(sequencer_mode_off) or 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.IsAvailable(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.IsAvailable(exposure_auto_off) or 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.IsAvailable(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.IsAvailable(gain_auto_off) or 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.IsAvailable(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.IsAvailable(sequencer_configuration_mode_on)\ + or 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.IsAvailable(node_sequencer_set_selector) or 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.IsAvailable(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.IsAvailable(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.IsAvailable(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.IsAvailable(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.IsAvailable(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.IsAvailable(sequencer_trigger_source_frame_start) or \ + 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.IsAvailable(node_sequencer_set_next) or 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.IsAvailable(node_sequencer_set_save) or 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.IsAvailable(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.IsAvailable(sequencer_configuration_mode_off)\ + or 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.IsAvailable(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.IsAvailable(sequencer_mode_on) or 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.IsAvailable(node_sequencer_configuration_valid) \ + or 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.IsAvailable(sequencer_configuration_valid_yes) \ + or 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.IsAvailable(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.IsAvailable(sequencer_mode_off) or 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.IsAvailable(node_exposure_auto) and PySpin.IsWritable(node_exposure_auto): + exposure_auto_continuous = node_exposure_auto.GetEntryByName('Continuous') + if PySpin.IsAvailable(exposure_auto_continuous) and 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.IsAvailable(node_gain_auto) and PySpin.IsWritable(node_gain_auto): + gain_auto_continuous = node_exposure_auto.GetEntryByName('Continuous') + if PySpin.IsAvailable(gain_auto_continuous) and 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.IsAvailable(node_device_information) and 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 available.') + + 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.IsAvailable(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.IsAvailable(node_acquisition_mode_continuous) or \ + 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.IsAvailable(node_device_serial_number) and 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 + 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 = image_result.Convert(PySpin.PixelFormat_Mono8, PySpin.HQ_LINEAR) + + # 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.IsAvailable(node_width) or 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.IsAvailable(node_height) or 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.IsAvailable(node_exposure_time) or 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.IsAvailable(node_exposure_time) or 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) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/SpinUpdate.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/SpinUpdate.py new file mode 100644 index 0000000..409fb80 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/SpinUpdate.py @@ -0,0 +1,89 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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. +# ============================================================================= +# +# SpinUpdate.py is a sample firmware updater application that takes in +# command line arguments. The example also demonstrates usage of callback +# functions to keep track of current update progress. +# +# Run with arguments in format (no quotes): "-R -P -UU " + +import PySpin +import sys + + +last_action = '' + + +def progress_callback(action, address, global_percent, curr_percent): + """ + Example progress callback function. + NOTE: This function must take exactly 4 arguments, + otherwise the update process will hang/crash! + + :param action: Current action being done in firmware update (as a byte string). + :param address: Address in camera being written to. + :param global_percent: Global completion percentage of update. + :param curr_percent: Completion percentage of current action. + :type action: str + :type address: int + :type global_percent: int + :type curr_percent: int + :rtype: int + """ + global last_action + if action != last_action: + # Prints action only if changed from previous one + print('Action: %s' % action) + last_action = action + + return 1 + + +def message_callback(message): + """ + Example message callback function. + NOTE: This function must take exactly 1 argument, + otherwise the update process will hang/crash! + + :param message: Message from updator (as a byte string). + :type message: str + :rtype: None + """ + print('Message: %s' % message) + + return 1 + + +def main(): + # Register callbacks + PySpin.SetProgressCallback(progress_callback) + PySpin.SetMessageCallback(message_callback) + + # Example usage for firmware update: + # Use either UpdateFirmware() or UpdateFirmwareConsole(): + # + # cmd = "-R3932019 C:\\firmware\\bfly2_u3_python1300.zim" # Add -P to argument list for callbacks + # return UpdateFirmware(cmd); + + return PySpin.UpdateFirmwareConsole(sys.argv) # uses command line args + +if __name__ == '__main__': + if main(): + sys.exit(0) + else: + sys.exit(1) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/Trigger-20343286-0.jpg b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Trigger-20343286-0.jpg new file mode 100644 index 0000000..17fde7f Binary files /dev/null and b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Trigger-20343286-0.jpg differ diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/Trigger.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Trigger.py new file mode 100644 index 0000000..b1f8936 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Trigger.py @@ -0,0 +1,516 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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.py shows how to trigger the camera. 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 they are somewhat shorter and simpler, either +# provides a strong introduction to camera customization. +# +# This example shows the process of configuring, using, and cleaning up a +# camera for use with both a software and a hardware trigger. + +import os +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +class TriggerType: + SOFTWARE = 1 + HARDWARE = 2 + + +CHOSEN_TRIGGER = TriggerType.HARDWARE + + +def configure_trigger(cam): + """ + This function configures the camera to use a trigger. First, trigger mode is + set to off in order to select the trigger source. Once the trigger source + has been selected, trigger mode is then enabled, which has the camera + capture only a single image upon the execution of the chosen trigger. + + :param cam: Camera to configure trigger for. + :type cam: CameraPtr + :return: True if successful, False otherwise. + :rtype: bool + """ + result = True + + print('*** CONFIGURING TRIGGER ***\n') + + if CHOSEN_TRIGGER == TriggerType.SOFTWARE: + print('Software trigger chosen ...') + elif CHOSEN_TRIGGER == TriggerType.HARDWARE: + print('Hardware trigger chose ...') + + try: + # Ensure trigger mode off + # The trigger must be disabled in order to configure whether the source + # is software or hardware. + nodemap = cam.GetNodeMap() + node_trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerMode')) + if not PySpin.IsAvailable(node_trigger_mode) or not PySpin.IsReadable(node_trigger_mode): + print('Unable to disable trigger mode (node retrieval). Aborting...') + return False + + node_trigger_mode_off = node_trigger_mode.GetEntryByName('Off') + if not PySpin.IsAvailable(node_trigger_mode_off) or not PySpin.IsReadable(node_trigger_mode_off): + print('Unable to disable trigger mode (enum entry retrieval). Aborting...') + return False + + node_trigger_mode.SetIntValue(node_trigger_mode_off.GetValue()) + + 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. + node_trigger_selector= PySpin.CEnumerationPtr(nodemap.GetNode('TriggerSelector')) + if not PySpin.IsAvailable(node_trigger_selector) or not PySpin.IsWritable(node_trigger_selector): + print('Unable to get trigger selector (node retrieval). Aborting...') + return False + + node_trigger_selector_framestart = node_trigger_selector.GetEntryByName('FrameStart') + if not PySpin.IsAvailable(node_trigger_selector_framestart) or not PySpin.IsReadable( + node_trigger_selector_framestart): + print('Unable to set trigger selector (enum entry retrieval). Aborting...') + return False + node_trigger_selector.SetIntValue(node_trigger_selector_framestart.GetValue()) + + 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. + node_trigger_source = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerSource')) + if not PySpin.IsAvailable(node_trigger_source) or not PySpin.IsWritable(node_trigger_source): + print('Unable to get trigger source (node retrieval). Aborting...') + return False + + if CHOSEN_TRIGGER == TriggerType.SOFTWARE: + node_trigger_source_software = node_trigger_source.GetEntryByName('Software') + if not PySpin.IsAvailable(node_trigger_source_software) or not PySpin.IsReadable( + node_trigger_source_software): + print('Unable to set trigger source (enum entry retrieval). Aborting...') + return False + node_trigger_source.SetIntValue(node_trigger_source_software.GetValue()) + print('Trigger source set to software...') + + elif CHOSEN_TRIGGER == TriggerType.HARDWARE: + node_trigger_source_hardware = node_trigger_source.GetEntryByName('Line0') + if not PySpin.IsAvailable(node_trigger_source_hardware) or not PySpin.IsReadable( + node_trigger_source_hardware): + print('Unable to set trigger source (enum entry retrieval). Aborting...') + return False + node_trigger_source.SetIntValue(node_trigger_source_hardware.GetValue()) + 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. + node_trigger_mode_on = node_trigger_mode.GetEntryByName('On') + if not PySpin.IsAvailable(node_trigger_mode_on) or not PySpin.IsReadable(node_trigger_mode_on): + print('Unable to enable trigger mode (enum entry retrieval). Aborting...') + return False + + node_trigger_mode.SetIntValue(node_trigger_mode_on.GetValue()) + 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(nodemap, cam): + """ + This function acquires an image by executing the trigger node. + + :param cam: Camera to acquire images from. + :param nodemap: Device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :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 + node_softwaretrigger_cmd = PySpin.CCommandPtr(nodemap.GetNode('TriggerSoftware')) + if not PySpin.IsAvailable(node_softwaretrigger_cmd) or not PySpin.IsWritable(node_softwaretrigger_cmd): + print('Unable to execute trigger. Aborting...') + return False + + node_softwaretrigger_cmd.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, nodemap, nodemap_tldevice): + """ + 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. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + + print('*** IMAGE ACQUISITION ***\n') + try: + result = True + + # Set acquisition mode to continuous + # In order to access the node entries, they have to be casted to a pointer type (CEnumerationPtr here) + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.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(nodemap, 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; height and width recorded in pixels + # + # *** NOTES *** + # Images have quite a bit of available metadata including + # things such as CRC, image status, and offset values, to + # name a few. + width = image_result.GetWidth() + height = image_result.GetHeight() + print('Grabbed Image %d, width = %d, height = %d' % (i, width, height)) + + # Convert image to mono 8 + # + # *** NOTES *** + # Images can be converted between pixel formats by using + # the appropriate enumeration value. Unlike the original + # image, the converted one does not need to be released as + # it does not affect the camera buffer. + # + # When converting images, color processing algorithm is an + # optional parameter. + 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 + # + # *** NOTES *** + # The standard practice of the examples is to use device + # serial numbers to keep images of one device from + # overwriting those of another. + image_converted.Save(filename) + print('Image saved at %s\n' % filename) + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return result + + +def reset_trigger(nodemap): + """ + This function returns the camera to a normal state by turning off trigger mode. + + :param nodemap: Transport layer device nodemap. + :type nodemap: INodeMap + :returns: True if successful, False otherwise. + :rtype: bool + """ + try: + result = True + node_trigger_mode = PySpin.CEnumerationPtr(nodemap.GetNode('TriggerMode')) + if not PySpin.IsAvailable(node_trigger_mode) or not PySpin.IsReadable(node_trigger_mode): + print('Unable to disable trigger mode (node retrieval). Aborting...') + return False + + node_trigger_mode_off = node_trigger_mode.GetEntryByName('Off') + if not PySpin.IsAvailable(node_trigger_mode_off) or not PySpin.IsReadable(node_trigger_mode_off): + print('Unable to disable trigger mode (enum entry retrieval). Aborting...') + return False + + node_trigger_mode.SetIntValue(node_trigger_mode_off.GetValue()) + + 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, nodemap, nodemap_tldevice) + + # Reset trigger + result &= reset_trigger(nodemap) + + # 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 + """ + + # 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: %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) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/Examples/Trigger_QuickSpin.py b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Trigger_QuickSpin.py new file mode 100644 index 0000000..36166cb --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/Examples/Trigger_QuickSpin.py @@ -0,0 +1,421 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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.HARDWARE + + +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') + + 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.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(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 + 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!') + 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) diff --git a/FLIR/FLIRcodev4.1/Spinnaker/README.txt b/FLIR/FLIRcodev4.1/Spinnaker/README.txt new file mode 100644 index 0000000..42057f3 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/README.txt @@ -0,0 +1,342 @@ +============================================================================= +Copyright (c) 2001-2019 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. +============================================================================= + +============================================================================= +== +== README +== +============================================================================= + +PySpin is a wrapper for FLIR Integrated Imaging Solutions' Spinnaker library. + +FLIR Integrated Imaging Solutions' website is located at https://www.flir.com/iis/machine-vision + +The PySpin Python extension provides a common software interface +to control and acquire images from FLIR USB 3.0, GigE, +and USB 2.0 cameras using the same API under 32- or 64-bit Windows. + +============================================================================= +TABLE OF CONTENTS +============================================================================= +1. INSTALLATION +1.1 INSTALLATION ON WINDOWS +1.2 INSTALLATION ON LINUX +1.3 INSTALLATION ON MACOS +2. API DIFFERENCES +3. REMOVE PYSPIN + +============================================================================= +1. INSTALLATION +============================================================================= + +----------------------------------------------------------------------------- +1.1 WINDOWS +----------------------------------------------------------------------------- + +1. Install Python. Currently we support Python 2.7, 3.5, 3.6, and 3.7. To + download Python, visit https://www.python.org/downloads/. Note that the + Python website defaults to 32-bit interpreters, so if you want a 64-bit + version of Python you have to click into the specific release version. + +2. (Optional) Set the PATH environment variable for your Python installation. + This may have been done automatically as part of installation, but to do + this manually you have to open Environment Variables through the following: + + My Computer > Properties > Advanced System Settings > Environment Variables + + Add your Python installation location to your PATH variable. For example, + if you installed Python at C:\Python37\, you would add the following entry + to the PATH variable: + + C:\Python37\ + +3. Configure your Python installation. From a command line, run the following + commands to update and install dependencies for your associated Python version: + + -m ensurepip + -m pip install --upgrade pip numpy matplotlib + + NumPy is a requirement for PySpin and needs to be at least version 1.15 or + above. Matplotlib is not required for the library itself but is used in some + of our examples to highlight possible usages of PySpin. For better support of + matplotlib output image file formats, Pillow is suggested to be installed. + Note: some versions of Pillow might NOT support some Python versions. + + The full list of supported Pillow versions given a Python version can be found here: + https://pillow.readthedocs.io/en/stable/installation.html#notes + + For example, with Python 3.7, install a supported Pillow using the following command: + + ex. py -3.7 -m pip install Pillow==5.2.0 + + Older installations of Python 2.7 do NOT come with enum34, which is required by + the Inference.py Python2 example. Install enum34 for Python 2.7 using the following command: + + py -2.7 -m pip install enum34 + +4. To ensure prerequisites such as drivers and Visual Studio redistributables + are installed on the system, run the Spinnaker SDK installer that corresponds + with the PySpin version number. For example, if installing PySpin 1.8.0.0, + install Spinnaker 1.8.0.0 beforehand, selecting only the Visual Studio + runtimes and drivers. + +5. Run the following command to install PySpin to your associated Python version. + This command assumes you have your PATH variable set correctly for Python: + + -m pip install spinnaker_python-1.x.x.x-cp37-cp37m-win_amd64.whl + + Ensure that the wheel downloaded matches the Python version you are installing to! + +After installation, PySpin examples can be ran directly from the command prompt. +For example, if PySpin is installed for Python 3.7, run a preinstalled example +using the following: + + ex. py -3.7 Examples\Python3\Acquisition.py + +----------------------------------------------------------------------------- +1.2 LINUX +----------------------------------------------------------------------------- + +1. Check that pip is available for your respective Python versions + by running the following command: + + sudo apt-get install python-pip python3-pip + +2. Install library dependencies for PySpin: numpy and matplotlib. NumPy is a + requirement for PySpin and needs to be at least version 1.15 or above. + Matplotlib is not required for the library itself but is used in some of + our examples to highlight possible usages of PySpin. Install these + dependencies by running one of the following commands. + + - Install for Python 2.7, user only: + python -m pip install --upgrade --user numpy matplotlib + + - Install for Python 2.7, site wide: + sudo python -m pip install --upgrade numpy matplotlib + + - Install for Python 3.5, user only (16.04 only): + python3.5 -m pip install --upgrade --user numpy matplotlib + + - Install for Python 3.5, site wide (16.04 only): + sudo python3.5 -m pip install --upgrade numpy matplotlib + + - Install for Python 3.6, user only: + python3.6 -m pip install --upgrade --user numpy matplotlib + + - Install for Python 3.6, site wide: + sudo python3.6 -m pip install --upgrade numpy matplotlib + + - Install for Python 3.7, user only: + python3.7 -m pip install --upgrade --user numpy matplotlib + + - Install for Python 3.7, site wide: + sudo python3.7 -m pip install --upgrade numpy matplotlib + + For better support of matplotlib output image file formats, Pillow is suggested to be installed. + Note: some versions of Pillow might NOT support some Python versions. + + The full list of supported Pillow versions given a Python version can be found here: + https://pillow.readthedocs.io/en/stable/installation.html#notes + + For example, with Python 3.7, install a supported Pillow using the following command: + + ex. python3.7 -m pip install Pillow==5.2.0 + + Older installations of Python 2.7 do NOT come with enum34, which is required by + the Inference.py Python2 example. Install enum34 for Python 2.7 using the following command: + + python2.7 -m pip install enum34 + +3. Ensure that the corresponding version of the Spinnaker SDK Debian packages + and their prerequisites are installed beforehand + (ex. install the 1.21.0.61 packages if the wheel version is also 1.21.0.61) + +4. Install wheel for specific Python version. This can be installed site-wide + for all users or for a specific user. + + - Python 2.7, site wide: + sudo python -m pip install spinnaker_python-1.x.x.x-cp27-cp27mu-linux_x86_64.whl + + - Python 2.7, user only: + python -m pip install --user spinnaker_python-1.x.x.x-cp27-cp27mu-linux_x86_64.whl + + - Python 3.5, site wide (16.04 only): + sudo python3.5 -m pip install spinnaker_python-1.x.x.x-cp35-cp35m-linux_x86_64.whl + + - Python 3.5, user only (16.04 only): + python3.5 -m pip install --user spinnaker_python-1.x.x.x-cp35-cp35m-linux_x86_64.whl + + - Python 3.6, site wide: + sudo python3.6 -m pip install spinnaker_python-1.x.x.x-cp36-cp36m-linux_x86_64.whl + + - Python 3.6, user only: + python3.6 -m pip install --user spinnaker_python-1.x.x.x-cp36-cp36m-linux_x86_64.whl + + - Python 3.7, site wide: + sudo python3.7 -m pip install spinnaker_python-1.x.x.x-cp37-cp37m-linux_x86_64.whl + + - Python 3.7, user only: + python3.7 -m pip install --user spinnaker_python-1.x.x.x-cp37-cp37m-linux_x86_64.whl + +5. The examples are located in the Examples folder of the extracted tarball. Run with: + ex. python3.7 Examples/Python3/DeviceEvents.py + +----------------------------------------------------------------------------- +1.3 MACOS +----------------------------------------------------------------------------- + +1. Check that Python is installed. MacOS comes with Python 2.7 installed, + but it may be an older build of Python. Up-to-date Python packages + can be downloaded from https://www.python.org/downloads. + +2. Update pip for Python. Run the following command for your version of Python: + + sudo -m ensurepip + + This will install a version of pip and allow you to update or install new wheels. + +3. Install library dependencies for PySpin: numpy and matplotlib. NumPy is a + requirement for PySpin and needs to be at least version 1.15 or above. + Matplotlib is not required for the library itself but is used in some of + our examples to highlight possible usages of PySpin. Install these + dependencies by running one of the following commands. + + - Install for Python 2.7, user only: + python -m pip install --upgrade --user numpy matplotlib + + - Install for Python 2.7, site wide: + sudo python -m pip install --upgrade numpy matplotlib + + - Install for Python 3.6, user only: + python3.6 -m pip install --upgrade --user numpy matplotlib + + - Install for Python 3.6, site wide: + sudo python3.6 -m pip install --upgrade numpy matplotlib + + - Install for Python 3.7, user only: + python3.7 -m pip install --upgrade --user numpy matplotlib + + - Install for Python 3.7, site wide: + sudo python3.7 -m pip install --upgrade numpy matplotlib + + For better support of matplotlib output image file formats, Pillow is suggested to be installed. + Note: some versions of Pillow might NOT support some Python versions. + + The full list of supported Pillow versions given a Python version can be found here: + https://pillow.readthedocs.io/en/stable/installation.html#notes + + For example, with Python 3.7, install a supported Pillow using the following command: + + ex. python3.7 -m pip install Pillow==5.2.0 + + Older installations of Python 2.7 do NOT come with enum34, which is required by + the Inference.py Python2 example. Install enum34 for Python 2.7 using the following command: + + python2.7 -m pip install enum34 + +4. Ensure that the corresponding version of the Spinnaker SDK MacOS packages + and their prerequisites are installed beforehand. + (ex. install 1.21.0.61 packages if the wheel version is also 1.21.0.61) + +5. Install the PySpin wheel for specific Python version. + ex. sudo python3.7 -m pip install spinnaker_python-1.x.x.x-cp37-cp37mu-macos_x86_x64.whl" for 64-bit Python 3.7 + +6. The examples are located in the Examples folder of the extracted tarball. Run with: + ex. python3.7 Examples/Python3/DeviceEvents.py + +============================================================================= +2. API DIFFERENCES +============================================================================= + +Except for the changes listed below, most function names are exactly the same +as the C++ API. See examples for PySpin usage! + +- All methods of SpinnakerException no longer exist, please replace all + usages of SpinnakerException with any of the following attributes: + message: Normal exception message. + fullmessage: Exception message including line, file, function, + build date, and time (from C++ library). + errorcode: Integer error code of the exception. + The SpinnakerException instance itself can be printed, as it derives from + the BaseException class and has a default __str__ representation. + See examples for usage. + +- Image creation using NumPy arrays (although the int type of the array must be uint8) + +- The majority of headers from the C++ API have been wrapped, with the exception of: + - Headers with "Adapter" or "Port" in the name + - NodeMapRef.h, NodeMapFactory.h + - Synch.h, GCSynch.h, Counter.h, filestream.h + +- INode and IValue types (esp. returned from GetNode()) have to + be initialized to their respective pointer types + (ex. CFloatPtr, CEnumerationPtr) to access their functions + +- CameraPtr, CameraList, InterfacePtr, InterfaceList, and SystemPtr + have to be manually released and/or deleted before program exit (use del operator) + - See EnumerationEvents example + +- Image.GetData() returns a 1-D NumPy array of integers, the int type + depends on the pixel format of the image + +- Image.GetNDArray() returns a 2 or 3-D NumPy array of integers, only for select + image formats. This can be used in libraries such as PIL and/or OpenCV. + +- Node callbacks take in a callback class instead of a function pointer + - Register is now RegisterNodeCallback, Deregister is now DeregisterNodeCallback + - See NodeMapCallback example for more details + +- IImage.CalculateChannelStatistics(StatisticsChannel channel) returns + a ChannelStatistics object representing stats for the given channel + in the image. These stats are properties within the ChannelStatistics object, + Please see the docstring for details. This replaces ImageStatistics! + +- Pass-by-reference functions now return the type and take in void + - GetFeatures() returns a Python list of IValue, instead of taking + in a FeatureList_t reference + - GetChildren() returns a Python list of INode, instead of taking + in a NodeList_t reference + - Same with GetEntries(), GetNodes() + - GetPropertyNames() returns a Python list of str, + instead of taking in a gcstring_vector reference + - See DeviceEvents example for usage + +- Methods Get() and Set() for IRegister and register nodes use NumPy arrays + - Get() takes in the length of the register to read and two optional + bools, returns a NumPy array + - Set() takes in a single NumPy array + +============================================================================= +3. REMOVE PYSPIN +============================================================================= + +Removing or updating PySpin is similar to removing or updating other wheels. + +For Windows, if you need to remove PySpin, the following command needs to be +run from an administrator command prompt to remove your associated Python version: + + -m pip uninstall spinnaker-python + +For Linux or MacOS, if you need to remove PySpin from a user-specific install, run +the following command to remove your associated Python version: + + -m pip uninstall spinnaker-python + +For Linux or MacOS, if you need to remove PySpin from a site-wide install the +following command needs to be run as sudo to remove your associated Python version: + +sudo -m pip uninstall spinnaker-python \ No newline at end of file diff --git a/FLIR/FLIRcodev4.1/Spinnaker/docs/PySpinDoc.chm b/FLIR/FLIRcodev4.1/Spinnaker/docs/PySpinDoc.chm new file mode 100644 index 0000000..4e69f95 Binary files /dev/null and b/FLIR/FLIRcodev4.1/Spinnaker/docs/PySpinDoc.chm differ diff --git a/FLIR/FLIRcodev4.1/Spinnaker/docs/PySpinDoc.pdf b/FLIR/FLIRcodev4.1/Spinnaker/docs/PySpinDoc.pdf new file mode 100644 index 0000000..5b2a889 Binary files /dev/null and b/FLIR/FLIRcodev4.1/Spinnaker/docs/PySpinDoc.pdf differ diff --git a/FLIR/FLIRcodev4.1/Spinnaker/licenses/FFmpeg_compliance_doc.txt b/FLIR/FLIRcodev4.1/Spinnaker/licenses/FFmpeg_compliance_doc.txt new file mode 100644 index 0000000..7b06e29 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Spinnaker/licenses/FFmpeg_compliance_doc.txt @@ -0,0 +1,2 @@ +This software uses code of FFmpeg http://ffmpeg.org licensed under the LGPL v2.1 (http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html). +The FFmpeg code can be found online at https://github.com/FFmpeg/FFmpeg/tree/5156578d1f486163d5b83f1d63246cd23d107933. \ No newline at end of file diff --git a/FLIR/FLIRcodev4.1/Spinnaker/licenses/Spinnaker-Open-Source-Licenses.pdf b/FLIR/FLIRcodev4.1/Spinnaker/licenses/Spinnaker-Open-Source-Licenses.pdf new file mode 100644 index 0000000..55a8894 Binary files /dev/null and b/FLIR/FLIRcodev4.1/Spinnaker/licenses/Spinnaker-Open-Source-Licenses.pdf differ diff --git a/FLIR/FLIRcodev4.1/Spinnaker/spinnaker_python-2.0.0.146-cp38-cp38-win_amd64.whl b/FLIR/FLIRcodev4.1/Spinnaker/spinnaker_python-2.0.0.146-cp38-cp38-win_amd64.whl new file mode 100644 index 0000000..bd0497a Binary files /dev/null and b/FLIR/FLIRcodev4.1/Spinnaker/spinnaker_python-2.0.0.146-cp38-cp38-win_amd64.whl differ diff --git a/FLIR/FLIRcodev4.1/Trigger_QuickSpin.py b/FLIR/FLIRcodev4.1/Trigger_QuickSpin.py new file mode 100644 index 0000000..9a33cb4 --- /dev/null +++ b/FLIR/FLIRcodev4.1/Trigger_QuickSpin.py @@ -0,0 +1,422 @@ +# coding=utf-8 +# ============================================================================= +# Copyright (c) 2001-2019 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 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.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 + 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 + 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!') + 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) diff --git a/FLIR/FLIRcodev4.1/build/lib/flir/__init__.py b/FLIR/FLIRcodev4.1/build/lib/flir/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/FLIR/FLIRcodev4.1/build/lib/flir/aqctl_flir.py b/FLIR/FLIRcodev4.1/build/lib/flir/aqctl_flir.py new file mode 100644 index 0000000..be65248 --- /dev/null +++ b/FLIR/FLIRcodev4.1/build/lib/flir/aqctl_flir.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 + +# Written by Joe Britton, 2015 + +import argparse +import logging +import sys +import os +import asyncio + +from flir.driver import FLIR +from flir.driver import TriggerType +from sipyco.pc_rpc import simple_server_loop +from sipyco import common_args + + +logger = logging.getLogger(__name__) +print("prepreinit") + +def get_argparser(): + parser = argparse.ArgumentParser( + description="ARTIQ controller for the FLIR camera") + common_args.simple_network_args(parser, 3200) + parser.add_argument( + "-d", "--device", default=None, + help="serial port.") + parser.add_argument( + "--softtrig", default=False, action="store_true", + help="Sets trigger to software. Default is hardware") + parser.add_argument( + "--num", default=1, + help="Sets number of images. Default is hardware") + parser.add_argument( + "--simulation", action="store_true", + help="Put the driver in simulation mode, even if --device is used.") + common_args.verbosity_args(parser) + return parser + + +def main(): + print("preinit") + args = get_argparser().parse_args() + common_args.init_logger_from_args(args) + if os.name == "nt": + asyncio.set_event_loop(asyncio.ProactorEventLoop()) + # if args.device is None: + # print("Starting in Simulation mode...") + # dev = FLIR(args.device if not args.simulation else None) + + print("Software trigger is:",args.softtrig) + triggerset=TriggerType(args.softtrig) + dev = FLIR() + #asyncio.get_event_loop().run_until_complete(dev.setup()) + try: + print("Startup on port",args.port,"successful...") + simple_server_loop( + {"flir": dev}, common_args.bind_address_from_args(args), args.port) + finally: + dev.close() + + + +print(__name__) + +if __name__ == "__main__": + main() diff --git a/FLIR/FLIRcodev4.1/build/lib/flir/driver(backup).py b/FLIR/FLIRcodev4.1/build/lib/flir/driver(backup).py new file mode 100644 index 0000000..f6295b4 --- /dev/null +++ b/FLIR/FLIRcodev4.1/build/lib/flir/driver(backup).py @@ -0,0 +1,535 @@ +# Written by Joe Britton, 2015 + +import math +import logging +import asyncio +import asyncserial + +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +class TriggerType: + SOFTWARE = 1 + HARDWARE = 2 + +CHOSEN_TRIGGER = TriggerType.SOFTWARE + + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + pass + + +class FLIR: + """Driver for FLIR camera """ + + error_codes = { + "?0": "Unrecognized Command", + "?1": "Bad Frequency", + "?2": "Bad AM Command", + "?3": "Input line too long", + "?4": "Bad Phase", + "?5": "Bad Time", + "?6": "Bad Mode", + "?7": "Bad Amp", + "?8": "Bad Constant", + "?f": "Bad Byte" + } + + def __init__(self, serial_dev): + if serial_dev is None: + self.simulation = True + else: + self.simulation = False + self.port = asyncserial.AsyncSerial( + serial_dev, + baudrate=19200, + bytesize=8, + parity="N", + stopbits=1, + xonxoff=0) + + async def _ser_readline(self): + c = await self.port.read(1) + print(c) + r = c + while c != b"\n": + c = await self.port.read(1) + r += c + return r + + async def _ser_send(self, cmd, get_response=True): + """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + if self.simulation: + logger.info("simulation _ser_send(\"%s\")", cmd) + else: + logger.debug("_ser_send(\"%s\")", cmd) + self.port.ser.reset_input_buffer() + await self.port.write((cmd + "\r\n").encode()) + if get_response: + result = (await self._ser_readline()).rstrip().decode() + logger.debug("got response from device: %s", result) + if result != "OK": + errstr = self.error_codes.get(result, "Unrecognized reply") + s = "Erroneous reply from device: {ec}, {ecs}".format( + ec=result, ecs=errstr) + raise ValueError(s) + else: + pass + + async def setup(self): + """Initial setup of FLIR.""" + await self._ser_send("E d", get_response=False) + + + def close(self): + """Close the serial hardware port.""" + if not self.simulation: + self.port.close() + + async def ping(self): + try: + stat = await self.get_status() + except asyncio.CancelledError: + raise + except: + return False + # check that version number matches is "21" + if stat[4][20:] == "21": + logger.debug("ping successful") + return True + else: + return False + + + 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.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 + 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 + 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 + """ + print("393-postfunction") + try: + print("395") + result = True + err = False + print("398") + # Retrieve TL device nodemap and print device information + nodemap_tldevice = cam.GetTLDeviceNodeMap() + print("401") + result &= print_device_info(nodemap_tldevice) + print("403") + # Initialize camera + cam.Init() + print("406") + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + print("409") + # Configure trigger + if configure_trigger(cam) is False: + return False + print("413") + # Acquire images + result &= grab_next_image_by_trigger(cam) #acquire_images(cam) THIS IS WHAT I CHANGED TO TRY TO GRAB ONLY ONE IMAGE AT A TIME! + print("416") + # Reset trigger + result &= reset_trigger(cam) + print("419") + # Deinitialize camera + cam.DeInit() + print("422") + except PySpin.SpinnakerException as ex: + print("424-exception") + print('Error: %s' % ex) + result = False + + + return result + + + def picture(cam): + """ + Run this code to take a single triggered picture! + + :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!') + print("Closing camera instance...") #input('Done! Press Enter to exit...') + return False + print(cam) + # Run example on each camera + for i, cam in enumerate(cam_list): + + print('Running example for camera %d...' % i) + + print("472-prefunction") + 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() + + print("Closing camera instance...") #input('Done! Press Enter to exit...') + return result + + + # if __name__ == '__picture__': + # if picture(): + # sys.exit(0) + # else: + # sys.exit(1) + + + + +############################################################ + + + + + + # async def reset(self): + # """Hardware reset of FLIR.""" + # await self._ser_send("R", get_response=False) + # await asyncio.sleep(1) + # await self.setup() + + # async def setup(self): + # """Initial setup of FLIR.""" + + # await self._ser_send("E d", get_response=False) + + # async def get_status(self): + # if self.simulation: + # return ["00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "80 BC0000 0000 0102 21"] + # else: + # self.port.ser.reset_input_buffer() + # result = [] + # await self.port.write(("QUE" + "\r\n").encode()) + # for i in range(5): + # m = (await self._ser_readline()).rstrip().decode() + # result.append(m) + # logger.debug("got device status: %s", result) + # return result + + \ No newline at end of file diff --git a/FLIR/FLIRcodev4.1/build/lib/flir/driver(backup_old).py b/FLIR/FLIRcodev4.1/build/lib/flir/driver(backup_old).py new file mode 100644 index 0000000..f6295b4 --- /dev/null +++ b/FLIR/FLIRcodev4.1/build/lib/flir/driver(backup_old).py @@ -0,0 +1,535 @@ +# Written by Joe Britton, 2015 + +import math +import logging +import asyncio +import asyncserial + +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +class TriggerType: + SOFTWARE = 1 + HARDWARE = 2 + +CHOSEN_TRIGGER = TriggerType.SOFTWARE + + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + pass + + +class FLIR: + """Driver for FLIR camera """ + + error_codes = { + "?0": "Unrecognized Command", + "?1": "Bad Frequency", + "?2": "Bad AM Command", + "?3": "Input line too long", + "?4": "Bad Phase", + "?5": "Bad Time", + "?6": "Bad Mode", + "?7": "Bad Amp", + "?8": "Bad Constant", + "?f": "Bad Byte" + } + + def __init__(self, serial_dev): + if serial_dev is None: + self.simulation = True + else: + self.simulation = False + self.port = asyncserial.AsyncSerial( + serial_dev, + baudrate=19200, + bytesize=8, + parity="N", + stopbits=1, + xonxoff=0) + + async def _ser_readline(self): + c = await self.port.read(1) + print(c) + r = c + while c != b"\n": + c = await self.port.read(1) + r += c + return r + + async def _ser_send(self, cmd, get_response=True): + """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + if self.simulation: + logger.info("simulation _ser_send(\"%s\")", cmd) + else: + logger.debug("_ser_send(\"%s\")", cmd) + self.port.ser.reset_input_buffer() + await self.port.write((cmd + "\r\n").encode()) + if get_response: + result = (await self._ser_readline()).rstrip().decode() + logger.debug("got response from device: %s", result) + if result != "OK": + errstr = self.error_codes.get(result, "Unrecognized reply") + s = "Erroneous reply from device: {ec}, {ecs}".format( + ec=result, ecs=errstr) + raise ValueError(s) + else: + pass + + async def setup(self): + """Initial setup of FLIR.""" + await self._ser_send("E d", get_response=False) + + + def close(self): + """Close the serial hardware port.""" + if not self.simulation: + self.port.close() + + async def ping(self): + try: + stat = await self.get_status() + except asyncio.CancelledError: + raise + except: + return False + # check that version number matches is "21" + if stat[4][20:] == "21": + logger.debug("ping successful") + return True + else: + return False + + + 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.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 + 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 + 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 + """ + print("393-postfunction") + try: + print("395") + result = True + err = False + print("398") + # Retrieve TL device nodemap and print device information + nodemap_tldevice = cam.GetTLDeviceNodeMap() + print("401") + result &= print_device_info(nodemap_tldevice) + print("403") + # Initialize camera + cam.Init() + print("406") + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + print("409") + # Configure trigger + if configure_trigger(cam) is False: + return False + print("413") + # Acquire images + result &= grab_next_image_by_trigger(cam) #acquire_images(cam) THIS IS WHAT I CHANGED TO TRY TO GRAB ONLY ONE IMAGE AT A TIME! + print("416") + # Reset trigger + result &= reset_trigger(cam) + print("419") + # Deinitialize camera + cam.DeInit() + print("422") + except PySpin.SpinnakerException as ex: + print("424-exception") + print('Error: %s' % ex) + result = False + + + return result + + + def picture(cam): + """ + Run this code to take a single triggered picture! + + :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!') + print("Closing camera instance...") #input('Done! Press Enter to exit...') + return False + print(cam) + # Run example on each camera + for i, cam in enumerate(cam_list): + + print('Running example for camera %d...' % i) + + print("472-prefunction") + 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() + + print("Closing camera instance...") #input('Done! Press Enter to exit...') + return result + + + # if __name__ == '__picture__': + # if picture(): + # sys.exit(0) + # else: + # sys.exit(1) + + + + +############################################################ + + + + + + # async def reset(self): + # """Hardware reset of FLIR.""" + # await self._ser_send("R", get_response=False) + # await asyncio.sleep(1) + # await self.setup() + + # async def setup(self): + # """Initial setup of FLIR.""" + + # await self._ser_send("E d", get_response=False) + + # async def get_status(self): + # if self.simulation: + # return ["00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "80 BC0000 0000 0102 21"] + # else: + # self.port.ser.reset_input_buffer() + # result = [] + # await self.port.write(("QUE" + "\r\n").encode()) + # for i in range(5): + # m = (await self._ser_readline()).rstrip().decode() + # result.append(m) + # logger.debug("got device status: %s", result) + # return result + + \ No newline at end of file diff --git a/FLIR/FLIRcodev4.1/build/lib/flir/driver(complex).py b/FLIR/FLIRcodev4.1/build/lib/flir/driver(complex).py new file mode 100644 index 0000000..b4167c8 --- /dev/null +++ b/FLIR/FLIRcodev4.1/build/lib/flir/driver(complex).py @@ -0,0 +1,202 @@ +# Written by Joe Britton, 2015 + +import math +import logging +import asyncio +import asyncserial + + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + print("Exception Error :(") + pass + + +class FLIR: + """Driver for Novatech 409B 4-channel DDS. + + All output channels are in range [0, 1, 2, 3]. + All frequencies are in Hz. + All phases are in turns. + All amplitudes are in volts. + """ + + error_codes = { + "?0": "Unrecognized Command", + "?1": "Bad Frequency", + "?2": "Bad AM Command", + "?3": "Input line too long", + "?4": "Bad Phase", + "?5": "Bad Time", + "?6": "Bad Mode", + "?7": "Bad Amp", + "?8": "Bad Constant", + "?f": "Bad Byte" + } + + def __init__(self, serial_dev): + if serial_dev is None: + self.simulation = True + else: + self.simulation = False + self.port = asyncserial.AsyncSerial( + serial_dev, + baudrate=19200, + bytesize=8, + parity="N", + stopbits=1, + xonxoff=0) + + def close(self): + """Close the serial port.""" + if not self.simulation: + self.port.close() + + async def _ser_readline(self): + c = await self.port.read(1) + print(c) + r = c + while c != b"\n": + c = await self.port.read(1) + r += c + return r + + async def _ser_send(self, cmd, get_response=True): + """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + if self.simulation: + logger.info("simulation _ser_send(\"%s\")", cmd) + else: + logger.debug("_ser_send(\"%s\")", cmd) + self.port.ser.reset_input_buffer() + await self.port.write((cmd + "\r\n").encode()) + if get_response: + result = (await self._ser_readline()).rstrip().decode() + logger.debug("got response from device: %s", result) + if result != "OK": + errstr = self.error_codes.get(result, "Unrecognized reply") + s = "Erroneous reply from device: {ec}, {ecs}".format( + ec=result, ecs=errstr) + raise ValueError(s) + else: + pass + + async def reset(self): + """Hardware reset of 409B.""" + await self._ser_send("R", get_response=False) + await asyncio.sleep(1) + await self.setup() + + async def setup(self): + """Initial setup of 409B.""" + + # Setup the Novatech 409B with the following defaults: + # * command echo off ("E d") + # * external clock ("") 10 MHz sinusoid -1 to +7 dBm + print("setup is working") + await self._ser_send("E d", get_response=False) + await self.set_phase_continuous(True) + await self.set_simultaneous_update(False) + + async def save_state_to_eeprom(self): + """Save current state to EEPROM.""" + await self._ser_send("S") + + async def set_phase_continuous(self, is_continuous): + """Toggle phase continuous mode. + + Sends the "M n" command. This turns off the automatic + clearing of the phase register. In this mode, the phase + register is left intact when a command is performed. + Use this mode if you want frequency changes to remain + phase synchronous, with no phase discontinuities. + + :param is_continuous: True or False + """ + if is_continuous: + await self._ser_send("M n") + else: + await self._ser_send("M a") + + async def set_simultaneous_update(self, simultaneous): + """Set simultaneous update mode. + + Sends the "I m" command. In this mode an update + pulse will not be sent to the DDS chip until + an "I p" command is sent. This is useful when it is + important to change all the outputs to new values + simultaneously. + """ + if simultaneous: + await self._ser_send("I m") + else: + await self._ser_send("I a") + + async def do_simultaneous_update(self): + """Apply update in simultaneous update mode.""" + await self._ser_send("I p") + + async def set_freq(self, ch_no, freq): + """Set frequency of one channel.""" + # Novatech expects MHz + await self._ser_send("F{:d} {:f}".format(ch_no, freq/1e6)) + + async def set_phase(self, ch_no, phase): + """Set phase of one channel.""" + # phase word is required by device + # N is an integer from 0 to 16383. Phase is set to + # N*360/16384 deg; in ARTIQ represent phase in cycles [0, 1] + phase_word = round(phase*16383) + cmd = "P{:d} {:d}".format(ch_no, phase_word) + await self._ser_send(cmd) + + async def set_gain(self, ch_no, volts): + """Set amplitude of one channel.""" + + # due to error in Novatech it doesn't generate an error for + # dac_value>1024, so need to trap. + dac_value = int(math.floor(volts/0.51*1024)) + if dac_value < 0 or dac_value > 1023: + s = "Amplitude out of range {v}".format(v=volts) + raise ValueError(s) + + s = "V{:d} {:d}".format(ch_no, dac_value) + await self._ser_send(s) + + async def get_status(self): + if self.simulation: + return ["00989680 2000 01F5 0000 00000000 00000000 000301", + "00989680 2000 01F5 0000 00000000 00000000 000301", + "00989680 2000 01F5 0000 00000000 00000000 000301", + "00989680 2000 01F5 0000 00000000 00000000 000301", + "80 BC0000 0000 0102 21"] + else: + self.port.ser.reset_input_buffer() + result = [] + await self.port.write(("QUE" + "\r\n").encode()) + for i in range(5): + m = (await self._ser_readline()).rstrip().decode() + result.append(m) + logger.debug("got device status: %s", result) + return result + + async def ping(self): + try: + stat = await self.get_status() + except asyncio.CancelledError: + raise + except: + return False + # check that version number matches is "21" + if stat[4][20:] == "21": + logger.debug("ping successful") + return True + else: + return False diff --git a/FLIR/FLIRcodev4.1/build/lib/flir/driver(old).py b/FLIR/FLIRcodev4.1/build/lib/flir/driver(old).py new file mode 100644 index 0000000..f7b83d4 --- /dev/null +++ b/FLIR/FLIRcodev4.1/build/lib/flir/driver(old).py @@ -0,0 +1,715 @@ +import math +import logging +import asyncio +import asyncserial +import os +import matplotlib.pyplot as plt +import keyboard +import time +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + +global continue_recording +continue_recording = True + +global trigtype +SOFTWARE = 1 +HARDWARE = 2 +trigtype=SOFTWARE +class TriggerType(): + def __init__(self, softtrig): + global trigtype + if softtrig is True: + trigtype=SOFTWARE + else: + trigtype=HARDWARE + +CHOSEN_TRIGGER = trigtype + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + pass + + +class FLIR: + """Driver for FLIR camera """ + def __init__(self,num): + serial_dev = None + cam=0 + cam_list=0 + self.cameras=0 + result = True + self.num=num + system = PySpin.System.GetInstance() + version = system.GetLibraryVersion() + print('Library version: %d.%d.%d.%d' % (version.major, version.minor, version.type, version.build)) + cam_list = system.GetCameras() + self.system = system + self.cam_list = cam_list + self.cam=cam_list[0] + + num_cameras = cam_list.GetSize() + print('Number of cameras detected: %d' % num_cameras) + if num_cameras == 0: + cam_list.Clear() + system.ReleaseInstance() + print('Not enough cameras!') + print("Closing camera instance...") + return False + for i, cam in enumerate(cam_list): + print('Defining camera %d...' % i) + + self.nodemap_tldevice = cam.GetTLDeviceNodeMap() + result &= self.print_device_info(self.nodemap_tldevice) + cam.Init() + self.nodemap = cam.GetNodeMap() + + print("Going back to server now...") + + + + + + + # def picture(self): + # """ + # Run this code to take a single triggered picture! + + # :return: True if successful, False otherwise. + # :rtype: bool + # """ + # result = True + # print(self.cam) + # result &= self.run_single_camera(self.cam) + # for i, cam in enumerate(cam_list): + + # print('Running example for camera %d...' % i) + + # print("472-prefunction") + # result &= run_single_camera(cam) + # print('Camera %d example complete... \n' % i) + # return result + + def picture(self):#run_single_camera(self): + """ + 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 + cam=self.cam + cam.BeginAcquisition() + image_result = cam.GetNextImage(1000) + # Configure trigger + if self.configure_trigger(cam) is False: + return False + + # Acquire images + result &= self.grab_next_image_by_trigger(cam) #acquire_images(cam) THIS IS WHAT I CHANGED TO TRY TO GRAB ONLY ONE IMAGE AT A TIME! + + + 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 + filename = 'Trigger-%d.jpg' % i + + + # Save image + image_converted.Save(filename) + + print('Image saved at %s\n' % filename) + + # Release image + image_result.Release() + # Reset trigger + result &= self.reset_trigger(cam) + cam.EndAcquisition() + cam.EndAcquisition() + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + + return result + + async def _ser_readline(self): + c = await self.port.read(1) + print(c) + r = c + while c != b"\n": + c = await self.port.read(1) + r += c + return r + + async def _ser_send(self, cmd, get_response=True): + """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + if self.simulation: + logger.info("simulation _ser_send(\"%s\")", cmd) + else: + logger.debug("_ser_send(\"%s\")", cmd) + self.port.ser.reset_input_buffer() + await self.port.write((cmd + "\r\n").encode()) + if get_response: + result = (await self._ser_readline()).rstrip().decode() + logger.debug("got response from device: %s", result) + if result != "OK": + errstr = self.error_codes.get(result, "Unrecognized reply") + s = "Erroneous reply from device: {ec}, {ecs}".format( + ec=result, ecs=errstr) + raise ValueError(s) + else: + pass + + async def setup(self): + """Initial setup of FLIR.""" + await self._ser_send("E d", get_response=False) + + + def close(self): + """Close the serial hardware port.""" + # Deinitialize camera + self.cam.DeInit() + del self.cam + self.system.ReleaseInstance() + self.cam_list.Clear() + print("Closing camera instance...") #input('Done! Press Enter to exit...') + # if not self.simulation: + # self.port.close() + + async def ping(self): + try: + stat = await self.get_status() + except asyncio.CancelledError: + raise + except: + return False + # check that version number matches is "21" + if stat[4][20:] == "21": + logger.debug("ping successful") + return True + else: + return False + + + def configure_trigger(self,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 == SOFTWARE: + print('Software trigger chosen...') + elif CHOSEN_TRIGGER == 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.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 == SOFTWARE: + cam.TriggerSource.SetValue(PySpin.TriggerSource_Software) + print('Trigger source set to software...') + elif CHOSEN_TRIGGER == 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(self,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 == 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 == 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(self): + """ + 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 + """ + cam=self.cam + NUM_IMAGES=self.num + 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 &= self.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(self): + # Deinitialize camera + self.cam.DeInit() + + self.cam.Init() + + + def reset_trigger(self,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(self,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 handle_close(self,evt): + """ + This function will close the GUI when close event happens. + + :param evt: Event that occurs when the figure closes. + :type evt: Event + """ + + global continue_recording + continue_recording = False + + def display(self): + """ + This function continuously acquires images from a device and display them in a GUI. + + :param cam: Camera to acquire images from. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + global continue_recording + + cam=self.cam + nodemap=self.nodemap + nodemap_tldevice=self.nodemap_tldevice + sNodemap = cam.GetTLStreamNodeMap() + + # Change bufferhandling mode to NewestOnly + node_bufferhandling_mode = PySpin.CEnumerationPtr(sNodemap.GetNode('StreamBufferHandlingMode')) + if not PySpin.IsAvailable(node_bufferhandling_mode) or not PySpin.IsWritable(node_bufferhandling_mode): + print('Unable to set stream buffer handling mode.. Aborting...') + return False + + # Retrieve entry node from enumeration node + node_newestonly = node_bufferhandling_mode.GetEntryByName('NewestOnly') + if not PySpin.IsAvailable(node_newestonly) or not PySpin.IsReadable(node_newestonly): + print('Unable to set stream buffer handling mode.. Aborting...') + return False + + # Retrieve integer value from entry node + node_newestonly_mode = node_newestonly.GetValue() + + # Set integer value from entry node as new value of enumeration node + node_bufferhandling_mode.SetIntValue(node_newestonly_mode) + + print('*** IMAGE ACQUISITION ***\n') + try: + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # What happens when the camera begins acquiring images depends on the + # acquisition mode. Single frame captures only a single image, multi + # frame catures a set number of images, and continuous captures a + # continuous stream of images. + # + # *** LATER *** + # Image acquisition must be ended when no more images are needed. + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve device serial number for filename + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Close program + print('Press enter to close the program..') + + # Figure(1) is default so you can omit this line. Figure(0) will create a new window every time program hits this line + fig = plt.figure(1) + + # Close the GUI when close event happens + fig.canvas.mpl_connect('close_event', self.handle_close) + + # Retrieve and display images + while(continue_recording): + try: + + # Retrieve next received image + # + # *** NOTES *** + # Capturing an image houses images on the camera buffer. Trying + # to capture an image that does not exist will hang the camera. + # + # *** LATER *** + # Once an image from the buffer is saved and/or no longer + # needed, the image must be released in order to keep the + # buffer from filling up. + + image_result = cam.GetNextImage(1000) + + # Ensure image completion + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + + else: + + # Getting the image data as a numpy array + image_data = image_result.GetNDArray() + + # Draws an image on the current figure + plt.imshow(image_data, cmap='gray') + + # Interval in plt.pause(interval) determines how fast the images are displayed in a GUI + # Interval is in seconds. + plt.pause(0.001) + + # Clear current reference of a figure. This will improve display speed significantly + plt.clf() + + # If user presses enter, close the program + if keyboard.is_pressed('ENTER'): + print('Program is closing...') + + # Close figure + plt.close('all') + input('Done! Press Enter to exit...') + continue_recording=False + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return True + + + + + + + + + +############################################################ + + + + + + # async def reset(self): + # """Hardware reset of FLIR.""" + # await self._ser_send("R", get_response=False) + # await asyncio.sleep(1) + # await self.setup() + + # async def setup(self): + # """Initial setup of FLIR.""" + + # await self._ser_send("E d", get_response=False) + + # async def get_status(self): + # if self.simulation: + # return ["00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "80 BC0000 0000 0102 21"] + # else: + # self.port.ser.reset_input_buffer() + # result = [] + # await self.port.write(("QUE" + "\r\n").encode()) + # for i in range(5): + # m = (await self._ser_readline()).rstrip().decode() + # result.append(m) + # logger.debug("got device status: %s", result) + # return result + + \ No newline at end of file diff --git a/FLIR/FLIRcodev4.1/build/lib/flir/driver.py b/FLIR/FLIRcodev4.1/build/lib/flir/driver.py new file mode 100644 index 0000000..df94acd --- /dev/null +++ b/FLIR/FLIRcodev4.1/build/lib/flir/driver.py @@ -0,0 +1,179 @@ +import math +import logging +import asyncio +import asyncserial +import os +import matplotlib.pyplot as plt +import keyboard +import time +import PySpin +import sys +import time + +NUM_IMAGES = 10 # number of images to grab + +global continue_recording +continue_recording = True + +global trigtype +SOFTWARE = 1 +HARDWARE = 2 +trigtype=SOFTWARE +class TriggerType(): + def __init__(self, softtrig): + global trigtype + if softtrig is True: + trigtype=SOFTWARE + else: + trigtype=HARDWARE + +CHOSEN_TRIGGER = trigtype + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + pass + + +class FLIR: + """Driver for FLIR camera """ + def __init__(self): + try: + # Set camera serial numbers + serial_1 = '20343286' + ##### serial_2 = '16276941' + + # Get system + self.system = PySpin.System.GetInstance() + + # Get camera list + self.cam_list = self.system.GetCameras() + + # Get cameras by serial + self.cam_1 = self.cam_list.GetBySerial(serial_1) + ##### cam_2 = cam_list.GetBySerial(serial_2) + + # Initialize cameras + self.cam_1.Init() + ##### cam_2.Init() + + # Set acquisition mode to acquire a single frame, this ensures acquired images are sync'd since camera 2 and 3 are setup to be triggered + self.cam_1.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) + ##### cam_2.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) + + + #This takes an image quickly. The first image is always corrupt for whatever reason. This picture is not saved. + self.cam_1.TriggerMode.SetValue(PySpin.TriggerMode_Off) + self.cam_1.TriggerMode.SetValue(PySpin.TriggerMode_On) + self.cam_1.BeginAcquisition() + self.cam_1.EndAcquisition() + + ## Set up primary camera trigger + # self.cam_1.LineSelector.SetValue(PySpin.LineSelector_Line2) + # self.cam_1.V3_3Enable.SetValue(True) + + print("Initialization successful...") + except: + print("Error in __init__()") + + def await_trigger(self): + try: + self.cam_1.TriggerMode.SetValue(PySpin.TriggerMode_Off) + #self.cam_1.TriggerSource.SetValue(PySpin.TriggerSource_Line3) + #self.cam_1.TriggerOverlap.SetValue(PySpin.TriggerOverlap_ReadOut) + self.cam_1.TriggerMode.SetValue(PySpin.TriggerMode_On) + + # Set up secondary camera trigger + ##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_Off) + ##### cam_2.TriggerSource.SetValue(PySpin.TriggerSource_Line3) + ##### cam_2.TriggerOverlap.SetValue(PySpin.TriggerOverlap_ReadOut) + ##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_On) + + # Start acquisition; note that secondary cameras have to be started first so acquisition of primary camera triggers secondary cameras. + ##### cam_2.BeginAcquisition() + self.cam_1.BeginAcquisition() + + print("Awaiting trigger...") + + self.postpicture() + except: + print("Error in await_trigger()") + + def postpicture(self): + try: + # Acquire images + self.image_1 = self.cam_1.GetNextImage() + ##### image_2 = cam_2.GetNextImage() + + # Ensure image completion + if self.image_1.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + + else: + + # Save images + filename = 'Image_H%s_M%d_S%g.png' % (int(time.strftime("%H", time.localtime())), int(time.strftime("%M", time.localtime())),int(time.strftime("%S", time.localtime()))) + self.image_1.Save(filename) + ##### image_2.Save('cam_2.png') + + # Release images + self.image_1.Release() + ##### image_2.Release() + + # end acquisition + self.cam_1.EndAcquisition() + ##### cam_2.EndAcquisition() + print("Picture Successfully taken at: ",time.strftime("%d %b %Y %H:%M:%S", time.localtime())) + except: + print("Error in postpicture()") + + def reset(self): + self.cam_1.DeInit() + self.cam_1.EndAcquisition() + del self.cam + self.cam_list.Clear() + PySpin.System.CloseInstance() + + + + ##################################################################### + # async def _ser_readline(self): + # c = await self.port.read(1) + # print(c) + # r = c + # while c != b"\n": + # c = await self.port.read(1) + # r += c + # return r + + # async def _ser_send(self, cmd, get_response=True): + # """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + # if self.simulation: + # logger.info("simulation _ser_send(\"%s\")", cmd) + # else: + # logger.debug("_ser_send(\"%s\")", cmd) + # self.port.ser.reset_input_buffer() + # await self.port.write((cmd + "\r\n").encode()) + # if get_response: + # result = (await self._ser_readline()).rstrip().decode() + # logger.debug("got response from device: %s", result) + # if result != "OK": + # errstr = self.error_codes.get(result, "Unrecognized reply") + # s = "Erroneous reply from device: {ec}, {ecs}".format( + # ec=result, ecs=errstr) + # raise ValueError(s) + # else: + # pass + + # async def setup(self): + # """Initial setup of FLIR.""" + # await self._ser_send("E d", get_response=False) + + \ No newline at end of file diff --git a/FLIR/FLIRcodev4.1/build/lib/flir/examplev1.py b/FLIR/FLIRcodev4.1/build/lib/flir/examplev1.py new file mode 100644 index 0000000..b1a4896 --- /dev/null +++ b/FLIR/FLIRcodev4.1/build/lib/flir/examplev1.py @@ -0,0 +1,53 @@ +import PySpin + +# Set camera serial numbers +serial_1 = '20343286' +##### serial_2 = '16276941' + +# Get system +system = PySpin.System.GetInstance() + +# Get camera list +cam_list = system.GetCameras() + +# Get cameras by serial +cam_1 = cam_list.GetBySerial(serial_1) +##### cam_2 = cam_list.GetBySerial(serial_2) + +# Initialize cameras +cam_1.Init() +##### cam_2.Init() + +# Set up primary camera trigger +cam_1.LineSelector.SetValue(PySpin.LineSelector_Line2) +cam_1.V3_3Enable.SetValue(True) + +# Set up secondary camera trigger +##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_Off) +##### cam_2.TriggerSource.SetValue(PySpin.TriggerSource_Line3) +##### cam_2.TriggerOverlap.SetValue(PySpin.TriggerOverlap_ReadOut) +##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_On) + +# Set acquisition mode to acquire a single frame, this ensures acquired images are sync'd since camera 2 and 3 are setup to be triggered +cam_1.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) +##### cam_2.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) + +# Start acquisition; note that secondary cameras have to be started first so acquisition of primary camera triggers secondary cameras. +##### cam_2.BeginAcquisition() +cam_1.BeginAcquisition() + +# Acquire images +image_1 = cam_1.GetNextImage() +##### image_2 = cam_2.GetNextImage() + +# Save images +image_1.Save('cam_1.png') +##### image_2.Save('cam_2.png') + +# Release images +image_1.Release() +##### image_2.Release() + +# end acquisition +cam_1.EndAcquisition() +##### cam_2.EndAcquisition() \ No newline at end of file diff --git a/FLIR/FLIRcodev4.1/build/lib/flir/examplev2.py b/FLIR/FLIRcodev4.1/build/lib/flir/examplev2.py new file mode 100644 index 0000000..cc3d3ad --- /dev/null +++ b/FLIR/FLIRcodev4.1/build/lib/flir/examplev2.py @@ -0,0 +1,64 @@ +import math +import logging +import asyncio +import asyncserial + +import PySpin +import sys + + +def __init__(): + # Set camera serial numbers + serial_1 = '20343286' + ##### serial_2 = '16276941' + + # Get system + system = PySpin.System.GetInstance() + + # Get camera list + cam_list = system.GetCameras() + + # Get cameras by serial + cam_1 = cam_list.GetBySerial(serial_1) + ##### cam_2 = cam_list.GetBySerial(serial_2) + + # Initialize cameras + cam_1.Init() + ##### cam_2.Init() + + # Set up primary camera trigger + cam_1.LineSelector.SetValue(PySpin.LineSelector_Line2) + cam_1.V3_3Enable.SetValue(True) + + # Set acquisition mode to acquire a single frame, this ensures acquired images are sync'd since camera 2 and 3 are setup to be triggered + cam_1.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) + ##### cam_2.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) + +def await_trigger(): + + # Set up secondary camera trigger + ##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_Off) + ##### cam_2.TriggerSource.SetValue(PySpin.TriggerSource_Line3) + ##### cam_2.TriggerOverlap.SetValue(PySpin.TriggerOverlap_ReadOut) + ##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_On) + + # Start acquisition; note that secondary cameras have to be started first so acquisition of primary camera triggers secondary cameras. + ##### cam_2.BeginAcquisition() + cam_1.BeginAcquisition() + +def postpicture(): + # Acquire images + image_1 = cam_1.GetNextImage() + ##### image_2 = cam_2.GetNextImage() + + # Save images + image_1.Save('cam_1.png') + ##### image_2.Save('cam_2.png') + + # Release images + image_1.Release() + ##### image_2.Release() + + # end acquisition + cam_1.EndAcquisition() + ##### cam_2.EndAcquisition() \ No newline at end of file diff --git a/FLIR/FLIRcodev4.1/dist/flir-0.0.0-py3.5.egg b/FLIR/FLIRcodev4.1/dist/flir-0.0.0-py3.5.egg new file mode 100644 index 0000000..82bb8da Binary files /dev/null and b/FLIR/FLIRcodev4.1/dist/flir-0.0.0-py3.5.egg differ diff --git a/FLIR/FLIRcodev4.1/dist/flir-0.0.0-py3.7.egg b/FLIR/FLIRcodev4.1/dist/flir-0.0.0-py3.7.egg new file mode 100644 index 0000000..e41e83d Binary files /dev/null and b/FLIR/FLIRcodev4.1/dist/flir-0.0.0-py3.7.egg differ diff --git a/FLIR/FLIRcodev4.1/dist/flir-0.0.0-py3.8.egg b/FLIR/FLIRcodev4.1/dist/flir-0.0.0-py3.8.egg new file mode 100644 index 0000000..0d82f82 Binary files /dev/null and b/FLIR/FLIRcodev4.1/dist/flir-0.0.0-py3.8.egg differ diff --git a/FLIR/FLIRcodev4.1/doc/Makefile b/FLIR/FLIRcodev4.1/doc/Makefile new file mode 100644 index 0000000..298ea9e --- /dev/null +++ b/FLIR/FLIRcodev4.1/doc/Makefile @@ -0,0 +1,19 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/FLIR/FLIRcodev4.1/doc/conf.py b/FLIR/FLIRcodev4.1/doc/conf.py new file mode 100644 index 0000000..6cdd72e --- /dev/null +++ b/FLIR/FLIRcodev4.1/doc/conf.py @@ -0,0 +1,176 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config + + +import os +import sys +from unittest.mock import Mock + +sys.path.insert(0, os.path.abspath('..')) + +mock_modules = ["asyncserial"] + +for module in mock_modules: + sys.modules[module] = Mock() + +# -- Project information ----------------------------------------------------- + +project = 'FLIR' +copyright = '2019, M-Labs' +author = 'M-Labs' + +# The short X.Y version +version = '1.0' +# The full version, including alpha/beta/rc tags +release = '1.0' + + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinxarg.ext' +] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path. +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = None + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'FLIRdoc' + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'FLIR.tex', 'FLIR Documentation', + 'M-Labs', 'manual'), +] + + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'flir', 'FLIR Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'FLIR', 'FLIR Documentation', + author, 'FLIR', 'One line description of project.', + 'Miscellaneous'), +] + + +# -- Options for Epub output ------------------------------------------------- + +# Bibliographic Dublin Core info. +epub_title = project + +# The unique identifier of the text. This can be a ISBN number +# or the project homepage. +# +# epub_identifier = '' + +# A unique identification for the text. +# +# epub_uid = '' + +# A list of files that should not be packed into the epub file. +epub_exclude_files = ['search.html'] diff --git a/FLIR/FLIRcodev4.1/doc/index.rst b/FLIR/FLIRcodev4.1/doc/index.rst new file mode 100644 index 0000000..a92b827 --- /dev/null +++ b/FLIR/FLIRcodev4.1/doc/index.rst @@ -0,0 +1,24 @@ +Welcome to Novatech409B's documentation! +======================================== + +API +--- + +.. automodule:: flir.driver + :members: + + +ARTIQ controller +---------------- + +.. argparse:: + :ref: flir.aqctl_flir.get_argparser + :prog: aqctl_flir + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/FLIR/FLIRcodev4.1/flir.egg-info/PKG-INFO b/FLIR/FLIRcodev4.1/flir.egg-info/PKG-INFO new file mode 100644 index 0000000..bfed401 --- /dev/null +++ b/FLIR/FLIRcodev4.1/flir.egg-info/PKG-INFO @@ -0,0 +1,10 @@ +Metadata-Version: 1.0 +Name: flir +Version: 0.0.0 +Summary: UNKNOWN +Home-page: UNKNOWN +Author: UNKNOWN +Author-email: UNKNOWN +License: UNKNOWN +Description: UNKNOWN +Platform: UNKNOWN diff --git a/FLIR/FLIRcodev4.1/flir.egg-info/SOURCES.txt b/FLIR/FLIRcodev4.1/flir.egg-info/SOURCES.txt new file mode 100644 index 0000000..6a7d17b --- /dev/null +++ b/FLIR/FLIRcodev4.1/flir.egg-info/SOURCES.txt @@ -0,0 +1,13 @@ +setup.py +flir/__init__.py +flir/aqctl_flir.py +flir/driver(backup_old).py +flir/driver(old).py +flir/driver.py +flir/examplev1.py +flir/examplev2.py +flir.egg-info/PKG-INFO +flir.egg-info/SOURCES.txt +flir.egg-info/dependency_links.txt +flir.egg-info/entry_points.txt +flir.egg-info/top_level.txt \ No newline at end of file diff --git a/FLIR/FLIRcodev4.1/flir.egg-info/dependency_links.txt b/FLIR/FLIRcodev4.1/flir.egg-info/dependency_links.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/FLIR/FLIRcodev4.1/flir.egg-info/dependency_links.txt @@ -0,0 +1 @@ + diff --git a/FLIR/FLIRcodev4.1/flir.egg-info/entry_points.txt b/FLIR/FLIRcodev4.1/flir.egg-info/entry_points.txt new file mode 100644 index 0000000..62c21bb --- /dev/null +++ b/FLIR/FLIRcodev4.1/flir.egg-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +aqctl_flir = flir.aqctl_flir:main + diff --git a/FLIR/FLIRcodev4.1/flir.egg-info/top_level.txt b/FLIR/FLIRcodev4.1/flir.egg-info/top_level.txt new file mode 100644 index 0000000..c523cfe --- /dev/null +++ b/FLIR/FLIRcodev4.1/flir.egg-info/top_level.txt @@ -0,0 +1 @@ +flir diff --git a/FLIR/FLIRcodev4.1/flir/__init__.py b/FLIR/FLIRcodev4.1/flir/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/FLIR/FLIRcodev4.1/flir/__pycache__/__init__.cpython-38.pyc b/FLIR/FLIRcodev4.1/flir/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..814003d Binary files /dev/null and b/FLIR/FLIRcodev4.1/flir/__pycache__/__init__.cpython-38.pyc differ diff --git a/FLIR/FLIRcodev4.1/flir/__pycache__/driver.cpython-37.pyc b/FLIR/FLIRcodev4.1/flir/__pycache__/driver.cpython-37.pyc new file mode 100644 index 0000000..d0f4f64 Binary files /dev/null and b/FLIR/FLIRcodev4.1/flir/__pycache__/driver.cpython-37.pyc differ diff --git a/FLIR/FLIRcodev4.1/flir/__pycache__/driver.cpython-38.pyc b/FLIR/FLIRcodev4.1/flir/__pycache__/driver.cpython-38.pyc new file mode 100644 index 0000000..d8b042b Binary files /dev/null and b/FLIR/FLIRcodev4.1/flir/__pycache__/driver.cpython-38.pyc differ diff --git a/FLIR/FLIRcodev4.1/flir/__pycache__/examplev2.cpython-37.pyc b/FLIR/FLIRcodev4.1/flir/__pycache__/examplev2.cpython-37.pyc new file mode 100644 index 0000000..9ee1b6c Binary files /dev/null and b/FLIR/FLIRcodev4.1/flir/__pycache__/examplev2.cpython-37.pyc differ diff --git a/FLIR/FLIRcodev4.1/flir/aqctl_flir.py b/FLIR/FLIRcodev4.1/flir/aqctl_flir.py new file mode 100644 index 0000000..be65248 --- /dev/null +++ b/FLIR/FLIRcodev4.1/flir/aqctl_flir.py @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 + +# Written by Joe Britton, 2015 + +import argparse +import logging +import sys +import os +import asyncio + +from flir.driver import FLIR +from flir.driver import TriggerType +from sipyco.pc_rpc import simple_server_loop +from sipyco import common_args + + +logger = logging.getLogger(__name__) +print("prepreinit") + +def get_argparser(): + parser = argparse.ArgumentParser( + description="ARTIQ controller for the FLIR camera") + common_args.simple_network_args(parser, 3200) + parser.add_argument( + "-d", "--device", default=None, + help="serial port.") + parser.add_argument( + "--softtrig", default=False, action="store_true", + help="Sets trigger to software. Default is hardware") + parser.add_argument( + "--num", default=1, + help="Sets number of images. Default is hardware") + parser.add_argument( + "--simulation", action="store_true", + help="Put the driver in simulation mode, even if --device is used.") + common_args.verbosity_args(parser) + return parser + + +def main(): + print("preinit") + args = get_argparser().parse_args() + common_args.init_logger_from_args(args) + if os.name == "nt": + asyncio.set_event_loop(asyncio.ProactorEventLoop()) + # if args.device is None: + # print("Starting in Simulation mode...") + # dev = FLIR(args.device if not args.simulation else None) + + print("Software trigger is:",args.softtrig) + triggerset=TriggerType(args.softtrig) + dev = FLIR() + #asyncio.get_event_loop().run_until_complete(dev.setup()) + try: + print("Startup on port",args.port,"successful...") + simple_server_loop( + {"flir": dev}, common_args.bind_address_from_args(args), args.port) + finally: + dev.close() + + + +print(__name__) + +if __name__ == "__main__": + main() diff --git a/FLIR/FLIRcodev4.1/flir/driver(backup_old).py b/FLIR/FLIRcodev4.1/flir/driver(backup_old).py new file mode 100644 index 0000000..f6295b4 --- /dev/null +++ b/FLIR/FLIRcodev4.1/flir/driver(backup_old).py @@ -0,0 +1,535 @@ +# Written by Joe Britton, 2015 + +import math +import logging +import asyncio +import asyncserial + +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + + +class TriggerType: + SOFTWARE = 1 + HARDWARE = 2 + +CHOSEN_TRIGGER = TriggerType.SOFTWARE + + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + pass + + +class FLIR: + """Driver for FLIR camera """ + + error_codes = { + "?0": "Unrecognized Command", + "?1": "Bad Frequency", + "?2": "Bad AM Command", + "?3": "Input line too long", + "?4": "Bad Phase", + "?5": "Bad Time", + "?6": "Bad Mode", + "?7": "Bad Amp", + "?8": "Bad Constant", + "?f": "Bad Byte" + } + + def __init__(self, serial_dev): + if serial_dev is None: + self.simulation = True + else: + self.simulation = False + self.port = asyncserial.AsyncSerial( + serial_dev, + baudrate=19200, + bytesize=8, + parity="N", + stopbits=1, + xonxoff=0) + + async def _ser_readline(self): + c = await self.port.read(1) + print(c) + r = c + while c != b"\n": + c = await self.port.read(1) + r += c + return r + + async def _ser_send(self, cmd, get_response=True): + """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + if self.simulation: + logger.info("simulation _ser_send(\"%s\")", cmd) + else: + logger.debug("_ser_send(\"%s\")", cmd) + self.port.ser.reset_input_buffer() + await self.port.write((cmd + "\r\n").encode()) + if get_response: + result = (await self._ser_readline()).rstrip().decode() + logger.debug("got response from device: %s", result) + if result != "OK": + errstr = self.error_codes.get(result, "Unrecognized reply") + s = "Erroneous reply from device: {ec}, {ecs}".format( + ec=result, ecs=errstr) + raise ValueError(s) + else: + pass + + async def setup(self): + """Initial setup of FLIR.""" + await self._ser_send("E d", get_response=False) + + + def close(self): + """Close the serial hardware port.""" + if not self.simulation: + self.port.close() + + async def ping(self): + try: + stat = await self.get_status() + except asyncio.CancelledError: + raise + except: + return False + # check that version number matches is "21" + if stat[4][20:] == "21": + logger.debug("ping successful") + return True + else: + return False + + + 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.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 + 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 + 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 + """ + print("393-postfunction") + try: + print("395") + result = True + err = False + print("398") + # Retrieve TL device nodemap and print device information + nodemap_tldevice = cam.GetTLDeviceNodeMap() + print("401") + result &= print_device_info(nodemap_tldevice) + print("403") + # Initialize camera + cam.Init() + print("406") + # Retrieve GenICam nodemap + nodemap = cam.GetNodeMap() + print("409") + # Configure trigger + if configure_trigger(cam) is False: + return False + print("413") + # Acquire images + result &= grab_next_image_by_trigger(cam) #acquire_images(cam) THIS IS WHAT I CHANGED TO TRY TO GRAB ONLY ONE IMAGE AT A TIME! + print("416") + # Reset trigger + result &= reset_trigger(cam) + print("419") + # Deinitialize camera + cam.DeInit() + print("422") + except PySpin.SpinnakerException as ex: + print("424-exception") + print('Error: %s' % ex) + result = False + + + return result + + + def picture(cam): + """ + Run this code to take a single triggered picture! + + :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!') + print("Closing camera instance...") #input('Done! Press Enter to exit...') + return False + print(cam) + # Run example on each camera + for i, cam in enumerate(cam_list): + + print('Running example for camera %d...' % i) + + print("472-prefunction") + 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() + + print("Closing camera instance...") #input('Done! Press Enter to exit...') + return result + + + # if __name__ == '__picture__': + # if picture(): + # sys.exit(0) + # else: + # sys.exit(1) + + + + +############################################################ + + + + + + # async def reset(self): + # """Hardware reset of FLIR.""" + # await self._ser_send("R", get_response=False) + # await asyncio.sleep(1) + # await self.setup() + + # async def setup(self): + # """Initial setup of FLIR.""" + + # await self._ser_send("E d", get_response=False) + + # async def get_status(self): + # if self.simulation: + # return ["00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "80 BC0000 0000 0102 21"] + # else: + # self.port.ser.reset_input_buffer() + # result = [] + # await self.port.write(("QUE" + "\r\n").encode()) + # for i in range(5): + # m = (await self._ser_readline()).rstrip().decode() + # result.append(m) + # logger.debug("got device status: %s", result) + # return result + + \ No newline at end of file diff --git a/FLIR/FLIRcodev4.1/flir/driver(old).py b/FLIR/FLIRcodev4.1/flir/driver(old).py new file mode 100644 index 0000000..f7b83d4 --- /dev/null +++ b/FLIR/FLIRcodev4.1/flir/driver(old).py @@ -0,0 +1,715 @@ +import math +import logging +import asyncio +import asyncserial +import os +import matplotlib.pyplot as plt +import keyboard +import time +import PySpin +import sys + +NUM_IMAGES = 10 # number of images to grab + +global continue_recording +continue_recording = True + +global trigtype +SOFTWARE = 1 +HARDWARE = 2 +trigtype=SOFTWARE +class TriggerType(): + def __init__(self, softtrig): + global trigtype + if softtrig is True: + trigtype=SOFTWARE + else: + trigtype=HARDWARE + +CHOSEN_TRIGGER = trigtype + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + pass + + +class FLIR: + """Driver for FLIR camera """ + def __init__(self,num): + serial_dev = None + cam=0 + cam_list=0 + self.cameras=0 + result = True + self.num=num + system = PySpin.System.GetInstance() + version = system.GetLibraryVersion() + print('Library version: %d.%d.%d.%d' % (version.major, version.minor, version.type, version.build)) + cam_list = system.GetCameras() + self.system = system + self.cam_list = cam_list + self.cam=cam_list[0] + + num_cameras = cam_list.GetSize() + print('Number of cameras detected: %d' % num_cameras) + if num_cameras == 0: + cam_list.Clear() + system.ReleaseInstance() + print('Not enough cameras!') + print("Closing camera instance...") + return False + for i, cam in enumerate(cam_list): + print('Defining camera %d...' % i) + + self.nodemap_tldevice = cam.GetTLDeviceNodeMap() + result &= self.print_device_info(self.nodemap_tldevice) + cam.Init() + self.nodemap = cam.GetNodeMap() + + print("Going back to server now...") + + + + + + + # def picture(self): + # """ + # Run this code to take a single triggered picture! + + # :return: True if successful, False otherwise. + # :rtype: bool + # """ + # result = True + # print(self.cam) + # result &= self.run_single_camera(self.cam) + # for i, cam in enumerate(cam_list): + + # print('Running example for camera %d...' % i) + + # print("472-prefunction") + # result &= run_single_camera(cam) + # print('Camera %d example complete... \n' % i) + # return result + + def picture(self):#run_single_camera(self): + """ + 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 + cam=self.cam + cam.BeginAcquisition() + image_result = cam.GetNextImage(1000) + # Configure trigger + if self.configure_trigger(cam) is False: + return False + + # Acquire images + result &= self.grab_next_image_by_trigger(cam) #acquire_images(cam) THIS IS WHAT I CHANGED TO TRY TO GRAB ONLY ONE IMAGE AT A TIME! + + + 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 + filename = 'Trigger-%d.jpg' % i + + + # Save image + image_converted.Save(filename) + + print('Image saved at %s\n' % filename) + + # Release image + image_result.Release() + # Reset trigger + result &= self.reset_trigger(cam) + cam.EndAcquisition() + cam.EndAcquisition() + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + result = False + + + return result + + async def _ser_readline(self): + c = await self.port.read(1) + print(c) + r = c + while c != b"\n": + c = await self.port.read(1) + r += c + return r + + async def _ser_send(self, cmd, get_response=True): + """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + if self.simulation: + logger.info("simulation _ser_send(\"%s\")", cmd) + else: + logger.debug("_ser_send(\"%s\")", cmd) + self.port.ser.reset_input_buffer() + await self.port.write((cmd + "\r\n").encode()) + if get_response: + result = (await self._ser_readline()).rstrip().decode() + logger.debug("got response from device: %s", result) + if result != "OK": + errstr = self.error_codes.get(result, "Unrecognized reply") + s = "Erroneous reply from device: {ec}, {ecs}".format( + ec=result, ecs=errstr) + raise ValueError(s) + else: + pass + + async def setup(self): + """Initial setup of FLIR.""" + await self._ser_send("E d", get_response=False) + + + def close(self): + """Close the serial hardware port.""" + # Deinitialize camera + self.cam.DeInit() + del self.cam + self.system.ReleaseInstance() + self.cam_list.Clear() + print("Closing camera instance...") #input('Done! Press Enter to exit...') + # if not self.simulation: + # self.port.close() + + async def ping(self): + try: + stat = await self.get_status() + except asyncio.CancelledError: + raise + except: + return False + # check that version number matches is "21" + if stat[4][20:] == "21": + logger.debug("ping successful") + return True + else: + return False + + + def configure_trigger(self,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 == SOFTWARE: + print('Software trigger chosen...') + elif CHOSEN_TRIGGER == 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.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 == SOFTWARE: + cam.TriggerSource.SetValue(PySpin.TriggerSource_Software) + print('Trigger source set to software...') + elif CHOSEN_TRIGGER == 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(self,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 == 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 == 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(self): + """ + 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 + """ + cam=self.cam + NUM_IMAGES=self.num + 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 &= self.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(self): + # Deinitialize camera + self.cam.DeInit() + + self.cam.Init() + + + def reset_trigger(self,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(self,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 handle_close(self,evt): + """ + This function will close the GUI when close event happens. + + :param evt: Event that occurs when the figure closes. + :type evt: Event + """ + + global continue_recording + continue_recording = False + + def display(self): + """ + This function continuously acquires images from a device and display them in a GUI. + + :param cam: Camera to acquire images from. + :param nodemap: Device nodemap. + :param nodemap_tldevice: Transport layer device nodemap. + :type cam: CameraPtr + :type nodemap: INodeMap + :type nodemap_tldevice: INodeMap + :return: True if successful, False otherwise. + :rtype: bool + """ + global continue_recording + + cam=self.cam + nodemap=self.nodemap + nodemap_tldevice=self.nodemap_tldevice + sNodemap = cam.GetTLStreamNodeMap() + + # Change bufferhandling mode to NewestOnly + node_bufferhandling_mode = PySpin.CEnumerationPtr(sNodemap.GetNode('StreamBufferHandlingMode')) + if not PySpin.IsAvailable(node_bufferhandling_mode) or not PySpin.IsWritable(node_bufferhandling_mode): + print('Unable to set stream buffer handling mode.. Aborting...') + return False + + # Retrieve entry node from enumeration node + node_newestonly = node_bufferhandling_mode.GetEntryByName('NewestOnly') + if not PySpin.IsAvailable(node_newestonly) or not PySpin.IsReadable(node_newestonly): + print('Unable to set stream buffer handling mode.. Aborting...') + return False + + # Retrieve integer value from entry node + node_newestonly_mode = node_newestonly.GetValue() + + # Set integer value from entry node as new value of enumeration node + node_bufferhandling_mode.SetIntValue(node_newestonly_mode) + + print('*** IMAGE ACQUISITION ***\n') + try: + node_acquisition_mode = PySpin.CEnumerationPtr(nodemap.GetNode('AcquisitionMode')) + if not PySpin.IsAvailable(node_acquisition_mode) or not PySpin.IsWritable(node_acquisition_mode): + print('Unable to set acquisition mode to continuous (enum retrieval). Aborting...') + return False + + # Retrieve entry node from enumeration node + node_acquisition_mode_continuous = node_acquisition_mode.GetEntryByName('Continuous') + if not PySpin.IsAvailable(node_acquisition_mode_continuous) or 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 + # + # *** NOTES *** + # What happens when the camera begins acquiring images depends on the + # acquisition mode. Single frame captures only a single image, multi + # frame catures a set number of images, and continuous captures a + # continuous stream of images. + # + # *** LATER *** + # Image acquisition must be ended when no more images are needed. + cam.BeginAcquisition() + + print('Acquiring images...') + + # Retrieve device serial number for filename + # + # *** NOTES *** + # The device serial number is retrieved in order to keep cameras from + # overwriting one another. Grabbing image IDs could also accomplish + # this. + device_serial_number = '' + node_device_serial_number = PySpin.CStringPtr(nodemap_tldevice.GetNode('DeviceSerialNumber')) + if PySpin.IsAvailable(node_device_serial_number) and PySpin.IsReadable(node_device_serial_number): + device_serial_number = node_device_serial_number.GetValue() + print('Device serial number retrieved as %s...' % device_serial_number) + + # Close program + print('Press enter to close the program..') + + # Figure(1) is default so you can omit this line. Figure(0) will create a new window every time program hits this line + fig = plt.figure(1) + + # Close the GUI when close event happens + fig.canvas.mpl_connect('close_event', self.handle_close) + + # Retrieve and display images + while(continue_recording): + try: + + # Retrieve next received image + # + # *** NOTES *** + # Capturing an image houses images on the camera buffer. Trying + # to capture an image that does not exist will hang the camera. + # + # *** LATER *** + # Once an image from the buffer is saved and/or no longer + # needed, the image must be released in order to keep the + # buffer from filling up. + + image_result = cam.GetNextImage(1000) + + # Ensure image completion + if image_result.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + + else: + + # Getting the image data as a numpy array + image_data = image_result.GetNDArray() + + # Draws an image on the current figure + plt.imshow(image_data, cmap='gray') + + # Interval in plt.pause(interval) determines how fast the images are displayed in a GUI + # Interval is in seconds. + plt.pause(0.001) + + # Clear current reference of a figure. This will improve display speed significantly + plt.clf() + + # If user presses enter, close the program + if keyboard.is_pressed('ENTER'): + print('Program is closing...') + + # Close figure + plt.close('all') + input('Done! Press Enter to exit...') + continue_recording=False + + # Release image + # + # *** NOTES *** + # Images retrieved directly from the camera (i.e. non-converted + # images) need to be released in order to keep from filling the + # buffer. + image_result.Release() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + # End acquisition + # + # *** NOTES *** + # Ending acquisition appropriately helps ensure that devices clean up + # properly and do not need to be power-cycled to maintain integrity. + cam.EndAcquisition() + + except PySpin.SpinnakerException as ex: + print('Error: %s' % ex) + return False + + return True + + + + + + + + + +############################################################ + + + + + + # async def reset(self): + # """Hardware reset of FLIR.""" + # await self._ser_send("R", get_response=False) + # await asyncio.sleep(1) + # await self.setup() + + # async def setup(self): + # """Initial setup of FLIR.""" + + # await self._ser_send("E d", get_response=False) + + # async def get_status(self): + # if self.simulation: + # return ["00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "00989680 2000 01F5 0000 00000000 00000000 000301", + # "80 BC0000 0000 0102 21"] + # else: + # self.port.ser.reset_input_buffer() + # result = [] + # await self.port.write(("QUE" + "\r\n").encode()) + # for i in range(5): + # m = (await self._ser_readline()).rstrip().decode() + # result.append(m) + # logger.debug("got device status: %s", result) + # return result + + \ No newline at end of file diff --git a/FLIR/FLIRcodev4.1/flir/driver.py b/FLIR/FLIRcodev4.1/flir/driver.py new file mode 100644 index 0000000..df94acd --- /dev/null +++ b/FLIR/FLIRcodev4.1/flir/driver.py @@ -0,0 +1,179 @@ +import math +import logging +import asyncio +import asyncserial +import os +import matplotlib.pyplot as plt +import keyboard +import time +import PySpin +import sys +import time + +NUM_IMAGES = 10 # number of images to grab + +global continue_recording +continue_recording = True + +global trigtype +SOFTWARE = 1 +HARDWARE = 2 +trigtype=SOFTWARE +class TriggerType(): + def __init__(self, softtrig): + global trigtype + if softtrig is True: + trigtype=SOFTWARE + else: + trigtype=HARDWARE + +CHOSEN_TRIGGER = trigtype + +logger = logging.getLogger(__name__) + + +class UnexpectedResponse(Exception): + pass + + +class FLIR: + """Driver for FLIR camera """ + def __init__(self): + try: + # Set camera serial numbers + serial_1 = '20343286' + ##### serial_2 = '16276941' + + # Get system + self.system = PySpin.System.GetInstance() + + # Get camera list + self.cam_list = self.system.GetCameras() + + # Get cameras by serial + self.cam_1 = self.cam_list.GetBySerial(serial_1) + ##### cam_2 = cam_list.GetBySerial(serial_2) + + # Initialize cameras + self.cam_1.Init() + ##### cam_2.Init() + + # Set acquisition mode to acquire a single frame, this ensures acquired images are sync'd since camera 2 and 3 are setup to be triggered + self.cam_1.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) + ##### cam_2.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) + + + #This takes an image quickly. The first image is always corrupt for whatever reason. This picture is not saved. + self.cam_1.TriggerMode.SetValue(PySpin.TriggerMode_Off) + self.cam_1.TriggerMode.SetValue(PySpin.TriggerMode_On) + self.cam_1.BeginAcquisition() + self.cam_1.EndAcquisition() + + ## Set up primary camera trigger + # self.cam_1.LineSelector.SetValue(PySpin.LineSelector_Line2) + # self.cam_1.V3_3Enable.SetValue(True) + + print("Initialization successful...") + except: + print("Error in __init__()") + + def await_trigger(self): + try: + self.cam_1.TriggerMode.SetValue(PySpin.TriggerMode_Off) + #self.cam_1.TriggerSource.SetValue(PySpin.TriggerSource_Line3) + #self.cam_1.TriggerOverlap.SetValue(PySpin.TriggerOverlap_ReadOut) + self.cam_1.TriggerMode.SetValue(PySpin.TriggerMode_On) + + # Set up secondary camera trigger + ##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_Off) + ##### cam_2.TriggerSource.SetValue(PySpin.TriggerSource_Line3) + ##### cam_2.TriggerOverlap.SetValue(PySpin.TriggerOverlap_ReadOut) + ##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_On) + + # Start acquisition; note that secondary cameras have to be started first so acquisition of primary camera triggers secondary cameras. + ##### cam_2.BeginAcquisition() + self.cam_1.BeginAcquisition() + + print("Awaiting trigger...") + + self.postpicture() + except: + print("Error in await_trigger()") + + def postpicture(self): + try: + # Acquire images + self.image_1 = self.cam_1.GetNextImage() + ##### image_2 = cam_2.GetNextImage() + + # Ensure image completion + if self.image_1.IsIncomplete(): + print('Image incomplete with image status %d ...' % image_result.GetImageStatus()) + + else: + + # Save images + filename = 'Image_H%s_M%d_S%g.png' % (int(time.strftime("%H", time.localtime())), int(time.strftime("%M", time.localtime())),int(time.strftime("%S", time.localtime()))) + self.image_1.Save(filename) + ##### image_2.Save('cam_2.png') + + # Release images + self.image_1.Release() + ##### image_2.Release() + + # end acquisition + self.cam_1.EndAcquisition() + ##### cam_2.EndAcquisition() + print("Picture Successfully taken at: ",time.strftime("%d %b %Y %H:%M:%S", time.localtime())) + except: + print("Error in postpicture()") + + def reset(self): + self.cam_1.DeInit() + self.cam_1.EndAcquisition() + del self.cam + self.cam_list.Clear() + PySpin.System.CloseInstance() + + + + ##################################################################### + # async def _ser_readline(self): + # c = await self.port.read(1) + # print(c) + # r = c + # while c != b"\n": + # c = await self.port.read(1) + # r += c + # return r + + # async def _ser_send(self, cmd, get_response=True): + # """Send a string to the serial port.""" + + # Low-level routine for sending serial commands to device. It sends + # strings and listens for a response terminated by a carriage return. + # example: + # ser_send("F0 1.0") # sets the freq of channel 0 to 1.0 MHz + + # if self.simulation: + # logger.info("simulation _ser_send(\"%s\")", cmd) + # else: + # logger.debug("_ser_send(\"%s\")", cmd) + # self.port.ser.reset_input_buffer() + # await self.port.write((cmd + "\r\n").encode()) + # if get_response: + # result = (await self._ser_readline()).rstrip().decode() + # logger.debug("got response from device: %s", result) + # if result != "OK": + # errstr = self.error_codes.get(result, "Unrecognized reply") + # s = "Erroneous reply from device: {ec}, {ecs}".format( + # ec=result, ecs=errstr) + # raise ValueError(s) + # else: + # pass + + # async def setup(self): + # """Initial setup of FLIR.""" + # await self._ser_send("E d", get_response=False) + + \ No newline at end of file diff --git a/FLIR/FLIRcodev4.1/flir/examplev1.py b/FLIR/FLIRcodev4.1/flir/examplev1.py new file mode 100644 index 0000000..b1a4896 --- /dev/null +++ b/FLIR/FLIRcodev4.1/flir/examplev1.py @@ -0,0 +1,53 @@ +import PySpin + +# Set camera serial numbers +serial_1 = '20343286' +##### serial_2 = '16276941' + +# Get system +system = PySpin.System.GetInstance() + +# Get camera list +cam_list = system.GetCameras() + +# Get cameras by serial +cam_1 = cam_list.GetBySerial(serial_1) +##### cam_2 = cam_list.GetBySerial(serial_2) + +# Initialize cameras +cam_1.Init() +##### cam_2.Init() + +# Set up primary camera trigger +cam_1.LineSelector.SetValue(PySpin.LineSelector_Line2) +cam_1.V3_3Enable.SetValue(True) + +# Set up secondary camera trigger +##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_Off) +##### cam_2.TriggerSource.SetValue(PySpin.TriggerSource_Line3) +##### cam_2.TriggerOverlap.SetValue(PySpin.TriggerOverlap_ReadOut) +##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_On) + +# Set acquisition mode to acquire a single frame, this ensures acquired images are sync'd since camera 2 and 3 are setup to be triggered +cam_1.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) +##### cam_2.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) + +# Start acquisition; note that secondary cameras have to be started first so acquisition of primary camera triggers secondary cameras. +##### cam_2.BeginAcquisition() +cam_1.BeginAcquisition() + +# Acquire images +image_1 = cam_1.GetNextImage() +##### image_2 = cam_2.GetNextImage() + +# Save images +image_1.Save('cam_1.png') +##### image_2.Save('cam_2.png') + +# Release images +image_1.Release() +##### image_2.Release() + +# end acquisition +cam_1.EndAcquisition() +##### cam_2.EndAcquisition() \ No newline at end of file diff --git a/FLIR/FLIRcodev4.1/flir/examplev2.py b/FLIR/FLIRcodev4.1/flir/examplev2.py new file mode 100644 index 0000000..cc3d3ad --- /dev/null +++ b/FLIR/FLIRcodev4.1/flir/examplev2.py @@ -0,0 +1,64 @@ +import math +import logging +import asyncio +import asyncserial + +import PySpin +import sys + + +def __init__(): + # Set camera serial numbers + serial_1 = '20343286' + ##### serial_2 = '16276941' + + # Get system + system = PySpin.System.GetInstance() + + # Get camera list + cam_list = system.GetCameras() + + # Get cameras by serial + cam_1 = cam_list.GetBySerial(serial_1) + ##### cam_2 = cam_list.GetBySerial(serial_2) + + # Initialize cameras + cam_1.Init() + ##### cam_2.Init() + + # Set up primary camera trigger + cam_1.LineSelector.SetValue(PySpin.LineSelector_Line2) + cam_1.V3_3Enable.SetValue(True) + + # Set acquisition mode to acquire a single frame, this ensures acquired images are sync'd since camera 2 and 3 are setup to be triggered + cam_1.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) + ##### cam_2.AcquisitionMode.SetValue(PySpin.AcquisitionMode_SingleFrame) + +def await_trigger(): + + # Set up secondary camera trigger + ##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_Off) + ##### cam_2.TriggerSource.SetValue(PySpin.TriggerSource_Line3) + ##### cam_2.TriggerOverlap.SetValue(PySpin.TriggerOverlap_ReadOut) + ##### cam_2.TriggerMode.SetValue(PySpin.TriggerMode_On) + + # Start acquisition; note that secondary cameras have to be started first so acquisition of primary camera triggers secondary cameras. + ##### cam_2.BeginAcquisition() + cam_1.BeginAcquisition() + +def postpicture(): + # Acquire images + image_1 = cam_1.GetNextImage() + ##### image_2 = cam_2.GetNextImage() + + # Save images + image_1.Save('cam_1.png') + ##### image_2.Save('cam_2.png') + + # Release images + image_1.Release() + ##### image_2.Release() + + # end acquisition + cam_1.EndAcquisition() + ##### cam_2.EndAcquisition() \ No newline at end of file diff --git a/FLIR/FLIRcodev4.1/readme.txt b/FLIR/FLIRcodev4.1/readme.txt new file mode 100644 index 0000000..6f15efb --- /dev/null +++ b/FLIR/FLIRcodev4.1/readme.txt @@ -0,0 +1,24 @@ +v1.0 was a failure based on the simplistic code of the manual. Scrapped. +v2.0 was a copy-paste of novatech code with all names and unique functions REMOVED +v3.0 is v2.0 but with the addition of the flir camera functions. Methods are working without the camera. Call "sipyco_rpctool ::1 3200 call picture" to get trigger picture. +v3.1 I dont want to ruin v3.0 stability when hardware testing. v3.1 is hardware testing. Camera initialization and parent class problems. +v3.2 Attempt at initializing camera once and passing object to server. + + +Installation: +1. Install Spinnaker with python3.8 +conda install python3.8 +2. In Flircodevx.x directory, run: + +conda install sipyco +conda install asyncserial +python setup.py build +python setup.py install + +3. Change directories to flir and start server with: + +python aqctl_flir.py + +4. In another anaconda window, in the flir directory, take picture with: + +sipyco_rpctool ::1 3200 call picture \ No newline at end of file diff --git a/FLIR/FLIRcodev4.1/setup.py b/FLIR/FLIRcodev4.1/setup.py new file mode 100644 index 0000000..91e6954 --- /dev/null +++ b/FLIR/FLIRcodev4.1/setup.py @@ -0,0 +1,12 @@ +from setuptools import setup, find_packages + +setup( + name="flir", + install_requires=[],#"sipyco", "asyncserial"], #I disabled these because the installs were messed up! + packages=find_packages(), + entry_points={ + "console_scripts": [ + "aqctl_flir = flir.aqctl_flir:main", + ], + }, +)