Implementação do Algoritmo ICP para Alinhamento de Nuvens de Pontos

O algoritmo Iterativo de Pontos Mais Próximos (ICP) é um método de otimização iterativa utilizado para registrar duas nuvens de pontos, minimizando a distância entre pontos correspondentes. Dado um conjunto de pontos de origem A e um conjunto de pontos de destino B, o objetivo do ICP é encontrar a matriz de rotação R e o vetor de translação t que transformam A para alinhar-se com B com maior precisão. Devido à sua simplicidade e alta acurácia, o ICP é amplamente empregado em registro local.

O algoritmo segue um processo iterativo que se repete até a convergência:

  • Para cada ponto no conjunto A, identificar o ponto correspondente mais próximo no conjunto B.
  • Calcular a transformação rígida (rotação e translação) que minimize a soma das distâncias quadradas entre os pares correspondentes.
  • Aplicar a transformação ao conjunto A, obtendo um novo conjunto transformado.
  • Se a distância média entre o novo conjunto transformado e B for menor que um limiar pré-definido, encerrar; caso contrário, usar o novo conjunto como entrada para a próxima iteração.

A etapa mais demorada é encontrar os pontos mais próximos. Para eficiência, estruturas como kd-tree são utilizadas para acelerar a busca. A kd-tree organiza os pontos em uma estrutura de árvore binária baseada na divisão espacial, permitindo consultas rápidas de vizinhos próximos.

Para resolver a transformação rígida, métodos baseados em Decomposição em Valores Singluares (SVD) são comuns. O procedimento envolve centralizar os conjuntos de pontos, calcular a matriz de covariância, e aplicar SVD para obter a rotação e translação ótimas.

Exemplo em C++ com Eigen

O código a seguir demonstra uma implementação simplificada do ICP usando a biblioteca Eigen para operações lineares. As variáveis e estruturas foram renomeadas para clareza.

#include <Eigen/Dense>
#include <vector>

void alignPointClouds(const std::vector<Eigen::Vector3f>& source_points,
                      const std::vector<Eigen::Vector3f>& target_points,
                      Eigen::Matrix3f& rotation_matrix,
                      Eigen::Vector3f& translation_vector) {
    int num_points = source_points.size();
    Eigen::Vector3f source_center = Eigen::Vector3f::Zero();
    Eigen::Vector3f target_center = Eigen::Vector3f::Zero();

    // Calcular centros de massa
    for (int i = 0; i < num_points; ++i) {
        source_center += source_points[i];
        target_center += target_points[i];
    }
    source_center /= num_points;
    target_center /= num_points;

    // Centralizar pontos
    std::vector<Eigen::Vector3f> centered_source(num_points), centered_target(num_points);
    for (int i = 0; i < num_points; ++i) {
        centered_source[i] = source_points[i] - source_center;
        centered_target[i] = target_points[i] - target_center;
    }

    // Construir matriz de correlação
    Eigen::Matrix3f correlation_matrix = Eigen::Matrix3f::Zero();
    for (int i = 0; i < num_points; ++i) {
        correlation_matrix += centered_target[i] * centered_source[i].transpose();
    }

    // Decomposição SVD
    Eigen::JacobiSVD<Eigen::Matrix3f> svd(correlation_matrix, Eigen::ComputeFullU | Eigen::ComputeFullV);
    Eigen::Matrix3f U = svd.matrixU();
    Eigen::Matrix3f V = svd.matrixV();

    // Calcular rotação e translação
    rotation_matrix = V * U.transpose();
    translation_vector = target_center - rotation_matrix * source_center;
}

int main() {
    // Dados de teste simplificados
    std::vector<Eigen::Vector3f> source_pts = { {1.0f, 0.0f, 0.0f}, {0.0f, 1.0f, 0.0f} };
    std::vector<Eigen::Vector3f> target_pts = { {0.0f, -1.0f, 0.0f}, {1.0f, 0.0f, 0.0f} };

    Eigen::Matrix3f R;
    Eigen::Vector3f t;
    alignPointClouds(source_pts, target_pts, R, t);

    // Saída dos resultados
    // ...
    return 0;
}

Utilizando a Biblioteca PCL

A Point Cloud Library (PCL) fornece uma implementação otimizada do ICP. O exemplo abaixo configura e executa o algoritmo, alterando nomes de variáveis e parâmetros para ilustração.

#include <pcl/point_types.h>
#include <pcl/registration/icp.h>
#include <pcl/io/pcd_io.h>

int main() {
    // Carregar nuvens de pontos (exemplo simplificado)
    pcl::PointCloud<pcl::PointXYZ>::Ptr input_cloud(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointCloud<pcl::PointXYZ>::Ptr reference_cloud(new pcl::PointCloud<pcl::PointXYZ>);

    // Preencher dados (omitido para brevidade)
    // ...

    // Configurar parâmetros do ICP
    pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> icp_solver;
    icp_solver.setInputSource(input_cloud);
    icp_solver.setInputTarget(reference_cloud);
    icp_solver.setMaxCorrespondenceDistance(0.1);
    icp_solver.setMaximumIterations(100);
    icp_solver.setTransformationEpsilon(1e-6);
    icp_solver.setEuclideanFitnessEpsilon(0.01);

    // Executar registro
    pcl::PointCloud<pcl::PointXYZ> aligned_output;
    icp_solver.align(aligned_output);

    // Verificar convergência
    if (icp_solver.hasConverged()) {
        Eigen::Matrix4f final_transformation = icp_solver.getFinalTransformation();
        // Usar a transformação...
    }

    return 0;
}

Para compilar este código, é necessário configurar o ambiente com as bibliotecas Eigen e PCL, incluindo os cabeçalhos e links adequados no sistema de build.

Tags: ICP point cloud registration SVD Eigen PCL

Publicado em 7-13 07:55