Cython绑定的Spinnaker摄像头控制API。
项目描述
RotPy
RotPy为Spinnaker SDK提供Python绑定,以实现Python对Teledyne/FLIR/Point Grey USB和GigE摄像头的控制。
请参阅网站获取完整的文档。
安装
您可以使用Windows、Linux或Mac上的预编译轮件安装RotPy,或者通过安装Spinnaker SDK然后从源代码安装RotPy。
无论哪种方式,您可能需要安装Spinnaker驱动程序,以便摄像头被识别。请从他们的网站下载,并根据说明安装驱动程序,如果找不到摄像头。
预编译轮件
要从预编译轮件安装(假设您的平台上有),只需执行以下操作
python -m pip install rotpy
从源代码获取
要从源代码安装RotPy,您需要
安装Spinnaker SDK开发库。
安装支持C++11的C++编译器。例如,在Windows上Visual Studio等。在Mac上,您可能需要导出以下环境变量
export CXX="/usr/bin/clang" export CXXFLAGS="-std=c++11" export CPPFLAGS="-std=c++11"
设置环境变量,以便Python可以找到Spinnaker SDK。
您需要将ROTPY_INCLUDE设置为包含目录,例如,在Windows上可能是这样的:set ROTPY_INCLUDE="C:\Program Files\FLIR\Spinnaker\include"。在Linux和Mac上,通常可以自动找到。
您需要将ROTPY_LIB设置为包含库和二进制的路径。例如,在Windows上可能是这样的:set ROTPY_LIB="C:\Program Files\FLIR\Spinnaker\bin64\vs2015;C:\Program Files\FLIR\Spinnaker\lib64\vs2015"。在Linux和Mac上,同样可以自动找到。
然后使用以下命令安装RotPy
python -m pip install rotpy --no-binary rotpy
在运行时,您需要确保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_map、InterfaceDevice.get_tl_node_map、Camera.get_node_map、Camera.get_tl_dev_node_map或Camera.get_tl_stream_node_map。
可以通过例如SpinSystem.system_nodes、InterfaceDevice.interface_nodes、Camera.camera_nodes、Camera.tl_dev_nodes或Camera.tl_stream_nodes访问预定义节点。这些链接到以下相应的对象:SystemNodes、InterfaceNodes、CameraNodes、TLDevNodes和TLStreamNodes。
例如,使用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 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 5975f18a6dc3f2af293d10f19dfd79960c92a55259a306e4eeaf0f42ea5d2374 |
|
MD5 | 599e6e4aa12b33cdb645071a08a16b07 |
|
BLAKE2b-256 | 988ff2dff737c0bbb478293543031d496c962c5f112542c0a600666b7c2434a9 |
rotpy-0.2.1-cp311-cp311-win_amd64.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 5f6897d58197b3fb2173e585b2eb110be65d62ad31a275fb8dda431d8ca7cdc5 |
|
MD5 | 36d05315f202d8c8a9af80f7a34d54b7 |
|
BLAKE2b-256 | 8833c656fe269bb561d403dabfecf95b16f73ddb1628b9b2f398468ec9a65d98 |
rotpy-0.2.1-cp311-cp311-win32.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | e42501610b0bbe32ed93a0c9e2acd018bcc850076c572b25dfd5593c609f66c0 |
|
MD5 | 8d8547c93e9d3484bc30ea3386a5d31a |
|
BLAKE2b-256 | 5e51789907e7b6e5ceb79b9f6955908783a944a5539c249c7898ea90b8f527cb |
rotpy-0.2.1-cp311-cp311-manylinux_2_27_x86_64.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | d40e26c536f31d4e68375d08d46c1a65e7f5eb98da9eb5ec140925b8e33aae66 |
|
MD5 | aea301970632304364e3616031701a01 |
|
BLAKE2b-256 | d05952c5b05635e5bf684ffc30767bc3bb970fb11378624f39cee5af888e2cae |
rotpy-0.2.1-cp311-cp311-macosx_10_14_x86_64.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 4d71d34935203af64020026350d010fe4f108fa31181dede6c845e93352b1a6f |
|
MD5 | 4b11e4df0825410079af2cf970934811 |
|
BLAKE2b-256 | 73b04c246365dda9b166487d984246addd305ec50b3238594eec7f263e8e3629 |
rotpy-0.2.1-cp310-cp310-win_amd64.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 8b9ccf65da9580dcd06d464fbca84291b1cddd96dac137351ac2a721b0786596 |
|
MD5 | c0a4a27121a4c27796bedf84b4fb5187 |
|
BLAKE2b-256 | e602820d1bcfd51268b6300d34e919d4a36104f3a6b45b5fc01e5d431166a7b0 |
rotpy-0.2.1-cp310-cp310-win32.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | e902067941291adf1f5b7aefb1c46690cdb78161eb6d7128ad8393dda5e308ac |
|
MD5 | 56edf3424090abe0c8844a108713c83d |
|
BLAKE2b-256 | c2275e4c77a7d5307093bba795b0ce818f124b6faa9240340012919e0ee88618 |
rotpy-0.2.1-cp310-cp310-manylinux_2_27_x86_64.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 0245f7bf0c8e72d534f66d92be28f3f5b78f278e32bb1c6d14ad62ae952f608e |
|
MD5 | 7ca9b76704987fcb2f753c862d682e9b |
|
BLAKE2b-256 | f1c36de6aaffc0f9bb2735653d5db9f64fe8ea052f4ea65a01ef187df0db70f3 |
rotpy-0.2.1-cp310-cp310-macosx_10_14_x86_64.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 279eda3a1b4bc3f9146dc72c7dd4ff7b43bae1b3ba8cbfd9ebab70bed3e83fe8 |
|
MD5 | 38bfa12b1b80c4b2728f5d9edd0d80f9 |
|
BLAKE2b-256 | 49a1dea3b73547b1902da4dfbbf6656af75819d99cc6a31656f5010c35a774da |
哈希值 for rotpy-0.2.1-cp39-cp39-manylinux_2_27_x86_64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 9f2ed40bf6a6baa23408de546f54f75d14689239264f5f65b00a7b2c970760ca |
|
MD5 | 9dd45043cb3e4fd54bd0ccc6bba986d7 |
|
BLAKE2b-256 | 66af8cf44bab8993ca73a3b3641a9dac06eda3c2acb6ef46473af63417721988 |
哈希值 for rotpy-0.2.1-cp39-cp39-macosx_10_14_x86_64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 3a6ab291592937a93be0d752b8e024e2889e07d225adef86ed507ba74c1b5fff |
|
MD5 | 114a1fef148d17ef5b3034b8b28fd0c3 |
|
BLAKE2b-256 | 4f7cd706e2e14c5c76bc9f8d585cf85355262ea0038d78d6117659750687a3de |
哈希值 for rotpy-0.2.1-cp38-cp38-manylinux_2_27_x86_64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 2551ce0241b348b1cef413eabeb3dcff4634ac043bdf05da4b28de83a228315f |
|
MD5 | ede3c4105afe9c8c1ccbe2b288c2bada |
|
BLAKE2b-256 | e24c08aadb611bcb33cb61b9de7ef8a73c8859f634fc33a485dc73f320f1cc9d |
哈希值 for rotpy-0.2.1-cp38-cp38-macosx_10_14_x86_64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 7e04283ab07cc1af2b0d467846c00f604eee82b34b492fbc659b1e075f533708 |
|
MD5 | b67e679b78268244641d785ac27b340f |
|
BLAKE2b-256 | 325c3052b54315ae4d794c2e19e265509189324cb05383285c1baf07de56660e |
哈希值 for rotpy-0.2.1-cp37-cp37m-manylinux_2_27_x86_64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 008361b0adeee80c106990df7436e4bd888a35ccf68721a3ec9e19988426bcf2 |
|
MD5 | 446af23f7e00bdcbee88efac2572314d |
|
BLAKE2b-256 | 4d54bca601082dacf4f5901488bfcd9ef9d9f8757c97ca2c3851823cecfd1aa7 |
哈希值 for rotpy-0.2.1-cp37-cp37m-macosx_10_14_x86_64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 03e9ff4e6419591e2c9e4133e81a4e85ecb471077294f40d55138db2b0a6829c |
|
MD5 | 6beede66e2f45df4dbe38308612fe143 |
|
BLAKE2b-256 | 26382494dab4eb16e3752e24b4af54c9661108e2ab03c75051d2f354f4827c8c |