Point Cloud Tutorial

Introduction

이 튜토리얼은 Zivid SDK를 사용하여 Point Cloud 데이터를 처리하는 방법을 설명합니다.

비디오 시청을 선호하는 경우 웨비나 Getting your point cloud ready for your application 에서 포인트 클라우드에 대해 다룹니다.

Prerequisites

Frame

Zivid::Frame 은 포인트 클라우드 및 컬러 이미지(컴퓨팅 장치 메모리에 저장된)와 캡처 및 카메라 정보가 포함됩니다.

Zivid.NET.Frame 은 포인트 클라우드 및 컬러 이미지(컴퓨팅 장치 메모리에 저장됨)와 캡처 및 카메라 정보가 포함됩니다.

zivid.Frame 은 포인트 클라우드 및 컬러 이미지(컴퓨팅 장치 메모리에 저장됨)와 캡처 및 카메라 정보가 포함됩니다.

Capture

Zivid로 캡처하면 프레임을 받게 됩니다. 포인트 클라우드는 프레임에 저장되고, 프레임은 GPU 메모리에 저장됩니다. 호출하는 메서드에 따라 캡처에 색상이 포함될 수도 있고 포함되지 않을 수도 있습니다. 자세한 내용은 다양한 캡처 모드가 포함된 이 table with different capture modes 표를 참조하세요.

Capture with color

색상이 있는 포인트 클라우드를 캡처하려면 Zivid::Camera::capture2D3D() 메서드를 사용하면 됩니다.

소스로 이동

소스

const auto frame = camera.capture2D3D(settings);
소스로 이동

소스

using (var frame = camera.Capture2D3D(settings))
소스로 이동

소스


frame = camera.capture_2d_3d(settings)

Capture without color

색상 없이 포인트 클라우드를 캡처하려면 Zivid::Camera::capture3D() 메서드를 사용하면 됩니다.

소스로 이동

source

const auto frame3D = camera.capture3D(settings);
소스로 이동

소스

using (var frame3D = camera.Capture3D(settings))
소스로 이동

source

frame_3d = camera.capture_3d(settings)

캡처 방법에 대한 자세한 지침은 Capture Tutorial 에서 확인하십시오.

Load

Frame은 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);

using (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)

Point Cloud

Get handle from Frame

이제 GPU에서 포인트 클라우드 데이터를 얻을 수 있습니다.

소스로 이동

소스

const auto pointCloud = frame.pointCloud();
소스로 이동

소스

var pointCloud = frame.PointCloud;
소스로 이동

소스

point_cloud = frame.point_cloud()

포인트 클라우드는 2D 그리드에 배치된 XYZ, RGB 및 SNR을 포함합니다.

더 많은 정보를 확인하려면 Point Cloud Structure 를 참고하세요.

이 메서드 Zivid::Frame::pointCloud() 는 GPU 메모리에서 복사를 수행하지 않습니다.

참고

Zivid::Camera::capture2D3D()Zivid::Camera::capture3D() 메서드는 카메라가 RAW 이미지 캡처를 완료한 후 특정 시점에 반환됩니다. Zivid::Frame::pointCloud() 의 핸들은 즉시 사용할 수 있습니다. 그러나 실제 포인트 클라우드 데이터는 GPU에서 처리가 완료된 후에만 사용할 수 있습니다. 데이터 복사 함수(아래 섹션)에 대한 모든 호출은 차단되고 처리가 완료될 때까지 기다린 후 요청된 복사 작업을 진행합니다.

자세한 설명은 다음을 참조하십시오. Point Cloud Capture Process.

Zivid.NET.Frame.PointCloud 특성을 얻을 때는 GPU 메모리에서 복사를 수행하지 않습니다.

참고

Zivid.NET.Camera.Capture2D3D()Zivid.NET.Camera.Capture3D() 메서드는 카메라가 RAW 이미지 캡처를 완료한 후 특정 시점에 반환됩니다. Zivid.NET.Frame.PointCloud 의 핸들은 즉시 사용할 수 있습니다. 그러나 실제 포인트 클라우드 데이터는 GPU에서 처리가 완료된 후에만 사용할 수 있습니다. 데이터 복사 메서드(아래 섹션)에 대한 모든 호출은 차단되고 처리가 완료될 때까지 기다린 후 요청된 복사 작업을 진행합니다.

자세한 설명은 다음을 참조하십시오. Point Cloud Capture Process.

zivid.frame.point_cloud() 함수는 GPU 메모리에서 복사를 수행하지 않습니다.

참고

zivid.camera.capture_2d_3d()zivid.camera.capture_3d() 메서드는 카메라가 RAW 이미지 캡처를 완료한 후 특정 시점에 반환됩니다. zivid.frame.point_cloud() 의 핸들은 즉시 사용할 수 있습니다. 그러나 실제 포인트 클라우드 데이터는 GPU에서 처리가 완료된 후에만 사용할 수 있습니다. 데이터 복사 함수(아래 섹션)에 대한 모든 호출은 차단되고 처리가 완료될 때까지 기다린 후 요청된 복사 작업을 진행합니다.

자세한 설명은 다음을 참조하십시오. Point Cloud Capture Process.

Unorganized point cloud

체계화된(organized) 점군을 체계화되지 않은(unorganized) 포인트 클라우드로 변환할 수 있습니다. 이 과정에서 모든 NaN 값이 제거되고 포인트 클라우드를 1차원 배열로 변경합니다.

소스로 이동

source

const auto unorganizedPointCloud = frame.pointCloud().toUnorganizedPointCloud();
소스로 이동

소스

unorganized_point_cloud = frame.point_cloud().to_unorganized_point_cloud()

Combining multiple unorganized point clouds

체계화되지 않은(unorganized) 포인트 클라우드는 추가적인 체계화되지 않은 포인트 클라우드로 확장될 수 있습니다.

소스로 이동

소스

stitchedPointCloud.extend(currentPointCloud.transform(transformationMatrixZivid));
소스로 이동

소스

stitched_point_cloud.extend(current_point_cloud.transform(transformation_matrix))

Copy from GPU to CPU memory

이제 필요한 항목에 따라 데이터를 선택적으로 복사할 수 있습니다. 아래는 출력 데이터 형식의 전체 목록과 GPU에서 복사하는 방법입니다.

Return type

Copy functions

Data per pixel

Total data

Zivid::Array2D<Zivid::PointXYZ>

PointCloud::copyPointsXYZ() 또는 PointCloud::copyData<Zivid::PointXYZ>()

12 bytes

28 MB

Zivid::Array2D<Zivid::PointXYZW>

PointCloud::copyPointsXYZW() 또는 PointCloud::copyData<Zivid::PointXYZW>()

16 bytes

37 MB

Zivid::Array2D<Zivid::PointZ>

PointCloud::copyPointsZ() 또는 PointCloud::copyData<Zivid::PointZ>()

4 bytes

9 MB

Zivid::Array2D<Zivid::ColorRGBA>

PointCloud::copyColorsRGBA() 또는 PointCloud::copyData<Zivid::ColorRGBA>()

4 bytes

9 MB

Zivid::Array2D<Zivid::SNR>

PointCloud::copySNRs() 또는 PointCloud::copyData<Zivid::SNR>()

4 bytes

9 MB

Zivid::Array2D<Zivid::PointXYZColorRGBA>

PointCloud::copyData<PointXYZColorRGBA>()

16 bytes

37 MB

Zivid::Array2D<Zivid::PointXYZColorBGRA>

PointCloud::copyPointsXYZColorsBGRA() 또는 PointCloud::copyData<PointXYZColorBGRA>()

16 bytes

37 MB

Zivid::Image<Zivid::ColorRGBA>

PointCloud::copyImageRGBA()

4 bytes

9 MB

Zivid::Image<Zivid::ColorBGRA>

PointCloud::copyImageBGRA()

4 bytes

9 MB

Zivid::Image<Zivid::ColorsRGB>

PointCloud::copyImagesRGB()

4 bytes

9 MB

Return type

Copy methods

Data per pixel

Total data

float[height,width, 3]

PointCloud.CopyPointsXYZ()

12 bytes

28 MB

float[height,width, 4]

PointCloud.CopyPointsXYZW()

16 bytes

37 MB

float[height,width, 1]

PointCloud.CopyPointsZ()

4 bytes

9 MB

byte[height,width, 4]

PointCloud.CopyColorsRGBA()

4 bytes

9 MB

float[height,width]

PointCloud.CopySNR()

4 bytes

9 MB

Zivid.NET.PointXYZColorRGBA[height,width]

PointCloud.CopyPointsXYZColorsRGBA()

16 bytes

37 MB

Zivid.NET.PointXYZColorBGRA[height,width]

PointCloud.CopyPointsXYZColorsBGRA()

16 bytes

37 MB

Zivid.NET.ImageRGBA

PointCloud.CopyImageRGBA()

4 bytes

9 MB

Zivid.NET.ImageBGRA

PointCloud.CopyImageBGRA()

4 bytes

9 MB

Zivid.NET.ImageSRGB

PointCloud.CopyImageSRGB()

4 bytes

9 MB

Return type

Copy functions

Data per pixel

Total data

numpy.ndarray([height,width, 3], dtype=float32)

PointCloud.copy_data("xyz")

12 bytes

28 MB

numpy.ndarray([height,width, 3], dtype=float32)

PointCloud.copy_data("xyzw")

16 bytes

37 MB

numpy.ndarray([height,width], dtype=float32)

PointCloud.copy_data("z")

4 bytes

9 MB

numpy.ndarray([height,width, 4], dtype=uint8)

PointCloud.copy_data("rgba")

4 bytes

9 MB

numpy.ndarray([height,width, 4], dtype=uint8)

PointCloud.copy_data("bgra")

4 bytes

9 MB

numpy.ndarray([height,width, 4], dtype=uint8)

PointCloud.copy_data("srgb")

4 bytes

9 MB

numpy.ndarray([height,width], dtype=float32)

PointCloud.copy_data("snr")

4 bytes

9 MB

numpy.ndarray([height,width], dtype=[('x', '<f4'), ('y', '<f4'), ('z', '<f4'), (' r', 'u1'), ('g', 'u1'), ('b', 'u1'), ('a', 'u1')])

PointCloud.copy_data("xyzrgba")

16 bytes

37 MB

다음은 데이터를 복사하는 방법의 예입니다.

소스로 이동

소스

const auto data = pointCloud.copyData<Zivid::PointXYZColorRGBA_SRGB>();
소스로 이동

소스

var pointCloudData = pointCloud.CopyPointsXYZColorsRGBA();
소스로 이동

소스

xyz = point_cloud.copy_data("xyz")
rgba = point_cloud.copy_data("rgba_srgb")

Memory allocation options

메모리 할당 측면에서 데이터를 복사하는 두 가지 방법이 있습니다.

  • Zivid SDK는 메모리 버퍼를 할당하고 데이터를 복사할 수 있습니다.

  • 사용자는 사전 할당된 메모리 버퍼에 대한 포인터를 전달할 수 있으며 Zivid SDK는 데이터를 사전 할당된 메모리 버퍼에 복사합니다.

OpenCV를 사용하는 두 가지 메모리 할당 옵션에 대한 예를 제시합니다.

Copy selected data from GPU to CPU memory (Zivid-allocated)

예를 들어 포인트 클라우드의 RGB 색상 데이터는 해당 데이터만 CPU 메모리에 복사할 수 있습니다.

소스로 이동

소스

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

std::cout << "Copying colors with Zivid API from GPU to CPU" << std::endl;
auto colors = frame.frame2D().value().imageBGRA_SRGB();

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_SRGB 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(CI_WAITKEY_TIMEOUT_IN_MS);

Copy selected data from GPU to CPU memory (user-allocated)

위 예에서 데이터의 소유권은 반환된 Zivid::Array2D<> 개체에 의해 유지됩니다. 또는 사전 Zivid::PointCloud::copyData(dataPtr) 에 할당된 메모리 버퍼를 제공할 수 있습니다. dataPtr 의 유형은 복사할 대상을 정의합니다(PointXYZ, ColorRGBA, 등.).

이제 위와 똑같은 사용 사례를 살펴보겠습니다. 그러나 이번에는 OpenCV가 필요한 스토리지를 할당하도록 허용합니다. 그런 다음 GPU에서 이 메모리 위치로 데이터를 직접 복사하도록 Zivid API에 요청합니다.

소스로 이동

소스

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.capture2D3D(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_SRGB>()));

std::cout << "Displaying image" << std::endl;
cv::imshow("BGRA image User Allocated", bgraUserAllocated);
cv::waitKey(CI_WAITKEY_TIMEOUT_IN_MS);

Transform

포인트 클라우드의 원점을 카메라에서 로봇 기본 프레임 또는 예: scale the point cloud by transforming it from mm to m 으로 변경하기 위해 transform 를 원할 수 있습니다.

소스로 이동

소스

pointCloud.transform(baseToCameraTransform);
소스로 이동

소스

pointCloud.Transform(transformBaseToCamera);
소스로 이동

소스

point_cloud.transform(base_to_camera_transform)

Transformation can be done in-place:

  • Zivid::PointCloud::transform()

  • Zivid::UnorganizedPointCloud::transform()

or by creating a new instance:

  • Zivid::PointCloud::transformed()

  • Zivid::UnorganizedPointCloud::transformed()

다음 예제는 변환을 적용하여 Zivid::UnorganizedPointCloud 의 새 인스턴스를 생성하는 방법을 보여줍니다. 이 샘플에서는 변환 후 변환되지 않은 포인트 클라우드가 사용되지 않으므로 새 인스턴스를 생성할 필요가 없습니다.

소스로 이동

source

const auto transformedUnorganizedPointCloud = unorganizedPointCloud.transformed(transformationMatrix);
소스로 이동

소스

transformed_unorganized_point_cloud = unorganized_point_cloud.transformed(transformation_matrix)

제자리 API도 변환된 포인트 클라우드를 반환하므로 아래 예처럼 바로 사용할 수 있습니다.

소스로 이동

소스

stitchedPointCloud.extend(currentPointCloud.transform(transformationMatrixZivid));
소스로 이동

소스

stitched_point_cloud.extend(current_point_cloud.transform(transformation_matrix))

Downsample

때로는 카메라에서 촬영되는 high spatial resolution 와 같은 포인트 클라우드가 필요하지 않을 수 있습니다. 직접 포인트 클라우드를 downsample 할 수 있습니다.

참고

Sampling (3D) 캡처하는 동안 포인트 클라우드의 해상도를 낮추는 동시에 획득 및 캡처 시간을 줄이는 하드웨어 기반 하위/다운샘플링 방법을 설명합니다.

참고

Zivid::UnorganizedPointCloud 는 다운샘플링을 지원하지 않지만, Voxel 다운샘플링은 지원합니다. Voxel downsample 을 참조하세요.

다운샘플링은 현재 포인트 클라우드를 수정하면서 동시에 수행할 수 있습니다.

소스로 이동

소스

pointCloud.downsample(Zivid::PointCloud::Downsampling::by2x2);
소스로 이동

소스

pointCloud.Downsample(Zivid.NET.PointCloud.Downsampling.By2x2);
소스로 이동

source

point_cloud.downsample(zivid.PointCloud.Downsampling.by2x2)

다운샘플링된 포인트 클라우드를 기존 포인트 클라우드를 변경하지 않는 새로운 포인트 클라우드 인스턴스로 얻을 수도 있습니다.

소스로 이동

소스

auto downsampledPointCloud = pointCloud.downsampled(Zivid::PointCloud::Downsampling::by2x2);
소스로 이동

소스

var downsampledPointCloud = pointCloud.Downsampled(Zivid.NET.PointCloud.Downsampling.By2x2);
소스로 이동

source

downsampled_point_cloud = point_cloud.downsampled(zivid.PointCloud.Downsampling.by2x2)

Zivid SDK는 다음과 같은 다운샘플링 속도를 지원합니다. by2x2, by3x3, 그리고 by4x4, 다운샘플링을 여러 번 수행할 수 있습니다.

Voxel downsample

Zivid::UnorganizedPointCloud 는 Voxel 다운샘플링을 지원합니다. 이 API는 두 가지 인수를 사용합니다.

  1. voxelSize - Voxel의 크기(밀리미터)입니다.

  2. minPointsPerVoxel - Voxel당 유지하기 위한 최소 포인트 수입니다.

Voxel 다운샘플링은 3D 공간을 주어진 크기의 입방 Voxel 격자로 세분화합니다. 주어진 Voxel에 주어진 한계 이상의 여러 포인트들이 포함된 경우, 모든 소스 포인트는 다음과 같은 속성을 가진 단일 포인트로 대체됩니다.

  • 위치(XYZ)는 소스 지점 위치의 SNR 가중 평균입니다. 즉, 신뢰도가 높은 소스 지점은 신뢰도가 낮은 소스 지점보다 결과 위치에 더 큰 영향을 미칩니다.

  • 색상(RGBA)은 소스 포인트의 색상의 평균입니다.

  • 신호 대 잡음비(SNR)는 소스 포인트의 SNR 값의 sqrt(SNR^2의 합)입니다. 즉, 새 포인트의 SNR은 위치를 계산하는 데 사용된 소스 포인트의 수와 신뢰도가 높아질수록 증가합니다.

minPointsPerVoxel > 1을 사용하면 여러 각도에서 촬영된 포인트 클라우드의 조합인 비정형 포인트 클라우드에서 노이즈와 아티팩트를 제거하는 데 특히 유용합니다. 특정 아티팩트는 두 캡처 중 하나에만 존재할 가능성이 높기 때문에 minPointsPerVoxel을 사용하면 두 캡처가 “동의하는” Voxel로만 채울 수 있습니다.

소스로 이동

source

const auto finalPointCloud = stitchedPointCloud.voxelDownsampled(0.5, 1);
소스로 이동

소스

final_point_cloud = stitched_point_cloud.voxel_downsampled(0.5, 1)

Normals

일부 어플리케이션에는 포인트 클라우드에서 normals 얻기 위해 컴퓨팅이 필요합니다.

소스로 이동

source

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();
소스로 이동

source

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

Normals API는 포인트 클라우드의 각 지점에서 법선을 계산하고 GPU 메모리에서 CPU 메모리로 법선을 복사합니다. 결과는 입력 포인트 클라우드의 각 포인트에 대해 하나씩, 법선 벡터의 행렬입니다. 법선의 크기는 입력 포인트 클라우드의 크기와 같습니다.

Visualize

프레임이 있으면 포인트 클라우드를 시각화할 수 있습니다.

소스로 이동

소스

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();

자세한 내용은 다음을 확인하세요. Visualization Tutorial, 여기서 우리는 타사 라이브러리를 사용하여 포인트 클라우드, 컬러 이미지, 깊이 맵 및 법선 시각화를 다룹니다.

Conclusion

이 튜토리얼은 Zivid SDK를 사용하여 포인트 클라우드를 추출하고, 조작하고, 변환하고, 시각화하는 방법을 보여줍니다.

Version History

SDK

Changes

2.16.0

Zivid::UnorganizedPointCloud 에 대한 지원이 추가되었습니다. transformedZivid::PointCloud 에 함수로 추가되었습니다(Zivid::UnorganizedPointCloud 에서도 사용 가능).

2.11.0

SRGB 색 공간에 대한 지원이 추가되었습니다.

2.10.0

Monochrome CaptureDownsample 을 대체할 수 있는 보다 빠른 대안을 제공합니다.