点云教程
介绍
本教程介绍了如何使用Zivid SDK进行 点云 数据的相关操作。
小技巧
如果您更喜欢观看视频教程,我们的网络研讨会 Getting your point cloud ready for your application (为您的应用准备好点云)涵盖了点云教程。
先决条件
安装 Zivid软件.
对于Python:安装 Zivid-python
帧(Frame)
Zivid::Frame
包含了点云和彩色图像(存储在计算设备内存中)以及捕获设置和相机的信息。
Zivid.NET.Frame
包含了点云和彩色图像(存储在计算设备内存中)以及捕获设置和相机信息。
zivid.Frame
包含了点云和彩色图像(存储在计算设备内存中)以及捕获设置和相机信息。
捕获(Capture)
当您使用Zivid捕获图像时,您会得到一个帧(frame)作为返回值。
const auto frame = camera.capture(settings);
using (var frame = camera.Capture(settings))
with camera.capture(settings) as frame:
查看 捕获教程 了解有关如何捕获图像的详细说明。
加载(Load)
可以通过ZDF文件加载图像帧。
const auto dataFile = std::string(ZIVID_SAMPLE_DATA_DIR) + "/Zivid3D.zdf";
std::cout << "Reading ZDF frame from file: " << dataFile << std::endl;
const auto frame = Zivid::Frame(dataFile);
var dataFile =
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "/Zivid/Zivid3D.zdf";
Console.WriteLine("Reading ZDF frame from file: " + dataFile);
var frame = new Zivid.NET.Frame(dataFile);
data_file = get_sample_data_path() / "Zivid3D.zdf"
print(f"Reading point cloud from file: {data_file}")
frame = zivid.Frame(data_file)
点云
从Frame获取句柄
您现在可以从GPU上的点云数据获取句柄。
const auto pointCloud = frame.pointCloud();
var pointCloud = frame.PointCloud;
point_cloud = frame.point_cloud()
点云包含了XYZ、RGB和SNR数据,分布在2D网格上。
如需了解更多信息,请查看 点云结构。
方法 Zivid::Frame::pointCloud()
不从GPU内存执行任何复制。
备注
Zivid::Camera::capture()
方法在相机完成捕获原始图像后的某个时刻返回。来自 Zivid::Frame::pointCloud()
的句柄可以立即可用。但是,实际的点云数据只有在GPU上的处理完成后才可用。任何对数据复制功能的调用(下面的部分)都将在阻塞并等待处理完成,然后再继续请求的复制操作。
请查看 点云捕获过程 了解更多细节。
获取 Zivid.NET.Frame.PointCloud
不会从GPU内存执行任何复制。
备注
Zivid.NET.Camera.Capture()
方法在相机完成捕获原始图像后的某个时刻返回。来自 Zivid.NET.Frame.PointCloud
的句柄可以立即可用。但是,实际的点云数据只有在GPU上的处理完成后才可用。任何对数据复制功能的调用(下面的部分)都将在阻塞并等待处理完成,然后再继续请求的复制操作。
请查看 点云捕获过程 了解更多细节。
功能 zivid.frame.point_cloud()
不从GPU内存执行任何复制。
备注
zivid.camera.capture()
方法在相机完成捕获原始图像后的某个时刻返回。来自 zivid.frame.point_cloud()
的句柄可以立即可用。但是,实际的点云数据只有在GPU上的处理完成后才可用。任何对数据复制功能的调用(下面的部分)都将在阻塞并等待处理完成,然后再继续请求的复制操作。
请查看 点云捕获过程 了解更多细节。
将数据从GPU复制到CPU内存
您现在可以根据需要有选择地复制数据。下面的列表列出了输出数据格式以及如何从GPU复制它们。
返回类型 |
复制功能 |
单像素数据量 |
总数据量 |
---|---|---|---|
|
|
12 bytes |
28 MB |
|
|
16 bytes |
37 MB |
|
|
4 bytes |
9 MB |
|
|
4 bytes |
9 MB |
|
|
4 bytes |
9 MB |
|
|
16 bytes |
37 MB |
|
|
16 bytes |
37 MB |
|
|
4 bytes |
9 MB |
|
|
4 bytes |
9 MB |
|
|
4 bytes |
9 MB |
返回类型 |
复制方法 |
单像素数据量 |
总数据量 |
---|---|---|---|
|
|
12 bytes |
28 MB |
|
|
16 bytes |
37 MB |
|
|
4 bytes |
9 MB |
|
|
4 bytes |
9 MB |
|
|
4 bytes |
9 MB |
|
|
16 bytes |
37 MB |
|
|
16 bytes |
37 MB |
|
|
4 bytes |
9 MB |
|
|
4 bytes |
9 MB |
|
|
4 bytes |
9 MB |
返回类型 |
复制功能 |
单像素数据量 |
总数据量 |
---|---|---|---|
|
|
12 bytes |
28 MB |
|
|
16 bytes |
37 MB |
|
|
4 bytes |
9 MB |
|
|
4 bytes |
9 MB |
|
|
4 bytes |
9 MB |
|
|
4 bytes |
9 MB |
|
|
4 bytes |
9 MB |
|
|
16 bytes |
37 MB |
以下是如何复制数据的示例。
const auto data = pointCloud.copyData<Zivid::PointXYZColorRGBA>();
var pointCloudData = pointCloud.CopyPointsXYZColorsRGBA();
xyz = point_cloud.copy_data("xyz")
rgba = point_cloud.copy_data("rgba")
内存分配选项
在内存分配方面,复制数据有两种方式:
Zivid SDK可以分配内存缓冲区并将数据复制到其中。
用户可以将指针传递给预分配的内存缓冲区,Zivid SDK会将数据复制到预分配的内存缓冲区。
我们将展示两个使用了OpenCV的内存分配的示例。
将选定数据从GPU复制到 CPU内存(Zivid 分配)
如果您只关心例如点云的RGB颜色数据,您可以仅将该数据复制到CPU内存。
std::cout << "Capturing frame" << std::endl; frame = camera.capture(settings); pointCloud = frame.pointCloud(); std::cout << "Copying colors with Zivid API from GPU to CPU" << std::endl; auto colors = pointCloud.copyColorsBGRA(); std::cout << "Casting the data pointer as a void*, since this is what the OpenCV matrix constructor requires." << std::endl; auto *dataPtrZividAllocated = const_cast<void *>(static_cast<const void *>(colors.data())); std::cout << "Wrapping this block of data in an OpenCV matrix. This is possible since the layout of \n" << "Zivid::ColorBGRA exactly matches the layout of CV_8UC4. No copying occurs in this step." << std::endl; const cv::Mat bgraZividAllocated(colors.height(), colors.width(), CV_8UC4, dataPtrZividAllocated); std::cout << "Displaying image" << std::endl; cv::imshow("BGRA image Zivid Allocated", bgraZividAllocated); cv::waitKey(0);
将选定数据从GPU复制到CPU内存(用户分配)
在上面的示例中,数据的所有权由返回的 Zivid::Array2D<>
对象拥有。或者您可以提供预先分配的内存缓冲区到 Zivid::PointCloud::copyData(dataPtr)
。 dataPtr
的类型定义了将被复制的数据(PointXYZ
, ColorRGBA
等。)。
现在让我们看一下与上面完全相同的用例。但是,这一次我们允许OpenCV来分配必要的存储空间。然后我们让Zivid API将数据直接从GPU复制到这个内存位置。
std::cout << "Allocating the necessary storage with OpenCV API based on resolution info before any capturing" << std::endl; auto bgraUserAllocated = cv::Mat(resolution.height(), resolution.width(), CV_8UC4); std::cout << "Capturing frame" << std::endl; auto frame = camera.capture(settings); auto pointCloud = frame.pointCloud(); std::cout << "Copying data with Zivid API from the GPU into the memory location allocated by OpenCV" << std::endl; pointCloud.copyData(&(*bgraUserAllocated.begin<Zivid::ColorBGRA>())); std::cout << "Displaying image" << std::endl; cv::imshow("BGRA image User Allocated", bgraUserAllocated); cv::waitKey(0);
转换
你可能想要 转换 点云,将其原点从相机坐标系转换到机器人基坐标系,或者比如, 通过将点云从mm转换为m来缩放点云。
pointCloud.transform(baseToCameraTransform);
pointCloud.Transform(transformBaseToCamera);
point_cloud.transform(base_to_camera_transform)
降采样
有时您可能不需要相机输出的高空间分辨率(高空间分辨率意味着更多的细节和更短的点之间的距离)点云。那么您对点云进行 降采样 。
备注
Monochrome Capture(单色捕获) 是一种基于硬件的子采样方法,可在捕获过程中降低点云的分辨率,同时还可减少采集和捕获时间。
可以就地进行降采样,从而修改当前的点云。
pointCloud.downsample(Zivid::PointCloud::Downsampling::by2x2);
pointCloud.Downsample(Zivid.NET.PointCloud.Downsampling.By2x2);
point_cloud.downsample(zivid.PointCloud.Downsampling.by2x2)
也可以将降采样后的点云作为一个新的点云实例,它不会改变现有的点云。
auto downsampledPointCloud = pointCloud.downsampled(Zivid::PointCloud::Downsampling::by2x2);
var downsampledPointCloud = pointCloud.Downsampled(Zivid.NET.PointCloud.Downsampling.By2x2);
downsampled_point_cloud = point_cloud.downsampled(zivid.PointCloud.Downsampling.by2x2)
Zivid SDK支持以下降采样率: by2x2
, by3x3
, 和 by4x4
, 可以进行多次降采样。
法线
一些应用需要计算点云的 法线 数据。
std::cout << "Computing normals and copying them to CPU memory" << std::endl;
const auto normals = pointCloud.copyData<Zivid::NormalXYZ>();
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内存。其结果是一个法向量矩阵,每条法线对应输入点云的每个点。法线的大小和输入点云的大小相等。
可视化
您可以通过帧(frame)可视化点云。
std::cout << "Setting up visualization" << std::endl;
Zivid::Visualization::Visualizer visualizer;
std::cout << "Visualizing point cloud" << std::endl;
visualizer.showMaximized();
visualizer.show(frame);
visualizer.resetToFit();
std::cout << "Running visualizer. Blocking until window closes." << std::endl;
visualizer.run();
Console.WriteLine("Setting up visualization");
using (var visualizer = new Zivid.NET.Visualization.Visualizer())
{
Console.WriteLine("Visualizing point cloud");
visualizer.Show(frame);
visualizer.ShowMaximized();
visualizer.ResetToFit();
Console.WriteLine("Running visualizer. Blocking until window closes.");
visualizer.Run();
}
您也可以从点云对象来可视化点云。
std::cout << "Getting point cloud from frame" << std::endl;
auto pointCloud = frame.pointCloud();
std::cout << "Setting up visualization" << std::endl;
Zivid::Visualization::Visualizer visualizer;
std::cout << "Visualizing point cloud" << std::endl;
visualizer.showMaximized();
visualizer.show(pointCloud);
visualizer.resetToFit();
std::cout << "Running visualizer. Blocking until window closes." << std::endl;
visualizer.run();
Console.WriteLine("Getting point cloud from frame");
var pointCloud = frame.PointCloud;
Console.WriteLine("Setting up visualization");
var visualizer = new Zivid.NET.Visualization.Visualizer();
Console.WriteLine("Visualizing point cloud");
visualizer.Show(pointCloud);
visualizer.ShowMaximized();
visualizer.ResetToFit();
Console.WriteLine("Running visualizer. Blocking until window closes.");
visualizer.Run();
如需了解更多信息,请查看 可视化教程,里面包含了如何使用第三方库实现点云、彩色图像、深度图和法线的可视化。
结论
本教程展示了如何使用Zivid SDK来提取、操作、转换和可视化点云。
版本历史
SDK |
变更 |
---|---|
2.11.0 |
添加了对 SRGB 色彩空间(SRGB color space)的支持。 |
2.10.0 |
Monochrome Capture(单色捕获) 引入了比 降采样 更快的替代方案。 |