{"id":15532880,"url":"https://github.com/matham/rotpy","last_synced_at":"2025-04-15T16:39:21.980Z","repository":{"id":37650471,"uuid":"491719398","full_name":"matham/rotpy","owner":"matham","description":"Python bindings for the Spinnaker SDK to enable Pythonic control of Teledyne/FLIR/Point Grey USB and GigE cameras.","archived":false,"fork":false,"pushed_at":"2022-11-02T01:22:07.000Z","size":3523,"stargazers_count":18,"open_issues_count":5,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-28T22:31:59.730Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Cython","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/matham.png","metadata":{"files":{"readme":"README.rst","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-05-13T01:29:49.000Z","updated_at":"2025-03-21T15:01:46.000Z","dependencies_parsed_at":"2022-07-12T16:42:22.766Z","dependency_job_id":null,"html_url":"https://github.com/matham/rotpy","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matham%2Frotpy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matham%2Frotpy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matham%2Frotpy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/matham%2Frotpy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/matham","download_url":"https://codeload.github.com/matham/rotpy/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249109872,"owners_count":21214239,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-02T11:33:40.547Z","updated_at":"2025-04-15T16:39:21.960Z","avatar_url":"https://github.com/matham.png","language":"Cython","funding_links":[],"categories":[],"sub_categories":[],"readme":"RotPy\n=====\n\nRotPy provides python bindings for the Spinnaker SDK\nto enable Pythonic control of Teledyne/FLIR/Point Grey USB and GigE cameras.\n\nSee `the website \u003chttps://matham.github.io/rotpy/index.html\u003e`_ for the complete **documentation**.\n\n.. image:: https://github.com/matham/rotpy/workflows/Python%20application/badge.svg\n    :target: https://github.com/matham/rotpy/actions\n    :alt: Github CI status\n\nInstallation\n============\n\nYou can install RotPy using pre-compiled wheels on Windows, Linux, or Mac or by installing\nthe Spinnaker SDK and then installing RotPy from source.\n\nEither way, you'll likely need to install the **Spinnaker drivers** so that the cameras\nare recognized. Please download it from `their website \u003chttps://www.flir.com/products/spinnaker-sdk/\u003e`_\nand follow the instructions to install the drivers if the cameras are not found.\n\nPre-compiled wheels\n-------------------\n\nTo install from the pre-compiled wheels (assuming it's available on your platform), simply do::\n\n    python -m pip install rotpy\n\n\n.. note::\n\n    For Windows, if rotpy errors out saying dll not found, you probably need\n    to install the\n    `Microsoft Visual C++ Redistributable \u003chttps://docs.microsoft.com/en-us/cpp/windows/latest-supported-vc-redist\u003e`_\n    (`64-bit \u003chttps://aka.ms/vs/17/release/vc_redist.x64.exe\u003e`_,\n    `32-bit \u003chttps://aka.ms/vs/17/release/vc_redist.x86.exe\u003e`_).\n\n.. warning::\n\n    RotPy is licensed under MIT. However, the pre-compiled wheels contain some of the\n    Spinnaker SDK runtime libraries which have their own license. Please see the\n    license file packaged along with the binaries in the wheel.\n\nFrom source\n-----------\n\nTo install RotPy from source, you need to:\n\n#. Install the\n   `Spinnaker SDK \u003chttps://www.flir.com/products/spinnaker-sdk/\u003e`_ development\n   libraries.\n#. Install a C++ compiler that supports C++11. E.g. on Windows Visual Studio etc.\n   On Mac you may have to export the following environment variables::\n\n       export CXX=\"/usr/bin/clang\"\n       export CXXFLAGS=\"-std=c++11\"\n       export CPPFLAGS=\"-std=c++11\"\n\n#. Set the environment variables so Python can locate the Spinnaker SDK.\n\n   #. You need to set ``ROTPY_INCLUDE`` to the include directory, e.g. on Windows it may be something like\n      ``set ROTPY_INCLUDE=\"C:\\Program Files\\FLIR\\Spinnaker\\include\"``. On Linux and Mac it should typically\n      be automatically found.\n   #. You need to set ``ROTPY_LIB`` to the paths that contain the libraries and binaries. E.g. on Windows it may\n      be ``set ROTPY_LIB=\"C:\\Program Files\\FLIR\\Spinnaker\\bin64\\vs2015;C:\\Program Files\\FLIR\\Spinnaker\\lib64\\vs2015\"``.\n      On Linux and Mac, again, it should typically be automatically found.\n#. Then install RotPy with::\n\n       python -m pip install rotpy --no-binary rotpy\n\n#. At runtime, you'll need to ensure the Spinnaker runtime binaries are on the\n   system ``PATH`` using e.g.\n   `os.add_dll_directory \u003chttps://docs.python.org/3/library/os.html#os.add_dll_directory\u003e`_.\n\n   You may also have to set the environmental variable (depending on the OS bitness)\n   ``GENICAM_GENTL32_PATH``/``GENICAM_GENTL64_PATH``\n   to the directory containing the ``FLIR_GenTL*.cti`` file as well as any or all variables\n   ``FLIR_GENTL32_CTI_VS140``/``FLIR_GENTL64_CTI_VS140``/``FLIR_GENTL32_CTI``/``FLIR_GENTL64_CTI``\n   to the **full path** to the ``FLIR_GenTL*.cti`` file.\n\n   Additionally, the ``FLIR_GenTL*.cti`` file containing directory may also need to be added\n   to the system ``PATH``. Spinnaker will raise an error if the cti file cannot be loaded.\n\nExamples\n========\n\nGetting an image from a GigE camera\n-----------------------------------\n\n.. code-block:: python\n\n    \u003e\u003e\u003e from rotpy.system import SpinSystem\n    \u003e\u003e\u003e from rotpy.camera import CameraList\n    \u003e\u003e\u003e # get a system ref and a list of all attached cameras\n    \u003e\u003e\u003e system = SpinSystem()\n    \u003e\u003e\u003e cameras = CameraList.create_from_system(system, update_cams=True, update_interfaces=True)\n    \u003e\u003e\u003e cameras.get_size()\n        1\n    \u003e\u003e\u003e # get the camera attached from the list\n    \u003e\u003e\u003e camera = cameras.create_camera_by_index(0)\n    \u003e\u003e\u003e camera.get_unique_id()\n        '77T45WD4A84C_86TA1684_GGGGGG14_64CW3987'\n    \u003e\u003e\u003e # init the camera and get one image\n    \u003e\u003e\u003e camera.init_cam()\n    \u003e\u003e\u003e # get its serial number\n    \u003e\u003e\u003e camera.camera_nodes.DeviceSerialNumber.get_node_value()\n    '36548975'\n    \u003e\u003e\u003e camera.begin_acquisition()\n    \u003e\u003e\u003e image_cam = camera.get_next_image(timeout=5)\n    \u003e\u003e\u003e # we copy the image so that we can release its camera buffer\n    \u003e\u003e\u003e image = image_cam.deep_copy_image(image_cam)\n    \u003e\u003e\u003e image_cam.release()\n    \u003e\u003e\u003e camera.end_acquisition()\n    \u003e\u003e\u003e # save the image\n    \u003e\u003e\u003e image.save_png('image.png')\n    \u003e\u003e\u003e # get image metadata\n    \u003e\u003e\u003e image.get_bits_per_pixel()\n        8\n    \u003e\u003e\u003e image.get_height()\n        512\n    \u003e\u003e\u003e image.get_width()\n        612\n    \u003e\u003e\u003e image.get_frame_id()\n        1\n    \u003e\u003e\u003e image.get_frame_timestamp()\n        67557050882\n    \u003e\u003e\u003e image.get_pix_fmt()\n        'Mono8'\n    \u003e\u003e\u003e image.get_image_data_size()\n        313344\n    \u003e\u003e\u003e data = image.get_image_data()\n    \u003e\u003e\u003e type(data)\n        bytearray\n    \u003e\u003e\u003e len(data)\n        313344\n    \u003e\u003e\u003e 512 * 612\n        313344\n    \u003e\u003e\u003e camera.deinit_cam()\n    \u003e\u003e\u003e camera.release()\n\nConfiguring and getting an image from a USB3 camera\n---------------------------------------------------\n\n.. code-block:: python\n\n    \u003e\u003e\u003e from rotpy.system import SpinSystem\n    \u003e\u003e\u003e from rotpy.camera import CameraList\n    \u003e\u003e\u003e # create system/camera list instance and create the camera by serial number\n    \u003e\u003e\u003e system = SpinSystem()\n    \u003e\u003e\u003e cameras = CameraList.create_from_system(system, True, True)\n    \u003e\u003e\u003e cameras.get_size()\n    1\n    \u003e\u003e\u003e camera = cameras.create_camera_by_serial('87785435')\n    \u003e\u003e\u003e # init so we can read the pixel format node\n    \u003e\u003e\u003e camera.init_cam()\n    \u003e\u003e\u003e # the names of the pixel formats available for the camera\n    \u003e\u003e\u003e camera.camera_nodes.PixelFormat.get_entries_names()\n    ['Mono8',\n     'Mono12Packed',\n     'Mono12p',\n     'Mono16',\n     'BayerGR8',\n     ...,\n     'BayerBG16',\n     'YCbCr411_8_CbYYCrYY',\n     'YCbCr422_8_CbYCrY',\n     'YCbCr8_CbYCr',\n     'RGB8']\n    \u003e\u003e\u003e # the current one is BayerRG8\n    \u003e\u003e\u003e node = camera.camera_nodes.PixelFormat.get_node_value()\n    \u003e\u003e\u003e node\n    \u003crotpy.node.SpinEnumItemNode at 0x236edec43c8\u003e\n    \u003e\u003e\u003e node.get_enum_name()\n    'BayerRG8'\n    \u003e\u003e\u003e # instead set it to RGB8\n    \u003e\u003e\u003e camera.camera_nodes.PixelFormat.set_node_value_from_str('RGB8')\n    \u003e\u003e\u003e camera.camera_nodes.PixelFormat.get_node_value().get_enum_name()\n    'RGB8'\n    \u003e\u003e\u003e # set acquired image height to 800 pixels\n    \u003e\u003e\u003e camera.camera_nodes.Height.get_node_value()\n    1200\n    \u003e\u003e\u003e camera.camera_nodes.Height.set_node_value(800)\n    \u003e\u003e\u003e camera.camera_nodes.Height.get_node_value()\n    800\n    \u003e\u003e\u003e camera.camera_nodes.Height.get_max_value()\n    1200\n    \u003e\u003e\u003e # get the current framerate\n    \u003e\u003e\u003e camera.camera_nodes.AcquisitionFrameRate.is_readable()\n    True\n    \u003e\u003e\u003e camera.camera_nodes.AcquisitionFrameRate.get_node_value()\n    42.7807502746582\n    \u003e\u003e\u003e # get one image and copy and release it so we don't tie up the buffers\n    \u003e\u003e\u003e camera.begin_acquisition()\n    \u003e\u003e\u003e image_cam = camera.get_next_image()\n    \u003e\u003e\u003e image = image_cam.deep_copy_image(image_cam)\n    \u003e\u003e\u003e image_cam.release()\n    \u003e\u003e\u003e camera.end_acquisition()\n    \u003e\u003e\u003e # get some image metadat\n    \u003e\u003e\u003e image.get_frame_timestamp() / 1e9\n    512.51940629\n    \u003e\u003e\u003e image.get_height()\n    800\n    \u003e\u003e\u003e image.get_buffer_size()\n    4608000\n    \u003e\u003e\u003e 1920*800*3\n    4608000\n    \u003e\u003e\u003e image.get_pix_fmt()\n    'RGB8'\n    \u003e\u003e\u003e # cleanup\n    \u003e\u003e\u003e camera.deinit_cam()\n    \u003e\u003e\u003e camera.release()\n\nSystem and camera properties\n----------------------------\n\nThe system and camera properties can be read and set using\n`node \u003chttps://matham.github.io/rotpy/node.html\u003e`_\nobjects. These nodes, each represent a camera or system property, and they\ncan be integer nodes, float nodes, boolean nodes, string nodes, command\nnodes etc.\n\nThese nodes derive from Spinnaker's `GenICam \u003chttps://en.wikipedia.org/wiki/GenICam\u003e`_\nimplementation for their cameras. RotPy provides access to a generic node access API\nas well as to some pre-listed nodes available on many cameras.\n\nThe generic API is accessed through the `NodeMap \u003chttps://matham.github.io/rotpy/node.html#rotpy.node.NodeMap\u003e`_ using\ne.g. `SpinSystem.get_tl_node_map \u003chttps://matham.github.io/rotpy/system.html#rotpy.system.SpinSystem.get_tl_node_map\u003e`_,\n`InterfaceDevice.get_tl_node_map \u003chttps://matham.github.io/rotpy/system.html#rotpy.system.InterfaceDevice.get_tl_node_map\u003e`_,\n`Camera.get_node_map \u003chttps://matham.github.io/rotpy/camera.html#rotpy.camera.Camera.get_node_map\u003e`_,\n`Camera.get_tl_dev_node_map \u003chttps://matham.github.io/rotpy/camera.html#rotpy.camera.Camera.get_tl_dev_node_map\u003e`_, or\n`Camera.get_tl_stream_node_map \u003chttps://matham.github.io/rotpy/camera.html#rotpy.camera.Camera.get_tl_stream_node_map\u003e`_.\n\nThe pre-listed nodes can be accessed through e.g.\n`SpinSystem.system_nodes \u003chttps://matham.github.io/rotpy/system.html#rotpy.system.SpinSystem.system_nodes\u003e`_,\n`InterfaceDevice.interface_nodes \u003chttps://matham.github.io/rotpy/system.html#rotpy.system.InterfaceDevice.interface_nodes\u003e`_,\n`Camera.camera_nodes \u003chttps://matham.github.io/rotpy/camera.html#rotpy.camera.Camera.camera_nodes\u003e`_,\n`Camera.tl_dev_nodes \u003chttps://matham.github.io/rotpy/camera.html#rotpy.camera.Camera.tl_dev_nodes\u003e`_, or\n`Camera.tl_stream_nodes \u003chttps://matham.github.io/rotpy/camera.html#rotpy.camera.Camera.tl_stream_nodes\u003e`_.\nThese link to the following respective\nobjects: `SystemNodes \u003chttps://matham.github.io/rotpy/system_nodes.html#rotpy.system_nodes.SystemNodes\u003e`_,\n`InterfaceNodes \u003chttps://matham.github.io/rotpy/system_nodes.html#rotpy.system_nodes.InterfaceNodes\u003e`_,\n`CameraNodes \u003chttps://matham.github.io/rotpy/camera_nodes.html#rotpy.camera_nodes.CameraNodes\u003e`_,\n`TLDevNodes \u003chttps://matham.github.io/rotpy/camera_nodes.html#rotpy.camera_nodes.TLDevNodes\u003e`_, and\n`TLStreamNodes \u003chttps://matham.github.io/rotpy/camera_nodes.html#rotpy.camera_nodes.TLStreamNodes\u003e`_.\n\nE.g. to access some of the system nodes using\n`system_nodes \u003chttps://matham.github.io/rotpy/system.html#rotpy.system.SpinSystem.system_nodes\u003e`_:\n\n.. code-block:: python\n\n    \u003e\u003e\u003e from rotpy.system import SpinSystem\n    \u003e\u003e\u003e system = SpinSystem()\n    \u003e\u003e\u003e # get a list of all boolean nodes\n    \u003e\u003e\u003e system.system_nodes.bool_nodes\n    ['EnumerateGEVInterfaces', 'EnumerateUSBInterfaces', 'EnumerateGen2Cameras']\n    \u003e\u003e\u003e # let's inspect the USB node\n    \u003e\u003e\u003e system.system_nodes.EnumerateUSBInterfaces\n    \u003crotpy.node.SpinBoolNode at 0x26822c20d68\u003e\n    \u003e\u003e\u003e # first make sure this node is actually available for this system\n    \u003e\u003e\u003e system.system_nodes.EnumerateUSBInterfaces.is_available()\n    True\n    \u003e\u003e\u003e system.system_nodes.EnumerateUSBInterfaces.get_node_value()\n    True\n    \u003e\u003e\u003e system.system_nodes.EnumerateUSBInterfaces.get_description()\n    'Enables or disables enumeration of USB Interfaces.'\n    \u003e\u003e\u003e system.system_nodes.EnumerateUSBInterfaces.get_name()\n    'EnumerateUSBInterfaces'\n    \u003e\u003e\u003e system.system_nodes.EnumerateUSBInterfaces.get_node_value_as_str()\n    '1'\n    \u003e\u003e\u003e system.system_nodes.EnumerateUSBInterfaces.get_short_description()\n    'Enables or disables enumeration of USB Interfaces.'\n\nWe can similarly use the node map to get the same node if it's available:\n\n.. code-block:: python\n\n    \u003e\u003e\u003e from rotpy.system import SpinSystem\n    \u003e\u003e\u003e system = SpinSystem()\n    \u003e\u003e\u003e node_map = system.get_tl_node_map()\n    \u003e\u003e\u003e node = node_map.get_node_by_name('EnumerateUSBInterfaces')\n    \u003e\u003e\u003e node is not None and node.is_available()\n    True\n    \u003e\u003e\u003e node.get_node_value()\n    True\n    \u003e\u003e\u003e node.get_description()\n    'Enables or disables enumeration of USB Interfaces.'\n\nSimilarly, for the camera, we can use the pre-listed nodes:\n\n.. code-block:: python\n\n    \u003e\u003e\u003e # make sure to init the camera, otherwise many nodes won't be available\n    \u003e\u003e\u003e camera.init_cam()\n    \u003e\u003e\u003e # check that the auto-exposure setting is available\n    \u003e\u003e\u003e camera.camera_nodes.ExposureAuto.is_available()\n    True\n    \u003e\u003e\u003e camera.camera_nodes.ExposureAuto.get_description()\n    'Sets the automatic exposure mode when Exposure Mode is Timed.'\n    \u003e\u003e\u003e # the auto-exposure is a enum node with children items\n    \u003e\u003e\u003e camera.camera_nodes.ExposureAuto.get_node_value()\n    \u003crotpy.node.SpinEnumItemNode at 0x26822c2bc18\u003e\n    \u003e\u003e\u003e camera.camera_nodes.ExposureAuto.get_node_value().get_enum_name()\n    'Continuous'\n    \u003e\u003e\u003e # but we can just get the symbolic string name directly\n    \u003e\u003e\u003e camera.camera_nodes.ExposureAuto.get_node_value_as_str()\n    'Continuous'\n    \u003e\u003e\u003e # to see what options are available for this enum node, look in the names module\n    \u003e\u003e\u003e from rotpy.names.camera import ExposureAuto_names\n    \u003e\u003e\u003e ExposureAuto_names\n    {'Off': 0, 'Once': 1, 'Continuous': 2}\n    \u003e\u003e\u003e # or for pre-listed enum nodes, we can get it as an attribute\n    \u003e\u003e\u003e camera.camera_nodes.ExposureAuto.enum_names\n    {'Off': 0, 'Once': 1, 'Continuous': 2}\n    \u003e\u003e\u003e # try setting it to an incorrect value\n    \u003e\u003e\u003e camera.camera_nodes.ExposureAuto.set_node_value_from_str('off', verify=True)\n    Traceback (most recent call last):\n      File \"\u003cipython-input-48-d16a67f0044c\u003e\", line 1, in \u003cmodule\u003e\n        camera.camera_nodes.ExposureAuto.set_node_value_from_str('off', verify=True)\n      File \"rotpy\\node.pyx\", line 650, in rotpy.node.SpinValueNode.set_node_value_from_str\n        cpdef set_node_value_from_str(self, str value, cbool verify=True):\n      File \"rotpy\\node.pyx\", line 664, in rotpy.node.SpinValueNode.set_node_value_from_str\n        self._value_handle.FromString(s, verify)\n    RuntimeError: Spinnaker: GenICam::InvalidArgumentException= Feature 'ExposureAuto' : cannot convert value 'off', the value is invalid. : InvalidArgumentException thrown in node 'ExposureAuto' while calling 'ExposureAuto.FromString()' (file 'Enumeration.cpp', line 132) [-2001]\n    \u003e\u003e\u003e # now set it correctly\n    \u003e\u003e\u003e camera.camera_nodes.ExposureAuto.set_node_value_from_str('Off', verify=True)\n    \u003e\u003e\u003e camera.camera_nodes.ExposureAuto.get_node_value_as_str()\n    'Off'\n\nSimilarly, we can use the node map to set the exposure back to ``\"Continuous\"``:\n\n.. code-block:: python\n\n    \u003e\u003e\u003e node_map = camera.get_node_map()\n    \u003e\u003e\u003e node = node_map.get_node_by_name('ExposureAuto')\n    \u003e\u003e\u003e node is not None and node.is_available()\n    True\n    \u003e\u003e\u003e node.get_node_value_as_str()\n    'Off'\n    \u003e\u003e\u003e node.set_node_value_from_str('Continuous', verify=True)\n    \u003e\u003e\u003e node.get_node_value_as_str()\n    'Continuous'\n    \u003e\u003e\u003e # now de-init the camera and the node won't be available\n    \u003e\u003e\u003e camera.deinit_cam()\n    \u003e\u003e\u003e node.is_available()\n    False\n    \u003e\u003e\u003e camera.camera_nodes.ExposureAuto.is_available()\n    False\n\nAttaching event handlers\n------------------------\n\nCamera detection events\n^^^^^^^^^^^^^^^^^^^^^^^\n\nWe can register callbacks to be called when the system detects a camera arrival or\nremoval on any interface, or on specific interfaces. E.g. to be notified on any interface:\n\n.. code-block:: python\n\n    \u003e\u003e\u003e from rotpy.system import SpinSystem\n    \u003e\u003e\u003e system = SpinSystem()\n    \u003e\u003e\u003e # register a callback for both arrival and removal\n    \u003e\u003e\u003e def arrival(handler, system, serial):\n    ...     print('Arrived:', serial)\n    \u003e\u003e\u003e def removal(handler, system, serial):\n    ...     print('Removed:', serial)\n    \u003e\u003e\u003e # register and then plug and unplug a camera twice\n    \u003e\u003e\u003e handler = system.attach_interface_event_handler(arrival, removal, update=True)\n    Arrived: 36548975\n    Removed: 36548975\n    Arrived: 36548975\n    Removed: 36548975\n    \u003e\u003e\u003e system.detach_interface_event_handler(handler)\n\nLogging handler\n^^^^^^^^^^^^^^^\n\nWe can also register logging event handlers to get any logging events on the system or devices:\n\n.. code-block:: python\n\n    \u003e\u003e\u003e from rotpy.system import SpinSystem\n    \u003e\u003e\u003e from rotpy.camera import CameraList\n    \u003e\u003e\u003e # create system and set logging level to debug\n    \u003e\u003e\u003e system = SpinSystem()\n    \u003e\u003e\u003e system.set_logging_level('debug')\n    \u003e\u003e\u003e # create a callback that prints the message\n    \u003e\u003e\u003e def log_handler(handler, system, item):\n    ...     print('Log:', item['category'], item['priority'], item['message'])\n    \u003e\u003e\u003e # attach the callback and do something that causes logs\n    \u003e\u003e\u003e handler = system.attach_log_event_handler(log_handler)\n    \u003e\u003e\u003e cameras = CameraList.create_from_system(system, update_cams=True, update_interfaces=True)\n    Log: SpinnakerCallback DEBUG Spinnaker: GetCameras()\n    Log: GenTLCallback DEBUG Entering InterfaceGev::InterfaceGev()\n    Log: GenTLCallback DEBUG Leaving InterfaceGev::InterfaceGev()\n    Log: GenTLCallback DEBUG GenTL Trace: system.cpp, line 125, GenTL::EnumerateGigEInterfaces\n    Log: GenTLCallback DEBUG Entering HAL_UsbGetInterfaces()\n    Log: GenTLCallback DEBUG Enumerating host Controller PCI\\VEN_8086\u0026DEV_A12F\u0026SUBSYS_06E41028\u0026REV_31\\3\u002611458735\u00260\u0026A0\n    Log: GenTLCallback DEBUG Host Controller's child instance ID: USB\\VID_8087\u0026PID_0029\\5\u0026587A6F87\u00260\u00264\n    Log: GenTLCallback DEBUG Entering InterfaceUsb::InterfaceUsb()\n    Log: GenTLCallback DEBUG Leaving InterfaceUsb::InterfaceUsb()\n    Log: GenTLCallback DEBUG GenTL Trace: system.cpp, line 162, GenTL::EnumerateUsbInterfaces\n    Log: GenTLCallback DEBUG GenTL Trace: system.cpp, line 191, GenTL::InitializeInterfaces\n    Log: GenTLCallback DEBUG GenTL Trace: system.cpp, line 225, GenTL::System::RefreshInterfaces\n    Log: GenTLCallback DEBUG GenTL Trace: system.cpp, line 535, GenTL::System::UpdateInterfaceList\n    \u003e\u003e\u003e # now detach the handler\n    \u003e\u003e\u003e system.detach_log_event_handler(handler)\n\nCamera image handler\n^^^^^^^^^^^^^^^^^^^^\n\nWe can also register a callback that is called on every new image that is received from the\ndevice, as opposed to polling for new images:\n\n.. code-block:: python\n\n    \u003e\u003e\u003e from rotpy.camera import CameraList\n    \u003e\u003e\u003e from rotpy.system import SpinSystem\n    \u003e\u003e\u003e # create system and get a camera\n    \u003e\u003e\u003e system = SpinSystem()\n    \u003e\u003e\u003e cameras = CameraList.create_from_system(system, update_cams=True, update_interfaces=True)\n    \u003e\u003e\u003e camera = cameras.create_camera_by_index(0)\n    \u003e\u003e\u003e camera.init_cam()\n    \u003e\u003e\u003e # create an image handler that prints the frame ID and time\n    \u003e\u003e\u003e def image_callback(handler, camera, image):\n    ...     print('Image:', image.get_frame_id(), image.get_frame_timestamp())\n    \u003e\u003e\u003e # attach callback and start getting frames\n    \u003e\u003e\u003e handler = camera.attach_image_event_handler(image_callback)\n    \u003e\u003e\u003e camera.begin_acquisition()\n    Image: 1 388361262364\n    Image: 2 388366605529\n     ...\n    Image: 135 389077033335\n    \u003e\u003e\u003e # stop frames and printing\n    \u003e\u003e\u003e camera.end_acquisition()\n    \u003e\u003e\u003e camera.detach_image_event_handler(handler)\n    \u003e\u003e\u003e camera.deinit_cam()\n    \u003e\u003e\u003e camera.release()\n\nCamera events\n^^^^^^^^^^^^^\n\nWe can also register a callback that is called on camera events. E.g.:\n\n.. code-block:: python\n\n    \u003e\u003e\u003e from rotpy.camera import CameraList\n    \u003e\u003e\u003e from rotpy.system import SpinSystem\n    \u003e\u003e\u003e # create system and get a camera\n    \u003e\u003e\u003e system = SpinSystem()\n    \u003e\u003e\u003e cameras = CameraList.create_from_system(system, update_cams=True, update_interfaces=True)\n    \u003e\u003e\u003e camera = cameras.create_camera_by_index(0)\n    \u003e\u003e\u003e camera.init_cam()\n    \u003e\u003e\u003e # define the callback and attach it\n    \u003e\u003e\u003e def event_callback(handler, camera, event):\n    ...     print('Event:', event, handler.get_event_data(event), handler.get_event_metadata())\n    \u003e\u003e\u003e handler = camera.attach_device_event_handler(event_callback)\n    \u003e\u003e\u003e # now use the EventSelector enum to get the enum items which\n    \u003e\u003e\u003e correspond to the event names that are available.\n    \u003e\u003e\u003e nodes = camera.camera_nodes.EventSelector.get_entries()\n    \u003e\u003e\u003e # not all are actually available, so only activate the ones available\n    \u003e\u003e\u003e nodes = [node for node in nodes if node.is_available()]\n    \u003e\u003e\u003e for node in nodes:\n    ...     print(node.get_enum_name())\n    ...     camera.camera_nodes.EventSelector.set_node_value_from_str(node.get_enum_name())\n    ...     camera.camera_nodes.EventNotification.set_node_value_from_str('On')\n    ExposureEnd\n    \u003e\u003e\u003e # this printed just ExposureEnd, indicating only this event was available\n    \u003e\u003e\u003e # start acquisition so that the events occur\n    \u003e\u003e\u003e camera.begin_acquisition()\n    Event: EventExposureEnd {'frame_id': 62629213124996} ('device', 'EventExposureEnd', 40003)\n    Event: EventExposureEnd {'frame_id': 62633508092293} ('device', 'EventExposureEnd', 40003)\n    ...\n    Event: EventExposureEnd {'frame_id': 62676457765304} ('device', 'EventExposureEnd', 40003)\n    \u003e\u003e\u003e camera.end_acquisition()\n    \u003e\u003e\u003e camera.detach_device_event_handler(handler)\n    \u003e\u003e\u003e camera.deinit_cam()\n    \u003e\u003e\u003e camera.release()\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatham%2Frotpy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmatham%2Frotpy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmatham%2Frotpy/lists"}