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再进行配准,不过要注意的是我的点云文件转换只包含顶点信息,如果一份点云你只关注顶点信息,你可以使用我的代码进行文件转换,如果你想要更多信息,那么这份代码可能满足不了你的要求。
相关文章:
GO-ICP的使用(一)
一、代码下载以、修改以及使用 下载: 链接:yangjiaolong/Go-ICP: Implementation of the Go-ICP algorithm for globally optimal 3D pointset registration (github.com) 解压之后 : 首先visual studio项目,配置好PCL环境&…...
FPS游戏漫谈System.GC.Collect()强制进行垃圾回收
在Unity中,System.GC.Collect()用于强制进行垃圾回收,但是它是一个相当耗时的操作,可能会导致游戏的帧率下降,甚至出现卡顿。因此,你应该尽量避免在游戏的主循环中频繁调用它。以下是一些关于在Unity中使用System.GC.C…...
第3集《灵峰宗论导读》
《灵峰宗论》导读。诸位法师,诸位同学,阿弥陀佛!(阿弥陀佛!) 请大家打开讲义第5面,悟道。 这一科我们是说明论主略史,在这一科当中,我们根据弘一大师所编的《蕅益大师年…...
java面试设计模式篇
面试专题-设计模式 前言 在平时的开发中,涉及到设计模式的有两块内容,第一个是我们平时使用的框架(比如spring、mybatis等),第二个是我们自己开发业务使用的设计模式。 面试官一般比较关心的是你在开发过程中&#…...
桥接模式:解耦抽象与实现,实现灵活多变的扩展结构
文章目录 一、引言二、应用场景与技术背景三、模式定义与实现四、实例详解五、优缺点分析总结: 一、引言 桥接模式是一种结构型设计模式,它将抽象部分与它的实现部分分离,使它们可以独立变化。这种模式通过创建一个抽象层和实现层的结构&…...
HUAWEI Programming Contest 2024(AtCoder Beginner Contest 342)
D - Square Pair 题目大意 给一长为的数组,问有多少对,两者相乘为非负整数完全平方数 解题思路 一个数除以其能整除的最大的完全平方数,看前面有多少个与其余数相同的数,两者乘积满足条件(已经是完全平方数的部分无…...
Heap sorting
堆排序比较特殊,采用数组表示堆。 先将数组表示成大根堆或者小根堆。然后从堆中依次取根,最后形成有序序列。 #include<bits/stdc.h> using namespace std;const int N 1e5 10; int a[N];void bigheap(int* a, int start, int len) {if(start …...
开源模型应用落地-qwen2模型小试-入门篇(六)
一、前言 经过前五篇“qwen模型小试”文章的学习,我们已经熟练掌握qwen大模型的使用。然而,就在前几天开源社区又发布了qwen1.5版本,它是qwen2模型的测试版本。在基于transformers的使用方式上有较大的调整,现在,我们赶紧跟上脚步,去体验一下新版本模型的推理质量。 二、…...
c#程序,oracle使用Devart驱动解决第第三方库是us7ascii,数据乱码的问题
最近做项目,要跟对方系统的库进行读写,结果发现对方采用的是oracle的us7ascii编码,我们系统默认采用的是ZHS16GBK,导致我们客户端读取和写入对方库的数据都是乱码,搜索网上,发现需要采用独立的oracle驱动去…...
代码随想录算法训练营第四一天 | 背包问题
目录 背包问题01背包二维dp数组01背包一维 dp 数组(滚动数组)分割等和子集 LeetCode 背包问题 01背包 有n件物品和一个最多能背重量为 w 的背包,第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品只能用一次&#x…...
AIDL的工作原理与使用示例 跨进程通信 远程方法调用RPC
AIDL的介绍与使用 AIDL(Android Interface Definition Language)是Android中用于定义客户端和服务端之间通信接口的一种接口定义语言。它允许你定义客户端和服务的通信协议,用于在不同的进程间或同一进程的不同组件间进行数据传递。AIDL通过…...
K8S部署Java项目 pod报错 logs日志内容:no main manifest attribute, in app.jar
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...
SQL实现模糊查询的四种方法总结
目录 一、一般模糊查询 二、利用通配符查询 1. _ 表示任意的单个字符 2. % 表示匹配任意多个任意字符 3. [ ]表示筛选范围 4. 查询包含通配符的字符串 一、一般模糊查询 1. 单条件查询 //查询所有姓名包含“张”的记录select * from student where name like 张 2. 多条…...
爬虫基本库的使用(urllib库的详细解析)
学习爬虫,其基本的操作便是模拟浏览器向服务器发出请求,那么我们需要从哪个地方做起呢?请求需要我们自己构造吗? 我们需要关心请求这个数据结构怎么实现吗? 需要了解 HTTP、TCP、IP层的网络传输通信吗? 需要知道服务器如何响应以及响应的原理吗? 可…...
【PyQt5桌面应用开发】3.Qt Designer快速入门(控件详解)
一、Qt Designer简介 Qt Designer是PyQt程序UI界面的实现工具,可以帮助我们快速开发 PyQt 程序的速度。它生成的 UI 界面是一个后缀为 .ui 的文件,可以通过 pyiuc 转换为 .py 文件。 Qt Designer工具使用简单,可以通过拖拽和点击完成复杂界面…...
react useMemo 用法
1,useCallback 的功能完全可以由 useMemo 所取代,如果你想通过使用 useMemo 返回一个记忆函数也是完全可以的。 usecallback(fn,inputs)is equivalent to useMemo(()> fn, inputs). 区别是:useCallback不会执行第一个参数函数,而是将它返…...
python学习笔记 - 标准库函数
概述 为了方便程序员快速编写Python脚本程序,Python提供了很多好用的功能模块,它们内置于Python系统,也称为内置函数(Built-in Functions,BlF),Python 内置函数是 Python 解释器提供的一组函数,无需额外导…...
校招失败后,在小公司熬了 2 年终于进了字节跳动,竭尽全力....
其实两年前校招的时候就往字节投了一次简历,结果很明显凉了,随后这个理想就被暂时放下了,但是这个种子一直埋在心里这两年除了工作以外,也会坚持写博客,也因此结识了很多优秀的小伙伴,从他们身上学到了特别…...
PYTHON-使用正则表达式进行模式匹配
目录 Python 正则表达式Finding Patterns of Text Without Regular ExpressionsFinding Patterns of Text with Regular ExpressionsCreating Regex ObjectsMatching Regex ObjectsReview of Regular Expression MatchingMore Pattern Matching with Regular ExpressionsGroupi…...
Fiddler工具 — 19.Fiddler抓包HTTPS请求(二)
5、查看证书是否安装成功 方式一: 点击Tools菜单 —> Options... —> HTTPS —> Actions 选择第三项:Open Windows Certificate Manager打开Windows证书管理器。 打开Windows证书管理器,选择操作—>查看证书,在搜索…...
架构设计:流式处理与实时计算
引言 随着大数据技术的不断发展,流式处理和实时计算在各行各业中变得越来越重要。那么什么是流式处理呢?我们又该怎么使用它?流式处理允许我们对数据流进行实时分析和处理,而实时计算则使我们能够以低延迟和高吞吐量处理数据。本…...
Linux系统安装zookeeper
Linux安装zookeeper 安装zookeeper之前需要安装jdk,确认jdk环境没问题之后再开始安装zookeeper 下载zookeeper压缩包,官方下载地址:Apache Download Mirrors 将zookeeper压缩包拷贝到Linux并解压 # (-C 路径)可以解压到指定路径 tar -zxv…...
【前端素材】推荐优质后台管理系统Modernize平台模板(附源码)
一、需求分析 后台管理系统是一种用于管理和控制网站、应用程序或系统后台操作的软件工具,通常由授权用户(如管理员、编辑人员等)使用。它提供了一种用户友好的方式来管理网站或应用程序的内容、用户、数据等方面的操作,并且通常…...
二、Vue组件化编程
2、Vue组件化编程 2.1 非单文件组件 <div id"root"><school></school><hr><student></student> </div> <script type"text/javascript">//创建 school 组件const school Vue.extend({template: <div&…...
JVM跨代引用垃圾回收
1. 跨代引用概述 在Java堆内存中,年轻代和老年代之间存在的对象相互引用,假设现在要进行一次新生代的YGC,但新生代中的对象可能被老年代所引用的,为了找到新生代中的存活对象,不得不遍历整个老年代。这样明显效率很低…...
AI:135-基于卷积神经网络的艺术品瑕疵检测与修复
🚀点击这里跳转到本专栏,可查阅专栏顶置最新的指南宝典~ 🎉🎊🎉 你的技术旅程将在这里启航! 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带关键代码,详细讲解供大家学习,希望…...
C++标准头文件汇总及功能说明
文章目录 algorithmbitsetcctypecerrnoclocalecmathcstdioctimedequeiostreamexceptionfstreamfunctionallimitslistmapiosiosfwdsetsstreamstackstdexceptstreambufcstringutilityvectorcwcharcwctype algorithm algorithm头文件是C的标准算法库,它主要用在容器上。…...
glTF 添加数据属性(extras)
使用3D 模型作为可视化界面的一个关键是要能够在3D模型中添加额外的数据属性,利用这些数据属性能够与后台的信息模型建立对应关系,例如后台信息模型是opcua 信息模型的话,在3D模型中要能够包含OPC UA 的NodeId,BrowserName 等基本…...
linux系统消息中间件rabbitmq普通集群的部署
rabbitmq普通集群的部署 普通集群准备环境查询版本对应安装rabbitmq软件启动创建登录用户开启用户远程登录查看端口 部署集群创建数据存放目录和日志存放目录:拷⻉erlang.cookie将其他两台服务器作为节点加⼊节点集群中查看集群状态创建新的队列 普通集群准备环境 配置hosts⽂件…...
TextCNN:文本分类卷积神经网络
模型原理 1、前言2、模型结构3、示例3.1、词向量层3.2、卷积层3.3、最大池化层3.4、Fully Connected层 4、总结 1、前言 TextCNN 来源于《Convolutional Neural Networks for Sentence Classification》发表于2014年,是一个经典的模型,Yoon Kim将卷积神…...
如何增加新网站的百度收录/财经新闻最新消息
494. 目标和 给定一个非负整数数组,a1, a2, …, an, 和一个目标数,S。现在你有两个符号 和 -。对于数组中的任意一个整数,你都可以从 或 -中选择一个符号添加在前面。 返回可以使最终数组和为目标数 S 的所有添加符号的方法数。 示例 1:…...
wap网站开发语言/安卓系统最好优化软件
高内聚/低耦合 高内聚: 内聚就是一个模块内各个元素彼此结合的紧密程度。 高内聚就是一个模块内各个元素彼此结合的紧密程度高。 就类而言,一个类只处理一件事情,类中的属性和方法只与处理的这件事情相关; 就模块而言,…...
珠海专业做网站公司/大数据营销的概念
Web后门工具WeBaCooWeBaCoo是使用Perl语言编写的Web后门工具。渗透测试人员首先使用该工具生成一个后门PHP页面。然后,将该页面上传到目标服务器上。最后,在本地终端直接访问该页面,WeBaCoo将执行的命令Base64编码后,借助Cookie的…...
柯桥做网站/北京网站优化公司哪家好
1.Shell是什么 2.Linux权限: 要想了解并执行Shell脚本,首先我们需要知道linux系统中文件的权限,才能确定我们是否有执行此Shell脚本的权限。 r 读w 写x 执行Linux用户(分为三组):所有者——文件创造者所属组——文件创造者所在的组…...
网站建设的发展/长沙电商优化
是否是美国金融业监管机构( FINRA ) /美国证券投资人保护组织( SIPC )的资深会员,是评价一个美股券商是否正规有实力的最为直接的方式。 成为这两大机构的会员后,即使该会员券商破产,投资者的股…...
如何做音乐分享类网站/百度推广客户端app
测试前先启动hadoop [hadoopmini-yum ~]$ start-dfs.sh [hadoopmini-yum ~]$ start-yarn.sh 1在一堆给定的文本文件中统计输出每一个单词出现的总次数 代码 package cn.feizhou.wcdemo;import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.Path; impo…...