Windows10安装PCL1.14.0及点云配准

一、下载visual studio2022

下载网址:Visual Studio: 面向软件开发人员和 Teams 的 IDE 和代码编辑器 (microsoft.com)

安装的时候选择"使用C++的桌面开发“,同时可以修改文件路径,可以放在D盘。修改文件路径的时候,共享组件、工具和SDK的路径无法修改,可能是因为你之前有安装过Visual studio。可以通过以下操作解决:

1.首先WIN+R,输入regedit回车

2.按照这个顺序展开目录

HKEY_LOCAL_MACHINE
SOFTWARE
Microsoft
VisualStudio
Setup

3.右键删除SharedInstallationPath  CachePath,就可以修改共享组件、工具和SDK的路径了

二、安装PCL1.14.0

都是以我自己的安装路径为例

1.下载

官网下载:Releases · PointCloudLibrary/pcl · GitHub

只要下载PCL-1.14.0-AllInOne-msvc2022-win64.exe和pcl-1.14.0-pdb-msvc2022-win64.zip两个文件即可。

如果下载太慢,我这里已经下载好了:

链接:https://pan.baidu.com/s/177DvR5gOcVL7iPm4xI7s_w 
提取码:wstc 

2.安装

点击PCL-1.14.0-AllInOne-msvc2022-win64.exe进行安装

下一步

我接受

选择Add PCL to the system Path for all users,下一步

可以选择修改路径,我自己的路径是C:\Compiler\PCL\PCL 1.14.0,你可以选择自己的路径,不过一定要记得,因为之后配置环境变量要用到,然后下一步

没必要创建快捷方式,下一步,然后点击安装;在安装过程中,会出现提醒你变量名太长,没办法写入环境变量,这个时候你直接确定就行,等安装完成之后,自己配置环境变量。安装完成之后会出现这三个应用

把OpenNi2.2 SDK for Windows 64-bit给卸载掉,因为它有默认安装路径,即使我们修改文件安装路径,它还是安装在默认路径;卸载完之后,打开C:\Compiler\PCL\PCL 1.14.0\3rdParty\OpenNI2文件夹,发现里面有一个OpenNI-Windows-x64-2.2.msi,这是安装PCL-1.14.0-AllInOne-msvc2022-win64.exe的时候附带的,点击安装,可以帮你再次安装OpenNi2.2 SDK for Windows 64-bit,而且可以修改成自己的路径,我的路径是C:\Compiler\PCL\PCL 1.14.0\3rdParty\OpenNI2

安装完成之后就会包含这些内容

接着把pcl-1.14.0-pdb-msvc2022-win64.zip解压

把里面的所有pdb文件都复制到C:\Compiler\PCL\PCL 1.14.0\bin里面

3.配置环境变量

此电脑右键属性

点击高级系统设置

点击环境变量

确保这四个都存在,这是安装PCL-1.14.0-AllInOne-msvc2022-win64.exe的时候自动生成的,接着点击Path开始配置环境变量

C:\Compiler\PCL\PCL 1.14.0\bin
C:\Compiler\PCL\PCL 1.14.0\3rdParty\VTK\bin
C:\Compiler\PCL\PCL 1.14.0\3rdParty\OpenNI2\Tools
C:\Compiler\PCL\PCL 1.14.0\3rdParty\OpenNI2\Redist
C:\Compiler\PCL\PCL 1.14.0\3rdParty\Boost\lib
C:\Compiler\PCL\PCL 1.14.0\3rdParty\Qhull\bin
C:\Compiler\PCL\PCL 1.14.0\3rdParty\FLANN\bin

把这几个路径添加进环境变量即可。

三、创建项目

打开visual studio2022

创建新项目

选择空项目,下一步

可以修改项目名称,和位置;创建项目

右键点击源文件,添加新项,随便取个名字,点击添加(注意:我已经添加过文件了,如果是新创建的文件,源文件里面是啥也没有的)

右键点击解决方案下方的pointCloud(这个是项目名称),点击属性,就会出现这个属性页,点击VC++目录

C:\Compiler\PCL\PCL 1.14.0\3rdParty\Boost\include\boost-1_84
C:\Compiler\PCL\PCL 1.14.0\3rdParty\Eigen3\include\eigen3
C:\Compiler\PCL\PCL 1.14.0\3rdParty\FLANN\include
C:\Compiler\PCL\PCL 1.14.0\3rdParty\Qhull\include
C:\Compiler\PCL\PCL 1.14.0\3rdParty\VTK\include\vtk-9.3
C:\Compiler\PCL\PCL 1.14.0\3rdParty\OpenNI2\Include
C:\Compiler\PCL\PCL 1.14.0\include\pcl-1.14

把这些路径加入到包含目录里

C:\Compiler\PCL\PCL 1.14.0\3rdParty\FLANN\lib
C:\Compiler\PCL\PCL 1.14.0\3rdParty\Boost\lib
C:\Compiler\PCL\PCL 1.14.0\lib
C:\Compiler\PCL\PCL 1.14.0\3rdParty\VTK\lib
C:\Compiler\PCL\PCL 1.14.0\3rdParty\Qhull\lib
C:\Compiler\PCL\PCL 1.14.0\3rdParty\OpenNI2\Lib

这些路径放到库目录里

然后点击C/C++的所有选项,把SDL检查改成否

再点击C/C++的代码生成,修改启用增强指令集为高级适量扩展(X86/X64)(/arch:AVX)

BOOST_USE_WINDOWS_H
NOMINMAX
_CRT_SECURE_NO_DEPRECATE

在C/C++的预处理器里面的预处理定义增加这三行

pcl_commond.lib
pcl_featuresd.lib
pcl_filtersd.lib
pcl_iod.lib
pcl_io_plyd.lib
pcl_kdtreed.lib
pcl_keypointsd.lib
pcl_mld.lib
pcl_octreed.lib
pcl_outofcored.lib
pcl_peopled.lib
pcl_recognitiond.lib
pcl_registrationd.lib
pcl_sample_consensusd.lib
pcl_searchd.lib
pcl_segmentationd.lib
pcl_stereod.lib
pcl_surfaced.lib
pcl_trackingd.lib
pcl_visualizationd.lib
vtkcgns-9.3-gd.lib
vtkChartsCore-9.3-gd.lib
vtkCommonColor-9.3-gd.lib
vtkCommonComputationalGeometry-9.3-gd.lib
vtkCommonCore-9.3-gd.lib
vtkCommonDataModel-9.3-gd.lib
vtkCommonExecutionModel-9.3-gd.lib
vtkCommonMath-9.3-gd.lib
vtkCommonMisc-9.3-gd.lib
vtkCommonSystem-9.3-gd.lib
vtkCommonTransforms-9.3-gd.lib
vtkDICOMParser-9.3-gd.lib
vtkDomainsChemistry-9.3-gd.lib
vtkDomainsChemistryOpenGL2-9.3-gd.lib
vtkdoubleconversion-9.3-gd.lib
vtkexodusII-9.3-gd.lib
vtkexpat-9.3-gd.lib
vtkFiltersAMR-9.3-gd.lib
vtkFiltersCore-9.3-gd.lib
vtkFiltersExtraction-9.3-gd.lib
vtkFiltersFlowPaths-9.3-gd.lib
vtkFiltersGeneral-9.3-gd.lib
vtkFiltersGeneric-9.3-gd.lib
vtkFiltersGeometry-9.3-gd.lib
vtkFiltersHybrid-9.3-gd.lib
vtkFiltersHyperTree-9.3-gd.lib
vtkFiltersImaging-9.3-gd.lib
vtkFiltersModeling-9.3-gd.lib
vtkFiltersParallel-9.3-gd.lib
vtkFiltersParallelImaging-9.3-gd.lib
vtkFiltersPoints-9.3-gd.lib
vtkFiltersProgrammable-9.3-gd.lib
vtkFiltersSelection-9.3-gd.lib
vtkFiltersSMP-9.3-gd.lib
vtkFiltersSources-9.3-gd.lib
vtkFiltersStatistics-9.3-gd.lib
vtkFiltersTexture-9.3-gd.lib
vtkFiltersTopology-9.3-gd.lib
vtkFiltersVerdict-9.3-gd.lib
vtkfmt-9.3-gd.lib
vtkfreetype-9.3-gd.lib
vtkGeovisCore-9.3-gd.lib
vtkgl2ps-9.3-gd.lib
vtkglew-9.3-gd.lib
vtkhdf5-9.3-gd.lib
vtkhdf5_hl-9.3-gd.lib
vtkImagingColor-9.3-gd.lib
vtkImagingCore-9.3-gd.lib
vtkImagingFourier-9.3-gd.lib
vtkImagingGeneral-9.3-gd.lib
vtkImagingHybrid-9.3-gd.lib
vtkImagingMath-9.3-gd.lib
vtkImagingMorphological-9.3-gd.lib
vtkImagingSources-9.3-gd.lib
vtkImagingStatistics-9.3-gd.lib
vtkImagingStencil-9.3-gd.lib
vtkInfovisCore-9.3-gd.lib
vtkInfovisLayout-9.3-gd.lib
vtkInteractionImage-9.3-gd.lib
vtkInteractionStyle-9.3-gd.lib
vtkInteractionWidgets-9.3-gd.lib
vtkIOAMR-9.3-gd.lib
vtkIOAsynchronous-9.3-gd.lib
vtkIOCesium3DTiles-9.3-gd.lib
vtkIOCGNSReader-9.3-gd.lib
vtkIOChemistry-9.3-gd.lib
vtkIOCityGML-9.3-gd.lib
vtkIOCONVERGECFD-9.3-gd.lib
vtkIOCore-9.3-gd.lib
vtkIOEnSight-9.3-gd.lib
vtkIOExodus-9.3-gd.lib
vtkIOExport-9.3-gd.lib
vtkIOExportGL2PS-9.3-gd.lib
vtkIOExportPDF-9.3-gd.lib
vtkIOGeometry-9.3-gd.lib
vtkIOHDF-9.3-gd.lib
vtkIOImage-9.3-gd.lib
vtkIOImport-9.3-gd.lib
vtkIOInfovis-9.3-gd.lib
vtkIOIOSS-9.3-gd.lib
vtkIOLegacy-9.3-gd.lib
vtkIOLSDyna-9.3-gd.lib
vtkIOMINC-9.3-gd.lib
vtkIOMotionFX-9.3-gd.lib
vtkIOMovie-9.3-gd.lib
vtkIONetCDF-9.3-gd.lib
vtkIOOggTheora-9.3-gd.lib
vtkIOParallel-9.3-gd.lib
vtkIOParallelXML-9.3-gd.lib
vtkIOPLY-9.3-gd.lib
vtkIOSegY-9.3-gd.lib
vtkIOSQL-9.3-gd.lib
vtkioss-9.3-gd.lib
vtkIOTecplotTable-9.3-gd.lib
vtkIOVeraOut-9.3-gd.lib
vtkIOVideo-9.3-gd.lib
vtkIOXML-9.3-gd.lib
vtkIOXMLParser-9.3-gd.lib
vtkjpeg-9.3-gd.lib
vtkjsoncpp-9.3-gd.lib
vtkkissfft-9.3-gd.lib
vtklibharu-9.3-gd.lib
vtklibproj-9.3-gd.lib
vtklibxml2-9.3-gd.lib
vtkloguru-9.3-gd.lib
vtklz4-9.3-gd.lib
vtklzma-9.3-gd.lib
vtkmetaio-9.3-gd.lib
vtknetcdf-9.3-gd.lib
vtkogg-9.3-gd.lib
vtkParallelCore-9.3-gd.lib
vtkParallelDIY-9.3-gd.lib
vtkpng-9.3-gd.lib
vtkpugixml-9.3-gd.lib
vtkRenderingAnnotation-9.3-gd.lib
vtkRenderingContext2D-9.3-gd.lib
vtkRenderingContextOpenGL2-9.3-gd.lib
vtkRenderingCore-9.3-gd.lib
vtkRenderingFreeType-9.3-gd.lib
vtkRenderingGL2PSOpenGL2-9.3-gd.lib
vtkRenderingHyperTreeGrid-9.3-gd.lib
vtkRenderingImage-9.3-gd.lib
vtkRenderingLabel-9.3-gd.lib
vtkRenderingLICOpenGL2-9.3-gd.lib
vtkRenderingLOD-9.3-gd.lib
vtkRenderingOpenGL2-9.3-gd.lib
vtkRenderingSceneGraph-9.3-gd.lib
vtkRenderingUI-9.3-gd.lib
vtkRenderingVolume-9.3-gd.lib
vtkRenderingVolumeOpenGL2-9.3-gd.lib
vtkRenderingVtkJS-9.3-gd.lib
vtksqlite-9.3-gd.lib
vtksys-9.3-gd.lib
vtkTestingRendering-9.3-gd.lib
vtktheora-9.3-gd.lib
vtktiff-9.3-gd.lib
vtkverdict-9.3-gd.lib
vtkViewsContext2D-9.3-gd.lib
vtkViewsCore-9.3-gd.lib
vtkViewsInfovis-9.3-gd.lib
vtkWrappingTools-9.3-gd.lib
vtkzlib-9.3-gd.lib

在链接器的输入的附加依赖项里增加这些,配置完成,电脑重启,即可生效

四、点云配准

#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/features/fpfh_omp.h>
#include <pcl/io/ply_io.h>//pcd输入输出头文件
#include <pcl/registration/icp.h>//点云icp算法头文件
#include <pcl/registration/ndt.h>//点云NDT算法头文件
#include <pcl/registration/ia_ransac.h>//点云ransac迭代对齐算法(SAC-IA)算法头文件
#include <pcl/registration/gicp.h>//点云GICP算法的头文件
#include <pcl/visualization/pcl_visualizer.h>//点云可视化头文件
#include <time.h>
#include <boost/thread.hpp>
#include <pcl/features/normal_3d_omp.h>
typedef pcl::PointXYZ PointT; //重定义pcl::PointXYZ为PointT
typedef pcl::PointCloud<PointT> PointCloud; //重定义pcl::PointCloud<PointT>为PointCloud
//点云配准类型
typedef pcl::IterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> ICP;
typedef pcl::NormalDistributionsTransform<pcl::PointXYZ, pcl::PointXYZ> NDT;
typedef pcl::SampleConsensusInitialAlignment<pcl::PointXYZ, pcl::PointXYZ, pcl::FPFHSignature33> SAC_IA;
typedef pcl::GeneralizedIterativeClosestPoint<pcl::PointXYZ, pcl::PointXYZ> GICP;
//FPFH特征
typedef pcl::FPFHEstimationOMP<pcl::PointXYZ, pcl::Normal, pcl::FPFHSignature33> FPFHEstimation;
typedef pcl::PointCloud<pcl::FPFHSignature33> FPFH;
//法线估计
typedef pcl::NormalEstimationOMP<pcl::PointXYZ, pcl::Normal> NormalEstimation;
typedef pcl::PointCloud<pcl::Normal> Normal;
typedef pcl::search::KdTree<pcl::PointXYZ> KdTreeT;

//点云可视化
void visualize_pcd(PointCloud::Ptr pcd_src,
    PointCloud::Ptr pcd_tgt,
    PointCloud::Ptr pcd_final)
{
    pcl::visualization::PCLVisualizer viewer("registration Viewer");
    // 设置背景
    viewer.setBackgroundColor(1, 1, 1);
    // 添加坐标轴到可视化对象,参数指定轴的大小(长度),这里设置为1.0单位长度
    viewer.addCoordinateSystem(0.5);
    // 设置相机位置和方向
    viewer.initCameraParameters();
    pcl::visualization::PointCloudColorHandlerCustom<PointT> src_h(pcd_src, 0, 255, 0);
    pcl::visualization::PointCloudColorHandlerCustom<PointT> tgt_h(pcd_tgt, 255, 0, 0);
    pcl::visualization::PointCloudColorHandlerCustom<PointT> final_h(pcd_final, 0, 0, 255);
    //viewer.addPointCloud(pcd_src, src_h, "source cloud");    //source绿色
    viewer.addPointCloud(pcd_tgt, tgt_h, "tgt cloud");     //target红色
    viewer.addPointCloud (pcd_final, final_h, "final cloud");  //final蓝色

    while (!viewer.wasStopped())
    {
        viewer.spinOnce(100);
        boost::this_thread::sleep(boost::posix_time::microseconds(1000));
    }
}

void printinfo(Eigen::Matrix4f icp_trans, Eigen::Matrix3f rotation, 
    Eigen::Vector3f translation, Eigen::Vector3f euler_angles_deg,
    Eigen::Quaternionf quaternion)
{
    cout.setf(ios::fixed);
    cout.precision(5);
    cout << endl << "Transformation matrix:" << endl << icp_trans << endl;//输出变换矩阵
    cout << endl << "Rotation matrix:" << endl << rotation << endl;
    cout << endl << "Translation vector:" << endl << translation << endl;
    cout << endl << "Euler Angle:" << endl;
    cout << endl << "roll(x):" << euler_angles_deg[2] << endl;
    cout << endl << "pitch(y):" << euler_angles_deg[1] << endl;
    cout << endl << "yaw(z):" << euler_angles_deg[0] << endl;
    // 输出四元数,由于欧拉角时常出现万向节,所以可以使用四元数来表示旋转,这样更精确
    cout << endl <<"Rotation quaternion: " << endl
        << "w = " << quaternion.w() << endl
        << ", x = " << quaternion.x() << endl
        << ", y = " << quaternion.y() << endl
        << ", z = " << quaternion.z() << endl;
}

void downsampling(PointCloud::Ptr cloud_src_o, PointCloud::Ptr cloud_tgt_o,
    pcl::VoxelGrid<pcl::PointXYZ>::Ptr voxel_grid)
{
    float leaf = 0.005f;
    voxel_grid->setLeafSize(leaf, leaf, leaf); // 示例叶子大小
    voxel_grid->setInputCloud(cloud_src_o);
    voxel_grid->filter(*cloud_src_o);
    voxel_grid->setInputCloud(cloud_tgt_o);
    voxel_grid->filter(*cloud_tgt_o);
}
void normalestimation(NormalEstimation ne, Normal::Ptr src_normals, 
    Normal::Ptr tgt_normals, KdTreeT::Ptr tree, 
    PointCloud::Ptr cloud_src_o, PointCloud::Ptr cloud_tgt_o)
{
     创建一个NormalEstimationOMP对象,进行法线计算;
    ne.setSearchMethod(tree);
    ne.setKSearch(20);
    ne.setInputCloud(cloud_src_o);
    ne.compute(*src_normals);
    ne.setInputCloud(cloud_tgt_o);
    ne.compute(*tgt_normals);
    cout << "原点云法线计算完成" << endl <<*src_normals << endl;
    cout << "目标点云法线计算完成" << endl << *tgt_normals << endl;
}

void fpfh_features(FPFHEstimation fpfh, FPFH::Ptr src_fpfhs,
    FPFH::Ptr tgt_fpfhs, PointCloud::Ptr cloud_src_o, 
    PointCloud::Ptr cloud_tgt_o, KdTreeT::Ptr tree, 
    Normal::Ptr src_normals, Normal::Ptr tgt_normals)
{
    fpfh.setSearchMethod(tree);
    fpfh.setRadiusSearch(0.05); // Use a radius search instead of a KdTree search
    fpfh.setInputCloud(cloud_src_o);
    fpfh.setInputNormals(src_normals);
    fpfh.compute(*src_fpfhs);
    fpfh.setInputCloud(cloud_tgt_o);
    fpfh.setInputNormals(tgt_normals);
    fpfh.compute(*tgt_fpfhs);
    cout << "原点云特征计算完成" << *src_fpfhs << endl; 
    cout << "目标点云特征计算完成" << *tgt_fpfhs << endl;
}

GICP& gicp_registration(GICP& gicp, PointCloud& final_cloud,
    PointCloud::Ptr cloud_src_o, PointCloud::Ptr cloud_tgt_o)
{
    gicp.setInputSource(cloud_src_o);
    gicp.setInputTarget(cloud_tgt_o);
    // 配准时最大迭代次数
    gicp.setMaximumIterations(50);
    // 两次变化矩阵之间的差异小于这个阈值时,就认为已经收敛,停止迭代
    gicp.setTransformationEpsilon(1e-6);
    // 对应点之间的最大距离
    gicp.setMaxCorrespondenceDistance(0.05);
    // 采用随机采样一致性方法进行配准
    gicp.setRANSACOutlierRejectionThreshold(1.5);
    // 最小内点比例。在RANSAC配准方法中,当内点的比例小于此值时,认为配准失败。
    gicp.setRANSACIterations(20);
    // 执行配准,并将结果存储在Final中
    gicp.align(final_cloud);
    return gicp;

}
SAC_IA& sacia_registration(SAC_IA & sac_ia, PointCloud& final_cloud,
    PointCloud::Ptr cloud_src_o, PointCloud::Ptr cloud_tgt_o,
    FPFH::Ptr & src_fpfhs, FPFH::Ptr& tgt_fpfhs)
{
    sac_ia.setInputSource(cloud_src_o);
    sac_ia.setSourceFeatures(src_fpfhs);
    sac_ia.setInputTarget(cloud_tgt_o);
    sac_ia.setTargetFeatures(tgt_fpfhs);
    // 设置SAC-IA配准的参数
    sac_ia.setMinSampleDistance(0.05f);
    sac_ia.setMaxCorrespondenceDistance(0.01f);
    sac_ia.setMaximumIterations(500);
    // 创建一个空的PointCloud对象来接收结果
    pcl::PointCloud<pcl::PointXYZ> final_registration;
    // 执行配准,并将结果存储在final_registration中
    sac_ia.align(final_registration);
    return sac_ia;
}
NDT& ndt_registration(NDT & ndt, PointCloud& final_cloud,
    PointCloud::Ptr cloud_src_o, PointCloud::Ptr cloud_tgt_o)
{
    // 配置NDT
    ndt.setTransformationEpsilon(0.1);
    ndt.setStepSize(0.5);
    ndt.setResolution(2.0);
    ndt.setMaximumIterations(20);
    ndt.setInputSource(cloud_src_o);
    ndt.setInputTarget(cloud_tgt_o);
    ndt.align(final_cloud);
    return ndt;
}

ICP& icp_registration(ICP & icp, PointCloud & final_cloud, 
    PointCloud::Ptr cloud_src_o, PointCloud::Ptr cloud_tgt_o)
{
    icp.setMaximumIterations(50);
    // 两次变化矩阵之间的差值
    icp.setTransformationEpsilon(1e-10);
    // 均方误差
    icp.setEuclideanFitnessEpsilon(0.01);
    icp.setInputSource(cloud_src_o);//录入source点云
    icp.setInputTarget(cloud_tgt_o);//录入target点云
    icp.align(final_cloud);//最终配准结果
    return icp;
}
int main(int argc, char** argv)
{
    //加载点云文件
    PointCloud::Ptr cloud_src_o(new pcl::PointCloud<pcl::PointXYZ>);//原点云,待配准
    pcl::io::loadPLYFile("ply/bun_zipper.ply", *cloud_src_o);
    PointCloud::Ptr cloud_tgt_o(new pcl::PointCloud<pcl::PointXYZ>);//目标点云
    pcl::io::loadPLYFile("ply/bun_zipper2.ply", *cloud_tgt_o);
    clock_t start = clock();

    //下采样
    pcl::VoxelGrid<pcl::PointXYZ>::Ptr voxel_grid(new pcl::VoxelGrid<pcl::PointXYZ>);
    downsampling(cloud_src_o, cloud_tgt_o, voxel_grid);


     创建一个NormalEstimationOMP对象,进行法线计算
    NormalEstimation ne;
    Normal::Ptr src_normals(new pcl::PointCloud<pcl::Normal>);
    Normal::Ptr tgt_normals(new pcl::PointCloud<pcl::Normal>);
    KdTreeT::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());
    normalestimation(ne, src_normals, tgt_normals, tree, cloud_src_o, cloud_tgt_o);
    
    //计算FPFH特征
    /*FPFHEstimation fpfh;
    FPFH::Ptr src_fpfhs(new pcl::PointCloud<pcl::FPFHSignature33>());
    FPFH::Ptr tgt_fpfhs(new pcl::PointCloud<pcl::FPFHSignature33>());
    fpfh_features(fpfh, src_fpfhs, tgt_fpfhs, cloud_src_o, cloud_tgt_o, tree, src_normals, tgt_normals);*/


    // 点云配准
    PointCloud::Ptr icp_result(new pcl::PointCloud<pcl::PointXYZ>);
    PointCloud final_cloud;
    ICP icp;
    ICP & reg_p = icp_registration(icp, final_cloud, cloud_src_o, cloud_tgt_o);

    /*NDT ndt;
    NDT & reg_p = ndt_registration(ndt, final_cloud, cloud_src_o, cloud_tgt_o);*/

    /*GICP gicp;
    GICP& reg_p = gicp_registration(gicp, final_cloud, cloud_src_o, cloud_tgt_o);*/

    //SAC_IA sac_ia;
    //SAC_IA& reg_p = sacia_registration(sac_ia, final_cloud, cloud_src_o, cloud_tgt_o, src_fpfhs, tgt_fpfhs);
    clock_t end = clock();
    cout << "total time: " << (double)(end - start) / (double)CLOCKS_PER_SEC << " s" << endl;//输出配准所用时间
    cout << "ICP has converged:" << reg_p.hasConverged() << " score: " << reg_p.getFitnessScore() << std::endl;
    
    Eigen::Matrix4f reg_p_trans;
    // 变换矩阵
    reg_p_trans = reg_p.getFinalTransformation();
    // 平移向量
    Eigen::Vector3f translation = reg_p_trans.block<3, 1>(0, 3);
    // 旋转矩阵
    Eigen::Matrix3f rotation = reg_p_trans.block<3, 3>(0, 0);
    // 转换为四元数
    Eigen::Quaternionf quaternion(rotation);
    // 使用四元数重新计算欧拉角
    Eigen::Vector3f euler_angles_rad = quaternion.toRotationMatrix().eulerAngles(2, 1, 0);
    
     获取欧拉角(弧度)
    //Eigen::Vector3f euler_angles_rad = rotation.eulerAngles(0, 1, 2);
    // 将弧度转换为角度
    Eigen::Vector3f euler_angles_deg = euler_angles_rad * 180.0 / M_PI;
    printinfo(reg_p_trans, rotation, translation, euler_angles_deg, quaternion);
    //使用创建的变换对未过滤的输入点云进行变换
    pcl::transformPointCloud(*cloud_src_o, *icp_result, reg_p_trans);

    visualize_pcd(cloud_src_o, cloud_tgt_o, icp_result);
    return (0);
}

这里面有四种点云配准方法,ICP,NDT,GICP,SAC-IA,其中使用SAC-IA的时候要把fpfh计算的代码解开注释,其他算法使用的时候不需要解开fpfh计算的代码;提醒下,fpfh和SAC-IA计算较为缓慢,出结果需要四五分钟

这份配准所需点云文件链接:

链接:https://pan.baidu.com/s/1QduGSfYcMN2MLRa08e0eSg 
提取码:wstc 

五、未来如果你要用PCL做某些大型项目,可能会遇到 fatal error C1128: 节数超过对象文件格式限制: 请使用 /bigobj 进行编译,这种问题,解决方法:

打开该项目的“属性页”对话框,单击“C/C++”项,单击“命令行”属性页,在“附加选项”框中键入编译器选项,添加 /bigobj,再次编译即可。

在 Visual Studio 中使用 /bigobj 编译选项的主要好处是允许生成更大的对象文件。这是通过扩展 COFF(Common Object File Format)的限制来实现的。以下是 /bigobj 选项的一些具体好处:

  1. 增加节的数量限制: 正常情况下,COFF 格式的对象文件有限制,例如节的数量不能超过 2^16-1(65535)。使用 /bigobj 可以将这个限制提高到 2^32-1(约 4.29 亿),这对于包含大量代码的大型项目非常有用。

  2. 提供更多的符号: 对于有大量符号(例如函数、变量、模板实例化)的代码,/bigobj 也提供了更多的符号支持。

  3. 处理复杂的模板: 使用大量模板特化和模板元编程的 C++ 代码可能会生成非常大的对象文件。/bigobj 让编译器能够处理这些复杂的模板情况。

  4. 适用于大型项目: 对于非常大的项目,尤其是那些有大量源代码文件或者是由多个库组合而成的项目,使用 /bigobj 选项可以避免在编译过程中出现对象文件格式限制的错误。

使用 /bigobj 选项没有显著的缺点,除了可能会增加编译后的对象文件大小。然而,它确实是解决某些大型或复杂项目导致的对象文件格式限制问题的必要手段。如果你的项目没有遇到相关的编译限制问题,那么通常不需要使用这个选项。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/372139.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Web APIs 2 事件

Web APIs 2 事件 事件监听案例&#xff1a;广告关闭案例&#xff1a;随机问答 事件监听版本事件类型案例&#xff1a;轮播图完整焦点事件键盘事件输入事件案例&#xff1a;评论字数统计 事件对象获取事件对象事件对象常用属性案例&#xff1a;评论回车发布 环境对象this回调函数…

电脑怎么扫描纸质文件?6步轻松完成扫描!

“由于工作的需要&#xff0c;我要将部分纸质文件扫描到电脑上&#xff0c;不知道应该怎么操作会更方便呢&#xff1f;希望大家给我出出主意。” 随着科技的进步&#xff0c;电脑已经成为了我们日常生活和工作中不可或缺的工具。除了传统的文字处理和数据处理&#xff0c;电脑还…

【漏洞库】O2OA系统

O2OA invoke 后台远程命令执行漏洞 CNVD-2020-18740 漏洞描述 O2OA是一款开源免费的企业及团队办公平台,提供门户管理、流程管理、信息管理、数据管理四大平台,集工作汇报、项目协作、移动OA、文档分享、流程审批、数据协作等众多功能,满足企业各类管理和协作需求。 O2OA系…

拍摄的视频怎么做二维码?视频在线转二维码的技巧

现在学校经常会将学生日常的拍摄的短片做成二维码之后展示给其他人&#xff0c;其他人可以通过扫描二维码来查看个人表现的视频&#xff0c;有些活动视频也会用视频二维码的方式来传播。那么视频二维码制作的方法及步骤是什么样的呢&#xff1f;下面就让小编通过本文来给大家介…

力扣 121. 买卖股票的最佳时机

题目来源&#xff1a;https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/description/ 好久没写代码了&#xff0c;啥啥都忘了 C题解1&#xff1a;贪心算法。&#xff08;来源代码随想录&#xff09; 因为股票就买卖一次&#xff0c;那么贪心的想法很自然就是取…

读写锁ReentrantReadWriteLockStampLock详解

传送门&#xff1a;深入理解AQS独占锁之ReentrantLock源码分析 目录 读写锁介绍 ReentrantReadWriteLock介绍 ReentrantReadWriteLock的使用 应用场景 锁降级 读写锁设计思路 StampedLock介绍 StampedLock的使用 演示乐观读 在缓存中的应用 使用场景和注意事…

033-安全开发-JavaEE应用SQL预编译Filter过滤器Listener监听器访问控制

033-安全开发-JavaEE应用&SQL预编译&Filter过滤器&Listener监听器&访问控制 #知识点&#xff1a; 1、JavaEE-JDBC-SQL预编译 2、JavaEE-HTTP-Filter过滤器 3、JavaEE-对象域-Listen监听器 演示案例&#xff1a; ➢JavaEE-预编译-SQL ➢JavaEE-过滤器-Filter ➢…

python Cloudflare 批量关闭IPv6兼容性脚本

Cloudflare免费版控制台不给关IPv6&#xff0c;需要使用API关闭&#xff0c;先从我的个人资料里面申请API令牌&#xff0c;再执行脚本 import requests import jsonheaders {X-Auth-Email:cloudflare登入账户, #输入登入账户的邮箱X-Auth-Key: Global API Key, #输入上图申请…

计算机自顶向下 Wireshark labs——DNS

如本文第2.4节所述&#xff0c;域名系统(DNS)将主机名转换为IP地址&#xff0c;在互联网基础设施中发挥着关键作用。在本实验中&#xff0c;我们将仔细研究DNS的客户端。回想一下&#xff0c;客户端在DNS中的角色相对简单—客户端向其本地DNS服务器发送查询&#xff0c;并收到响…

探索设计模式的魅力:从单一继承到组合模式-软件设计的演变与未来

设计模式专栏&#xff1a;http://t.csdnimg.cn/nolNS 在面对层次结构和树状数据结构的软件设计任务时&#xff0c;我们如何优雅地处理单个对象与组合对象的一致性问题&#xff1f;组合模式&#xff08;Composite Pattern&#xff09;为此提供了一种简洁高效的解决方案。通过本…

使用 PyTorch 构建 NLP 聊天机器人

一、说明 聊天机器人提供自动对话&#xff0c;可以帮助用户完成任务或寻求信息。随着深度学习的最新进展&#xff0c;聊天机器人正变得越来越具有对话性和实用性。这个全面的教程将利用 PyTorch 和 Python 从头开始构建聊天机器人&#xff0c;涵盖模型架构、数据准备、训练循环…

【动态规划】【状态压缩】【2次选择】【广度搜索】1494. 并行课程 II

作者推荐 视频算法专题 本文涉及知识点 动态规划汇总 状态压缩 广度优先搜索 LeetCode1494. 并行课程 II 给你一个整数 n 表示某所大学里课程的数目&#xff0c;编号为 1 到 n &#xff0c;数组 relations 中&#xff0c; relations[i] [xi, yi] 表示一个先修课的关系&am…

nginx slice模块的使用和源码分析

文章目录 1. 为什么需要ngx_http_slice_module2. 配置指令3. 加载模块4. 源码分析4.1 指令分析4.2 模块初始化4.3 slice模块的上下文4.2 $slice_range字段值获取4.3 http header过滤处理4.4 http body过滤处理5 测试和验证 1. 为什么需要ngx_http_slice_module 顾名思义&#…

配置Jenkins自动构建打包项目

转载说明&#xff1a;如果您喜欢这篇文章并打算转载它&#xff0c;请私信作者取得授权。感谢您喜爱本文&#xff0c;请文明转载&#xff0c;谢谢。 需求说明 1、给A项目配置jenkins每2小时无条件自动构建一次&#xff0c;无论是否有代码提交。 2、给B项目配置jenkins每15分钟检…

FPGA高端项目:IMX327 MIPI 视频解码 USB3.0 UVC 输出,提供FPGA开发板+2套工程源码+技术支持

目录 1、前言免责声明 2、相关方案推荐我这里已有的 MIPI 编解码方案 3、本 MIPI CSI-RX IP 介绍4、个人 FPGA高端图像处理开发板简介5、详细设计方案设计原理框图IMX327 及其配置MIPI CSI RX图像 ISP 处理图像缓存UVC 时序USB3.0输出架构 6、vivado工程详解FPGA逻辑设计 7、工…

ChatGPT辅助编程,一次有益的尝试

如果大家想学习PCIe&#xff0c;搜索网上的信息&#xff0c;大概率会看到chinaaet上Felix的PCIe扫盲系列的博文 Felix-PCIe扫盲 每次看这个系列博文的时候&#xff0c;我都在想有没有什么方法可以把这个系列的博文都保存到一个pdf文件中&#xff0c;这样方便阅读。于是有了下…

异地办公必不可缺的远程控制软件,原理到底是什么?

目录 引言远程桌面连接软件的作用与重要性 基本概念与架构客户端-服务器模型网络通信协议 核心技术组件图形界面捕获与传输输入转发会话管理 性能优化策略带宽优化延迟优化 引言 远程桌面连接软件的作用与重要性 在当今这个高度数字化和网络化的时代&#xff0c;远程桌面连接软…

R语言学习case10:ggplot基础画图Parallel Coordinate Plot 平行坐标图

step1: 导入ggplot2库文件 library(ggplot2)step2&#xff1a;带入自带的iris数据集 iris <- datasets::irisstep3&#xff1a;查看数据信息 dim(iris)维度为 [150,5] head(iris)查看数据前6行的信息 step4&#xff1a;利用ggplot工具包绘图 plot5 <- ggparcoord(…

Linux目录:traceroute命令

目录 traceroute1、简介2、探测原理3、traceroute说明4、实例设置每跳探测数设置跳数探测包使用的基本UDP端口设置6789把对外发探测包的等待响应时间设置为3秒 总结 traceroute 1、简介 traceroute的主要功能是跟踪从IP网络发送到指定主机经过的网关的工具。它利用IP协议的生…

npm淘宝镜像源换新地址

新的淘宝npm镜像源地址&#xff1a;https://registry.npmmirror.com 切换新的镜像源 npm config set registry https://registry.npmmirror.com然后再执行以下操作查看是否成功 npm config list如果没安装过淘宝镜像源的&#xff0c;则直接安装 npm install -g cnpm --regi…