跳转到主要内容

Cython绑定的Spinnaker摄像头控制API。

项目描述

RotPy

RotPy为Spinnaker SDK提供Python绑定,以实现Python对Teledyne/FLIR/Point Grey USB和GigE摄像头的控制。

请参阅网站获取完整的文档

Github CI status

安装

您可以使用Windows、Linux或Mac上的预编译轮件安装RotPy,或者通过安装Spinnaker SDK然后从源代码安装RotPy。

无论哪种方式,您可能需要安装Spinnaker驱动程序,以便摄像头被识别。请从他们的网站下载,并根据说明安装驱动程序,如果找不到摄像头。

预编译轮件

要从预编译轮件安装(假设您的平台上有),只需执行以下操作

python -m pip install rotpy

从源代码获取

要从源代码安装RotPy,您需要

  1. 安装Spinnaker SDK开发库。

  2. 安装支持C++11的C++编译器。例如,在Windows上Visual Studio等。在Mac上,您可能需要导出以下环境变量

    export CXX="/usr/bin/clang"
    export CXXFLAGS="-std=c++11"
    export CPPFLAGS="-std=c++11"
  3. 设置环境变量,以便Python可以找到Spinnaker SDK。

    1. 您需要将ROTPY_INCLUDE设置为包含目录,例如,在Windows上可能是这样的:set ROTPY_INCLUDE="C:\Program Files\FLIR\Spinnaker\include"。在Linux和Mac上,通常可以自动找到。

    2. 您需要将ROTPY_LIB设置为包含库和二进制的路径。例如,在Windows上可能是这样的:set ROTPY_LIB="C:\Program Files\FLIR\Spinnaker\bin64\vs2015;C:\Program Files\FLIR\Spinnaker\lib64\vs2015"。在Linux和Mac上,同样可以自动找到。

  4. 然后使用以下命令安装RotPy

    python -m pip install rotpy --no-binary rotpy
  5. 在运行时,您需要确保Spinnaker运行时二进制文件位于系统PATH中,例如使用os.add_dll_directory

    您可能还需要根据操作系统位数设置环境变量(GENICAM_GENTL32_PATH/GENICAM_GENTL64_PATH)到包含FLIR_GenTL*.cti文件的目录,以及将任何或所有变量FLIR_GENTL32_CTI_VS140/FLIR_GENTL64_CTI_VS140/FLIR_GENTL32_CTI/FLIR_GENTL64_CTI设置为FLIR_GenTL*.cti文件的完整路径。

    此外,可能还需要将包含FLIR_GenTL*.cti文件的目录添加到系统PATH中。如果Spinnaker无法加载cti文件,将引发错误。

示例

从GigE相机获取图像

>>> from rotpy.system import SpinSystem
>>> from rotpy.camera import CameraList
>>> # get a system ref and a list of all attached cameras
>>> system = SpinSystem()
>>> cameras = CameraList.create_from_system(system, update_cams=True, update_interfaces=True)
>>> cameras.get_size()
    1
>>> # get the camera attached from the list
>>> camera = cameras.create_camera_by_index(0)
>>> camera.get_unique_id()
    '77T45WD4A84C_86TA1684_GGGGGG14_64CW3987'
>>> # init the camera and get one image
>>> camera.init_cam()
>>> # get its serial number
>>> camera.camera_nodes.DeviceSerialNumber.get_node_value()
'36548975'
>>> camera.begin_acquisition()
>>> image_cam = camera.get_next_image(timeout=5)
>>> # we copy the image so that we can release its camera buffer
>>> image = image_cam.deep_copy_image(image_cam)
>>> image_cam.release()
>>> camera.end_acquisition()
>>> # save the image
>>> image.save_png('image.png')
>>> # get image metadata
>>> image.get_bits_per_pixel()
    8
>>> image.get_height()
    512
>>> image.get_width()
    612
>>> image.get_frame_id()
    1
>>> image.get_frame_timestamp()
    67557050882
>>> image.get_pix_fmt()
    'Mono8'
>>> image.get_image_data_size()
    313344
>>> data = image.get_image_data()
>>> type(data)
    bytearray
>>> len(data)
    313344
>>> 512 * 612
    313344
>>> camera.deinit_cam()
>>> camera.release()

配置并从USB3相机获取图像

>>> from rotpy.system import SpinSystem
>>> from rotpy.camera import CameraList
>>> # create system/camera list instance and create the camera by serial number
>>> system = SpinSystem()
>>> cameras = CameraList.create_from_system(system, True, True)
>>> cameras.get_size()
1
>>> camera = cameras.create_camera_by_serial('87785435')
>>> # init so we can read the pixel format node
>>> camera.init_cam()
>>> # the names of the pixel formats available for the camera
>>> camera.camera_nodes.PixelFormat.get_entries_names()
['Mono8',
 'Mono12Packed',
 'Mono12p',
 'Mono16',
 'BayerGR8',
 ...,
 'BayerBG16',
 'YCbCr411_8_CbYYCrYY',
 'YCbCr422_8_CbYCrY',
 'YCbCr8_CbYCr',
 'RGB8']
>>> # the current one is BayerRG8
>>> node = camera.camera_nodes.PixelFormat.get_node_value()
>>> node
<rotpy.node.SpinEnumItemNode at 0x236edec43c8>
>>> node.get_enum_name()
'BayerRG8'
>>> # instead set it to RGB8
>>> camera.camera_nodes.PixelFormat.set_node_value_from_str('RGB8')
>>> camera.camera_nodes.PixelFormat.get_node_value().get_enum_name()
'RGB8'
>>> # set acquired image height to 800 pixels
>>> camera.camera_nodes.Height.get_node_value()
1200
>>> camera.camera_nodes.Height.set_node_value(800)
>>> camera.camera_nodes.Height.get_node_value()
800
>>> camera.camera_nodes.Height.get_max_value()
1200
>>> # get the current framerate
>>> camera.camera_nodes.AcquisitionFrameRate.is_readable()
True
>>> camera.camera_nodes.AcquisitionFrameRate.get_node_value()
42.7807502746582
>>> # get one image and copy and release it so we don't tie up the buffers
>>> camera.begin_acquisition()
>>> image_cam = camera.get_next_image()
>>> image = image_cam.deep_copy_image(image_cam)
>>> image_cam.release()
>>> camera.end_acquisition()
>>> # get some image metadat
>>> image.get_frame_timestamp() / 1e9
512.51940629
>>> image.get_height()
800
>>> image.get_buffer_size()
4608000
>>> 1920*800*3
4608000
>>> image.get_pix_fmt()
'RGB8'
>>> # cleanup
>>> camera.deinit_cam()
>>> camera.release()

系统和相机属性

可以使用node对象读取和设置系统和相机属性。这些节点代表一个相机或系统属性,可以是整数节点、浮点节点、布尔节点、字符串节点、命令节点等。

这些节点从Spinnaker为其相机实现的GenICam继承而来。RotPy提供了对通用节点访问API的访问,以及对许多相机上可用的预定义节点。

通过NodeMap访问通用API,例如使用SpinSystem.get_tl_node_mapInterfaceDevice.get_tl_node_mapCamera.get_node_mapCamera.get_tl_dev_node_mapCamera.get_tl_stream_node_map

可以通过例如SpinSystem.system_nodesInterfaceDevice.interface_nodesCamera.camera_nodesCamera.tl_dev_nodesCamera.tl_stream_nodes访问预定义节点。这些链接到以下相应的对象:SystemNodesInterfaceNodesCameraNodesTLDevNodesTLStreamNodes

例如,使用system_nodes来访问某些系统节点

>>> from rotpy.system import SpinSystem
>>> system = SpinSystem()
>>> # get a list of all boolean nodes
>>> system.system_nodes.bool_nodes
['EnumerateGEVInterfaces', 'EnumerateUSBInterfaces', 'EnumerateGen2Cameras']
>>> # let's inspect the USB node
>>> system.system_nodes.EnumerateUSBInterfaces
<rotpy.node.SpinBoolNode at 0x26822c20d68>
>>> # first make sure this node is actually available for this system
>>> system.system_nodes.EnumerateUSBInterfaces.is_available()
True
>>> system.system_nodes.EnumerateUSBInterfaces.get_node_value()
True
>>> system.system_nodes.EnumerateUSBInterfaces.get_description()
'Enables or disables enumeration of USB Interfaces.'
>>> system.system_nodes.EnumerateUSBInterfaces.get_name()
'EnumerateUSBInterfaces'
>>> system.system_nodes.EnumerateUSBInterfaces.get_node_value_as_str()
'1'
>>> system.system_nodes.EnumerateUSBInterfaces.get_short_description()
'Enables or disables enumeration of USB Interfaces.'

如果可用,我们可以类似地使用节点映射来获取相同的节点

>>> from rotpy.system import SpinSystem
>>> system = SpinSystem()
>>> node_map = system.get_tl_node_map()
>>> node = node_map.get_node_by_name('EnumerateUSBInterfaces')
>>> node is not None and node.is_available()
True
>>> node.get_node_value()
True
>>> node.get_description()
'Enables or disables enumeration of USB Interfaces.'

类似地,对于相机,我们可以使用预先列出的节点

>>> # make sure to init the camera, otherwise many nodes won't be available
>>> camera.init_cam()
>>> # check that the auto-exposure setting is available
>>> camera.camera_nodes.ExposureAuto.is_available()
True
>>> camera.camera_nodes.ExposureAuto.get_description()
'Sets the automatic exposure mode when Exposure Mode is Timed.'
>>> # the auto-exposure is a enum node with children items
>>> camera.camera_nodes.ExposureAuto.get_node_value()
<rotpy.node.SpinEnumItemNode at 0x26822c2bc18>
>>> camera.camera_nodes.ExposureAuto.get_node_value().get_enum_name()
'Continuous'
>>> # but we can just get the symbolic string name directly
>>> camera.camera_nodes.ExposureAuto.get_node_value_as_str()
'Continuous'
>>> # to see what options are available for this enum node, look in the names module
>>> from rotpy.names.camera import ExposureAuto_names
>>> ExposureAuto_names
{'Off': 0, 'Once': 1, 'Continuous': 2}
>>> # or for pre-listed enum nodes, we can get it as an attribute
>>> camera.camera_nodes.ExposureAuto.enum_names
{'Off': 0, 'Once': 1, 'Continuous': 2}
>>> # try setting it to an incorrect value
>>> camera.camera_nodes.ExposureAuto.set_node_value_from_str('off', verify=True)
Traceback (most recent call last):
  File "<ipython-input-48-d16a67f0044c>", line 1, in <module>
    camera.camera_nodes.ExposureAuto.set_node_value_from_str('off', verify=True)
  File "rotpy\node.pyx", line 650, in rotpy.node.SpinValueNode.set_node_value_from_str
    cpdef set_node_value_from_str(self, str value, cbool verify=True):
  File "rotpy\node.pyx", line 664, in rotpy.node.SpinValueNode.set_node_value_from_str
    self._value_handle.FromString(s, verify)
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]
>>> # now set it correctly
>>> camera.camera_nodes.ExposureAuto.set_node_value_from_str('Off', verify=True)
>>> camera.camera_nodes.ExposureAuto.get_node_value_as_str()
'Off'

类似地,我们可以使用节点映射将曝光时间设置回“连续”

>>> node_map = camera.get_node_map()
>>> node = node_map.get_node_by_name('ExposureAuto')
>>> node is not None and node.is_available()
True
>>> node.get_node_value_as_str()
'Off'
>>> node.set_node_value_from_str('Continuous', verify=True)
>>> node.get_node_value_as_str()
'Continuous'
>>> # now de-init the camera and the node won't be available
>>> camera.deinit_cam()
>>> node.is_available()
False
>>> camera.camera_nodes.ExposureAuto.is_available()
False

附加事件处理器

相机检测事件

我们可以注册回调,以便在系统检测到任何接口或特定接口上的相机到达或移除时调用。例如,要通知任何接口

>>> from rotpy.system import SpinSystem
>>> system = SpinSystem()
>>> # register a callback for both arrival and removal
>>> def arrival(handler, system, serial):
...     print('Arrived:', serial)
>>> def removal(handler, system, serial):
...     print('Removed:', serial)
>>> # register and then plug and unplug a camera twice
>>> handler = system.attach_interface_event_handler(arrival, removal, update=True)
Arrived: 36548975
Removed: 36548975
Arrived: 36548975
Removed: 36548975
>>> system.detach_interface_event_handler(handler)

日志处理器

我们还可以注册日志事件处理器,以获取系统或设备上的任何日志事件

>>> from rotpy.system import SpinSystem
>>> from rotpy.camera import CameraList
>>> # create system and set logging level to debug
>>> system = SpinSystem()
>>> system.set_logging_level('debug')
>>> # create a callback that prints the message
>>> def log_handler(handler, system, item):
...     print('Log:', item['category'], item['priority'], item['message'])
>>> # attach the callback and do something that causes logs
>>> handler = system.attach_log_event_handler(log_handler)
>>> cameras = CameraList.create_from_system(system, update_cams=True, update_interfaces=True)
Log: SpinnakerCallback DEBUG Spinnaker: GetCameras()
Log: GenTLCallback DEBUG Entering InterfaceGev::InterfaceGev()
Log: GenTLCallback DEBUG Leaving InterfaceGev::InterfaceGev()
Log: GenTLCallback DEBUG GenTL Trace: system.cpp, line 125, GenTL::EnumerateGigEInterfaces
Log: GenTLCallback DEBUG Entering HAL_UsbGetInterfaces()
Log: GenTLCallback DEBUG Enumerating host Controller PCI\VEN_8086&DEV_A12F&SUBSYS_06E41028&REV_31\3&11458735&0&A0
Log: GenTLCallback DEBUG Host Controller's child instance ID: USB\VID_8087&PID_0029\5&587A6F87&0&4
Log: GenTLCallback DEBUG Entering InterfaceUsb::InterfaceUsb()
Log: GenTLCallback DEBUG Leaving InterfaceUsb::InterfaceUsb()
Log: GenTLCallback DEBUG GenTL Trace: system.cpp, line 162, GenTL::EnumerateUsbInterfaces
Log: GenTLCallback DEBUG GenTL Trace: system.cpp, line 191, GenTL::InitializeInterfaces
Log: GenTLCallback DEBUG GenTL Trace: system.cpp, line 225, GenTL::System::RefreshInterfaces
Log: GenTLCallback DEBUG GenTL Trace: system.cpp, line 535, GenTL::System::UpdateInterfaceList
>>> # now detach the handler
>>> system.detach_log_event_handler(handler)

相机图像处理器

我们还可以注册一个回调,该回调在从设备接收到每个新图像时被调用,而不是轮询新图像

>>> from rotpy.camera import CameraList
>>> from rotpy.system import SpinSystem
>>> # create system and get a camera
>>> system = SpinSystem()
>>> cameras = CameraList.create_from_system(system, update_cams=True, update_interfaces=True)
>>> camera = cameras.create_camera_by_index(0)
>>> camera.init_cam()
>>> # create an image handler that prints the frame ID and time
>>> def image_callback(handler, camera, image):
...     print('Image:', image.get_frame_id(), image.get_frame_timestamp())
>>> # attach callback and start getting frames
>>> handler = camera.attach_image_event_handler(image_callback)
>>> camera.begin_acquisition()
Image: 1 388361262364
Image: 2 388366605529
 ...
Image: 135 389077033335
>>> # stop frames and printing
>>> camera.end_acquisition()
>>> camera.detach_image_event_handler(handler)
>>> camera.deinit_cam()
>>> camera.release()

相机事件

我们还可以注册一个回调,在相机事件上被调用。例如

>>> from rotpy.camera import CameraList
>>> from rotpy.system import SpinSystem
>>> # create system and get a camera
>>> system = SpinSystem()
>>> cameras = CameraList.create_from_system(system, update_cams=True, update_interfaces=True)
>>> camera = cameras.create_camera_by_index(0)
>>> camera.init_cam()
>>> # define the callback and attach it
>>> def event_callback(handler, camera, event):
...     print('Event:', event, handler.get_event_data(event), handler.get_event_metadata())
>>> handler = camera.attach_device_event_handler(event_callback)
>>> # now use the EventSelector enum to get the enum items which
>>> correspond to the event names that are available.
>>> nodes = camera.camera_nodes.EventSelector.get_entries()
>>> # not all are actually available, so only activate the ones available
>>> nodes = [node for node in nodes if node.is_available()]
>>> for node in nodes:
...     print(node.get_enum_name())
...     camera.camera_nodes.EventSelector.set_node_value_from_str(node.get_enum_name())
...     camera.camera_nodes.EventNotification.set_node_value_from_str('On')
ExposureEnd
>>> # this printed just ExposureEnd, indicating only this event was available
>>> # start acquisition so that the events occur
>>> camera.begin_acquisition()
Event: EventExposureEnd {'frame_id': 62629213124996} ('device', 'EventExposureEnd', 40003)
Event: EventExposureEnd {'frame_id': 62633508092293} ('device', 'EventExposureEnd', 40003)
...
Event: EventExposureEnd {'frame_id': 62676457765304} ('device', 'EventExposureEnd', 40003)
>>> camera.end_acquisition()
>>> camera.detach_device_event_handler(handler)
>>> camera.deinit_cam()
>>> camera.release()

项目详情


下载文件

下载您平台上的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。

源代码分发

rotpy-0.2.1.tar.gz (142.7 kB 查看哈希值)

上传时间 源代码

构建分发

rotpy-0.2.1-cp311-cp311-win_amd64.whl (12.4 MB 查看哈希值)

上传时间 CPython 3.11 Windows x86-64

rotpy-0.2.1-cp311-cp311-win32.whl (9.4 MB 查看哈希值)

上传时间 CPython 3.11 Windows x86

rotpy-0.2.1-cp311-cp311-manylinux_2_27_x86_64.whl (22.2 MB 查看哈希值)

上传时间 CPython 3.11 manylinux: glibc 2.27+ x86-64

rotpy-0.2.1-cp311-cp311-macosx_10_14_x86_64.whl (15.7 MB 查看哈希值)

上传时间 CPython 3.11 macOS 10.14+ x86-64

rotpy-0.2.1-cp310-cp310-win_amd64.whl (12.3 MB 查看哈希值)

上传时间 CPython 3.10 Windows x86-64

rotpy-0.2.1-cp310-cp310-win32.whl (9.4 MB 查看哈希值)

上传时间: CPython 3.10 Windows x86

rotpy-0.2.1-cp310-cp310-manylinux_2_27_x86_64.whl (21.9 MB 查看哈希值)

上传时间: CPython 3.10 manylinux: glibc 2.27+ x86-64

rotpy-0.2.1-cp310-cp310-macosx_10_14_x86_64.whl (15.7 MB 查看哈希值)

上传时间: CPython 3.10 macOS 10.14+ x86-64

rotpy-0.2.1-cp39-cp39-win_amd64.whl (12.4 MB 查看哈希值)

上传时间: CPython 3.9 Windows x86-64

rotpy-0.2.1-cp39-cp39-win32.whl (9.4 MB 查看哈希值)

上传时间: CPython 3.9 Windows x86

rotpy-0.2.1-cp39-cp39-manylinux_2_27_x86_64.whl (22.0 MB 查看哈希值)

上传时间: CPython 3.9 manylinux: glibc 2.27+ x86-64

rotpy-0.2.1-cp39-cp39-macosx_10_14_x86_64.whl (15.7 MB 查看哈希值)

上传时间: CPython 3.9 macOS 10.14+ x86-64

rotpy-0.2.1-cp38-cp38-win_amd64.whl (12.7 MB 查看哈希值)

上传时间: CPython 3.8 Windows x86-64

rotpy-0.2.1-cp38-cp38-win32.whl (9.7 MB 查看哈希值)

上传时间: CPython 3.8 Windows x86

rotpy-0.2.1-cp38-cp38-manylinux_2_27_x86_64.whl (22.4 MB 查看哈希值)

上传时间: CPython 3.8 manylinux: glibc 2.27+ x86-64

rotpy-0.2.1-cp38-cp38-macosx_10_14_x86_64.whl (15.6 MB 查看哈希值)

上传时间: CPython 3.8 macOS 10.14+ x86-64

rotpy-0.2.1-cp37-cp37m-win_amd64.whl (13.0 MB 查看哈希值)

上传于 CPython 3.7m Windows x86-64

rotpy-0.2.1-cp37-cp37m-win32.whl (10.1 MB 查看哈希值)

上传于 CPython 3.7m Windows x86

rotpy-0.2.1-cp37-cp37m-manylinux_2_27_x86_64.whl (21.5 MB 查看哈希值)

上传于 CPython 3.7m manylinux: glibc 2.27+ x86-64

rotpy-0.2.1-cp37-cp37m-macosx_10_14_x86_64.whl (15.6 MB 查看哈希值)

上传于 CPython 3.7m macOS 10.14+ x86-64

支持者:

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面