Stitch by Transform Tutorial

이 튜토리얼에서는 여러 대의 카메라를 서로 보정한 결과를 사용하는 방법을 설명합니다. 다중 카메라 변환 결과는 한 포인트 클라우드를 다른 포인트 클라우드의 좌표계로 변환하는 데 사용할 수 있는 변환 행렬입니다. 이는 포인트 클라우드를 연결하는 데 매우 유용한 첫 단계입니다.

Prerequisites

이 튜토리얼을 진행하기 전에 Multi-Camera Calibration Tutorial 를 완료해야 합니다.

연관된 변환 행렬을 로드하고 포인트 클라우드에 매핑합니다.

올바른 변환 행렬을 적용하려면 해당 프레임에 매핑해야 합니다. 카메라에서 직접 캡처할 때는 카메라의 일련 번호를 사용하고, 파일에서 불러올 때는 ZDF 프레임의 일련 번호를 사용합니다. 카메라의 일련 번호나 ZDF 파일의 일련 번호를 사용할 때는 YAML 파일 이름과 정확히 일치하는 것을 찾습니다.

변환 행렬을 포인트 클라우드에 매핑하는 방식은 카메라에서 직접 촬영하는 방식이나 파일에서 불러오는 방식과 매우 유사합니다. 가장 큰 차이점은 카메라로 촬영할 때는 일련 번호에 접근하여 해당 이름의 YAML 파일을 검색한다는 것입니다. 그런 다음 카메라에 변환 행렬을 매핑합니다.

소스로 이동

source

const auto transformsMappedToCameras =
    getTransformationMatricesFromYAML(transformationMatricesfileList, connectedCameras);
소스로 이동

소스

transforms_mapped_to_cameras = get_transformation_matrices_from_yaml(args.yaml_files, connected_cameras)

반면, ZDF 파일에서 로드할 때는 파일 목록에서 ZDF 파일을 찾아 프레임에서 해당 파일의 일련 번호를 추출해야 합니다. 그런 다음, 동일한 파일 목록에서 해당 일련 번호를 이름으로 사용하는 YAML 파일을 검색합니다. 그런 다음 변환 행렬을 프레임에 매핑합니다. getTransformedPointClouds 에서 변환을 적용하고, 정리되지 않은 포인트 클라우드를 바로 확장합니다.

소스로 이동

소스

Zivid::UnorganizedPointCloud getTransformedPointClouds(
    Zivid::UnorganizedPointCloud stitchedPointCloud;
                Zivid::Matrix4x4 transformationMatrixZivid(yamlFileName);
                Zivid::UnorganizedPointCloud currentPointCloud = frame.pointCloud().toUnorganizedPointCloud();
                stitchedPointCloud.extend(currentPointCloud.transform(transformationMatrixZivid));
소스로 이동

소스

def get_transformed_point_clouds(
    stitched_point_cloud = zivid.UnorganizedPointCloud()
        transformation_matrix = zivid.Matrix4x4(yaml_file)
        current_point_cloud = frame.point_cloud().to_unorganized_point_cloud()
        stitched_point_cloud.extend(current_point_cloud.transform(transformation_matrix))

변환 행렬을 적용하고 변환된 포인트 클라우드를 이전 포인트 클라우드와 연결합니다.

변환 행렬을 사용하여 캡처를 매핑했습니다. 이제 변환하고 스티칭할 준비가 되었습니다.

캡처한 뒤 transformsMappedToCameras 에서 transform 을 추출할 수 있습니다. 각 캡처마다 정리되지 않은 포인트 클라우드를 변환하고 확장합니다.

소스로 이동

source

for(auto &camera : connectedCameras)
{
    const auto settingsPath = std::string(ZIVID_SAMPLE_DATA_DIR) + "/Settings/" + sanitizedModelName(camera)
                              + "_ManufacturingSpecular.yml";
    std::cout << "Imaging from camera: " << camera.info().serialNumber() << std::endl;
    const auto frame = camera.capture2D3D(Zivid::Settings(settingsPath));
    const auto unorganizedPointCloud = frame.pointCloud().toUnorganizedPointCloud();
    const auto transformationMatrix = transformsMappedToCameras.at(camera.info().serialNumber().toString());
    const auto transformedUnorganizedPointCloud = unorganizedPointCloud.transformed(transformationMatrix);
    stitchedPointCloud.extend(transformedUnorganizedPointCloud);
}
소스로 이동

소스

for camera in connected_cameras:
    settings_path = (
        get_sample_data_path()
        / "Settings"
        / f"{camera.info.model_name.replace('2+', 'Two_Plus').replace('2', 'Two').replace('3', 'Three').replace(' ', '_')}_ManufacturingSpecular.yml"
    )
    print(f"Imaging from camera: {camera.info.serial_number}")
    frame = camera.capture(zivid.Settings.load(settings_path))
    unorganized_point_cloud = frame.point_cloud().to_unorganized_point_cloud()
    transformation_matrix = transforms_mapped_to_cameras[camera.info.serial_number]
    transformed_unorganized_point_cloud = unorganized_point_cloud.transformed(transformation_matrix)
    stitched_point_cloud.extend(transformed_unorganized_point_cloud)

Voxel downsample

시각화하기 전에 스티칭된 포인트 클라우드를 정리합니다.

소스로 이동

source

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

소스

final_point_cloud = stitched_point_cloud.voxel_downsampled(0.5, 1)

여기서는 0.5mm의 복셀 크기를 요청합니다. 두 번째 매개변수는 두 대 이상의 카메라가 관련된 경우 유용합니다. 이 경우 픽셀 내에서 다수결 투표를 하는 데 사용할 수 있습니다. 자세한 내용은 Voxel downsample 을 참조하세요.

Visualize

We use the Zivid::Visualization::Visualizer to visualize the stitched point cloud.

소스로 이동

source

void visualizePointCloud(const Zivid::UnorganizedPointCloud &unorganizedPointCloud)
{
    Zivid::Visualization::Visualizer visualizer;

    visualizer.showMaximized();
    visualizer.show(unorganizedPointCloud);
    visualizer.resetToFit();

    std::cout << "Running visualizer. Blocking until window closes." << std::endl;
    visualizer.run();
}

Save stitched point cloud

마지막으로 선택적으로 포인트 클라우드를 저장할 수 있습니다.

소스로 이동

source

const std::string &fileName = stitchedPointCloudFileName;
std::cout << "Saving " << finalPointCloud.size() << " data points to " << fileName << std::endl;

using PLY = Zivid::Experimental::PointCloudExport::FileFormat::PLY;
const auto colorSpace = Zivid::Experimental::PointCloudExport::ColorSpace::sRGB;
Zivid::Experimental::PointCloudExport::exportUnorganizedPointCloud(
    finalPointCloud, PLY{ fileName, PLY::Layout::unordered, colorSpace });
소스로 이동

source

print(f"Saving {len(final_point_cloud.size())} data points to {args.output_file}")
export_unorganized_point_cloud(
    final_point_cloud, PLY(args.output_file, layout=PLY.Layout.unordered, color_space=ColorSpace.srgb)
)