跳转到内容
STAGING SERVER
DEVELOPMENT SERVER

第三方驱动程序、库和示例#

本页面提供有关使用 Basler Stereo mini 相机的第三方库和示例代码的信息。

NumPy#

Python 示例中使用了 NumPy 来处理 pypylon 返回的原始分量数据。

pip install numpy

OpenCV#

OpenCV 可用于处理从 Stereo mini 相机获取的强度图像。强度分量提供了一个 RGBA8 图像,可以将其转换为适合 OpenCV 处理的格式。

pip install opencv-python

示例:将强度分量转换为 OpenCV 图像

import cv2
import numpy as np
from pypylon import pylon

# ... camera setup (see Python Programmer's Guide) ...

data_container = grab_result.GetDataContainer()
for i in range(data_container.DataComponentCount):
    component = data_container.GetDataComponentByIndex(i)
    try:
        if component.ComponentType == pylon.ComponentType_Intensity:
            raw = component.GetData()
            h, w = component.Height, component.Width
            # Stereo mini intensity is RGBA8
            rgba = np.frombuffer(raw, dtype=np.uint8).reshape(h, w, 4)
            bgr = cv2.cvtColor(rgba, cv2.COLOR_RGBA2BGR)
            cv2.imshow("Intensity", bgr)
            cv2.waitKey(1)
    finally:
        component.Release()

有关详细信息,请参阅 OpenCV。

Open3D#

Open3D 用于 ShowPointCloud 示例中,以可视化来自 Stereo mini 相机的 3D 点云。其中的距离分量 Coord3D_ABC32f 格式直接提供 XYZ 坐标。

pip install open3d

示例:从距离和强度数据构建 Open3D 点云

import numpy as np
import open3d as o3d
from pypylon import pylon

# ... camera setup with ComponentSelector Range, PixelFormat Coord3D_ABC32f ...

data_container = grab_result.GetDataContainer()
xyz = None
colors = None

for i in range(data_container.DataComponentCount):
    component = data_container.GetDataComponentByIndex(i)
    try:
        if component.ComponentType == pylon.ComponentType_Range:
            h, w = component.Height, component.Width
            raw = component.GetData()
            pts = np.frombuffer(raw, dtype=np.float32).reshape(h * w, 3)
            valid = np.isfinite(pts).all(axis=1)
            xyz = pts[valid]
        elif component.ComponentType == pylon.ComponentType_Intensity:
            h, w = component.Height, component.Width
            raw = component.GetData()
            rgba = np.frombuffer(raw, dtype=np.uint8).reshape(h * w, 4)
            colors = rgba[..., :3].astype(np.float64) / 255.0
    finally:
        component.Release()

if xyz is not None and colors is not None:
    pcd = o3d.geometry.PointCloud()
    pcd.points = o3d.utility.Vector3dVector(xyz)
    pcd.colors = o3d.utility.Vector3dVector(colors[:len(xyz)])
    o3d.visualization.draw_geometries([pcd])

有关详细信息,请参阅 Open3D。

Point Cloud Library (PCL)#

PCL 可用于高级 3D 点云处理。来自 Stereo mini 相机的 Coord3D_ABC32f 格式的距离数据可以馈送到 PCL 数据结构中。

sudo apt-get install libpcl-dev

Download from PCL website.

有关详细信息,请参阅 C++ 程序员指南。

ROS 2#

Stereo mini 相机可以通过使用 pypylon 作为桥接并发布 sensor_msgs/Image 主题来集成到 ROS 2 中。

所需的软件包:

pip install pypylon numpy
sudo apt install ros-humble-rclpy ros-humble-sensor-msgs

在此方法中,从 Stereo mini 数据分量(Intensity, Range)读取图像数据并发布到 ROS 主题,例如:

  • /stereo_mini/intensity_rgba8 (编码 rgba8)
  • /stereo_mini/range_c16_mm (编码 mono16)

最小桥接示例:

import numpy as np
import rclpy
from rclpy.node import Node
from sensor_msgs.msg import Image
from pypylon import pylon


class StereoMiniBridge(Node):
    def __init__(self):
        super().__init__("stereo_mini_bridge")
        self.pub_intensity = self.create_publisher(Image, "/stereo_mini/intensity_rgba8", 10)

        di = pylon.DeviceInfo()
        di.SetDeviceClass("BaslerGTC/Basler/TLModel_keep")
        self.camera = pylon.InstantCamera(pylon.TlFactory.GetInstance().CreateFirstDevice(di))
        self.camera.Open()

        self.camera.ComponentSelector.Value = "Intensity"
        self.camera.ComponentEnable.Value = True
        try:
            self.camera.PixelFormat.Value = "RGBA8"
        except Exception:
            self.camera.PixelFormat.Value = "RGBA8packed"

        self.camera.StartGrabbing()
        self.timer = self.create_timer(0.03, self.tick)

    def tick(self):
        grab = self.camera.RetrieveResult(3000, pylon.TimeoutHandling_ThrowException)
        try:
            if not grab.GrabSucceeded():
                return
            dc = grab.GetDataContainer()
            for i in range(dc.DataComponentCount):
                c = dc.GetDataComponentByIndex(i)
                try:
                    if c.ComponentType == pylon.ComponentType_Intensity:
                        h, w = c.Height, c.Width
                        rgba = np.frombuffer(c.GetData(), dtype=np.uint8).reshape(h, w, 4)
                        msg = Image()
                        msg.header.stamp = self.get_clock().now().to_msg()
                        msg.header.frame_id = "stereo_mini"
                        msg.height = h
                        msg.width = w
                        msg.encoding = "rgba8"
                        msg.is_bigendian = 0
                        msg.step = w * 4
                        msg.data = rgba.tobytes()
                        self.pub_intensity.publish(msg)
                finally:
                    c.Release()
        finally:
            grab.Release()


def main():
    rclpy.init()
    node = StereoMiniBridge()
    rclpy.spin(node)


if __name__ == "__main__":
    main()