image-processingcomputer-visionflirpyspin

No module named 'PySpin'


I am trying to import PySpin in Visual Studio to be able to work with Flir's camera but every time I encounter this:

"No module named 'PySpin'"

And when I try the Pip install PySpin, nothing would change! I've downloaded the Spinnaker packages and install them but again I see this error!

Can anyone help me how to fix this error, thanks :)

I've tried:


Solution

  • If you're installing pyspin via pip it's the wrong library (this one simply renders a spinning loader in Terminal, nothing to do with the FLIR SDK).

    I know it's confusing because of the name (pyspin != PySpin).

    Try this:

    1. Go to https://www.flir.co.uk/products/spinnaker-sdk : you'll need to create an account (free) if you don't have one already
    2. Once logged in scroll to the OS and Python version you can use and download the zip.
    3. (optionally: setup/init a virtual environment then ), unzip then pip install the .whl file

    Here are few screenshots from FLIR's website (on Windows): Select your OS first screenshot of the Spinnaker SDK Download page displaying links to select between version 3.1 or 4.0 as well as different operating systems (Linux, Windows, MacOS) Then select your Python version (from what they support): screenshot of the Spinnaker SDK Download page displaying a table with various versions of the FLIR SDK Python bindings for different versions of Python (3.5, 3.6, 3.7, 3.8, 3.10)

    Once installed you should be able to run their examples. For reference this is their AcquireAndDisplay.py script:

    # coding=utf-8
    # =============================================================================
    # Copyright (c) 2001-2023 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.
    #
    # Please leave us feedback at: https://www.surveymonkey.com/r/TDYMVAPI
    # More source code examples at: https://github.com/Teledyne-MV/Spinnaker-Examples
    # Need help? Check out our forum at: https://teledynevisionsolutions.zendesk.com/hc/en-us/community/topics
    
    
    import os
    import PySpin
    import 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.IsReadable(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.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.IsReadable(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.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.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)
    
    

    Personally I've used simple-pyspin for a quick test and it was less verbose. Note: This library on its down doesn't do much: you still need to install the Spinnaker SDK and Python bindings from FLIR first.