GO-ICP的使用(一)

news2024/11/19 16:46:37

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

下载:

链接: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 header
    writePLYHeader(ply_file, num_points);

    // Write the point data
    float x, y, z;
    for (int i = 0; i < num_points; ++i) {
        txt_file >> x >> y >> z;
        ply_file << x << " " << y << " " << z << "\n";
    }

    // Clean up
    txt_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 elements
    while (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 file
    txt_file << num_points << std::endl;

    // Read and write the point data
    float x, y, z;
    for (int i = 0; i < num_points; ++i) {
        ply_file >> x >> y >> z;
        txt_file << x << " " << y << " " << z << std::endl;
    }

    // Clean up
    ply_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 file
    int num_points;
    txt_file >> num_points;

    // Write the PCD header
    writePCDHeader(pcd_file, num_points);

    // Read and write the point data
    float x, y, z;
    for (int i = 0; i < num_points; ++i) {
        txt_file >> x >> y >> z;
        pcd_file << x << " " << y << " " << z << "\n";
    }

    // Clean up
    txt_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 header
    while (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, exit
    if (!headerPassed) {
        std::cerr << "PCD header not found or improper format." << std::endl;
        return 0;
    }

    // Write the number of points to the TXT file
    txt_file << num_points << "\n";

    // Read and write the point data
    float x, y, z;
    while (pcd_file >> x >> y >> z) {
        txt_file << x << " " << y << " " << z << "\n";
    }

    // Clean up
    pcd_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 provided
    int num_points;
    txt_file >> num_points;

    // Write vertices to the OBJ file
    float x, y, z;
    while (txt_file >> x >> y >> z) {
        obj_file << "v " << x << " " << y << " " << z << "\n";
    }

    // Clean up
    txt_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 file
    while (std::getline(obj_file, line)) {
        // Skip empty lines and comments
        if (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 vertices
    txt_file << vertices.size() << std::endl;

    // Then write all vertices
    for (const auto& vertex : vertices) {
        txt_file << vertex.x << " " << vertex.y << " " << vertex.z << std::endl;
    }

    // Clean up
    obj_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 lines
            continue;
        }
        else {
            // Read point data
            Vertex point;
            if (ss >> point.x >> point.y >> point.z) {
                points.push_back(point);
            }
        }
    }

    // Write PCD header
    writePCDHeader(pcdFile, vertexCount);

    // Write point data to PCD file
    for (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 file
    while (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 header
    writePLYHeader(plyFile, pointCount);

    // Write points to PLY file
    for (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 header
    while (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 data
    while (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 file
    for (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 file
    while (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 header
    writePLYHeader(plyFile, vertices.size());

    // Write vertex data to PLY file
    for (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 header
    while (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 points
    while (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 file
    for (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 data
    while (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 header
    writePCDHeader(pcdFile, vertices.size());

    // Write vertices to PCD file
    for (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), 2013

Copyright (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 clouds
	loadPointCloud(modelFName, Nm, &pModel);
	loadPointCloud(dataFName, Nd, &pData);

	goicp.pModel = pModel;
	goicp.Nm = Nm;
	goicp.pData = pData;
	goicp.Nd = Nd;

	// Build Distance Transform
	cout << "Building Distance Transform..." << flush;
	clockBegin = clock();
	goicp.BuildDT();
	clockEnd = clock();
	cout << (double)(clockEnd - clockBegin) / CLOCKS_PER_SEC << "s (CPU)" << endl;

	// Run GO-ICP
	if (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 values
	modelFName = DEFAULT_MODEL_FNAME;
	dataFName = DEFAULT_DATA_FNAME;
	configFName = DEFAULT_CONFIG_FNAME;
	outputFName = DEFAULT_OUTPUT_FNAME;
	//NdDownsampled = 0; // No downsampling
	NdDownsampled = 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 file
	ConfigMap 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 trimming
	if (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://www.coloradmin.cn/o/1469537.html

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

相关文章

软件应用场景,物流货运配货单打印模板软件单据打印查询管理系统软件教程

软件应用场景&#xff0c;物流货运配货单打印模板软件单据打印查询管理系统软件教程 一、前言 以下软件以 佳易王物流快运单打印查询管理系统软件V17.1 软件文件下载可以点击最下方官网卡片——软件下载——试用版软件下载 1、打印模式可以分为 直打模式和套打模式 直打模…

消息中间件之RocketMQ源码分析(十六)

Broker读写分离机制 在RocketMQ中,有两处地方使用了"读写分离"机制 Broker Master-Slave读写分离:写消息到Master Broker,从Slave Broker读取消息。Broker配置为Slave Broker读取消息。 Broker配置为slaveReadEnableTrue(默认False)&#xff0c;消息占用内存百分比配…

力扣随笔之寻找重复数(中等287)

思路1&#xff1a;暴力解法&#xff0c;根据要求不修改数组且只用常量级O(1)的额外空间&#xff0c;我们写两层嵌套循环&#xff0c;寻找重复的数;可以解决部分问题&#xff0c;但会超出时间限制无论Java还是C; Java实现&#xff1a; class Solution {public int findDuplicat…

WSL里的Ubuntu 登录密码忘了怎么更改

环境&#xff1a; Win10 专业版 WSL2 如何 Ubuntu22.04 问题描述&#xff1a; WSL里的Ubuntu 登录密码忘了怎么更改 解决方案&#xff1a; 在WSL中的Ubuntu系统中&#xff0c;忘记了密码&#xff0c;可以通过以下步骤重置密码&#xff1a; 1.打开命令提示符或PowerShel…

[HTML]Web前端开发技术29(HTML5、CSS3、JavaScript )JavaScript基础——喵喵画网页

希望你开心,希望你健康,希望你幸福,希望你点赞! 最后的最后,关注喵,关注喵,关注喵,佬佬会看到更多有趣的博客哦!!! 喵喵喵,你对我真的很重要! 目录 前言 上一节的课后练习

Stable Diffusion 3重磅发布

刚不久&#xff0c;Stability AI发布了Stable Diffusion 3.0&#xff0c;这一版本采用了与备受瞩目的爆火Sora相同的DiT架构。通过这一更新&#xff0c;画面质量、文字渲染以及对复杂对象的理解能力都得到了显著提升。由于这些改进&#xff0c;先前的技术Midjourney和DALL-E 3在…

【Vue3】‘vite‘ 不是内部或外部命令,也不是可运行的程序或批处理文件。

问题 今天拿到别人项目的时候&#xff0c;我平时比较习惯用pnpm&#xff0c;我就使用pnpm i先下载依赖包&#xff0c;下载完成后&#xff0c;启动项目&#xff0c;就开始报以下错误&#xff01; 但是当我执行pnpm i的时候&#xff0c;vite不应该就已经被我下载下来了吗 研究了…

vivo 基于 StarRocks 构建实时大数据分析平台,为业务搭建数据桥梁

在大数据时代&#xff0c;数据分析和处理能力对于企业的决策和发展至关重要。 vivo 作为一家全球移动互联网智能终端公司&#xff0c;需要基于移动终端的制造、物流、销售等各个方面的数据进行分析以满足业务决策。 而随着公司数字化服务的演进&#xff0c;业务诉求和技术架构有…

解密高并发系统设计:聊聊负载均衡算法

引言 随着公司业务的飞速发展&#xff0c;以及业务的多样性&#xff0c;用户数会迅猛增长&#xff0c;系统的流量会越来越大。因此&#xff0c;大规模的并发用户访问会对系统的处理能力造成巨大的压力&#xff0c;系统必须要有足够强的处理能力才能应对。 这篇文章就来介绍一…

VMware使用虚拟机,开启时报错:无法连接虚拟设备 0:0,因为主机上没有相应的设备。——解决方法

检查虚拟机配置文件并确保物理设备已正确连接。 操作&#xff1a; 选中虚拟机&#xff0c;打开设置&#xff0c;点击CD/DVD。在连接处选择使用ISO镜像文件

被动收入 | Audible 联盟营销计划:如何每月赚取 5000 美元?

你是否正在寻求被动收入的方式&#xff0c;或者在你的网站或平台上寻求赚钱的方式&#xff1f;亚马逊的Audible Depot联盟营销计划是一个不错的选择。作为会员&#xff0c;可以向听众推广有声读物&#xff0c;并从中获得收益。每月有可能赚取高达5000美元的收入&#xff0c;现在…

【Vuforia+Unity】AR04-地面、桌面平面识别功能(Ground Plane Target)

不论你是否曾有过相关经验,只要跟随本文的步骤,你就可以成功地创建你自己的AR应用。 官方教程Ground Plane in Unity | Vuforia Library 这个功能很棒,但是要求也很不友好,只能支持部分移动设备,具体清单如下: 01.Vuforia的地面识别功能仅支持的设备清单: Recommended…

【MySQL】MySQL从0到0.9 - 持续更新ing

MySQL SQL 基础 DDL 语句 show databases; show tables; desc table_name; # 获取表信息 show create table 表名; // 查询指定表的建表语句 数据类型 char(10) 不满10个会用空格填充&#xff0c;性能好一点 varchar(10) 变长字符串&#xff0c;性能差一点 CREATE TABLE tabl…

数据库-MySQL-01

这里写目录标题 数据库开发-MySQL首先来了解一下什么是数据库。1. MySQL概述1.1 安装1.1.1 版本1.1.2 安装1.1.3 连接1.1.4 企业使用方式(了解) 1.2 数据模型1.3 SQL简介1.3.1 SQL通用语法1.3.2 分类 2. 数据库设计-DDL2.1 项目开发流程2.2 数据库操作2.2.1 查询数据库2.2.2 创…

从SDRAM到DDR的变化

1、结构概述 在此之前&#xff0c;曾经通过一篇文章从SDRAM的内部芯片框图出发&#xff0c;分析过SDRAM的功能实现&#xff0c;本文开始继续分析DDR、DDR2、DDR3的芯片内部框图&#xff0c;从而认识他们各自的区别&#xff0c;便于后续使用。 下图时镁光的128Mb的SDRAM内存芯片…

大学生多媒体课程学习网站thinkphp+vue

开发语言&#xff1a;php 后端框架&#xff1a;Thinkphp 前端框架&#xff1a;vue.js 服务器&#xff1a;apache 数据库&#xff1a;mysql 运行环境:phpstudy/wamp/xammp等开发背景 &#xff08;一&#xff09; 研究课程的提出 &#xff08;二&#xff09;学习网站的分类与界定…

RabbitMq:RabbitMq 主从镜像模式②

一、模式思想 所有的技术设计思想&#xff0c;基本都在两点上下功夫&#xff1a;1. 生产力上 2. 稳定上 二、集群模式 今天又有人问起来rabbitmq的高可用方式&#xff0c;因为和常见的主从模式有点区别&#xff0c;所以就记录一下。 rabbitmq集群的镜像队列提供了更高级的主从…

数字化转型导师坚鹏:数据安全法解读与政府数字化转型

网络安全法、数据安全法、个人信息保护法解读与政府数字化转型 课程背景&#xff1a; 很多机构存在以下问题&#xff1a; 不清楚网络安全法、数据安全法、个人信息保护法立法背景&#xff1f; 不知道如何理解网络安全法、数据安全法、个人信息保护法政策&#xff1f; 不…

LeetCode 第一题: 两数之和

文章目录 第一题: 两数之和题目描述示例 解题思路Go语言实现 - 一遍哈希表法C实现算法分析 排序和双指针法Go语言实现 - 排序和双指针法C算法分析 暴力法Go语言实现 - 暴力法C算法分析 二分搜索法Go语言实现 - 二分搜索法C算法分析 第一题: 两数之和 ‍ 题目描述 给定一个整…

【统计分析数学模型】聚类分析: 系统聚类法

【统计分析数学模型】聚类分析&#xff1a; 系统聚类法 一、聚类分析1. 基本原理2. 距离的度量&#xff08;1&#xff09;变量的测量尺度&#xff08;2&#xff09;距离&#xff08;3&#xff09;R语言计算距离 三、聚类方法1. 系统聚类法2. K均值法 三、示例1. Q型聚类&#x…