法线

小技巧

我们的网络研讨会 Getting your point cloud ready for your application (为您的应用准备好点云)部分涵盖了法线的相关内容。

介绍

本文介绍了表面法线,如何在Zivid SDK中通过点云计算它们,以及为什么法线是一项有价值的功能。最后,文章还提供了一个带有代码示例的教程。

表面法线是几何曲面的一个重要属性。它表示了垂直于点云中特定点平面的切面的单位向量。由于它是一个向量,因此表面法线包含了三个用于描述3D坐标向量元素(x、y、z),每个元素的范围为-1至1。平面的所有表面法线都是平行的,而球体的表面法线指向所有可能的方向。

法线描述了表面的方向,而法线的变化率描述了表面的曲率。

Zivid Studio 中的法线图

法线图提供了场景表面法线的 2D 表示,其中 RGB 颜色分量描述法线向量。下图中的箱壁和底板很好地显示了法线图中法线向量与颜色分量之间的关系。这是因为每个表面上的所有点的法线向量都或多或少指向同一方向。

法线图的颜色约定与 相机坐标系 负对齐。因此,蓝色像素表示的法线向量垂直指向相机。查看法线图,可以在箱底上看到蓝色像素。这些法线指向相机坐标系 Z 轴的负方向。左下角的状态栏接近 [0, 0, -1]。

此外,右侧箱壁以红色像素为主。这些法线与相机坐标系的 X 轴负对齐。这意味着表面的法线向量在场景中指向左侧。同样,底部箱壁被涂成绿色,因为法线在场景中指向上方。因此,状态栏将分别读取接近 [-1, 0, 0](红色像素)和 [0, -1, 0](绿色像素)。

../../_images/normal-map-bin.png

因此,法线图对于查看点云中的平面非常有用。法线贴图还有助于检查表面曲率、表面纹理和物体之间的过渡,因为颜色渐变可以很好地描述这些。

法线API

跳转到源码

源码

std::cout << "Computing normals and copying them to CPU memory" << std::endl;
const auto normals = pointCloud.copyData<Zivid::NormalXYZ>();
跳转到源码

source

Console.WriteLine("Computing normals and copying them to CPU memory");
var normals = pointCloud.CopyNormalsXYZ();
跳转到源码

源码

print("Computing normals and copying them to CPU memory")
normals = point_cloud.copy_data("normals")

法线API将计算点云中每个点的法线,并将法线从GPU内存复制到CPU内存。其结果是一个法向量矩阵,每条法线对应输入点云的每个点。法线的大小和输入点云的大小相等。

备注

Zivid SDK中法线API的处理速度非常快,因为其计算是在GPU中并行完成的,而此时点云数据仍在GPU内存中。使用第三方库计算法线可能更耗时:因为CPU计算通常要慢得多,而GPU计算则需要多出一次数据复制过程。查看 点云捕获过程 了解更多信息。

如果您已经有一个缓冲区,那么您可以使用包含模板参数 NormalXYZcopyData ,直接将数据从GPU内存复制到目标缓冲区。

小技巧

  • 使用Zivid SDK中的法线,降采样和转换API可以获得更好的表现,因为GPU执行所有这些计算时, 点云数据仍在GPU内存中时。

  • 为了获得最好的性能,您可以先对点云进行降采样,然后计算法线。

  • 当请求复制法线时,法线将在点云上进行计算。您可以在转换点云后计算法线,使得法线与点云在同一坐标系中。

  • 转换法线需要先转换点云,然后从转换后的点云计算法线。不能只变换法线。

应用中的法线

基于各种原因,不同的应用可能需要从点云计算法线。法线描述了表面的方向,法线的变化率描述了表面的曲率。

使用法线的应用包括基于CAD和基于表面的匹配、边缘检测和基于法线差异的分割算法。网格算法和过滤算法也可以通过法线来移除点云伪像或异常值。例如,几乎垂直于从相机原点到某个点的线的法线可以被判断为伪像并被过滤掉。

使用PCL计算法线并可视化

本教程展示了如何从Zivid点云计算法线,将点云和法线转换为PCL格式,并在3D中将它们可视化为法线贴图。

首先,我们连接到相机并捕获点云。

跳转到源码

source

std::cout << "Connecting to camera" << std::endl;
auto camera = zivid.connectCamera();

std::cout << "Configuring settings" << std::endl;
Zivid::Settings2D settings2D{ Zivid::Settings2D::Acquisitions{ Zivid::Settings2D::Acquisition{} } };
Zivid::Settings settings{ Zivid::Settings::Color{ settings2D } };
for(const auto aperture : { 5.66, 4.00, 2.59 })
{
    std::cout << "Adding acquisition with aperture = " << aperture << std::endl;
    const auto acquisitionSettings = Zivid::Settings::Acquisition{
        Zivid::Settings::Acquisition::Aperture{ aperture },
    };
    settings.acquisitions().emplaceBack(acquisitionSettings);
}

std::cout << "Capturing frame (HDR)" << std::endl;
const auto frame = camera.capture2D3D(settings);
const auto pointCloud = frame.pointCloud();

然后计算点云的法线。

跳转到源码

source

std::cout << "Computing point cloud normals" << std::endl;
const auto normals = pointCloud.copyData<Zivid::NormalXYZ>();

我们再将点云和法线转换为PCL格式。

跳转到源码

source

std::cout << "Creating PCL point cloud structure" << std::endl;
const auto data = pointCloud.copyData<Zivid::PointXYZColorRGBA>();
const auto pointCloudPCL = convertToPCLPointCloud(data);
std::cout << "Creating PCL normals structure suited for visualization" << std::endl;
const auto pointCloudWithNormalsPCL = convertToPCLVisualizationNormals(data, normals);

最后,我们在3D中可视化点云和法线。

跳转到源码

source

std::cout << "Visualizing normals" << std::endl;
visualizePointCloudAndNormalsPCL(pointCloudPCL.makeShared(), pointCloudWithNormalsPCL.makeShared());

版本历史

SDK

变更

2.8.0

Zivid Studio新增了法线图显示功能。

2.5.0

添加了法线API。