课题研究需要super4pcs算法复现,网上找了一轮发现大部分是基于Ubuntu系统的复现,csdn上一位博主做了在vs2019上复现super4pcs的工作:
点云全局配准复现——Super4pcs实现_小修勾的博客-CSDN博客
写的很详细,但是最后一些地方讲的不是很清楚,这里我也是花了一些功夫才最终成功,这里主要根据是上面这篇博客,写一篇文章记录下来,对这个复现工作做一个补充整合。
(1)VS2019(别的版本没有用过)
(2)PCL1.11.1
(3)cmake 3.24
关于如何安装配置vs2019以及PCL1.11.1,网站上有很多详细教程在此不再赘述。
cmake安装可参考以下这位博主的文章:
Windows下Cmake安装步骤详解(图文)_L_Li_L的博客-CSDN博客_windows安装cmake
(1)相关原代码:
super4pcs原有的github目前已经不再维护了,原作者将super4pcs的内容与PCL等库做了结合,命名为OpenGR,github地址如下:
GitHub - STORM-IRIT/OpenGR: OpenGR: A C++ library for 3D Global Registration
(2)主要流程
首先在上面的github地址中下载源码的zip文件,解压
解压后的文件夹如下所示
其中3rdparty里的happly和stb是空的,需要在刚才的github上另外下载下来解压到对应文件夹中
在此处下载happly和stb的zip文件并解压到对应文件夹中:
解压完后如下两图所示
happly:
stb:
接下来是cmake的步骤,先在OpenGR文件夹下的install文件夹下新建两个文件夹,分别命名为build和install
然后运行cmake,将红圈处的两个路径设置为刚刚安装好的OpenGR的位置以及OpenGR中build文件的位置,记得勾选下方的Grouped
然后点击下方的Generate,会跳出如下界面,按图中方式填写,然后Finish
此时再点击configure,等待进度满后出现如下界面,
此时勾选Advanced,界面变为
将Ungrouped Entries中的EIFGEN3——INCLUDE DIR项的内容改为自己PCL库中eigen库的位置(其实就是和上面那行的内容一样,可以直接复制)
然后取消勾选Advanced,再将CMAKE下的CMAKE_INSTALL_PREFIX项中的内容改为刚才创建的install文件夹的路径
最后点击generate,至此cmake步骤完成。
双击运行刚刚创建的build文件夹下的 OpenGR.sln项目文件
修改上面的模式为Release,x64模式
接下来分别右击ALL_ BUILD和INSTALL,点击里面的生成
完成后,install文件夹下就会生成以下几个文件
首先新建VS2019的空项目,选择与PCL库安装时相符的模式(debug64或release64),打开视图——其他窗口——属性管理器,在对应的模式下右击添加PCL库的属性表(安装PCL库时已经提前保存好,不清楚可以去看相关教程),这里之前我碰到了一个疑问,当时安装PCL库时用的是Debug版本,而原博主使用的时Release版本,我本身也是个小白,因此担心会遇到问题,实际操作后没有遇到问题成功实现了算法,所以这两种版本应该都可以。
添加PCL库的属性表后,新建一个属性表命名为super4PCS
双击这个属性表进行配置
在VC ++目录中,点击包含目录——编辑,在其中添加之前创建的install文件夹下的include文件的路径
同样的, 点击库目录——编辑,在其中添加install文件夹下lib文件的路径
然后点击确定,最后将新建的这个super4PCS属性表保存到合适的位置,以后每次运行super4pcs算法需要添加这个属性表,因此要记住保存到了哪里。
接下来,在此电脑——属性——高级系统设置——环境变量——系统变量中,双击Path
在其中添加install文件夹下bin文件的路径
到此配置工作就完成了。
在之前新建的空项目中测试的代码(如果要重新新建项目,记得要添加PCL属性表和之前创建保存好的super4PCS属性表),其实与PCL库下实现的4PCS的代码基本一样,不过需要先添加以下三个头文件:
#include
#include
#include
我的具体测试代码如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud PointCloud;
void visualize_pcd(PointCloud::Ptr pcd_src, PointCloud::Ptr pcd_tgt, PointCloud::Ptr pcd_final)
{
pcl::visualization::PCLVisualizer viewer1("registration Viewer1");
pcl::visualization::PCLVisualizer viewer2("registration Viewer2");
//原始点云绿色
pcl::visualization::PointCloudColorHandlerCustom src_h(pcd_src, 0, 255, 0);
//目标点云红色
pcl::visualization::PointCloudColorHandlerCustom tgt_h(pcd_tgt, 255, 0, 0);
//匹配好的点云绿色
pcl::visualization::PointCloudColorHandlerCustom final_h(pcd_final, 0, 255, 0);
viewer1.addCoordinateSystem(5.0);
viewer2.addCoordinateSystem(5.0);
viewer1.setBackgroundColor(0, 0, 0);
viewer2.setBackgroundColor(0, 0, 0);
viewer1.addPointCloud(pcd_src, src_h, "source cloud");
viewer1.addPointCloud(pcd_tgt, tgt_h, "target cloud");
viewer2.addPointCloud(pcd_final, final_h, "result cloud");
viewer2.addPointCloud(pcd_tgt, tgt_h, "target cloud");
while (!viewer1.wasStopped())
{
viewer1.spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
}
int main(int argc, char** argv)
{
//加载点云文件
PointCloud::Ptr cloud_source(new PointCloud);
PointCloud::Ptr cloud_target0(new PointCloud);
PointCloud::Ptr cloud_target(new PointCloud);
//std::string filename = "point_source/hippo1-1224_s100.pcd";//
std::string filename = "100bun045-100.pcd";//
if (pcl::io::loadPCDFile(filename, *cloud_source) == -1)//*打开点云文件
{
PCL_ERROR("Couldn't read file source\n");
return(-1);
}
std::string filename2 = "100bun045-100.pcd";//
if (pcl::io::loadPCDFile(filename2, *cloud_target0) == -1)//*打开点云文件
{
PCL_ERROR("Couldn't read file source\n");
return(-1);
}
Eigen::Matrix4f tras0 = Eigen::Matrix4f::Identity();
// 定义旋转矩阵,绕y轴
float theta = M_PI / 4; // 旋转弧度 45°
tras0(0, 0) = cos(theta);
tras0(0, 2) = sin(theta);
tras0(2, 0) = -sin(theta);
tras0(2, 2) = cos(theta);
// 定义在x轴上的平移
tras0(0, 3) = 2.5;
//定义在y轴上的平移
tras0(1, 3) = 0;
//定义在z轴上的平移
tras0(2, 3) = 5;
cout << "tars0matrix:" << endl << tras0 << endl;
pcl::transformPointCloud(*cloud_target0, *cloud_target, tras0);
//四点法配准
PointCloud::Ptr pcs(new PointCloud);
pcl::Super4PCSsfpcs;
sfpcs.setInputSource(cloud_source);
sfpcs.setInputTarget(cloud_target);
sfpcs.setOverlap(0.5);
sfpcs.setDelta(0.08);//增量
sfpcs.setMaxTimeSeconds(500);//最大计算时间
//sfpcs.setSampleSize(paraD);//采样点
Eigen::Matrix4f tras;
clock_t start = clock();
sfpcs.align(*pcs);
clock_t end = clock();
cout << "time:" << (double)(end - start) / (double)CLOCKS_PER_SEC << endl;
cout << "score:" << sfpcs.getFitnessScore() << endl;
tras = sfpcs.getFinalTransformation();
cout << "matrix:" << endl << tras << endl << endl << endl;
//for (int i = 0; i < 20; i++)//for循环20次用于查看多次实验下的不同结果
//{
// clock_t start = clock();
// fpcs.align(*pcs);
// clock_t end = clock();
// cout << "time:" << (double)(end - start) / (double)CLOCKS_PER_SEC << endl;
// cout << "score:" << fpcs.getFitnessScore() << endl;
// tras = fpcs.getFinalTransformation();
// cout << "matrix:" << endl << tras << endl << endl << endl;
//}
PointCloud::Ptr cloud_end(new PointCloud);
pcl::transformPointCloud(*cloud_source, *cloud_end, tras);
visualize_pcd(cloud_source, cloud_target, cloud_end);
return (0);
}
所用的点云数据类型为pcd
若出现如下报错:error C1128:字节数超过对象文件格式main.cpp限制:请使用/bigobj进行编译
可参考这篇博客里的办法:
error C1128:字节数超过对象文件格式main.cpp限制:请使用/bigobj进行编译_熊L的博客-CSDN博客_字节数超过对象文件格式限制
配准结果:
配准前:
配准后: