网上教程很少,但是想用PCL GPU功能,于是决定自己踩坑,我有几个不同的环境组合:
(1)win10+cuda10.0+vs2019+PCL1.11.1+cmake3.18.5(失败)
(2)win10+cuda11.2+vs2019+PCL1.11.1+cmake3.18.5(成功)
(3)win11+cuda11.2+vs2019+PCL1.11.1+cmake3.18.5(未测,应该和2类似)
参考教程:Win10+VS2019编译PCL库1.12.0(含gpu)_pcl编译_番茄V王子的博客-CSDN博客
基础配置:
(1)环境变量:以下变量不必补全所有的变量,缺啥补啥即可
这里用到了PCL官方下载的PCL-1.11.1-AllInOne-msvc2019-win64.exe或者PCL-1.13.1-AllInOne-msvc2022-win64.exe;
类似教程中的,添加EIGEN_ROOT、EIGEN_INCLUDE_DIR、BOOST_ROOT、BOOST_INCLUDEDIR、BOOST_LIBRARYDIR、FLANN_INCLUDE_DIR、FLANN_LIBRARY、FLANN_LIBRARY_DEBUG、VTK_DIR、QHULL_INCLUDE_DIR、QHULL_LIBRARY、QHULL_LIBRARY_DEBUG
(2)cmake-gui设置
首先关于boost的警告我们忽略,保证能够Configuring done即可;
WITH_CUDA、BUILD_CUDA、BUILD_GPU勾选,点一次Configuring;
再勾选我们后面可能会使用到的BUILD_cuda_io、BUILD_gpu_surface,点一次Configuring;
CMAKE_INSTALL_PREFIX选择你希望生成的路径,将关于Anaconda找到的依赖库PNG、ZLIB的路径都删除,点一次Configuring;
然后Generate和Open Project,在VS中选择Release,然后ALL_BUILD,最后INSTALL;
第一次尝试(失败):使用环境(1)
原因是对于PCL1.11.1来说cuda10.0版本太低。
第二次尝试(成功):使用环境(2)
期间报了几个错误:
(1)openni检查MSVC版本,如下图,我这里宏的值为1929,于是后续我改成1929即可;
(2)eigen的cuda的报错,上述参考教程中也提到了,但是我只报了一处错误,改成如下图就好了;
(3)一些关于gpu_kinfu的错误,忘记截图了,查了一下是kinect fusion算法相关的东西,暂时没用到,所以cmake-gui里面把相关去掉,再重新编译;
(4) 一些关于openni的报错,忘记截图了,从报错信息看的出是openni出的问题,我想着我也没用这玩意,干脆在cmake-gui里面把它两的勾去掉,再重新编译;
然后就成功编译完成未有任何报错;
最后来运行一下PCL GPU程序:
CMakeLists.txt内容为:
cmake_minimum_required(VERSION 3.1...3.20)
add_compile_options("/std:c++17")
project(pcl_gpu_test)
#pcl
set(PCL_ROOT D:/soft/PCL/PCL_1.11.1_GPU/install)
find_package(PCL 1.11 REQUIRED)
include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})
#message(STATUS "PCL include path is: " ${PCL_INCLUDE_DIRS})
#message(STATUS "PCL lib path is: " ${PCL_LIBRARIES})
#include_directories(./include)
FILE(GLOB CPP_FILE0 ${PROJECT_SOURCE_DIR}/src/*.cpp)
add_executable(pcl_gpu_test0 ${CPP_FILE0})
target_link_libraries(pcl_gpu_test0 ${PCL_LIBRARIES})
main.cpp为:
#include <iostream>
#include <string>
#include <pcl/PointIndices.h>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/io/obj_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/segmentation/extract_clusters.h>
#include <pcl/gpu/octree/octree.hpp>
#include <pcl/gpu/containers/device_array.hpp>
#include <pcl/gpu/segmentation/gpu_extract_clusters.h>
#include <pcl/gpu/segmentation/impl/gpu_extract_clusters.hpp>
int main()
{
//例子参考https://zhuanlan.zhihu.com/p/258780417
using namespace std;
string obj_path = R"(F:\temp\test.ply)";
using T = pcl::PointXYZ;
pcl::PointCloud<T>::Ptr cldPtr(new pcl::PointCloud<T>);
pcl::io::loadPLYFile(obj_path, *cldPtr);
double radius = 20.0;
int minSize = 1;
int maxSize = INT_MAX;
//cpu欧式聚类
std::vector<pcl::PointIndices> cluster_indices_cpu;
{
typename pcl::search::KdTree<T>::Ptr tree(new pcl::search::KdTree<T>);
tree->setInputCloud(cldPtr);
pcl::EuclideanClusterExtraction<T> ec;
ec.setClusterTolerance(radius); //设置近邻搜索的搜索半径
ec.setMinClusterSize(minSize);//设置一个聚类需要的最少点数目
ec.setMaxClusterSize(maxSize); //设置一个聚类需要的最大点数目
ec.setSearchMethod(tree);//设置点云的搜索机制
ec.setInputCloud(cldPtr);
ec.extract(cluster_indices_cpu);//从点云中提取聚类,并将点云索引保存在cluster_indices中
}
cout << "cpu 计算结果:" << endl;
for (int i = 0; i < (int)cluster_indices_cpu.size(); ++i)
{
cout << cluster_indices_cpu[i].indices.size() << endl;
}
//gpu欧式聚类
std::vector<pcl::PointIndices> cluster_indices_gpu;
{
pcl::gpu::Octree::PointCloud cldPtr_gpu;
cldPtr_gpu.upload(cldPtr->points);
pcl::gpu::Octree::Ptr octree_gpu(new pcl::gpu::Octree);
octree_gpu->setCloud(cldPtr_gpu);
octree_gpu->build();
pcl::gpu::EuclideanClusterExtraction gec;
gec.setClusterTolerance(radius);
gec.setMinClusterSize(minSize);
gec.setMaxClusterSize(maxSize);
gec.setSearchMethod(octree_gpu);
gec.setHostCloud(cldPtr);
gec.extract(cluster_indices_gpu);
}
std::sort(cluster_indices_gpu.begin(), cluster_indices_gpu.end(), [](const pcl::PointIndices& a, const pcl::PointIndices& b)
{return a.indices.size() < b.indices.size(); });//cluster_indices_gpu是未排序的
cout << "gpu 计算结果:" << endl;
for (int i = 0; i < (int)cluster_indices_gpu.size(); ++i)
{
cout << cluster_indices_gpu[i].indices.size() << endl;
}
return 0;
}
最后我这个例子中结果是一致的,但是!!!我如果把参数radius改成10.0,发现结果不一致,具体原因不知为何。