GO-ICP的使用(一)

一、代码下载以、修改以及使用

下载:

链接:yangjiaolong/Go-ICP: Implementation of the Go-ICP algorithm for globally optimal 3D pointset registration (github.com)

解压之后 :

首先visual studio项目,配置好PCL环境;首先把上述图片中看得到的以cpp、h、hpp结尾的文件全都放入你的项目中就行了。

其中pointTypeTrans.h和pointTypeTrans.cpp是我为了可视化新建的文件 ,源文件里面并没有。

修改 :

由于该代码运行时可能会出现重定义的情况,你需要修改定义,源码有可视化程序,不过是用matlab进行可视化,代码就在demo文件夹下,我这里修改了下,使得程序可以直接进行可视化

 1、重定义修改

matrix.h把这行注释掉,或者重定义成另一个名字,不过重定义成另一个新名字之后,要把matrix.h和matrix.cpp的所有引用原来的名字的地方都改成新名字

matrix.h把这两行重定义成另一个名字FLOAT2,不过重定义成FLOAT2之后,要把matrix.h和matrix.cpp的所有引用FLOAT的地方都改成FLOAT2

2、可视化的修改

pointTypeTrans.h

#ifndef POINTTYPETRANS_H
#define POINTTYPETRANS_H
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <sstream>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>
#include <pcl/console/parse.h>
#include <pcl/console/print.h>
#include <pcl/io/ply_io.h>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/common/transforms.h>
typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<PointT> PloudCloud;
struct Vertex {float x, y, z;
};
class PointTypeTrans
{
public:PointTypeTrans();void writePLYHeader(std::ofstream& ply_file, int num_points);void writePCDHeader(std::ofstream& pcdFile, int vertexCount);int txtToPly(const std::string txt_filename, const std::string ply_filename);int plyTotxt(const std::string ply_filename, const std::string txt_filename);int txtToPcd(const std::string txt_filename, const std::string pcd_filename);int pcdTotxt(const std::string pcd_filename, const std::string txt_filename);int txtToObj(const std::string txt_filename, const std::string obj_filename);int objTotxt(const std::string obj_filename, const std::string txt_filename);int plyToPcd(const std::string plyFilename, const std::string pcdFilename);int pcdToPly(const std::string pcdFilename, const std::string plyFilename);int plyToObj(const std::string plyFilename, const std::string objFilename);int objToPly(const std::string objFilename, const std::string plyFilename);int pcdToObj(const std::string pcdFilename, const std::string objFilename);int objToPcd(const std::string objFilename, const std::string pcdFilename);void view_display(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_target, pcl::PointCloud<pcl::PointXYZ>::Ptr result);void format_selection(std::string& suffix, int flag, std::string& file);~PointTypeTrans();};#endif // !POINTTYPETRANS_H

pointTypeTrans.cpp

#include "pointTypeTrans.h"PointTypeTrans::PointTypeTrans()
{}void PointTypeTrans::writePLYHeader(std::ofstream& ply_file, int num_points)
{ply_file << "ply\n";ply_file << "format ascii 1.0\n";ply_file << "element vertex " << num_points << "\n";ply_file << "property float x\n";ply_file << "property float y\n";ply_file << "property float z\n";ply_file << "end_header\n";
}void PointTypeTrans::writePCDHeader(std::ofstream& pcdFile, int vertexCount)
{pcdFile << "# .PCD v0.7 - Point Cloud Data file format\n";pcdFile << "VERSION 0.7\n";pcdFile << "FIELDS x y z\n";pcdFile << "SIZE 4 4 4\n";pcdFile << "TYPE F F F\n";pcdFile << "COUNT 1 1 1\n";pcdFile << "WIDTH " << vertexCount << "\n";pcdFile << "HEIGHT 1\n";pcdFile << "VIEWPOINT 0 0 0 1 0 0 0\n";pcdFile << "POINTS " << vertexCount << "\n";pcdFile << "DATA ascii\n";
}
//1
int PointTypeTrans::txtToPly(const std::string txt_filename, const std::string ply_filename)
{if (strcmp(txt_filename.substr(txt_filename.size() - 4, 4).c_str(), ".txt") != 0)return 0;if (strcmp(ply_filename.substr(ply_filename.size() - 4, 4).c_str(), ".ply") != 0)return 0;std::ifstream txt_file(txt_filename);std::ofstream ply_file(ply_filename);if (!txt_file.is_open() || !ply_file.is_open()) {std::cerr << "Error opening files!" << std::endl;return 0;}int num_points;txt_file >> num_points;// Write the PLY headerwritePLYHeader(ply_file, num_points);// Write the point datafloat x, y, z;for (int i = 0; i < num_points; ++i) {txt_file >> x >> y >> z;ply_file << x << " " << y << " " << z << "\n";}// Clean uptxt_file.close();ply_file.close();std::cout << "Conversion from TXT to PLY completed successfully." << std::endl;return 1;
}//2
int PointTypeTrans::plyTotxt(const std::string ply_filename, const std::string txt_filename)
{if (strcmp(txt_filename.substr(txt_filename.size() - 4, 4).c_str(), ".txt") != 0)return 0;if (strcmp(ply_filename.substr(ply_filename.size() - 4, 4).c_str(), ".ply") != 0)return 0;std::ifstream ply_file(ply_filename);std::ofstream txt_file(txt_filename);if (!ply_file.is_open() || !txt_file.is_open()) {std::cerr << "Error opening files!" << std::endl;return 0;}std::string line;int num_points = 0;bool header_ended = false;// Read the PLY header to find the number of vertex elementswhile (getline(ply_file, line)) {std::istringstream iss(line);std::string token;iss >> token;if (token == "element") {iss >> token; // This should be "vertex"if (token == "vertex") {iss >> num_points;}}else if (token == "end_header") {header_ended = true;break;}}if (!header_ended) {std::cerr << "Could not find the end of the header." << std::endl;return 0;}// Write the number of points to the TXT filetxt_file << num_points << std::endl;// Read and write the point datafloat x, y, z;for (int i = 0; i < num_points; ++i) {ply_file >> x >> y >> z;txt_file << x << " " << y << " " << z << std::endl;}// Clean upply_file.close();txt_file.close();std::cout << "Conversion from PLY to TXT completed successfully." << std::endl;return 1;
}//3
int PointTypeTrans::txtToPcd(const std::string txt_filename, const std::string pcd_filename)
{if (strcmp(txt_filename.substr(txt_filename.size() - 4, 4).c_str(), ".txt") != 0)return 0;if (strcmp(pcd_filename.substr(pcd_filename.size() - 4, 4).c_str(), ".pcd") != 0)return 0;std::ifstream txt_file(txt_filename);std::ofstream pcd_file(pcd_filename);if (!txt_file.is_open() || !pcd_file.is_open()) {std::cerr << "Error opening files!" << std::endl;return 0;}// Read the number of points from the first line of the TXT fileint num_points;txt_file >> num_points;// Write the PCD headerwritePCDHeader(pcd_file, num_points);// Read and write the point datafloat x, y, z;for (int i = 0; i < num_points; ++i) {txt_file >> x >> y >> z;pcd_file << x << " " << y << " " << z << "\n";}// Clean uptxt_file.close();pcd_file.close();std::cout << "Conversion from TXT to PCD completed successfully." << std::endl;return 1;
}
//4
int PointTypeTrans::pcdTotxt(const std::string pcd_filename, const std::string txt_filename)
{if (strcmp(txt_filename.substr(txt_filename.size() - 4, 4).c_str(), ".txt") != 0)return 0;if (strcmp(pcd_filename.substr(pcd_filename.size() - 4, 4).c_str(), ".pcd") != 0)return 0;std::ifstream pcd_file(pcd_filename);std::ofstream txt_file(txt_filename);if (!pcd_file.is_open() || !txt_file.is_open()) {std::cerr << "Error opening files!" << std::endl;return 0;}std::string line;int num_points = 0;bool headerPassed = false;// Skip the PCD headerwhile (std::getline(pcd_file, line)) {std::stringstream ss(line);std::string firstWord;ss >> firstWord;// Check for lines starting with "POINTS"if (firstWord == "POINTS") {ss >> num_points;}// Check for the end of the header, which is marked as "DATA"if (firstWord == "DATA") {headerPassed = true;break;}}// If we didn't reach the end of the header, exitif (!headerPassed) {std::cerr << "PCD header not found or improper format." << std::endl;return 0;}// Write the number of points to the TXT filetxt_file << num_points << "\n";// Read and write the point datafloat x, y, z;while (pcd_file >> x >> y >> z) {txt_file << x << " " << y << " " << z << "\n";}// Clean uppcd_file.close();txt_file.close();std::cout << "Conversion from PCD to TXT completed successfully." << std::endl;return 1;
}
//5
int PointTypeTrans::txtToObj(const std::string txt_filename, const std::string obj_filename)
{if (strcmp(txt_filename.substr(txt_filename.size() - 4, 4).c_str(), ".txt") != 0)return 0;if (strcmp(obj_filename.substr(obj_filename.size() - 4, 4).c_str(), ".obj") != 0)return 0;std::ifstream txt_file(txt_filename);std::ofstream obj_file(obj_filename);if (!txt_file.is_open() || !obj_file.is_open()) {std::cerr << "Error opening files!" << std::endl;return 0;}// Optional: Read the number of points if it's providedint num_points;txt_file >> num_points;// Write vertices to the OBJ filefloat x, y, z;while (txt_file >> x >> y >> z) {obj_file << "v " << x << " " << y << " " << z << "\n";}// Clean uptxt_file.close();obj_file.close();std::cout << "Conversion from TXT to OBJ completed successfully." << std::endl;return 1;
}
//6
int PointTypeTrans::objTotxt(const std::string obj_filename, const std::string txt_filename)
{if (strcmp(txt_filename.substr(txt_filename.size() - 4, 4).c_str(), ".txt") != 0)return 0;if (strcmp(obj_filename.substr(obj_filename.size() - 4, 4).c_str(), ".obj") != 0)return 0;std::ifstream obj_file(obj_filename);std::ofstream txt_file(txt_filename);if (!obj_file.is_open() || !txt_file.is_open()) {std::cerr << "Error opening files!" << std::endl;return 0;}std::vector<Vertex> vertices;std::string line;// Process each line of the OBJ filewhile (std::getline(obj_file, line)) {// Skip empty lines and commentsif (line.empty() || line[0] == '#') continue;std::stringstream ss(line);std::string prefix;ss >> prefix;// Store vertex data if the line starts with 'v'if (prefix == "v") {Vertex vertex;ss >> vertex.x >> vertex.y >> vertex.z;vertices.push_back(vertex);}}// First write the total number of verticestxt_file << vertices.size() << std::endl;// Then write all verticesfor (const auto& vertex : vertices) {txt_file << vertex.x << " " << vertex.y << " " << vertex.z << std::endl;}// Clean upobj_file.close();txt_file.close();std::cout << "Conversion from OBJ to TXT completed successfully." << std::endl;return 1;
}
//7
int PointTypeTrans::plyToPcd(const std::string plyFilename, const std::string pcdFilename)
{if (strcmp(plyFilename.substr(plyFilename.size() - 4, 4).c_str(), ".ply") != 0)return 0;if (strcmp(pcdFilename.substr(pcdFilename.size() - 4, 4).c_str(), ".pcd") != 0)return 0;std::ifstream plyFile(plyFilename);std::ofstream pcdFile(pcdFilename);if (!plyFile.is_open() || !pcdFile.is_open()) {std::cerr << "Error opening files!" << std::endl;return 0;}std::vector<Vertex> points;std::string line;bool headerPassed = false;int vertexCount = 0;while (std::getline(plyFile, line)) {std::stringstream ss(line);if (line == "end_header") {headerPassed = true;continue;}if (!headerPassed) {if (line.substr(0, 14) == "element vertex") {ss >> line >> line >> vertexCount; // Read vertex count}// Skip header linescontinue;}else {// Read point dataVertex point;if (ss >> point.x >> point.y >> point.z) {points.push_back(point);}}}// Write PCD headerwritePCDHeader(pcdFile, vertexCount);// Write point data to PCD filefor (const auto& point : points) {pcdFile << point.x << " " << point.y << " " << point.z << "\n";}plyFile.close();pcdFile.close();std::cout << "Conversion from PLY to PCD completed successfully." << std::endl;return 1;
}
//8
int PointTypeTrans::pcdToPly(const std::string pcdFilename, const std::string plyFilename)
{if (strcmp(plyFilename.substr(plyFilename.size() - 4, 4).c_str(), ".ply") != 0)return 0;if (strcmp(pcdFilename.substr(pcdFilename.size() - 4, 4).c_str(), ".pcd") != 0)return 0;std::ifstream pcdFile(pcdFilename);std::ofstream plyFile(plyFilename);if (!pcdFile.is_open() || !plyFile.is_open()) {std::cerr << "Error opening files!" << std::endl;return 0;}std::vector<Vertex> points;std::string line;int pointCount = 0;bool dataSection = false;// Parse PCD filewhile (std::getline(pcdFile, line)) {std::stringstream ss(line);if (line.substr(0, 6) == "POINTS") {ss >> line >> pointCount;}else if (line.substr(0, 4) == "DATA") {dataSection = true;continue;}if (dataSection) {Vertex point;if (ss >> point.x >> point.y >> point.z) {points.push_back(point);}}}// Write PLY headerwritePLYHeader(plyFile, pointCount);// Write points to PLY filefor (const auto& point : points) {plyFile << point.x << " " << point.y << " " << point.z << "\n";}pcdFile.close();plyFile.close();std::cout << "Conversion from PCD to PLY completed successfully." << std::endl;return 1;
}
//9
int PointTypeTrans::plyToObj(const std::string plyFilename, const std::string objFilename)
{if (strcmp(plyFilename.substr(plyFilename.size() - 4, 4).c_str(), ".ply") != 0)return 0;if (strcmp(objFilename.substr(objFilename.size() - 4, 4).c_str(), ".obj") != 0)return 0;std::ifstream plyFile(plyFilename);std::ofstream objFile(objFilename);if (!plyFile.is_open() || !objFile.is_open()) {std::cerr << "Error opening files!" << std::endl;return 0;}std::vector<Vertex> vertices;std::string line;int vertexCount = 0;bool inHeader = true;// Process PLY headerwhile (inHeader && std::getline(plyFile, line)) {std::istringstream iss(line);std::string token;iss >> token;if (token == "element") {iss >> token;if (token == "vertex") {iss >> vertexCount;}}else if (token == "end_header") {inHeader = false;}}// Process vertex datawhile (vertexCount > 0 && std::getline(plyFile, line)) {std::istringstream iss(line);Vertex vertex;iss >> vertex.x >> vertex.y >> vertex.z;vertices.push_back(vertex);--vertexCount;}// Write to OBJ filefor (const Vertex& vertex : vertices) {objFile << "v " << vertex.x << " " << vertex.y << " " << vertex.z << std::endl;}plyFile.close();objFile.close();std::cout << "Conversion from PLY to OBJ completed successfully." << std::endl;return 1;
}//10
int PointTypeTrans::objToPly(const std::string objFilename, const std::string plyFilename)
{if (strcmp(plyFilename.substr(plyFilename.size() - 4, 4).c_str(), ".ply") != 0)return 0;if (strcmp(objFilename.substr(objFilename.size() - 4, 4).c_str(), ".obj") != 0)return 0;std::ifstream objFile(objFilename);std::ofstream plyFile(plyFilename);if (!objFile.is_open() || !plyFile.is_open()) {std::cerr << "Error opening files!" << std::endl;return 0;}std::vector<Vertex> vertices;std::string line;// Process OBJ filewhile (std::getline(objFile, line)) {if (line.empty() || line[0] == '#') continue;std::istringstream iss(line);std::string prefix;iss >> prefix;if (prefix == "v") {Vertex vertex;iss >> vertex.x >> vertex.y >> vertex.z;vertices.push_back(vertex);}}// Write PLY headerwritePLYHeader(plyFile, vertices.size());// Write vertex data to PLY filefor (const Vertex& vertex : vertices) {plyFile << vertex.x << " " << vertex.y << " " << vertex.z << "\n";}objFile.close();plyFile.close();std::cout << "Conversion from OBJ to PLY completed successfully." << std::endl;return 1;
}//11
int PointTypeTrans::pcdToObj(const std::string pcdFilename, const std::string objFilename)
{if (strcmp(pcdFilename.substr(pcdFilename.size() - 4, 4).c_str(), ".pcd") != 0)return 0;if (strcmp(objFilename.substr(objFilename.size() - 4, 4).c_str(), ".obj") != 0)return 0;std::ifstream pcdFile(pcdFilename);std::ofstream objFile(objFilename);if (!pcdFile.is_open() || !objFile.is_open()) {std::cerr << "Error opening files!" << std::endl;return 0;}std::vector<Vertex> vertices;std::string line;int pointsCount = 0;bool isDataSection = false;// Read PCD headerwhile (std::getline(pcdFile, line)) {std::stringstream ss(line);std::string keyword;ss >> keyword;if (keyword == "POINTS") {ss >> pointsCount;}else if (keyword == "DATA" && line.find("ascii") != std::string::npos) {isDataSection = true;break; // Stop reading header lines after "DATA"}}// Read PCD data pointswhile (isDataSection && pointsCount > 0 && std::getline(pcdFile, line)) {std::stringstream ss(line);Vertex vertex;ss >> vertex.x >> vertex.y >> vertex.z;vertices.push_back(vertex);--pointsCount;}// Write vertices as points to OBJ filefor (const Vertex& vertex : vertices) {objFile << "v " << vertex.x << " " << vertex.y << " " << vertex.z << "\n";}pcdFile.close();objFile.close();std::cout << "Conversion from PCD to OBJ completed successfully." << std::endl;return 1;
}//12
int PointTypeTrans::objToPcd(const std::string objFilename, const std::string pcdFilename)
{if (strcmp(pcdFilename.substr(pcdFilename.size() - 4, 4).c_str(), ".pcd") != 0)return 0;if (strcmp(objFilename.substr(objFilename.size() - 4, 4).c_str(), ".obj") != 0)return 0;std::ifstream objFile(objFilename);std::ofstream pcdFile(pcdFilename);if (!objFile.is_open() || !pcdFile.is_open()) {std::cerr << "Error opening files!" << std::endl;return 0;}std::vector<Vertex> vertices;std::string line;// Read OBJ vertex datawhile (std::getline(objFile, line)) {if (line.empty() || line[0] == '#') continue;std::stringstream ss(line);std::string prefix;ss >> prefix;if (prefix == "v") {Vertex vertex;ss >> vertex.x >> vertex.y >> vertex.z;vertices.push_back(vertex);}}// Write PCD headerwritePCDHeader(pcdFile, vertices.size());// Write vertices to PCD filefor (const Vertex& vertex : vertices) {pcdFile << vertex.x << " " << vertex.y << " " << vertex.z << "\n";}objFile.close();pcdFile.close();std::cout << "Conversion from OBJ to PCD completed successfully." << std::endl;return 1;
}void PointTypeTrans::view_display(PloudCloud::Ptr cloud_target, PloudCloud::Ptr result)
{boost::shared_ptr<pcl::visualization::PCLVisualizer>viewer(new pcl::visualization::PCLVisualizer("PCL Viewer"));viewer->setBackgroundColor(0, 0, 0);对目标点云着色可视化 (red).pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>target_color(cloud_target, 255, 0, 0);//红色viewer->addPointCloud<pcl::PointXYZ>(cloud_target, target_color, "target cloud");viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "target cloud");// 对配准点云着色可视化 (green).pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ>output_color(result, 0, 255, 0);//绿色viewer->addPointCloud<pcl::PointXYZ>(result, output_color, "output_color");viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "output_color");while (!viewer->wasStopped()){viewer->spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(1000));}
}void PointTypeTrans::format_selection(std::string &suffix, int flag, std::string& file)
{std::string filef = file;int pos = filef.find(suffix);switch (flag){case 1:{file = filef.substr(0, pos) + ".ply";int res = pcdToPly(filef, file);suffix = ".ply";if (res){std::cout << "A pcd file was successfully imported" << std::endl;}break;}case 2:{file = filef.substr(0, pos) + ".ply";int res = txtToPly(filef, file);suffix = ".ply";if (res){std::cout << "A pcd file was successfully imported" << std::endl;}break;}}}
PointTypeTrans::~PointTypeTrans()
{}

main.cpp,在main.cpp增加了调用,同时取消了从命令行读取参数,改成固定的参数,方便测试,当然你想用也可以,直接把if(argc > 5)这段代码解开注释就行

/********************************************************************
Main Function for point cloud registration with Go-ICP Algorithm
Last modified: Feb 13, 2014"Go-ICP: Solving 3D Registration Efficiently and Globally Optimally"
Jiaolong Yang, Hongdong Li, Yunde Jia
International Conference on Computer Vision (ICCV), 2013Copyright (C) 2013 Jiaolong Yang (BIT and ANU)This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*********************************************************************/#include <time.h>
#include <iostream>
#include <fstream>
#include "pointTypeTrans.h"
#include "jly_goicp.h"
#include "ConfigMap.hpp"
#include <io.h>
#include <direct.h>
using namespace std;#define DEFAULT_OUTPUT_FNAME "./data/output.txt"
#define DEFAULT_CONFIG_FNAME "./data/config.txt"
#define DEFAULT_MODEL_FNAME "./data/model_bunny.txt"
#define DEFAULT_DATA_FNAME "./data/data_bunny.txt"void parseInput(int argc, char** argv, string& modelFName, string& dataFName, int& NdDownsampled, string& configFName, string& outputFName);
void readConfig(string FName, GoICP& goicp);
int loadPointCloud(string FName, int& N, POINT3D** p);int main(int argc, char** argv)
{string data_file = "./data";if (_access(data_file.c_str(), 0) == -1)	//如果文件夹不存在_mkdir(data_file.c_str());int Nm, Nd, NdDownsampled;clock_t  clockBegin, clockEnd;string modelFName, dataFName, configFName, outputFname;POINT3D* pModel, * pData;GoICP goicp;parseInput(argc, argv, modelFName, dataFName, NdDownsampled, configFName, outputFname);readConfig(configFName, goicp);// Load model and data point cloudsloadPointCloud(modelFName, Nm, &pModel);loadPointCloud(dataFName, Nd, &pData);goicp.pModel = pModel;goicp.Nm = Nm;goicp.pData = pData;goicp.Nd = Nd;// Build Distance Transformcout << "Building Distance Transform..." << flush;clockBegin = clock();goicp.BuildDT();clockEnd = clock();cout << (double)(clockEnd - clockBegin) / CLOCKS_PER_SEC << "s (CPU)" << endl;// Run GO-ICPif (NdDownsampled > 0){goicp.Nd = NdDownsampled; // Only use first NdDownsampled data points (assumes data points are randomly ordered)}cout << "Model ID: " << modelFName << " (" << goicp.Nm << "), Data ID: " << dataFName << " (" << goicp.Nd << ")" << endl;cout << "Registering..." << endl;clockBegin = clock();goicp.Register();clockEnd = clock();double time = (double)(clockEnd - clockBegin) / CLOCKS_PER_SEC;cout << "Optimal Rotation Matrix:" << endl;cout << goicp.optR << endl;cout << "Optimal Translation Vector:" << endl;cout << goicp.optT << endl;cout << "Finished in " << time << endl;ofstream ofile;ofile.open(outputFname.c_str(), ofstream::out);ofile << time << endl;ofile << goicp.optR << endl;ofile << goicp.optT << endl;ofile.close();delete(pModel);delete(pData);//可视化std::ifstream transformFile(DEFAULT_OUTPUT_FNAME);if (!transformFile.is_open()) {std::cerr << "无法打开变换文件。" << std::endl;return 1;}float value;// 跳过第一行std::string line;std::getline(transformFile, line);// 读取旋转矩阵Eigen::Matrix3f rotationMatrix;for (int i = 0; i < 3; ++i) {for (int j = 0; j < 3; ++j) {transformFile >> rotationMatrix(i, j);}}// 读取平移向量Eigen::Vector3f translationVector;for (int i = 0; i < 3; ++i) {transformFile >> translationVector(i);}transformFile.close();// 构造齐次变换矩阵Eigen::Matrix4f transform = Eigen::Matrix4f::Identity();transform.block<3, 3>(0, 0) = rotationMatrix; // 逆转置,因为Eigen默认是行主序的transform.block<3, 1>(0, 3) = translationVector;// 变换点云PloudCloud::Ptr result(new pcl::PointCloud<pcl::PointXYZ>);PloudCloud::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);PloudCloud::Ptr cloud_target(new pcl::PointCloud<pcl::PointXYZ>);PointTypeTrans v;//std::string resultF = data_file + "/Result" + ".ply";std::string sourceF = data_file + "/Source" + ".ply";std::string targetF = data_file + "/Target" + ".ply";pcl::console::setVerbosityLevel(pcl::console::L_ERROR);//int res1 = v.txtToPly(DEFAULT_OUTPUT_FNAME, resultF);int res2 = v.txtToPly(DEFAULT_MODEL_FNAME, targetF);int res3 = v.txtToPly(DEFAULT_DATA_FNAME, sourceF);bool trans_or_no =  res2 && res3;if (!trans_or_no){cout << "falled!!!" << endl;}if (pcl::io::loadPLYFile<pcl::PointXYZ>(sourceF, *cloud) == -1){PCL_ERROR("加载点云失败\n");}if (pcl::io::loadPLYFile<pcl::PointXYZ>(targetF, *cloud_target) == -1){PCL_ERROR("加载点云失败\n");}pcl::transformPointCloud(*cloud, *result, transform);v.view_display(cloud_target, cloud);v.view_display(cloud_target, result);return 0;
}void parseInput(int argc, char** argv, string& modelFName, string& dataFName, int& NdDownsampled, string& configFName, string& outputFName)
{// Set default valuesmodelFName = DEFAULT_MODEL_FNAME;dataFName = DEFAULT_DATA_FNAME;configFName = DEFAULT_CONFIG_FNAME;outputFName = DEFAULT_OUTPUT_FNAME;//NdDownsampled = 0; // No downsamplingNdDownsampled = 500; // No downsampling/*if (argc > 5){outputFName = argv[5];}if (argc > 4){configFName = argv[4];}if (argc > 3){NdDownsampled = atoi(argv[3]);}if (argc > 2){dataFName = argv[2];}if (argc > 1){modelFName = argv[1];}*/cout << "INPUT:" << endl;cout << "(modelFName)->(" << modelFName << ")" << endl;cout << "(dataFName)->(" << dataFName << ")" << endl;cout << "(NdDownsampled)->(" << NdDownsampled << ")" << endl;cout << "(configFName)->(" << configFName << ")" << endl;cout << "(outputFName)->(" << outputFName << ")" << endl;cout << endl;
}void readConfig(string FName, GoICP& goicp)
{// Open and parse the associated config fileConfigMap config(FName.c_str());goicp.MSEThresh = config.getF("MSEThresh");goicp.initNodeRot.a = config.getF("rotMinX");goicp.initNodeRot.b = config.getF("rotMinY");goicp.initNodeRot.c = config.getF("rotMinZ");goicp.initNodeRot.w = config.getF("rotWidth");goicp.initNodeTrans.x = config.getF("transMinX");goicp.initNodeTrans.y = config.getF("transMinY");goicp.initNodeTrans.z = config.getF("transMinZ");goicp.initNodeTrans.w = config.getF("transWidth");goicp.trimFraction = config.getF("trimFraction");// If < 0.1% trimming specified, do no trimmingif (goicp.trimFraction < 0.001){goicp.doTrim = false;}goicp.dt.SIZE = config.getI("distTransSize");goicp.dt.expandFactor = config.getF("distTransExpandFactor");cout << "CONFIG:" << endl;config.print();//cout << "(doTrim)->(" << goicp.doTrim << ")" << endl;cout << endl;
}int loadPointCloud(string FName, int& N, POINT3D** p)
{int i;ifstream ifile;ifile.open(FName.c_str(), ifstream::in);if (!ifile.is_open()){cout << "Unable to open point file '" << FName << "'" << endl;exit(-1);}ifile >> N; // First line has number of points to follow*p = (POINT3D*)malloc(sizeof(POINT3D) * N);for (i = 0; i < N; i++){ifile >> (*p)[i].x >> (*p)[i].y >> (*p)[i].z;}ifile.close();return 0;
}

 使用:

main.cpp下图第一行是输出文件路径,这份文件并不是配准后的点云文件,里面是旋转矩阵和位移矩阵;第二行是配准需要的参数文件路径,里面都是GO-ICP配准所需参数,如果配准效果不满意,可以在这个文件里面调整参数;第三第四行分别是目标点云文件路径和输入点云文件路径。

结果:

这是我修改程序之后的可视化

配准前

配准后 

 

这是用源码自带的matlab程序实现的可视化,直接运行demo文件夹的demo.m文件即可,不过我是把demo文件放到自己的项目文件夹里了,并改名为data文件夹,所以我之前的文件路径都是./data开头的。

配准前

 

配准后 

 

其实我的pointTypeTrans.h和pointTypeTrans.cpp还包含了几种点云文件转换代码,有兴趣的话可以试试利用代码把ply\pcd\obj点云文件转换成txt再进行配准,不过要注意的是我的点云文件转换只包含顶点信息,如果一份点云你只关注顶点信息,你可以使用我的代码进行文件转换,如果你想要更多信息,那么这份代码可能满足不了你的要求。

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【leetcode热题】不同的子序列

给你两个字符串 s 和 t &#xff0c;统计并返回在 s 的 子序列 中 t 出现的个数&#xff0c;结果需要对 109 7 取模。 示例 1&#xff1a; 输入&#xff1a;s "rabbbit", t "rabbit" 输出&#xff1a;3 解释&#xff1a; 如下所示, 有 3 种可以从 s 中…

Ps:明度直方图

明度 Luminosity直方图显示了图像中各个亮度级别的像素分布情况。 与 RGB 直方图不同&#xff0c;“明度”直方图专注于图像的亮度信息&#xff0c;而不是单独的颜色信息。 在“直方图”面板的通道中选择“明度”。 “明度”直方图提供了一种量化的方式来理解图像的整体明暗结构…

数字滚动实现

介绍 vue-countup-v3 插件是一个基于 Vue3 的数字动画插件&#xff0c;用于在网站或应用程序中创建带有数字动画效果的计数器。通过该插件&#xff0c;我们可以轻松地实现数字的递增或递减动画&#xff0c;并自定义其样式和动画效果。该插件可以用于许多场景&#xff0c;例如展…

MYSQL安装及卸载

目录 一、下载 二、解压 三、配置 1. 添加环境变量 2. 初始化MySQL 3. 注册MySQL服务 4. 启动MySQL服务 5. 修改默认账户密码 四、登录MySQL 五、卸载MySQL 一、下载 点开下面的链接&#xff1a;MySQL :: Download MySQL Community Server 点击Download 就可以下载对…

【深度学习目标检测】十八、基于深度学习的人脸检测系统-含GUI和源码(python,yolov8)

人脸检测是计算机视觉中的一个重要方向&#xff0c;也是一个和人们生活息息相关的研究方向&#xff0c;因为人脸是人最重要的外貌特征。人脸检测技术的重要性主要体现在以下几个方面&#xff1a; 人脸识别与安全&#xff1a;人脸检测是人脸识别系统的一个关键部分&#xff0c;是…

人工智能 — 特征选择、特征提取、PCA

目录 一、特征选择1、定义2、原因3、做法4、生成过程5、停止条件 二、特征提取三、PCA 算法1、零均值化&#xff08;中心化&#xff09;2、方差3、协方差4、协方差矩阵5、对协方差矩阵求特征值、特征矩阵6、对特征值进行排序7、评价模型8、代码实现9、sklearn 库10、鸢尾花实例…

Flink join详解(含两类API及coGroup、connect详解)

Flink SQL支持对动态表进行复杂而灵活的连接操作。 为了处理不同的场景&#xff0c;需要多种查询语义&#xff0c;因此有几种不同类型的 Join。 默认情况下&#xff0c;joins 的顺序是没有优化的。表的 join 顺序是在 FROM 从句指定的。可以通过把更新频率最低的表放在第一个、…

Python 实现 BRAR 指标计算(情绪指标):股票技术分析的利器系列(11)

Python 实现 BRAR 指标计算&#xff08;情绪指标&#xff09;&#xff1a;股票技术分析的利器系列&#xff08;11&#xff09; 介绍算法公式 代码rolling函数介绍核心代码计算BR计算AR 完整代码 介绍 BRAR 是一种情绪指标&#xff0c;用于衡量特定金融市场中的买卖情绪。它代表…

高考志愿辅助填报系统

高考志愿辅助填报系统 获取源码——》公主号&#xff1a;计算机专业毕设大全

一文搞懂TCP三次握手与四次挥手

什么是TCP协议&#xff1f; TCP&#xff08;Transmission control protocol&#xff09;即传输控制协议&#xff0c;是一种面向连接、可靠的数据传输协议&#xff0c;它是为了在不可靠的互联网上提供可靠的端到端字节流而专门设计的一个传输协议。 面向连接&#xff1a;数据传…

Java智慧工地云综合管理平台SaaS源码 助力工地实现精细化管理

目录 智慧工地系统介绍 1、可视化大屏 2、视频监控 3、Wi-Fi安全教育 4、环境监测 5、高支模监测 6、深基坑监测 7、智能水电监测 8、塔机升降安全监测 智慧工地系统功能模块 1、基础数据管理 2、考勤管理 3、安全隐患管理 4、视频监控 5、塔吊监控 6、升降机监…

泰迪智能科技中职大数据专业建设解决方案

泰迪智能科技基于十余年的数据智能产业实践经验&#xff0c;专注于大数据和人工智能方向&#xff0c;构建“产、岗、课、赛、证、文”融通的特色职业人才培养模式&#xff0c;助力中国职业教育高质量发展。 面相中职学校的大数据岗位群 目前就业市场上&#xff0c;大数据相关…

Python奇幻之旅(从入门到入狱高级篇)——面向对象进阶篇(下)

目录 引言 3. 面向对象高级和应用 3.1. 继承【补充】 3.1.1. mro和c3算法 c3算法 一句话搞定继承关系 3.1.2. py2和py3区别 3.3. 异常处理 3.3.1. 异常细分 3.3.2. 自定义异常&抛出异常 3.3.3. 特殊的finally 3.4. 反射 3.4.1. 一些皆对象 3.4.2. import_modu…

第十四章[面向对象]:14.8:枚举类

一,定义枚举类 1,把一个类定义为枚举类: 只需要让它继承自 enum 模块中的 Enum 类即可。 例如在下面的例子中,Weekday 类继承自 Enum 类, 则表明这是一个枚举类 枚举类的每个成员都由 2 部分组成,分别是 name 和 value, 其中 name 属性值为该枚举值的变量名(如下例中: …

微信小程序 ---- 生命周期

目录 生命周期 1. 小程序运行机制 2. 小程序更新机制 3. 生命周期介绍 4. 应用级别生命周期 5. 页面级别生命周期 6. 生命周期两个细节补充说明 7. 组件生命周期 总结 生命周期 1. 小程序运行机制 冷启动与热启动&#xff1a; 小程序启动可以分为两种情况&#xff0…

flutter插件开发基础教程

前言 虽然现在已经有很多插件了&#xff0c;但是有时候还是需要自己开发一个插件。因此打算学习一下如何开发一个插件。这里只考虑安卓&#xff0c;安卓使用kotlin&#xff0c;kotlin不会也没事&#xff0c;我也不会。 参考项目&#xff1a;https://github.com/TBoyLi/flutte…

【更换yarn的位置】解决yarn和nodejs不在同一盘下产生的某些命令应用失败问题

具体问题我记得是command fail什么error&#xff0c;记不太清楚了&#xff0c;文章主要写了如何替换yarn路径&#xff0c;希望可以帮助到大家。

【YOLO系列算法人员摔倒检测】

YOLO系列算法人员摔倒检测 模型和数据集下载YOLO系列算法的人员摔倒检测数据集可视化数据集图像示例&#xff1a; 模型和数据集下载 yolo行人跌倒检测一&#xff1a; 1、训练好的行人跌倒检测权重以及PR曲线&#xff0c;loss曲线等等&#xff0c;map达90%多&#xff0c;在行人跌…

测试需求平台7-产品管理服务接口一篇搞定

✍此系列为整理分享已完结入门搭建《TPM提测平台》系列的迭代版&#xff0c;拥抱Vue3.0将前端框架替换成字节最新开源的arco.design&#xff0c;其中约60%重构和20%新增内容&#xff0c;定位为从 0-1手把手实现简单的测试平台开发教程&#xff0c;内容将囊括基础、扩展和实战&a…

VSCode中打开md文件的智能提示

VSCode中打开md文件的智能提示 vscode中md的只能提示是默认关闭的,要打开必须要做些设置. 搜了好多文章,都是坑! 明明没设置成功,参数类型不对还信誓旦旦的坑自己同胞! 也难怪国内人学的那么难,反而国外学的很简单! 找了以下外面的资料,还是隔壁的人认真,给出了以下方法,测试成…