// M063.3D.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。 // #include "pch.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // TicToc #include #include #include #include #include // 相机内参 const double camera_factor = 0.0002; const double camera_cx = 0; const double camera_cy = 0; const double camera_fx = 0.015; const double camera_fy = 0.015; bool next_iteration; #define PointT pcl::PointXYZ; void print4x4Matrix(const Eigen::Matrix4d & matrix) { printf("Rotation matrix :\n"); printf(" | %6.3f %6.3f %6.3f | \n", matrix(0, 0), matrix(0, 1), matrix(0, 2)); printf("R = | %6.3f %6.3f %6.3f | \n", matrix(1, 0), matrix(1, 1), matrix(1, 2)); printf(" | %6.3f %6.3f %6.3f | \n", matrix(2, 0), matrix(2, 1), matrix(2, 2)); printf("Translation vector :\n"); printf("t = < %6.3f, %6.3f, %6.3f >\n\n", matrix(0, 3), matrix(1, 3), matrix(2, 3)); } void keyboardEventOccurred(const pcl::visualization::KeyboardEvent& event, void* nothing) { if (event.getKeySym() == "space" && event.keyDown()) next_iteration = true; } void getFiles1(const std::string &path, std::vector& files) { //文件句柄 //long hFile = 0; //win7 intptr_t hFile = 0; //win10 //文件信息 struct _finddata_t fileinfo; std::string p; if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1) // "\\*"是指读取文件夹下的所有类型的文件,若想读取特定类型的文件,以png为例,则用“\\*.png” { do { //如果是目录,迭代之 //如果不是,加入列表 if ((fileinfo.attrib & _A_SUBDIR)) { if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0) getFiles1(p.assign(path).append("\\").append(fileinfo.name), files); } else { files.push_back(path + "\\" + fileinfo.name); } } while (_findnext(hFile, &fileinfo) == 0); _findclose(hFile); } } void string_replace(std::string &strBig, const std::string &strsrc, const std::string &strdst) { std::string::size_type pos = 0; std::string::size_type srclen = strsrc.size(); std::string::size_type dstlen = strdst.size(); while ((pos = strBig.find(strsrc, pos)) != std::string::npos) { strBig.replace(pos, srclen, strdst); pos += dstlen; } } void step1(std::string &fileName) { cv::Mat depth; depth = cv::imread(fileName, cv::ImreadModes::IMREAD_ANYDEPTH); pcl::PointCloud::Ptr cloud(new pcl::PointCloud); // 遍历深度图 for (int m = 0; m < depth.rows; m += 4) for (int n = 0; n < depth.cols; n += 4) { // 获取深度图中(m,n)处的值 ushort d = depth.ptr(m)[n]; // d 可能没有值,若如此,跳过此点 if (d == 0) continue; // d 存在值,则向点云增加一个点 pcl::PointXYZ p; // 计算这个点的空间坐标 p.z = double(d) * camera_factor; p.x = n * camera_fx; p.y = m * camera_fy; // 把p加入到点云中 cloud->points.push_back(p); } // 设置并保存点云 cloud->height = 1; cloud->width = cloud->points.size(); cout << "point cloud size = " << cloud->points.size() << endl; cloud->is_dense = false; string_replace(fileName, ".tif", ".pcd"); pcl::io::savePCDFile(fileName, *cloud); // 清除数据并退出 cloud->points.clear(); cout << "Point cloud saved." << endl; } void step2() { std::string fileName1 = "D:\\calibration_3d_0331_2\\5_T.pcd"; std::string fileName2 = "D:\\calibration_3d_0331_2\\6.pcd"; std::string outFileName = "D:\\calibration_3d_0331_2\\6_T.pcd"; // Set initial alignment estimate found using robot odometry. Eigen::AngleAxisf init_rotation(0, Eigen::Vector3f::UnitZ()); Eigen::Translation3f init_translation(-200, 0, 0); Eigen::Matrix4f init_guess = (init_translation * init_rotation).matrix(); pcl::PointCloud::Ptr target_cloud(new pcl::PointCloud); if (pcl::io::loadPCDFile(fileName1, *target_cloud) == -1) { PCL_ERROR("Couldn't read file 1 \n"); return; } std::cout << "Loaded " << target_cloud->size() << " data points from "<< fileName1 << std::endl; // Loading second scan of room from new perspective. pcl::PointCloud::Ptr input_cloud(new pcl::PointCloud); if (pcl::io::loadPCDFile(fileName2, *input_cloud) == -1) { PCL_ERROR("Couldn't read file 2.pcd \n"); return; } std::cout << "Loaded " << input_cloud->size() << " data points from" << fileName2 << std::endl; // ===================================删除离群点=====================================// //// Create the filtering object //pcl::StatisticalOutlierRemoval sor; //sor.setMeanK(50);//50个临近点 //sor.setStddevMulThresh(1.0);//距离大于1倍标准方差 //sor.setInputCloud(target_cloud); //sor.filter(*target_cloud); //sor.setInputCloud(input_cloud); //sor.filter(*input_cloud); //=================================================================================// // Filtering input scan to roughly 10% of original size to increase speed of registration. pcl::PointCloud::Ptr filtered_cloud(new pcl::PointCloud); pcl::ApproximateVoxelGrid approximate_voxel_filter; approximate_voxel_filter.setLeafSize(0.8, 0.8, 0.8); approximate_voxel_filter.setInputCloud(input_cloud); approximate_voxel_filter.filter(*filtered_cloud); std::cout << "Filtered cloud contains " << filtered_cloud->size() << " data points from "<< fileName2 << std::endl; //pcl::CropBox cropBox; //cropBox.setMin(Eigen::Vector4f(20, 0, 0, 1.0)); //cropBox.setMax(Eigen::Vector4f(50, 250, 30, 1.0)); //cropBox.setInputCloud(filtered_cloud); //cropBox.filter(*filtered_cloud); // Initializing Normal Distributions Transform (NDT). pcl::NormalDistributionsTransform ndt; // Setting scale dependent NDT parameters // Setting minimum transformation difference for termination condition. ndt.setTransformationEpsilon(0.01); // Setting maximum step size for More-Thuente line search. ndt.setStepSize(1); //Setting Resolution of NDT grid structure (VoxelGridCovariance). ndt.setResolution(1); // Setting max number of registration iterations. ndt.setMaximumIterations(100); // Setting point cloud to be aligned. ndt.setInputSource(filtered_cloud); // Setting point cloud to be aligned to. ndt.setInputTarget(target_cloud); // Calculating required rigid transform to align the input cloud to the target cloud. pcl::PointCloud::Ptr output_cloud(new pcl::PointCloud); ndt.align(*output_cloud, init_guess); std::cout << "Normal Distributions Transform has converged:" << ndt.hasConverged() << " score: " << ndt.getFitnessScore() << std::endl; print4x4Matrix(ndt.getFinalTransformation().cast()); // Transforming unfiltered, input cloud using found transform. pcl::transformPointCloud(*input_cloud, *output_cloud, ndt.getFinalTransformation()); // Saving transformed input cloud. pcl::io::savePCDFile(outFileName, *output_cloud); // Initializing point cloud visualizer pcl::visualization::PCLVisualizer::Ptr viewer_final(new pcl::visualization::PCLVisualizer("3D Viewer")); viewer_final->setBackgroundColor(0, 0, 0); // Coloring and visualizing target cloud (red). pcl::visualization::PointCloudColorHandlerCustom target_color(target_cloud, 255, 0, 0); viewer_final->addPointCloud(target_cloud, target_color, "target cloud"); viewer_final->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "target cloud"); // Coloring and visualizing transformed input cloud (green). pcl::visualization::PointCloudColorHandlerCustom output_color(output_cloud, 0, 255, 0); viewer_final->addPointCloud(output_cloud, output_color, "output cloud"); viewer_final->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "output cloud"); // Starting visualizer viewer_final->addCoordinateSystem(1.0, "global"); viewer_final->initCameraParameters(); // Wait until visualizer window is closed. while (!viewer_final->wasStopped()) { viewer_final->spinOnce(100); boost::this_thread::sleep(boost::posix_time::microseconds(100000)); } } void step3() { pcl::PointCloud::Ptr target_cloud(new pcl::PointCloud); if (pcl::io::loadPCDFile("D:\\Images\\1.pcd", *target_cloud) == -1) { PCL_ERROR("Couldn't read file 1.pcd \n"); return; } std::cout << "Loaded " << target_cloud->size() << " data points from 1.pcd" << std::endl; // Loading second scan of room from new perspective. pcl::PointCloud::Ptr input_cloud(new pcl::PointCloud); if (pcl::io::loadPCDFile("D:\\Images\\2.pcd", *input_cloud) == -1) { PCL_ERROR("Couldn't read file 2.pcd \n"); return; } std::cout << "Loaded " << input_cloud->size() << " data points from 2.pcd" << std::endl; // ===================================删除离群点=====================================// // Create the filtering object pcl::StatisticalOutlierRemoval sor; sor.setMeanK(50);//50个临近点 sor.setStddevMulThresh(1.0);//距离大于1倍标准方差 sor.setInputCloud(target_cloud); sor.filter(*target_cloud); sor.setInputCloud(input_cloud); sor.filter(*input_cloud); //=================================================================================// // Filtering input scan to roughly 10% of original size to increase speed of registration. pcl::PointCloud::Ptr filtered_cloud(new pcl::PointCloud); pcl::ApproximateVoxelGrid approximate_voxel_filter; approximate_voxel_filter.setLeafSize(0.8, 0.8, 0.8); approximate_voxel_filter.setInputCloud(input_cloud); approximate_voxel_filter.filter(*filtered_cloud); std::cout << "Filtered cloud contains " << filtered_cloud->size() << " data points from 2.pcd" << std::endl; pcl::CropBox cropBox; cropBox.setMin(Eigen::Vector4f(15, 0, 0, 1.0)); cropBox.setMax(Eigen::Vector4f(40, 250, 30, 1.0)); cropBox.setInputCloud(filtered_cloud); cropBox.filter(*filtered_cloud); int iterations = 1; // Set initial alignment estimate found using robot odometry. Eigen::AngleAxisd init_rotation(0, Eigen::Vector3d::UnitZ()); Eigen::Translation3d init_translation(41, 0, 2); Eigen::Matrix4d init_guess = (init_translation * init_rotation).matrix(); pcl::PointCloud::Ptr testCloud(new pcl::PointCloud); pcl::transformPointCloud(*filtered_cloud, *testCloud, init_guess); // The Iterative Closest Point algorithm pcl::IterativeClosestPoint icp; pcl::console::TicToc time; time.tic(); icp.setMaximumIterations(1); icp.setInputSource(testCloud); icp.setInputTarget(target_cloud); pcl::PointCloud::Ptr output_cloud(new pcl::PointCloud); icp.align(*output_cloud); std::cout << "Applied " << iterations << " ICP iteration(s) in " << time.toc() << " ms" << std::endl; Eigen::Matrix4d finalMat; if (icp.hasConverged()) { std::cout << "\nICP has converged, score is " << icp.getFitnessScore() << std::endl; std::cout << "\nICP transformation " << iterations << " : cloud_icp -> cloud_in" << std::endl; finalMat = init_guess * icp.getFinalTransformation().cast(); pcl::transformPointCloud(*filtered_cloud, *output_cloud, finalMat); } else { PCL_ERROR("\nICP has not converged.\n"); return; } // Visualization pcl::visualization::PCLVisualizer viewer("ICP demo"); // Create two vertically separated viewports int v1(0); int v2(1); viewer.createViewPort(0.0, 0.0, 0.5, 1.0, v1); viewer.createViewPort(0.5, 0.0, 1.0, 1.0, v2); // The color we will be using float bckgr_gray_level = 0.0; // Black float txt_gray_lvl = 1.0 - bckgr_gray_level; // Original point cloud is white pcl::visualization::PointCloudColorHandlerCustom cloud_target_color_h(target_cloud, 255 ,255 ,255); viewer.addPointCloud(target_cloud, cloud_target_color_h, "cloud_in_v1", v1); viewer.addPointCloud(target_cloud, cloud_target_color_h, "cloud_in_v2", v2); // Transformed point cloud is green pcl::visualization::PointCloudColorHandlerCustom cloud_input_color_h(input_cloud, 20, 180, 20); viewer.addPointCloud(input_cloud, cloud_input_color_h, "cloud_tr_v1", v1); // ICP aligned point cloud is red pcl::visualization::PointCloudColorHandlerCustom cloud_output_color_h(output_cloud, 180, 20, 20); viewer.addPointCloud(output_cloud, cloud_output_color_h, "cloud_icp_v2", v2); // Adding text descriptions in each viewport viewer.addText("White: Original point cloud\nGreen: Matrix transformed point cloud", 10, 15, 16, txt_gray_lvl, txt_gray_lvl, txt_gray_lvl, "icp_info_1", v1); viewer.addText("White: Original point cloud\nRed: ICP aligned point cloud", 10, 15, 16, txt_gray_lvl, txt_gray_lvl, txt_gray_lvl, "icp_info_2", v2); std::stringstream ss; ss << iterations; std::string iterations_cnt = "ICP iterations = " + ss.str(); viewer.addText(iterations_cnt, 10, 60, 16, txt_gray_lvl, txt_gray_lvl, txt_gray_lvl, "iterations_cnt", v2); // Set background color viewer.setBackgroundColor(bckgr_gray_level, bckgr_gray_level, bckgr_gray_level, v1); viewer.setBackgroundColor(bckgr_gray_level, bckgr_gray_level, bckgr_gray_level, v2); // Set camera position and orientation viewer.setCameraPosition(-3.68332, 2.94092, 5.71266, 0.289847, 0.921947, -0.256907, 0); viewer.setSize(1280, 1024); // Visualiser window size // Register keyboard callback : viewer.registerKeyboardCallback(&keyboardEventOccurred, (void*)NULL); // Display the visualiser while (!viewer.wasStopped()) { viewer.spinOnce(); // The user pressed "space" : if (next_iteration) { // The Iterative Closest Point algorithm time.tic(); icp.setInputSource(output_cloud); icp.setInputTarget(target_cloud); icp.align(*output_cloud); std::cout << "Applied 1 ICP iteration in " << time.toc() << " ms" << std::endl; if (icp.hasConverged()) { //printf("\033[11A"); // Go up 11 lines in terminal output. printf("\nICP has converged, score is %+.0e\n", icp.getFitnessScore()); std::cout << "\nICP transformation " << ++iterations << " : cloud_icp -> cloud_in" << std::endl; finalMat *= icp.getFinalTransformation().cast(); // WARNING /!\ This is not accurate! For "educational" purpose only! print4x4Matrix(finalMat); // Print the transformation between original pose and current pose ss.str(""); ss << iterations; std::string iterations_cnt = "ICP iterations = " + ss.str(); viewer.updateText(iterations_cnt, 10, 60, 16, txt_gray_lvl, txt_gray_lvl, txt_gray_lvl, "iterations_cnt"); viewer.updatePointCloud(output_cloud, cloud_output_color_h, "cloud_icp_v2"); } else { PCL_ERROR("\nICP has not converged.\n"); return; } } next_iteration = false; } } void step4() { pcl::PointCloud::Ptr target_cloud(new pcl::PointCloud); pcl::PointCloud::Ptr cloud_inliner(new pcl::PointCloud); pcl::PointCloud::Ptr cloud_outliner(new pcl::PointCloud); if (pcl::io::loadPCDFile("D:\\Images\\1.pcd", *target_cloud) == -1) { PCL_ERROR("Couldn't read file 1.pcd \n"); return; } std::cout << "Loaded " << target_cloud->size() << " data points from 1.pcd" << std::endl; // Create the filtering object pcl::StatisticalOutlierRemoval sor; sor.setInputCloud(target_cloud); sor.setMeanK(50);//50个临近点 sor.setStddevMulThresh(1.0);//距离大于1倍标准方差 sor.filter(*cloud_inliner); // Initializing point cloud visualizer pcl::visualization::PCLVisualizer::Ptr viewer_final(new pcl::visualization::PCLVisualizer("3D Viewer")); viewer_final->setBackgroundColor(0, 0, 0); // Coloring and visualizing target cloud (red). pcl::visualization::PointCloudColorHandlerCustom target_color(target_cloud, 255, 0, 0); viewer_final->addPointCloud(cloud_inliner, target_color, "target cloud"); viewer_final->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "target cloud"); // Coloring and visualizing transformed input cloud (green). /*pcl::visualization::PointCloudColorHandlerCustom output_color(output_cloud, 0, 255, 0); viewer_final->addPointCloud(output_cloud, output_color, "output cloud"); viewer_final->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "output cloud");*/ // Starting visualizer viewer_final->addCoordinateSystem(1.0, "global"); viewer_final->initCameraParameters(); // Wait until visualizer window is closed. while (!viewer_final->wasStopped()) { viewer_final->spinOnce(100); boost::this_thread::sleep(boost::posix_time::microseconds(100000)); } } int main() { std::vector files; getFiles1("D:\\1", files); for (int i = 0; i < files.size(); i++) { step1(files[i]); } return (0); } // 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单 // 调试程序: F5 或调试 >“开始调试”菜单 // 入门提示: // 1. 使用解决方案资源管理器窗口添加/管理文件 // 2. 使用团队资源管理器窗口连接到源代码管理 // 3. 使用输出窗口查看生成输出和其他消息 // 4. 使用错误列表窗口查看错误 // 5. 转到“项目”>“添加新项”以创建新的代码文件,或转到“项目”>“添加现有项”以将现有代码文件添加到项目 // 6. 将来,若要再次打开此项目,请转到“文件”>“打开”>“项目”并选择 .sln 文件