点云结构和输出格式

结构点云

Zivid 默认输出有序的点云。这意味着点云以类似于图像结构的二维点阵列形式排列。

这种结构有几个优点。

  • 为无结构点云设计的算法也可以用于结构点云,因为 2D 数组可以看做 1D 数组。 而相反情况并不总是正确的。

  • 有序点云在 2D 图像(颜色和深度)中的像素与点云中的 3D 点之间具有 1:1 的相关性。 这意味着图像中的相邻像素是点云中的相邻点。 这使得 2D 操作和算法能够应用于 2D 图像,而结果可以直接应用于点云。 例如,对物体的检测和分割,可以分割 2D 图像并直接从所需像素中提取 3D 点。

  • 点的有序性加快了计算并降低了某些算法的消耗,尤其是使用相邻点的操作。

像素索引:Studio (x, y) 与 API (row, column) 的区别

结构点云和 2D 图像共用同一网格,但 Zivid Studio 和 API 对该网格中像素的表示方式不同。两者的原点都在左上角。

  • Zivid Studio 将像素位置显示为 (x, y),其中 x 是水平位置(列,向右增大),y 是垂直位置(行,向下增大)。

  • API 将像素表示为 (row, column),即先给出垂直索引,再给出水平索引。例如,PointCloud 和 Array2D 均按 (row, column) 索引,其中 row 的取值范围为 0 到 height - 1,column 的取值范围为 0 到 width - 1;而 C#、Python 和 MATLAB 中的数组形状为 [height, width, ...]。

因此这两种表示方式是互为相反的:在 Studio 中显示为 (x, y) 的像素,对应于 API 中的 (row = y, column = x)。在代码中使用从 Studio 读取的像素坐标来索引点云时,请牢记这一点。

ReadIterateZDF 示例遍历点云,并通过 (row, column) 索引读取各个点:

跳转到源码

源码

const size_t iStart = (pointCloud.height() - pixelsToDisplay) / 2;
const size_t iEnd = (pointCloud.height() + pixelsToDisplay) / 2;
const size_t jStart = (pointCloud.width() - pixelsToDisplay) / 2;
const size_t jEnd = (pointCloud.width() + pixelsToDisplay) / 2;
for(size_t i = iStart; i < iEnd; i++)
{
    for(size_t j = jStart; j < jEnd; j++)
    {
        const auto &point = data(i, j);
        const auto &pointSnr = snr(i, j);

        std::cout << std::setprecision(1) << std::fixed << "Values at pixel (" << i << "," << j << "):   "
                  << "X:" << std::left << std::setfill(' ') << std::setw(8) << point.point.x
                  << "Y:" << std::setw(8) << point.point.y << "Z:" << std::setw(8) << point.point.z
                  << "R:" << std::setw(8) << std::to_string(point.color.r) << "G:" << std::setw(8)
                  << std::to_string(point.color.g) << "B:" << std::setw(8) << std::to_string(point.color.b)
                  << "SNR:" << std::setw(8) << pointSnr.value << std::endl;
    }
}
跳转到源码

源码

ulong iStart = (height - pixelsToDisplay) / 2;
ulong iStop = (height + pixelsToDisplay) / 2;
ulong jStart = (width - pixelsToDisplay) / 2;
ulong jStop = (width + pixelsToDisplay) / 2;
for (ulong i = iStart; i < iStop; i++)
{
    for (ulong j = jStart; j < jStop; j++)
    {
        Console.WriteLine(string.Format(
            "{0} {1} {2,-7} {3} {4,-7} {5} {6,-7} {7} {8,-7} {9} {10,-7} {11} {12,-7} {13} {14,-7}",
            "Values at pixel (" + i + "," + j + "):  ",
            "X:",
            pointCloudData[i, j].point.x.ToString("F1"),
            "Y:",
            pointCloudData[i, j].point.y.ToString("F1"),
            "Z:",
            pointCloudData[i, j].point.z.ToString("F1"),
            "R:",
            pointCloudData[i, j].color.r.ToString(),
            "G:",
            pointCloudData[i, j].color.g.ToString(),
            "B:",
            pointCloudData[i, j].color.b.ToString(),
            "SNR:",
            pointCloudSNR[i, j].ToString("F1")));
    }
}
跳转到源码

源码

for row in range(int((height - pixels_to_display) / 2), int((height + pixels_to_display) / 2)):
    for col in range(int((width - pixels_to_display) / 2), int((width + pixels_to_display) / 2)):
        print(
            f"Values at pixel ({row} , {col}): X:{xyz[row,col,0]:.1f} Y:{xyz[row,col,1]:.1f}"
            f" Z:{xyz[row,col,2]:.1f} R:{rgba[row,col,0]} G:{rgba[row,col,1]} B:{rgba[row,col,2]}"
            f" SNR:{snr[row,col]:.1f}"
        )

无序点云

无序点云是一维数组中的点列表。每个点包含与有序点云相同的信息。

无序点云也有其优势。

  • 由于没有保留到传感器像素的映射,因此无信息点(NaN)也不存在。因此,无序点云的尺寸可能比有序点云更小。

  • 当您组合多个点云时,将它们合并为单个无序的点云会更容易。

备注

可以从无序点云中恢复像素索引。这可以通过使用固有函数来实现。然而,固有函数模型并不能涵盖相机的完整校准。真正获得正确像素映射的唯一方法是使用有序点云。更多信息请参阅 相机内参 。

Zivid 点云

不同型号的 Zivid 相机使用具有不同分辨率的传感器来捕获场景的点云。关于 传感器分辨率 的定义,请参阅 Zivid 规格术语。

相机

百万像素 (MP)

分辨率

Zivid 3

8

2816 x 2816

Zivid 2+

5

2448 x 2048

Zivid 2

2.3

1944 x 1200

有多种方法可以从 SDK 获取分辨率信息。

跳转到源码

源码

const auto cameraInfo = camera.info();

auto defaultSettings = Zivid::Experimental::SettingsInfo::defaultValue<Zivid::Settings>(cameraInfo);
defaultSettings.acquisitions().emplaceBack(
    Zivid::Experimental::SettingsInfo::defaultValue<Zivid::Settings::Acquisition>(cameraInfo));

defaultSettings.set(
    Zivid::Settings::Color{
        Zivid::Experimental::SettingsInfo::defaultValue<Zivid::Settings2D>(cameraInfo)
            .copyWith(
                Zivid::Settings2D::Acquisitions{
                    Zivid::Experimental::SettingsInfo::defaultValue<Zivid::Settings2D::Acquisition>(
                        cameraInfo) }) });


std::cout << "Camera resolution for default settings:" << std::endl;
const auto resolution = Zivid::Experimental::SettingsInfo::resolution(cameraInfo, defaultSettings);
std::cout << "  Height: " << resolution.height() << std::endl;
std::cout << "  Width: " << resolution.width() << std::endl;

std::cout << "Point cloud (GPU memory) resolution:" << std::endl;
const auto pointCloud = camera.capture2D3D(defaultSettings).pointCloud();
std::cout << "  Height: " << pointCloud.height() << std::endl;
std::cout << "  Width: " << pointCloud.width() << std::endl;

std::cout << "Point cloud (CPU memory) resolution:" << std::endl;
const auto data = pointCloud.copyPointsXYZColorsRGBA_SRGB();
std::cout << "  Height: " << data.height() << std::endl;
std::cout << "  Width: " << data.width() << std::endl;
Zivid 3

生成的点云由 800 万个点组成。由于像素和点之间存在 1:1 的相关性,因此可以获得每个像素的 XYZ(mm)、RGB(8 位)和 SNR,其中 SNR 是信噪比。在 GPU 内部,3D 坐标、颜色值和 SNR 值分别被存储为大小为 2816 x 2816 的单独二维数组。在用户端(CPU 内存),数据可以以不同的格式存储,具体取决于请求的方式。请参阅 点云教程 了解相关详细说明。

Zivid 2+

生成的点云由 500 万个点组成。由于像素和点之间存在 1:1 的相关性,因此可以获得每个像素的 XYZ(mm)、RGB(8 位)和 SNR,其中 SNR 是信噪比。在 GPU 内部,3D 坐标、颜色值和 SNR 值分别被存储为大小为 2448 x 2048 的单独二维数组。在用户端(CPU 内存),数据可以以不同的格式存储,具体取决于请求的方式。请参阅 点云教程 了解相关详细说明。

Zivid 2

生成的点云由 230 万个点组成。由于像素和点之间存在 1:1 的相关性,因此可以获得每个像素的 XYZ(mm)、RGB(8 位)和 SNR,其中 SNR 是信噪比。在 GPU 内部,3D 坐标、颜色值和 SNR 值分别被存储为大小为 1944 x 1200 的单独二维数组。在用户端(CPU 内存),数据可以以不同的格式存储,具体取决于请求的方式。请参阅 点云教程 了解相关详细说明。

结构点云

颜色图像和深度图像可以直接从 Zivid 点云中提取。您可以 从 GitHub repository 中找到相关示例。

Zivid 输出格式

在 Zivid Studio 中,您可以将点云保存在 Zivid 数据文件(*.zdf)中。 此外,您也可以将点云导出(File → Export)为以下格式:

  • Polygon (PLY)

  • Point Cloud Data (PCD)

  • ASCII(XYZ)

对于每种格式,您可以在从 Zivid Studio 导出时选择不同的导出选项,例如 颜色空间 和 法线 。

PLY、PCD 和 XYZ 文件格式的导出选项。

Zivid 数据文件 (*.zdf) 是 Zivid 的原生文件格式。如果您使用 API,可以遍历点云,并以您喜欢的任意格式保存 X、Y、Z、R、G、B 和 SNR 数据。要了解如何读取或转换 Zivid 数据,请查看我们的 C++ file format samples、 C# file format samples 和 Python file format samples。

小技巧

查看 Zivid 点云最简单的方法是将 ZDF 文件复制到您的电脑上,并使用 Zivid Studio。您也可以使用 API 将 ZDF 转换为 PLY(或使用我们的 Python script),然后在 MeshLab 或 CloudCompare 等 3D 点云工具中打开该文件,以可视化并测量距离、平面和偏差。

ASCII points (*.xyz)

ASCII 字符用于存储笛卡尔坐标。 XYZ 用空格隔开。在我们的版本中,还为每个点添加了 RGB 值。每个新点都用换行符隔开。该文件可以在常规文本编辑器中查看。

PLY file (*.ply)

PLY 是斯坦福大学开发的一种文件格式 。 Learn more about PLY。

Point Cloud Data file (*.pcd)

PCD 是点云库的原生文件格式 。 Learn more about PCD。

使用 Experimental::PointCloudExport::exportFrame API 通过 Zivid SDK 将点云导出为您喜欢的格式。

如果您使用 Frame::save API 将点云导出为 PCD,请阅读此内容

结构 PCD 格式

使用 Frame::save 时,Zivid SDK 保存有序点云时带有一个标头,用于指示一个无序点云。从 SDK 2.5 开始,可以使用 Config.yml 文件配置 SDK,以便导出带有正确标头(用于指示有序点云)的 PCD。如果该文件已存在,且位于 Windows 系统的 %LOCALAPPDATA%\Zivid\API 或 Ubuntu 系统的 "${XDG_CONFIG_HOME-$HOME/.config}"/Zivid/API 中,请更新 Configuration/APIBreakingBugFixes/FileFormats/PCD/UseOrganizedFormat 。

如果文件不存在:

  1. 下 载 Config.yml 文件。

    配置文件包含以下信息:

    __version__:
        serializer: 1
        data: 12
    Configuration:
        APIBreakingBugFixes:
            FileFormats:
                PCD:
                    UseOrganizedFormat: yes
    
  2. 将配置文件放在以下目录中:

    Windows
    mkdir %LOCALAPPDATA%\Zivid\API
    move %HOMEPATH%\Downloads\Config.yml %LOCALAPPDATA%\Zivid\API\
    
    Ubuntu
    mkdir --parents "${XDG_CONFIG_HOME-$HOME/.config}"/Zivid/API
    mv ~/Downloads/Config.yml "${XDG_CONFIG_HOME-$HOME/.config}"/Zivid/API/
    

    小心

    任何现有的配置文件都将被覆盖。

小心

Zivid 配置文件必须使用.yml 文件扩展名(而不是.yaml)。

Version History

SDK

变更

2.17.0

新增对 Zivid 3 XL250 的支持。

2.16.0

新增对 UnorganizedPointCloud 的支持。