diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml new file mode 100644 index 0000000..3dc0119 --- /dev/null +++ b/.github/workflows/cd.yml @@ -0,0 +1,61 @@ +name: CD (continuous delivery) + +on: + push: + tags: + - "*" +env: + IMAGE_NAME: pcdtomesh + +jobs: + ci: + uses: ./.github/workflows/lint_and_test.yml + deploy: + runs-on: ubuntu-22.04 + needs: [ci] + name: cd / Deploy + + steps: + - name: Clone Repository + uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Download artifact + uses: actions/download-artifact@master + with: + name: build + path: ${{github.workspace}}/install + + - name: Install PCL + run: sudo apt-get -o Dpkg::Use-Pty=0 install libpcl-dev + + - name: Docker meta + id: meta + uses: docker/metadata-action@v4 + with: + # list of Docker images to use as base name for tags + images: | + ghcr.io/${{ github.repository_owner }}/${{ env.IMAGE_NAME }} + # generate Docker tags based on the following events/attributes + tags: | + type=semver,pattern={{version}} + type=sha + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + + - name: Log in to registry + # This is where you will update the PAT to GITHUB_TOKEN + run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u $ --password-stdin + + - name: Build and push + uses: docker/build-push-action@v3 + with: + context: . + file: Dockerfile.release + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=registry,ref=ghcr.io/danieltobon43/${{ env.IMAGE_NAME }}:latest + cache-to: type=inline diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 66681d6..b67ef63 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,18 +1,14 @@ -name: build -on: [push] -jobs: - Explore-GitHub-Actions: - runs-on: ubuntu-20.04 - steps: - - - name: Install PCL - run: sudo apt-get install libpcl-dev +name: CI (continuous integration) - - name: Configure CMake - run: cmake -B ${{dir}}/build -DCMAKE_BUILD_TYPE=Release +on: + # pull_request: + # branches: [main] + push: + # branches: [main] + paths-ignore: ["**.md"] + branches-ignore: ["master"] + workflow_call: - - name: Build - run: cmake --build ${{dir}}/build --config Release - - - name: Test - run: build/pointcloudToMESH +jobs: + ci: + uses: ./.github/workflows/lint_and_test.yml diff --git a/.github/workflows/lint_and_test.yml b/.github/workflows/lint_and_test.yml new file mode 100644 index 0000000..62dfdb7 --- /dev/null +++ b/.github/workflows/lint_and_test.yml @@ -0,0 +1,60 @@ +name: Lint & Test + +on: + workflow_call: + +env: + BUILD_TYPE: Release + +jobs: + build: + runs-on: ubuntu-22.04 + name: Build Check + steps: + - name: Clone Repository + uses: actions/checkout@v3 + with: + submodules: recursive + + - name: Install PCL + run: sudo apt-get -o Dpkg::Use-Pty=0 install libpcl-dev + + - name: Configure CMake + run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DCMAKE_INSTALL_PREFIX=install + + - name: Build app + run: cmake --build ${{github.workspace}}/build --config $BUILD_TYPE + + - name: Install app + run: cmake --install build + + - name: Test app + run: ${{github.workspace}}/build/pointcloudToMESH + + - name: Store artifact + uses: actions/upload-artifact@master + with: + name: build + path: ${{github.workspace}}/install + + lint: + needs: [build] + name: Formatting Check + runs-on: ubuntu-20.04 + + steps: + - uses: actions/checkout@v2 + - name: Run clang-format style check for C/C++/Protobuf programs. + uses: jidicula/clang-format-action@v4.5.0 + with: + clang-format-version: "10" + check-path: "." + exclude-regex: "external" + + test: + needs: [build] + name: Tests Check + runs-on: ubuntu-20.04 + steps: + - uses: actions/checkout@v2 + - run: echo "🍏 This job's status is ${{ job.status }}." diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7f2eb11 --- /dev/null +++ b/.gitignore @@ -0,0 +1,43 @@ +# Prerequisites +*.d + +# Compiled Object files +*.slo +*.lo +*.o +*.obj + +# Precompiled Headers +*.gch +*.pch + +# Compiled Dynamic libraries +*.so +*.dylib +*.dll + +# Fortran module files +*.mod +*.smod + +# Compiled Static libraries +*.lai +*.la +*.a +*.lib + +# Executables +*.exe +*.out +*.app + +# Folders +build/ +build-vscode/ +PCL-Build-Action/ +.vscode + +# nektos/act secrets +.secrets + +run_dev.sh \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..171d9a6 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,54 @@ +############################################################################## +# CMAKE CONFIGURATION +############################################################################## +cmake_minimum_required(VERSION 3.15 FATAL_ERROR) + +set(CMAKE_BUILD_TYPE Release) +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") +project(pointcloudToMESH VERSION 1.0.0) + +message("\n" "=========================================") +message("Project: ${PROJECT_NAME} ") +message("=========================================") + +############################################################################## +# PACKAGES +############################################################################## +message("***********************") +message("PCL PACKAGE") +message("***********************") + +find_package(PCL 1.8 REQUIRED QUIET) + +if(PCL_FOUND) + message(STATUS "PCL status:") + message(STATUS " version: ${PCL_VERSION}") + message(STATUS " directory: ${PCL_DIR}") +else() + message(FATAL_ERROR " ERROR: PCL minimum required version 1.8. Not found") +endif() + +############################################################################## +# SOURCE CODE +############################################################################## +set(MAIN_SOURCE "src/main.cpp") + +############################################################################## +# EXECUTABLES +############################################################################## +add_executable(${PROJECT_NAME} ${MAIN_SOURCE}) + +############################################################################## +# TARGET LIBRARIES +############################################################################## +target_link_libraries(${PROJECT_NAME} PRIVATE ${PCL_LIBRARIES}) +target_include_directories(${PROJECT_NAME} PRIVATE ${PCL_INCLUDE_DIRS}) + +message("=========================================") +message("Project: ${PROJECT_NAME} COMPILED WITH CMAKE " ${CMAKE_VERSION}) +message("=========================================") + +install(TARGETS ${PROJECT_NAME} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} +) diff --git a/Dockerfile.release b/Dockerfile.release new file mode 100644 index 0000000..aa95c3e --- /dev/null +++ b/Dockerfile.release @@ -0,0 +1,9 @@ +FROM ubuntu:20.04 AS runtime +RUN apt-get -qq -o=Dpkg::Use-Pty=0 update && DEBIAN_FRONTEND=noninteractive apt-get -y -qq -o=Dpkg::Use-Pty=0 install \ + libpcl-dev \ + && rm -rf /var/lib/apt/lists/* +COPY install /usr +ENV MESA_LOADER_DRIVER_OVERRIDE i965 + +# ======== Run binary file ======== +ENTRYPOINT ["pointcloudToMESH"] diff --git a/src/main.cpp b/src/main.cpp index dce76f7..80b8b95 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2,301 +2,325 @@ HEADERS **********************************/ +#include +#include #include +#include +#include #include #include -#include #include -#include -#include -#include #include #include -#include #include +#include #include #include -#include -#include #include #include +#include +#include #include -#include #include +#include #include #include #include -#include -#include #include +#include #include #include #include +#include -#include #include +#include -#include +#include +#include #include +#include #include #include -#include -#include #include #include -#include #include +#include -#include #include +#include #include -#include #include +#include #include -void printUsage (const char* progName){ - std::cout << "\nUsage: " << progName << " " << std::endl; +void printUsage(const char *progName) { + std::cout << "\nUsage: " << progName + << " " + "" + << std::endl; std::cout << "surface method: \n '1' for poisson \n '2' for gp3" << std::endl; - std::cout << "normal estimation method: \n '1' for normal estimation \n '2' for mls normal estimation" << std::endl; + std::cout << "normal estimation method: \n '1' for normal estimation \n '2' " + "for mls normal estimation" + << std::endl; } -void create_mesh(pcl::PointCloud::Ptr& cloud,int& surface_mode,int& normal_method,pcl::PolygonMesh& triangles){ - - /* ****Translated point cloud to origin**** */ - Eigen::Vector4f centroid; - pcl::compute3DCentroid(*cloud, centroid); - - Eigen::Affine3f transform = Eigen::Affine3f::Identity(); - transform.translation() << -centroid[0], -centroid[1], -centroid[2]; - - pcl::PointCloud::Ptr cloudTranslated(new pcl::PointCloud()); - pcl::transformPointCloud(*cloud, *cloudTranslated, transform); - - /* ****kdtree search and msl object**** */ - pcl::search::KdTree::Ptr kdtree_for_points (new pcl::search::KdTree); - kdtree_for_points->setInputCloud(cloudTranslated); - pcl::PointCloud::Ptr cloud_with_normals (new pcl::PointCloud ()); - - bool mls_mode = false; - bool normal_mode = false; - - if(normal_method == 1){ - normal_mode = true; - }else if(normal_method == 2){ - mls_mode = true; - }else{ - std::cout << "Select:\n '1' for normal estimation \n '2' for mls normal estimation " << std::endl; - std::exit(-1); - } - - bool gp3_mode = false; - bool poisson_mode = false; - - if(surface_mode == 1){ - poisson_mode = true; - }else if(surface_mode == 2){ - gp3_mode = true; - }else{ - std::cout << "Select: \n'1' for surface poisson method \n '2' for surface gp3 method " << std::endl; - std::exit(-1); - } - - if(mls_mode){ - - std::cout << "Using mls method estimation..."; - - pcl::PointCloud::Ptr mls_points (new pcl::PointCloud()); - pcl::MovingLeastSquares mls; - - //Set parameters - mls.setComputeNormals(true); - mls.setInputCloud(cloudTranslated); - // mls.setDilationIterations(10); - //mls.setDilationVoxelSize(0.5); - //mls.setSqrGaussParam(2.0); - //mls.setUpsamplingRadius(5); - //mls.setPolynomialOrder (2); - //mls.setPointDensity(30); - mls.setSearchMethod(kdtree_for_points); - mls.setSearchRadius(0.03); - mls.process(*mls_points); - - pcl::PointCloud::Ptr temp(new pcl::PointCloud()); - - for(int i = 0; i < mls_points->points.size(); i++) { - - pcl::PointXYZ pt; - pt.x = cloud->points[i].x; - pt.y = cloud->points[i].y; - pt.z = cloud->points[i].z; - - temp->points.push_back(pt); - } - - - pcl::concatenateFields (*temp, *mls_points, *cloud_with_normals); - std::cout << "[OK]" << std::endl; - - }else if(normal_mode){ - - std::cout << "Using normal method estimation..."; - - pcl::NormalEstimationOMP n; - pcl::PointCloud::Ptr normals (new pcl::PointCloud); - - n.setInputCloud(cloudTranslated); - n.setSearchMethod(kdtree_for_points); - n.setKSearch(20); //It was 20 - n.compute(*normals);//Normals are estimated using standard method. +void create_mesh(pcl::PointCloud::Ptr &cloud, int &surface_mode, + int &normal_method, pcl::PolygonMesh &triangles) { + + /* ****Translated point cloud to origin**** */ + Eigen::Vector4f centroid; + pcl::compute3DCentroid(*cloud, centroid); + + Eigen::Affine3f transform = Eigen::Affine3f::Identity(); + transform.translation() << -centroid[0], -centroid[1], -centroid[2]; + + pcl::PointCloud::Ptr cloudTranslated( + new pcl::PointCloud()); + pcl::transformPointCloud(*cloud, *cloudTranslated, transform); + + /* ****kdtree search and msl object**** */ + pcl::search::KdTree::Ptr kdtree_for_points( + new pcl::search::KdTree); + kdtree_for_points->setInputCloud(cloudTranslated); + pcl::PointCloud::Ptr cloud_with_normals( + new pcl::PointCloud()); + + bool mls_mode = false; + bool normal_mode = false; + + if (normal_method == 1) { + normal_mode = true; + } else if (normal_method == 2) { + mls_mode = true; + } else { + std::cout << "Select:\n '1' for normal estimation \n '2' for mls normal " + "estimation " + << std::endl; + std::exit(-1); + } - //pcl::PointCloud::Ptr cloud_with_normals (new pcl::PointCloud ()); - pcl::concatenateFields(*cloud, *normals, *cloud_with_normals); + bool gp3_mode = false; + bool poisson_mode = false; + + if (surface_mode == 1) { + poisson_mode = true; + } else if (surface_mode == 2) { + gp3_mode = true; + } else { + std::cout << "Select: \n'1' for surface poisson method \n '2' for surface " + "gp3 method " + << std::endl; + std::exit(-1); + } + + if (mls_mode) { - std::cout << "[OK]" << std::endl; - - }else{ - std::cout << "Select: '1' for normal method estimation \n '2' for mls normal estimation " << std::endl; - std::exit(-1); - } + std::cout << "Using mls method estimation..."; - // Create search tree* - pcl::search::KdTree::Ptr kdtree_for_normals (new pcl::search::KdTree); - kdtree_for_normals->setInputCloud(cloud_with_normals); + pcl::PointCloud::Ptr mls_points( + new pcl::PointCloud()); + pcl::MovingLeastSquares mls; - std::cout << "Applying surface meshing..."; + // Set parameters + mls.setComputeNormals(true); + mls.setInputCloud(cloudTranslated); + // mls.setDilationIterations(10); + // mls.setDilationVoxelSize(0.5); + // mls.setSqrGaussParam(2.0); + // mls.setUpsamplingRadius(5); + // mls.setPolynomialOrder (2); + // mls.setPointDensity(30); + mls.setSearchMethod(kdtree_for_points); + mls.setSearchRadius(0.03); + mls.process(*mls_points); - if(gp3_mode){ + pcl::PointCloud::Ptr temp( + new pcl::PointCloud()); - std::cout << "Using surface method: gp3 ..." << std::endl; + for (int i = 0; i < mls_points->points.size(); i++) { - int searchK = 100; - int search_radius = 10; - int setMU = 5; - int maxiNearestNeighbors = 100; - bool normalConsistency = false; + pcl::PointXYZ pt; + pt.x = cloud->points[i].x; + pt.y = cloud->points[i].y; + pt.z = cloud->points[i].z; - pcl::GreedyProjectionTriangulation gp3; + temp->points.push_back(pt); + } - gp3.setSearchRadius(search_radius);//It was 0.025 - gp3.setMu(setMU); //It was 2.5 - gp3.setMaximumNearestNeighbors(maxiNearestNeighbors); //It was 100 - //gp3.setMaximumSurfaceAngle(M_PI/4); // 45 degrees //it was 4 - //gp3.setMinimumAngle(M_PI/18); // 10 degrees //It was 18 - //gp3.setMaximumAngle(M_PI/1.5); // 120 degrees //it was 1.5 - gp3.setNormalConsistency(normalConsistency); //It was false - gp3.setInputCloud(cloud_with_normals); - gp3.setSearchMethod(kdtree_for_normals); - gp3.reconstruct(triangles); + pcl::concatenateFields(*temp, *mls_points, *cloud_with_normals); + std::cout << "[OK]" << std::endl; - //vtkSmartPointer polydata = vtkSmartPointer::New(); - //pcl::PolygonMesh mesh_pcl; - //pcl::VTKUtils::convertToVTK(triangles,polydata); - //pcl::VTKUtils::convertToPCL(polydata,mesh_pcl); + } else if (normal_mode) { - //pcl::io::savePolygonFilePLY("mesh.ply", mesh_pcl); + std::cout << "Using normal method estimation..."; - std::cout << "[OK]" << std::endl; + pcl::NormalEstimationOMP n; + pcl::PointCloud::Ptr normals(new pcl::PointCloud); - }else if(poisson_mode){ - - std::cout << "Using surface method: poisson ..." << std::endl; + n.setInputCloud(cloudTranslated); + n.setSearchMethod(kdtree_for_points); + n.setKSearch(20); // It was 20 + n.compute(*normals); // Normals are estimated using standard method. - int nThreads=8; - int setKsearch=10; - int depth=7; - float pointWeight=2.0; - float samplePNode=1.5; - float scale=1.1; - int isoDivide=8; - bool confidence=true; - bool outputPolygons=true; - bool manifold=true; - int solverDivide=8; + // pcl::PointCloud::Ptr cloud_with_normals (new + // pcl::PointCloud ()); + pcl::concatenateFields(*cloud, *normals, *cloud_with_normals); - pcl::Poisson poisson; + std::cout << "[OK]" << std::endl; + + } else { + std::cout << "Select: '1' for normal method estimation \n '2' for mls " + "normal estimation " + << std::endl; + std::exit(-1); + } - poisson.setDepth(depth);//9 - poisson.setInputCloud(cloud_with_normals); - poisson.setPointWeight(pointWeight);//4 - poisson.setDegree(2); - poisson.setSamplesPerNode(samplePNode);//1.5 - poisson.setScale(scale);//1.1 - poisson.setIsoDivide(isoDivide);//8 - poisson.setConfidence(confidence); - poisson.setOutputPolygons(outputPolygons); - poisson.setManifold(manifold); - poisson.setSolverDivide(solverDivide);//8 - poisson.reconstruct(triangles); + // Create search tree* + pcl::search::KdTree::Ptr kdtree_for_normals( + new pcl::search::KdTree); + kdtree_for_normals->setInputCloud(cloud_with_normals); + + std::cout << "Applying surface meshing..."; + + if (gp3_mode) { + + std::cout << "Using surface method: gp3 ..." << std::endl; + + int searchK = 100; + int search_radius = 10; + int setMU = 5; + int maxiNearestNeighbors = 100; + bool normalConsistency = false; + + pcl::GreedyProjectionTriangulation gp3; + + gp3.setSearchRadius(search_radius); // It was 0.025 + gp3.setMu(setMU); // It was 2.5 + gp3.setMaximumNearestNeighbors(maxiNearestNeighbors); // It was 100 + // gp3.setMaximumSurfaceAngle(M_PI/4); // 45 degrees //it was 4 + // gp3.setMinimumAngle(M_PI/18); // 10 degrees //It was 18 + // gp3.setMaximumAngle(M_PI/1.5); // 120 degrees //it was 1.5 + gp3.setNormalConsistency(normalConsistency); // It was false + gp3.setInputCloud(cloud_with_normals); + gp3.setSearchMethod(kdtree_for_normals); + gp3.reconstruct(triangles); + + // vtkSmartPointer polydata = + // vtkSmartPointer::New(); pcl::PolygonMesh mesh_pcl; + // pcl::VTKUtils::convertToVTK(triangles,polydata); + // pcl::VTKUtils::convertToPCL(polydata,mesh_pcl); + + // pcl::io::savePolygonFilePLY("mesh.ply", mesh_pcl); + + std::cout << "[OK]" << std::endl; + + } else if (poisson_mode) { + + std::cout << "Using surface method: poisson ..." << std::endl; + + int nThreads = 8; + int setKsearch = 10; + int depth = 7; + float pointWeight = 2.0; + float samplePNode = 1.5; + float scale = 1.1; + int isoDivide = 8; + bool confidence = true; + bool outputPolygons = true; + bool manifold = true; + int solverDivide = 8; + + pcl::Poisson poisson; + + poisson.setDepth(depth); // 9 + poisson.setInputCloud(cloud_with_normals); + poisson.setPointWeight(pointWeight); // 4 + poisson.setDegree(2); + poisson.setSamplesPerNode(samplePNode); // 1.5 + poisson.setScale(scale); // 1.1 + poisson.setIsoDivide(isoDivide); // 8 + poisson.setConfidence(confidence); + poisson.setOutputPolygons(outputPolygons); + poisson.setManifold(manifold); + poisson.setSolverDivide(solverDivide); // 8 + poisson.reconstruct(triangles); + + // pcl::PolygonMesh mesh2; + // poisson.reconstruct(mesh2); + // pcl::surface::SimplificationRemoveUnusedVertices rem; + // rem.simplify(mesh2,triangles); + + std::cout << "[OK]" << std::endl; + + } else { + std::cout << "Select: \n'1' for surface poisson method \n '2' for surface " + "gp3 method " + << std::endl; + std::exit(-1); + } +} - //pcl::PolygonMesh mesh2; - //poisson.reconstruct(mesh2); - //pcl::surface::SimplificationRemoveUnusedVertices rem; - //rem.simplify(mesh2,triangles); +void vizualizeMesh(pcl::PointCloud::Ptr &cloud, + pcl::PolygonMesh &mesh) { - std::cout << "[OK]" << std::endl; - - }else{ - std::cout << "Select: \n'1' for surface poisson method \n '2' for surface gp3 method " << std::endl; - std::exit(-1); - } - - } - -void vizualizeMesh(pcl::PointCloud::Ptr & cloud,pcl::PolygonMesh &mesh){ - - boost::shared_ptr viewer (new pcl::visualization::PCLVisualizer ("MAP3D MESH")); + boost::shared_ptr viewer( + new pcl::visualization::PCLVisualizer("MAP3D MESH")); int PORT1 = 0; viewer->createViewPort(0.0, 0.0, 0.5, 1.0, PORT1); - viewer->setBackgroundColor (0, 0, 0, PORT1); + viewer->setBackgroundColor(0, 0, 0, PORT1); viewer->addText("ORIGINAL", 10, 10, "PORT1", PORT1); int PORT2 = 0; viewer->createViewPort(0.5, 0.0, 1.0, 1.0, PORT2); - viewer->setBackgroundColor (0, 0, 0, PORT2); + viewer->setBackgroundColor(0, 0, 0, PORT2); viewer->addText("MESH", 10, 10, "PORT2", PORT2); - viewer->addPolygonMesh(mesh,"mesh",PORT2); + viewer->addPolygonMesh(mesh, "mesh", PORT2); viewer->addCoordinateSystem(); pcl::PointXYZ p1, p2, p3; p1.getArray3fMap() << 1, 0, 0; p2.getArray3fMap() << 0, 1, 0; - p3.getArray3fMap() << 0,0.1,1; + p3.getArray3fMap() << 0, 0.1, 1; viewer->addText3D("x", p1, 0.2, 1, 0, 0, "x_"); viewer->addText3D("y", p2, 0.2, 0, 1, 0, "y_"); - viewer->addText3D ("z", p3, 0.2, 0, 0, 1, "z_"); + viewer->addText3D("z", p3, 0.2, 0, 0, 1, "z_"); - if(cloud->points[0].r <= 0 and cloud->points[0].g <= 0 and cloud->points[0].b<= 0 ){ - pcl::visualization::PointCloudColorHandlerCustom color_handler(cloud,255,255,0); + if (cloud->points[0].r <= 0 and cloud->points[0].g <= 0 and + cloud->points[0].b <= 0) { + pcl::visualization::PointCloudColorHandlerCustom + color_handler(cloud, 255, 255, 0); viewer->removeAllPointClouds(0); - viewer->addPointCloud(cloud,color_handler,"original_cloud",PORT1); - }else{ - viewer->addPointCloud(cloud,"original_cloud",PORT1); + viewer->addPointCloud(cloud, color_handler, "original_cloud", PORT1); + } else { + viewer->addPointCloud(cloud, "original_cloud", PORT1); } - - viewer->initCameraParameters (); + + viewer->initCameraParameters(); viewer->resetCamera(); std::cout << "Press [q] to exit!" << std::endl; - while (!viewer->wasStopped ()){ - viewer->spin(); + while (!viewer->wasStopped()) { + viewer->spin(); } } /* -void cloudPointFilter(pcl::PointCloud::Ptr & cloud,pcl::PointCloud::Ptr& filterCloud){ +void cloudPointFilter(pcl::PointCloud::Ptr & +cloud,pcl::PointCloud::Ptr& filterCloud){ std::cout << "Filtering point cloud..." << std::endl; std::cout << "Point cloud before filter:" << cloud->points.size()<< std::endl; @@ -307,203 +331,215 @@ void cloudPointFilter(pcl::PointCloud::Ptr & cloud,pcl::PointClou radius_outlier_removal.setMinNeighborsInRadius(1); radius_outlier_removal.filter(*filterCloud); - std::cout << "Point cloud after filter:" << filterCloud->points.size() << std::endl; + std::cout << "Point cloud after filter:" << filterCloud->points.size() << +std::endl; } */ -int main(int argc, char **argv){ +int main(int argc, char **argv) { - pcl::PointCloud::Ptr cloud (new pcl::PointCloud()); + pcl::PointCloud::Ptr cloud( + new pcl::PointCloud()); pcl::PolygonMesh cl; std::vector filenames; bool file_is_pcd = false; bool file_is_ply = false; bool file_is_txt = false; - bool file_is_xyz = false; + bool file_is_xyz = false; - if(argc < 5 or argc > 5){ - printUsage(argv[0]); - return -1; + if (argc < 5 or argc > 5) { + printUsage(argv[0]); + return 0; } pcl::console::TicToc tt; pcl::console::print_highlight("Loading "); filenames = pcl::console::parse_file_extension_argument(argc, argv, ".ply"); - if(filenames.size()<=0){ - filenames = pcl::console::parse_file_extension_argument(argc, argv, ".pcd"); - if(filenames.size()<=0){ - filenames = pcl::console::parse_file_extension_argument(argc, argv, ".txt"); - if(filenames.size()<=0){ - filenames = pcl::console::parse_file_extension_argument(argc, argv, ".xyz"); - if(filenames.size()<=0){ - printUsage (argv[0]); - return -1; - }else if(filenames.size() == 1){ - file_is_xyz = true; - } - }else if(filenames.size() == 1){ - file_is_txt = true; + if (filenames.size() <= 0) { + filenames = pcl::console::parse_file_extension_argument(argc, argv, ".pcd"); + if (filenames.size() <= 0) { + filenames = + pcl::console::parse_file_extension_argument(argc, argv, ".txt"); + if (filenames.size() <= 0) { + filenames = + pcl::console::parse_file_extension_argument(argc, argv, ".xyz"); + if (filenames.size() <= 0) { + printUsage(argv[0]); + return -1; + } else if (filenames.size() == 1) { + file_is_xyz = true; } - }else if(filenames.size() == 1){ - file_is_pcd = true; + } else if (filenames.size() == 1) { + file_is_txt = true; + } + } else if (filenames.size() == 1) { + file_is_pcd = true; } - } - else if(filenames.size() == 1){ - file_is_ply = true; - }else{ - printUsage (argv[0]); - return -1; + } else if (filenames.size() == 1) { + file_is_ply = true; + } else { + printUsage(argv[0]); + return -1; } - if(file_is_pcd){ - if(pcl::io::loadPCDFile(argv[filenames[0]], *cloud) < 0){ - std::cout << "Error loading point cloud " << argv[filenames[0]] << "\n"; - return -1; - } - pcl::console::print_info("\nFound pcd file.\n"); - pcl::console::print_info ("[done, "); - pcl::console::print_value ("%g", tt.toc ()); - pcl::console::print_info (" ms : "); - pcl::console::print_value ("%d", cloud->size ()); - pcl::console::print_info (" points]\n"); - }else if(file_is_ply){ - pcl::io::loadPLYFile(argv[filenames[0]],*cloud); - if(cloud->points.size()<=0 or cloud->points[0].x<=0 and cloud->points[0].y<=0 and cloud->points[0].z<=0){ - pcl::console::print_warn("\nloadPLYFile could not read the cloud, attempting to loadPolygonFile...\n"); - pcl::io::loadPolygonFile(argv[filenames[0]], cl); - pcl::fromPCLPointCloud2(cl.cloud, *cloud); - if(cloud->points.size()<=0 or cloud->points[0].x<=0 and cloud->points[0].y<=0 and cloud->points[0].z<=0){ - pcl::console::print_warn("\nloadPolygonFile could not read the cloud, attempting to PLYReader...\n"); - pcl::PLYReader plyRead; - plyRead.read(argv[filenames[0]],*cloud); - if(cloud->points.size()<=0 or cloud->points[0].x<=0 and cloud->points[0].y<=0 and cloud->points[0].z<=0){ - pcl::console::print_error("\nError. ply file is not compatible.\n"); - return -1; - } - } - } - - pcl::console::print_info("\nFound ply file."); - pcl::console::print_info ("[done, "); - pcl::console::print_value ("%g", tt.toc ()); - pcl::console::print_info (" ms : "); - pcl::console::print_value ("%d", cloud->size ()); - pcl::console::print_info (" points]\n"); - - }else if(file_is_txt){ - std::ifstream file(argv[filenames[0]]); - if(!file.is_open()){ - std::cout << "Error: Could not find "<< argv[filenames[0]] << std::endl; - return -1; - } - - std::cout << "file opened." << std::endl; - double x_,y_,z_; - unsigned int r, g, b; - - while(file >> x_ >> y_ >> z_ >> r >> g >> b){ - pcl::PointXYZRGB pt; - pt.x = x_; - pt.y = y_; - pt.z= z_; - - uint8_t r_, g_, b_; - r_ = uint8_t(r); - g_ = uint8_t(g); - b_ = uint8_t(b); - - uint32_t rgb_ = ((uint32_t)r_ << 16 | (uint32_t)g_ << 8 | (uint32_t)b_); - pt.rgb = *reinterpret_cast(&rgb_); - - cloud->points.push_back(pt); - //std::cout << "pointXYZRGB:" << pt << std::endl; - } - - pcl::console::print_info("\nFound txt file.\n"); - pcl::console::print_info ("[done, "); - pcl::console::print_value ("%g", tt.toc ()); - pcl::console::print_info (" ms : "); - pcl::console::print_value ("%d", cloud->points.size ()); - pcl::console::print_info (" points]\n"); - - }else if(file_is_xyz){ - - std::ifstream file(argv[filenames[0]]); - if(!file.is_open()){ - std::cout << "Error: Could not find "<< argv[filenames[0]] << std::endl; + if (file_is_pcd) { + if (pcl::io::loadPCDFile(argv[filenames[0]], *cloud) < 0) { + std::cout << "Error loading point cloud " << argv[filenames[0]] << "\n"; + return -1; + } + pcl::console::print_info("\nFound pcd file.\n"); + pcl::console::print_info("[done, "); + pcl::console::print_value("%g", tt.toc()); + pcl::console::print_info(" ms : "); + pcl::console::print_value("%d", cloud->size()); + pcl::console::print_info(" points]\n"); + } else if (file_is_ply) { + pcl::io::loadPLYFile(argv[filenames[0]], *cloud); + if (cloud->points.size() <= 0 or cloud->points[0].x <= 0 and + cloud->points[0].y <= 0 and + cloud->points[0].z <= 0) { + pcl::console::print_warn("\nloadPLYFile could not read the cloud, " + "attempting to loadPolygonFile...\n"); + pcl::io::loadPolygonFile(argv[filenames[0]], cl); + pcl::fromPCLPointCloud2(cl.cloud, *cloud); + if (cloud->points.size() <= 0 or cloud->points[0].x <= 0 and + cloud->points[0].y <= 0 and + cloud->points[0].z <= 0) { + pcl::console::print_warn("\nloadPolygonFile could not read the cloud, " + "attempting to PLYReader...\n"); + pcl::PLYReader plyRead; + plyRead.read(argv[filenames[0]], *cloud); + if (cloud->points.size() <= 0 or cloud->points[0].x <= 0 and + cloud->points[0].y <= 0 and + cloud->points[0].z <= 0) { + pcl::console::print_error("\nError. ply file is not compatible.\n"); return -1; + } } - - std::cout << "file opened." << std::endl; - double x_,y_,z_; - - while(file >> x_ >> y_ >> z_){ - - pcl::PointXYZRGB pt; - pt.x = x_; - pt.y = y_; - pt.z= z_; - - cloud->points.push_back(pt); - //std::cout << "pointXYZRGB:" << pt << std::endl; - } - - pcl::console::print_info("\nFound xyz file.\n"); - pcl::console::print_info ("[done, "); - pcl::console::print_value ("%g", tt.toc ()); - pcl::console::print_info (" ms : "); - pcl::console::print_value ("%d", cloud->points.size ()); - pcl::console::print_info (" points]\n"); + } + + pcl::console::print_info("\nFound ply file."); + pcl::console::print_info("[done, "); + pcl::console::print_value("%g", tt.toc()); + pcl::console::print_info(" ms : "); + pcl::console::print_value("%d", cloud->size()); + pcl::console::print_info(" points]\n"); + + } else if (file_is_txt) { + std::ifstream file(argv[filenames[0]]); + if (!file.is_open()) { + std::cout << "Error: Could not find " << argv[filenames[0]] << std::endl; + return -1; + } + + std::cout << "file opened." << std::endl; + double x_, y_, z_; + unsigned int r, g, b; + + while (file >> x_ >> y_ >> z_ >> r >> g >> b) { + pcl::PointXYZRGB pt; + pt.x = x_; + pt.y = y_; + pt.z = z_; + + uint8_t r_, g_, b_; + r_ = uint8_t(r); + g_ = uint8_t(g); + b_ = uint8_t(b); + + uint32_t rgb_ = ((uint32_t)r_ << 16 | (uint32_t)g_ << 8 | (uint32_t)b_); + pt.rgb = *reinterpret_cast(&rgb_); + + cloud->points.push_back(pt); + // std::cout << "pointXYZRGB:" << pt << std::endl; + } + + pcl::console::print_info("\nFound txt file.\n"); + pcl::console::print_info("[done, "); + pcl::console::print_value("%g", tt.toc()); + pcl::console::print_info(" ms : "); + pcl::console::print_value("%d", cloud->points.size()); + pcl::console::print_info(" points]\n"); + + } else if (file_is_xyz) { + + std::ifstream file(argv[filenames[0]]); + if (!file.is_open()) { + std::cout << "Error: Could not find " << argv[filenames[0]] << std::endl; + return -1; + } + + std::cout << "file opened." << std::endl; + double x_, y_, z_; + + while (file >> x_ >> y_ >> z_) { + + pcl::PointXYZRGB pt; + pt.x = x_; + pt.y = y_; + pt.z = z_; + + cloud->points.push_back(pt); + // std::cout << "pointXYZRGB:" << pt << std::endl; + } + + pcl::console::print_info("\nFound xyz file.\n"); + pcl::console::print_info("[done, "); + pcl::console::print_value("%g", tt.toc()); + pcl::console::print_info(" ms : "); + pcl::console::print_value("%d", cloud->points.size()); + pcl::console::print_info(" points]\n"); } - cloud->width = (int) cloud->points.size (); + cloud->width = (int)cloud->points.size(); cloud->height = 1; cloud->is_dense = true; std::string select_mode = argv[2]; - std::string select_normal_method = argv[3];//10 - std::string output_dir = argv[4];//10 - - int surface_mode = std::atoi(select_mode.c_str()); - int normal_method = std::atoi(select_normal_method.c_str()); - - boost::filesystem::path dirPath(output_dir); - - if(not boost::filesystem::exists(dirPath) or not boost::filesystem::is_directory(dirPath)){ - pcl::console::print_error("\nError. does not exist or it's not valid: "); - std::cout << output_dir << std::endl; - std::exit(-1); + std::string select_normal_method = argv[3]; // 10 + std::string output_dir = argv[4]; // 10 + + int surface_mode = std::atoi(select_mode.c_str()); + int normal_method = std::atoi(select_normal_method.c_str()); + + boost::filesystem::path dirPath(output_dir); + + if (not boost::filesystem::exists(dirPath) or + not boost::filesystem::is_directory(dirPath)) { + pcl::console::print_error("\nError. does not exist or it's not valid: "); + std::cout << output_dir << std::endl; + std::exit(-1); } - pcl::PointCloud::Ptr cloud_xyz (new pcl::PointCloud()); - pcl::copyPointCloud(*cloud,*cloud_xyz); + pcl::PointCloud::Ptr cloud_xyz( + new pcl::PointCloud()); + pcl::copyPointCloud(*cloud, *cloud_xyz); - //pcl::PointCloud::Ptr cloud_xyz_filtered (new pcl::PointCloud()); - //cloudPointFilter(cloud_xyz,cloud_xyz_filtered); + // pcl::PointCloud::Ptr cloud_xyz_filtered (new + // pcl::PointCloud()); + // cloudPointFilter(cloud_xyz,cloud_xyz_filtered); pcl::PolygonMesh cloud_mesh; - create_mesh(cloud_xyz,surface_mode,normal_method,cloud_mesh); + create_mesh(cloud_xyz, surface_mode, normal_method, cloud_mesh); output_dir += "/cloud_mesh.ply"; std::string sav = "saved mesh in:"; sav += output_dir; - //typedef pcl::geometry::DefaultMeshTraits <> MeshTraits; - //typedef pcl::geometry::TriangleMesh Mesh; - //typedef pcl::geometry::MeshIO MeshIO; + // typedef pcl::geometry::DefaultMeshTraits <> MeshTraits; + // typedef pcl::geometry::TriangleMesh Mesh; + // typedef pcl::geometry::MeshIO MeshIO; pcl::console::print_info(sav.c_str()); std::cout << std::endl; - pcl::io::savePLYFileBinary(output_dir.c_str(),cloud_mesh); - //pcl::io::savePolygonFilePLY(output_dir.c_str(),cloud_mesh,true); - - - vtkObject::GlobalWarningDisplayOff(); // Disable vtk render warning - vizualizeMesh(cloud,cloud_mesh); - + pcl::io::savePLYFileBinary(output_dir.c_str(), cloud_mesh); + // pcl::io::savePolygonFilePLY(output_dir.c_str(),cloud_mesh,true); + + vtkObject::GlobalWarningDisplayOff(); // Disable vtk render warning + vizualizeMesh(cloud, cloud_mesh); + return 0; } -