From 98b4b377abdb2a0e630f2952a3941e8e52c1fad1 Mon Sep 17 00:00:00 2001 From: Dakota Benjamin Date: Thu, 26 Oct 2017 15:55:30 -0400 Subject: [PATCH] Remove old odm_texturing Former-commit-id: b54882ed302f8ddb61d5e91b9fdc8ad807024661 --- modules/CMakeLists.txt | 1 - modules/odm_texturing/CMakeLists.txt | 37 - modules/odm_texturing/CMakeLists.txt.user | 203 --- modules/odm_texturing/src/Logger.cpp | 31 - modules/odm_texturing/src/Logger.hpp | 68 - modules/odm_texturing/src/OdmTexturing.cpp | 1138 ----------------- modules/odm_texturing/src/OdmTexturing.hpp | 211 --- modules/odm_texturing/src/main.cpp | 15 - .../src/modifiedPclFunctions.cpp | 336 ----- .../src/modifiedPclFunctions.hpp | 20 - 10 files changed, 2060 deletions(-) delete mode 100644 modules/odm_texturing/CMakeLists.txt delete mode 100644 modules/odm_texturing/CMakeLists.txt.user delete mode 100644 modules/odm_texturing/src/Logger.cpp delete mode 100644 modules/odm_texturing/src/Logger.hpp delete mode 100644 modules/odm_texturing/src/OdmTexturing.cpp delete mode 100644 modules/odm_texturing/src/OdmTexturing.hpp delete mode 100644 modules/odm_texturing/src/main.cpp delete mode 100644 modules/odm_texturing/src/modifiedPclFunctions.cpp delete mode 100644 modules/odm_texturing/src/modifiedPclFunctions.hpp diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt index 3ca676e3..e1afd164 100644 --- a/modules/CMakeLists.txt +++ b/modules/CMakeLists.txt @@ -3,7 +3,6 @@ add_subdirectory(odm_extract_utm) add_subdirectory(odm_georef) add_subdirectory(odm_meshing) add_subdirectory(odm_orthophoto) -add_subdirectory(odm_texturing) add_subdirectory(odm_25dmeshing) if (ODM_BUILD_SLAM) add_subdirectory(odm_slam) diff --git a/modules/odm_texturing/CMakeLists.txt b/modules/odm_texturing/CMakeLists.txt deleted file mode 100644 index 2a098bab..00000000 --- a/modules/odm_texturing/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -project(odm_texturing) -cmake_minimum_required(VERSION 2.8) - -# Set pcl dir to the input spedified with option -DPCL_DIR="path" -set(PCL_DIR "PCL_DIR-NOTFOUND" CACHE "PCL_DIR" "Path to the pcl installation directory") - -# Set opencv dir to the input spedified with option -DOPENCV_DIR="path" -set(OPENCV_DIR "OPENCV_DIR-NOTFOUND" CACHE "OPENCV_DIR" "Path to the opencv installation directory") - -# Add compiler options. -add_definitions(-Wall -Wextra) - -# Find pcl at the location specified by PCL_DIR -find_package(PCL 1.8 HINTS "${PCL_DIR}/share/pcl-1.8" REQUIRED) - -# Find OpenCV at the default location -find_package(OpenCV HINTS "${OPENCV_DIR}" REQUIRED) - -# Only link with required opencv modules. -set(OpenCV_LIBS opencv_core opencv_imgproc opencv_highgui) - -# Add the PCL, Eigen and OpenCV include dirs. -# Necessary since the PCL_INCLUDE_DIR variable set by find_package is broken.) -include_directories(${PCL_ROOT}/include/pcl-${PCL_VERSION_MAJOR}.${PCL_VERSION_MINOR}) -include_directories(${EIGEN_ROOT}) -include_directories(${OpenCV_INCLUDE_DIRS}) - -#library_directories(${OpenCV_LIBRARY_DIRS}) - -# Add source directory -aux_source_directory("./src" SRC_LIST) - -# Add exectuteable -add_executable(${PROJECT_NAME} ${SRC_LIST}) -target_link_libraries(odm_texturing ${PCL_COMMON_LIBRARIES} ${PCL_IO_LIBRARIES} ${PCL_SURFACE_LIBRARIES} ${OpenCV_LIBS}) - - diff --git a/modules/odm_texturing/CMakeLists.txt.user b/modules/odm_texturing/CMakeLists.txt.user deleted file mode 100644 index cfc3ea3a..00000000 --- a/modules/odm_texturing/CMakeLists.txt.user +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - ProjectExplorer.Project.ActiveTarget - 0 - - - ProjectExplorer.Project.EditorSettings - - true - false - - Cpp - - CppGlobal - - - - QmlJS - - QmlJSGlobal - - - 2 - System - false - 4 - true - 1 - true - 0 - true - 0 - 8 - true - 1 - true - true - true - false - - - - ProjectExplorer.Project.PluginSettings - - - - ProjectExplorer.Project.Target.0 - - Desktop - - CMakeProjectManager.DefaultCMakeTarget - 0 - 0 - 0 - - /home/spotscale/odm/OpenDroneMap_spotscale/odm_texturing4-build - ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-32bit./usr/bin/gdb - ProjectExplorer.ToolChain.Gcc:/usr/bin/g++.x86-linux-generic-elf-32bit./usr/bin/gdb - - - - - false - Make - - CMakeProjectManager.MakeStep - - 1 - Build - - ProjectExplorer.BuildSteps.Build - - - - clean - - true - Make - - CMakeProjectManager.MakeStep - - 1 - Clean - - ProjectExplorer.BuildSteps.Clean - - 2 - false - - all - - CMakeProjectManager.CMakeBuildConfiguration - - 1 - - - 0 - Deploy - - ProjectExplorer.BuildSteps.Deploy - - 1 - No deployment - - ProjectExplorer.DefaultDeployConfiguration - - 1 - - true - true - - - false - false - false - false - false - false - false - false - true - true - 0.01 - 0.01 - 10 - 10 - true - true - 25 - 25 - - - true - true - valgrind - valgrind - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - - 0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - - 2 - odm_texturing - -verbose -bundleFile "../../../shared_folder/copr2/reconstruction-with-image-size-1200/bundle/bundle.out" -imagesPath "../../../shared_folder/copr2" -imagesListPath "../../../shared_folder/copr2/reconstruction-with-image-size-1200/list.txt" -inputModelPath "../../../shared_folder/copr2/reconstruction-with-image-size-1200-results/odm_mesh-0000.ply" -outputFolder "../../../shared_folder/copr2/reconstruction-with-image-size-1200-results/odm_texturing/" -textureResolution 4096 -textureWithSize 3600 -bundleResizedTo 1200 - false - - - odm_texturing - - CMakeProjectManager.CMakeRunConfiguration. - 3768 - true - false - false - - 1 - - - - ProjectExplorer.Project.TargetCount - 1 - - - ProjectExplorer.Project.Updater.EnvironmentId - {785a73be-b55f-490c-9d46-e1451c235840} - - - ProjectExplorer.Project.Updater.FileVersion - 10 - - diff --git a/modules/odm_texturing/src/Logger.cpp b/modules/odm_texturing/src/Logger.cpp deleted file mode 100644 index a6c81a8b..00000000 --- a/modules/odm_texturing/src/Logger.cpp +++ /dev/null @@ -1,31 +0,0 @@ -#include "Logger.hpp" - - -Logger::Logger(bool isPrintingInCout) : isPrintingInCout_(isPrintingInCout) -{ - -} - -Logger::~Logger() -{ - -} - -void Logger::printToFile(std::string filePath) -{ - std::ofstream file(filePath.c_str(), std::ios::binary); - file << logStream_.str(); - file.close(); -} - -bool Logger::isPrintingInCout() const -{ - return isPrintingInCout_; -} - -void Logger::setIsPrintingInCout(bool isPrintingInCout) -{ - isPrintingInCout_ = isPrintingInCout; -} - - diff --git a/modules/odm_texturing/src/Logger.hpp b/modules/odm_texturing/src/Logger.hpp deleted file mode 100644 index 31c5538c..00000000 --- a/modules/odm_texturing/src/Logger.hpp +++ /dev/null @@ -1,68 +0,0 @@ -#pragma once - -// STL -#include -#include -#include -#include - -/*! - * \brief The Logger class is used to store program messages in a log file. - * \details By using the << operator while printInCout is set, the class writes both to - * cout and to file, if the flag is not set, output is written to file only. - */ -class Logger -{ -public: - /*! - * \brief Logger Contains functionality for printing and displaying log information. - * \param printInCout Flag toggling if operator << also writes to cout. - */ - Logger(bool isPrintingInCout = true); - - /*! - * \brief Destructor. - */ - ~Logger(); - - /*! - * \brief print Prints the contents of the log to file. - * \param filePath Path specifying where to write the log. - */ - void printToFile(std::string filePath); - - /*! - * \brief isPrintingInCout Check if console printing flag is set. - * \return Console printing flag. - */ - bool isPrintingInCout() const; - - /*! - * \brief setIsPrintingInCout Set console printing flag. - * \param isPrintingInCout Value, if true, messages added to the log are also printed in cout. - */ - void setIsPrintingInCout(bool isPrintingInCout); - - /*! - * Operator for printing messages to log and in the standard output stream if desired. - */ - template - friend Logger& operator<< (Logger &log, T t) - { - // If console printing is enabled. - if (log.isPrintingInCout_) - { - std::cout << t; - std::cout.flush(); - } - // Write to log. - log.logStream_ << t; - - return log; - } - -private: - bool isPrintingInCout_; /*!< If flag is set, log is printed in cout and written to the log. */ - - std::stringstream logStream_; /*!< Stream for storing the log. */ -}; diff --git a/modules/odm_texturing/src/OdmTexturing.cpp b/modules/odm_texturing/src/OdmTexturing.cpp deleted file mode 100644 index c3e26bd5..00000000 --- a/modules/odm_texturing/src/OdmTexturing.cpp +++ /dev/null @@ -1,1138 +0,0 @@ -#include "OdmTexturing.hpp" - -OdmTexturing::OdmTexturing() : log_(false) -{ - logFilePath_ = "odm_texturing_log.txt"; - - bundleResizedTo_ = 1200.0; - textureWithSize_ = 2000.0; - textureResolution_ = 4096.0; - nrTextures_ = 0; - padding_ = 15.0; - - mesh_ = pcl::TextureMeshPtr(new pcl::TextureMesh); - patches_ = std::vector(0); - tTIA_ = std::vector(0); - -} - -OdmTexturing::~OdmTexturing() -{ - -} - -int OdmTexturing::run(int argc, char **argv) -{ - if (argc <= 1) - { - printHelp(); - return EXIT_SUCCESS; - } - - try - { - parseArguments(argc, argv); - loadMesh(); - loadCameras(); - triangleToImageAssignment(); - calculatePatches(); - sortPatches(); - createTextures(); - writeObjFile(); - } - catch (const OdmTexturingException& e) - { - log_.setIsPrintingInCout(true); - log_ << "Error in OdmTexturing:\n"; - log_ << e.what() << "\n"; - log_.printToFile(logFilePath_); - log_ << "For more detailed information, see log file." << "\n"; - return EXIT_FAILURE; - } - catch (const std::exception& e) - { - log_.setIsPrintingInCout(true); - log_ << "Error in OdmTexturing:\n"; - log_ << e.what() << "\n"; - log_.printToFile(logFilePath_); - log_ << "For more detailed information, see log file." << "\n"; - return EXIT_FAILURE; - } - catch (...) - { - log_.setIsPrintingInCout(true); - log_ << "Unknown error in OdmTexturing:\n"; - log_.printToFile(logFilePath_); - log_ << "For more detailed information, see log file." << "\n"; - return EXIT_FAILURE; - } - - log_.printToFile(logFilePath_); - return EXIT_SUCCESS; -} - -void OdmTexturing::parseArguments(int argc, char** argv) -{ - for(int argIndex = 1; argIndex < argc; ++argIndex) - { - // The argument to be parsed - std::string argument = std::string(argv[argIndex]); - if (argument == "-help") - { - printHelp(); - } - else if (argument == "-verbose") - { - log_.setIsPrintingInCout(true); - } - else if (argument == "-bundleFile") - { - ++argIndex; - if (argIndex >= argc) - { - throw OdmTexturingException("Missing argument for '" + argument + "'."); - } - bundlePath_ = std::string(argv[argIndex]); - std::ifstream testFile(bundlePath_.c_str(), std::ios_base::binary); - if (!testFile.is_open()) - { - throw OdmTexturingException("Argument '" + argument + "' has a bad value (file not accessible)."); - } - log_ << "Bundle path was set to: " << bundlePath_ << "\n"; - } - else if (argument == "-imagesPath") - { - ++argIndex; - if (argIndex >= argc) - { - throw OdmTexturingException("Missing argument for '" + argument + "'."); - } - std::stringstream ss(argv[argIndex]); - ss >> imagesPath_; - if (ss.bad()) - { - throw OdmTexturingException("Argument '" + argument + "' has a bad value. (wrong type)"); - } - log_ << "Images path was set to: " << imagesPath_ << "\n"; - } - else if (argument == "-imagesListPath") - { - ++argIndex; - if (argIndex >= argc) - { - throw OdmTexturingException("Missing argument for '" + argument + "'."); - } - imagesListPath_ = std::string(argv[argIndex]); - std::ifstream testFile(imagesListPath_.c_str(), std::ios_base::binary); - if (!testFile.is_open()) - { - throw OdmTexturingException("Argument '" + argument + "' has a bad value (file not accessible)."); - } - log_ << "Images list path was set to: " << imagesListPath_ << "\n"; - } - else if (argument == "-inputModelPath") - { - ++argIndex; - if (argIndex >= argc) - { - throw OdmTexturingException("Missing argument for '" + argument + "'."); - } - inputModelPath_ = std::string(argv[argIndex]); - std::ifstream testFile(inputModelPath_.c_str(), std::ios_base::binary); - if (!testFile.is_open()) - { - throw OdmTexturingException("Argument '" + argument + "' has a bad value (file not accessible)."); - - } - log_ << "Input model path was set to: " << inputModelPath_ << "\n"; - } - else if (argument == "-outputFolder") - { - ++argIndex; - if (argIndex >= argc) - { - throw OdmTexturingException("Missing argument for '" + argument + "'."); - } - std::stringstream ss(argv[argIndex]); - ss >> outputFolder_; - if (ss.bad()) - { - throw OdmTexturingException("Argument '" + argument + "' has a bad value. (wrong type)"); - } - log_ << "Output folder path was set to: " << outputFolder_ << "\n"; - } - else if (argument == "-logFile") - { - ++argIndex; - if (argIndex >= argc) - { - throw OdmTexturingException("Missing argument for '" + argument + "'."); - } - logFilePath_ = std::string(argv[argIndex]); - std::ofstream testFile(logFilePath_.c_str()); - if (!testFile.is_open()) - { - throw OdmTexturingException("Argument '" + argument + "' has a bad value."); - } - log_ << "Log file path was set to: " << logFilePath_ << "\n"; - } - else if (argument == "-textureResolution") - { - ++argIndex; - if (argIndex >= argc) - { - throw OdmTexturingException("Missing argument for '" + argument + "'."); - } - std::stringstream ss(argv[argIndex]); - ss >> textureResolution_; - if (ss.bad()) - { - throw OdmTexturingException("Argument '" + argument + "' has a bad value. (wrong type)"); - } - log_ << "The texture resolution was set to: " << textureResolution_ << "\n"; - } - else if (argument == "-textureWithSize") - { - ++argIndex; - if (argIndex >= argc) - { - throw OdmTexturingException("Missing argument for '" + argument + "'."); - } - std::stringstream ss(argv[argIndex]); - ss >> textureWithSize_; - if (ss.bad()) - { - throw OdmTexturingException("Argument '" + argument + "' has a bad value. (wrong type)"); - } - log_ << "The resolution to texture with was set to: " << textureWithSize_ << "\n"; - } - else if (argument == "-bundleResizedTo") - { - ++argIndex; - if (argIndex >= argc) - { - throw OdmTexturingException("Missing argument for '" + argument + "'."); - } - std::stringstream ss(argv[argIndex]); - ss >> bundleResizedTo_; - if (ss.bad()) - { - throw OdmTexturingException("Argument '" + argument + "' has a bad value. (wrong type)"); - } - log_ << "The resized resolution used in bundler was set to: " << bundleResizedTo_ << "\n"; - } - else - { - printHelp(); - throw OdmTexturingException("Unrecognized argument '" + argument + "'."); - } - } - - if (textureWithSize_ > textureResolution_) - { - textureWithSize_ = textureResolution_; - log_ << "textureWithSize parameter was set to a lower value since it can not be greater than the texture resolution.\n"; - } - -} - -void OdmTexturing::loadMesh() -{ - // Read model from ply-file - pcl::PolygonMeshPtr plyMeshPtr(new pcl::PolygonMesh); - if (pcl::io::loadPLYFile(inputModelPath_, *plyMeshPtr.get()) == -1) - { - throw OdmTexturingException("Error when reading model from:\n" + inputModelPath_ + "\n"); - } - else - { - log_ << "Successfully loaded " << plyMeshPtr->polygons.size() << " polygons from file.\n"; - } - - // Transfer data from ply file to TextureMesh - mesh_->cloud = plyMeshPtr->cloud; - std::vector polygons; - - // Push faces from ply-mesh into TextureMesh - polygons.resize(plyMeshPtr->polygons.size()); - for (size_t i = 0; i < plyMeshPtr->polygons.size(); ++i) - { - polygons[i] = plyMeshPtr->polygons[i]; - } - mesh_->tex_polygons.push_back(polygons); - -} - -void OdmTexturing::loadCameras() -{ - std::ifstream bundleFile, imageListFile; - bundleFile.open(bundlePath_.c_str(), std::ios_base::binary); - imageListFile.open(imagesListPath_.c_str(), std::ios_base::binary); - - // Check if file is open - if(!bundleFile.is_open()) - { - throw OdmTexturingException("Error when reading the bundle file."); - } - else - { - log_ << "Successfully read the bundle file.\n"; - } - - if (!imageListFile.is_open()) - { - throw OdmTexturingException("Error when reading the image list file."); - } - else - { - log_ << "Successfully read the image list file.\n"; - } - - // A temporary storage for a line from the file. - std::string dummyLine = ""; - - std::getline(bundleFile, dummyLine); - - int nrCameras= 0; - bundleFile >> nrCameras; - bundleFile >> dummyLine; - for (int i = 0; i < nrCameras;++i) - { - double val; - pcl::TextureMapping::Camera cam; - Eigen::Affine3f transform; - bundleFile >> val; //Read focal length from bundle file - cam.focal_length = val; - bundleFile >> val; //Read k1 from bundle file - bundleFile >> val; //Read k2 from bundle file - - bundleFile >> val; transform(0,0) = val; // Read rotation (0,0) from bundle file - bundleFile >> val; transform(0,1) = val; // Read rotation (0,1) from bundle file - bundleFile >> val; transform(0,2) = val; // Read rotation (0,2) from bundle file - - bundleFile >> val; transform(1,0) = val; // Read rotation (1,0) from bundle file - bundleFile >> val; transform(1,1) = val; // Read rotation (1,1) from bundle file - bundleFile >> val; transform(1,2) = val; // Read rotation (1,2) from bundle file - - bundleFile >> val; transform(2,0) = val; // Read rotation (2,0) from bundle file - bundleFile >> val; transform(2,1) = val; // Read rotation (2,1) from bundle file - bundleFile >> val; transform(2,2) = val; // Read rotation (2,2) from bundle file - - bundleFile >> val; transform(0,3) = val; // Read translation (0,3) from bundle file - bundleFile >> val; transform(1,3) = val; // Read translation (1,3) from bundle file - bundleFile >> val; transform(2,3) = val; // Read translation (2,3) from bundle file - - transform(3,0) = 0.0; - transform(3,1) = 0.0; - transform(3,2) = 0.0; - transform(3,3) = 1.0; - - transform = transform.inverse(); - - // Column negation - transform(0,2) = -1.0*transform(0,2); - transform(1,2) = -1.0*transform(1,2); - transform(2,2) = -1.0*transform(2,2); - - transform(0,1) = -1.0*transform(0,1); - transform(1,1) = -1.0*transform(1,1); - transform(2,1) = -1.0*transform(2,1); - - // Set values from bundle to current camera - cam.pose = transform; - - std::getline(imageListFile, dummyLine); - /*size_t firstWhitespace = dummyLine.find_first_of(" "); - - if (firstWhitespace != std::string::npos) - { - cam.texture_file = imagesPath_ + "/" + dummyLine.substr(2,firstWhitespace-2); - } - else - { - cam.texture_file = imagesPath_ + "/" + dummyLine.substr(2); - }*/ - - if (imagesPath_.size() == 0) - cam.texture_file = dummyLine; - else - cam.texture_file = imagesPath_ + "/" + dummyLine; - - // Read image to get full resolution size - cv::Mat image = cv::imread(cam.texture_file); - - if (image.empty()) - { - throw OdmTexturingException("Failed to read image:\n'" + cam.texture_file + "'\n"); - } - - double imageWidth = static_cast(image.cols); - double textureWithWidth = static_cast(textureWithSize_); - - // Calculate scale factor to texture with textureWithSize - double factor = textureWithWidth/imageWidth; - if (factor > 1.0f) - { - factor = 1.0f; - } - - // Update camera size and focal length - cam.height = static_cast(std::floor(factor*(static_cast(image.rows)))); - cam.width = static_cast(std::floor(factor*(static_cast(image.cols)))); - cam.focal_length *= static_cast(cam.width)/bundleResizedTo_; - - // Add camera - cameras_.push_back(cam); - - } - -} - -void OdmTexturing::triangleToImageAssignment() -{ - // Resize the triangleToImageAssigmnent vector to match the number of faces in the mesh - tTIA_.resize(mesh_->tex_polygons[0].size()); - - // Set all values in the triangleToImageAssignment vector to a default value (-1) if there are no optimal camera - for (size_t i = 0; i < tTIA_.size(); ++i) - { - tTIA_[i] = -1; - } - - // Vector containing information if the face has been given an optimal camera or not - std::vector hasOptimalCamera = std::vector(mesh_->tex_polygons[0].size()); - - // Set default value that no face has an optimal camera - for (size_t faceIndex = 0; faceIndex < hasOptimalCamera.size(); ++faceIndex) - { - hasOptimalCamera[faceIndex] = false; - } - - // Convert vertices to pcl::PointXYZ cloud - pcl::PointCloud::Ptr meshCloud (new pcl::PointCloud); - pcl::fromPCLPointCloud2 (mesh_->cloud, *meshCloud); - - // Create dummy point and UV-index for vertices not visible in any cameras - pcl::PointXY nanPoint; - nanPoint.x = std::numeric_limits::quiet_NaN(); - nanPoint.y = std::numeric_limits::quiet_NaN(); - pcl::texture_mapping::UvIndex uvNull; - uvNull.idx_cloud = -1; - uvNull.idx_face = -1; - - for (size_t cameraIndex = 0; cameraIndex < cameras_.size(); ++cameraIndex) - { - // Move vertices in mesh into the camera coordinate system - pcl::PointCloud::Ptr cameraCloud (new pcl::PointCloud); - pcl::transformPointCloud (*meshCloud, *cameraCloud, cameras_[cameraIndex].pose.inverse()); - - // Cloud to contain points projected into current camera - pcl::PointCloud::Ptr projections (new pcl::PointCloud); - - // Vector containing information if the polygon is visible in current camera - std::vector visibility; - visibility.resize(mesh_->tex_polygons[0].size()); - - // Vector for remembering the correspondence between uv-coordinates and faces - std::vector indexUvToPoints; - - // Count the number of vertices inside the camera frustum - int countInsideFrustum = 0; - - // Frustum culling for all faces - for (size_t faceIndex = 0; faceIndex < mesh_->tex_polygons[0].size(); ++faceIndex) - { - // Variables for the face vertices as projections in the camera plane - pcl::PointXY pixelPos0; pcl::PointXY pixelPos1; pcl::PointXY pixelPos2; - - // If the face is inside the camera frustum - if (isFaceProjected(cameras_[cameraIndex], - cameraCloud->points[mesh_->tex_polygons[0][faceIndex].vertices[0]], - cameraCloud->points[mesh_->tex_polygons[0][faceIndex].vertices[1]], - cameraCloud->points[mesh_->tex_polygons[0][faceIndex].vertices[2]], - pixelPos0, pixelPos1, pixelPos2)) - { - // Add pixel positions in camera to projections - projections->points.push_back((pixelPos0)); - projections->points.push_back((pixelPos1)); - projections->points.push_back((pixelPos2)); - - // Remember corresponding face - pcl::texture_mapping::UvIndex u1, u2, u3; - u1.idx_cloud = mesh_->tex_polygons[0][faceIndex].vertices[0]; - u2.idx_cloud = mesh_->tex_polygons[0][faceIndex].vertices[1]; - u3.idx_cloud = mesh_->tex_polygons[0][faceIndex].vertices[2]; - u1.idx_face = faceIndex; u2.idx_face = faceIndex; u3.idx_face = faceIndex; - indexUvToPoints.push_back(u1); - indexUvToPoints.push_back(u2); - indexUvToPoints.push_back(u3); - - // Update visibility vector - visibility[faceIndex] = true; - - // Update count - ++countInsideFrustum; - } - else - { - // If not visible set nanPoint and uvNull - projections->points.push_back(nanPoint); - projections->points.push_back(nanPoint); - projections->points.push_back(nanPoint); - indexUvToPoints.push_back(uvNull); - indexUvToPoints.push_back(uvNull); - indexUvToPoints.push_back(uvNull); - - // Update visibility vector - visibility[faceIndex] = false; - } - - - } - - // If any faces are visible in the current camera perform occlusion culling - if (countInsideFrustum > 0) - { - // Set up acceleration structure - pcl::KdTreeFLANN kdTree; - kdTree.setInputCloud(projections); - - // Loop through all faces and perform occlusion culling for faces inside frustum - for (size_t faceIndex = 0; faceIndex < mesh_->tex_polygons[0].size(); ++faceIndex) - { - if (visibility[faceIndex]) - { - // Vectors to store output from radiusSearch in acceleration structure - std::vector neighbors; std::vector neighborsSquaredDistance; - - // Variables for the vertices in face as projections in the camera plane - pcl::PointXY pixelPos0; pcl::PointXY pixelPos1; pcl::PointXY pixelPos2; - - if (isFaceProjected(cameras_[cameraIndex], - cameraCloud->points[mesh_->tex_polygons[0][faceIndex].vertices[0]], - cameraCloud->points[mesh_->tex_polygons[0][faceIndex].vertices[1]], - cameraCloud->points[mesh_->tex_polygons[0][faceIndex].vertices[2]], - pixelPos0, pixelPos1, pixelPos2)) - { - // Variables for a radius circumscribing the polygon in the camera plane and the center of the polygon - double radius; pcl::PointXY center; - - // Get values for radius and center - getTriangleCircumscribedCircleCentroid(pixelPos0, pixelPos1, pixelPos2, center, radius); - - // Perform radius search in the acceleration structure - int radiusSearch = kdTree.radiusSearch(center, radius, neighbors, neighborsSquaredDistance); - - // If other projections are found inside the radius - if (radiusSearch > 0) - { - // Extract distances for all vertices for face to camera - double d0 = cameraCloud->points[mesh_->tex_polygons[0][faceIndex].vertices[0]].z; - double d1 = cameraCloud->points[mesh_->tex_polygons[0][faceIndex].vertices[1]].z; - double d2 = cameraCloud->points[mesh_->tex_polygons[0][faceIndex].vertices[2]].z; - - // Calculate largest distance and store in distance variable - double distance = std::max(d0, std::max(d1,d2)); - - // Compare distance to all neighbors inside radius - for (size_t i = 0; i < neighbors.size(); ++i) - { - // Distance variable from neighbor to camera - double neighborDistance = cameraCloud->points[indexUvToPoints[neighbors[i]].idx_cloud].z; - - // If the neighbor has a greater distance to the camera and is inside face polygon set it as not visible - if (distance < neighborDistance) - { - if (checkPointInsideTriangle(pixelPos0, pixelPos1, pixelPos2, projections->points[neighbors[i]])) - { - // Update visibility for neighbors - visibility[indexUvToPoints[neighbors[i]].idx_face] = false; - } - } - } - } - } - } - } - } - - // Number of polygons that add current camera as the optimal camera - int count = 0; - - // Update optimal cameras for faces visible in current camera - for (size_t faceIndex = 0; faceIndex < visibility.size();++faceIndex) - { - if (visibility[faceIndex]) - { - hasOptimalCamera[faceIndex] = true; - tTIA_[faceIndex] = cameraIndex; - ++count; - } - } - - } - -} - -void OdmTexturing::calculatePatches() -{ - // Convert vertices to pcl::PointXYZ cloud - pcl::PointCloud::Ptr meshCloud (new pcl::PointCloud); - pcl::fromPCLPointCloud2 (mesh_->cloud, *meshCloud); - - // Reserve size for patches_ - patches_.reserve(tTIA_.size()); - - // Vector containing vector with indicies to faces visible in corresponding camera index - std::vector > optFaceCameraVector = std::vector >(cameras_.size()); - - // Counter variables for visible and occluded faces - int countVis = 0; - int countOcc = 0; - - Patch nonVisibleFaces; - nonVisibleFaces.optimalCameraIndex_ = -1; - nonVisibleFaces.materialIndex_ = -1; - nonVisibleFaces.placed_ = true; - - // Setup vector containing vectors with all faces correspondning to camera according to triangleToImageAssignment vector - for (size_t i = 0; i < tTIA_.size(); ++i) - { - if (tTIA_[i] > -1) - { - // If face has an optimal camera add to optFaceCameraVector and update counter for visible faces - countVis++; - optFaceCameraVector[tTIA_[i]].push_back(i); - } - else - { - // Add non visible face to patch nonVisibleFaces - nonVisibleFaces.faces_.push_back(i); - - // Update counter for occluded faces - countOcc++; - } - } - - log_ << "Visible faces: "<::Ptr cameraCloud (new pcl::PointCloud); - pcl::transformPointCloud (*meshCloud, *cameraCloud, cameras_[cameraIndex].pose.inverse()); - - // While faces visible in camera remains to be assigned to a patch - while(0 < optFaceCameraVector[cameraIndex].size()) - { - // Create current patch - Patch patch; - - // Vector containing faces to check connectivity with current patch - std::vector addedFaces = std::vector(0); - - // Add last face in optFaceCameraVector to faces to check connectivity and add it to the current patch - addedFaces.push_back(optFaceCameraVector[cameraIndex].back()); - - // Add first face to patch - patch.faces_.push_back(optFaceCameraVector[cameraIndex].back()); - - // Remove face from optFaceCameraVector - optFaceCameraVector[cameraIndex].pop_back(); - - // Declare uv-coordinates for face - pcl::PointXY uvCoord1; pcl::PointXY uvCoord2; pcl::PointXY uvCoord3; - - // Calculate uv-coordinates for face in camera - if (isFaceProjected(cameras_[cameraIndex], - cameraCloud->points[mesh_->tex_polygons[0][addedFaces.back()].vertices[0]], - cameraCloud->points[mesh_->tex_polygons[0][addedFaces.back()].vertices[1]], - cameraCloud->points[mesh_->tex_polygons[0][addedFaces.back()].vertices[2]], - uvCoord1, uvCoord2, uvCoord3)) - { - // Set minimum and maximum uv-coordinate value for patch - patch.minu_ = std::min(uvCoord1.x, std::min(uvCoord2.x, uvCoord3.x)); - patch.minv_ = std::min(uvCoord1.y, std::min(uvCoord2.y, uvCoord3.y)); - patch.maxu_ = std::max(uvCoord1.x, std::max(uvCoord2.x, uvCoord3.x)); - patch.maxv_ = std::max(uvCoord1.y, std::max(uvCoord2.y, uvCoord3.y)); - - while(0 < addedFaces.size()) - { - // Set face to check neighbors - size_t patchFaceIndex = addedFaces.back(); - - // Remove patchFaceIndex from addedFaces - addedFaces.pop_back(); - - // Check against all remaining faces with the same optimal camera - for (size_t i = 0; i < optFaceCameraVector[cameraIndex].size(); ++i) - { - size_t modelFaceIndex = optFaceCameraVector[cameraIndex][i]; - - // Don't check against self - if (modelFaceIndex != patchFaceIndex) - { - // Store indices for vertices of both faces - size_t face0v0 = mesh_->tex_polygons[0][modelFaceIndex].vertices[0]; - size_t face0v1 = mesh_->tex_polygons[0][modelFaceIndex].vertices[1]; - size_t face0v2 = mesh_->tex_polygons[0][modelFaceIndex].vertices[2]; - size_t face1v0 = mesh_->tex_polygons[0][patchFaceIndex].vertices[0]; - size_t face1v1 = mesh_->tex_polygons[0][patchFaceIndex].vertices[1]; - size_t face1v2 = mesh_->tex_polygons[0][patchFaceIndex].vertices[2]; - - // Count the number of shared vertices - size_t nShared = 0; - nShared += (face0v0 == face1v0 ? 1 : 0) + (face0v0 == face1v1 ? 1 : 0) + (face0v0 == face1v2 ? 1 : 0); - nShared += (face0v1 == face1v0 ? 1 : 0) + (face0v1 == face1v1 ? 1 : 0) + (face0v1 == face1v2 ? 1 : 0); - nShared += (face0v2 == face1v0 ? 1 : 0) + (face0v2 == face1v1 ? 1 : 0) + (face0v2 == face1v2 ? 1 : 0); - - // If sharing a vertex - if (nShared > 0) - { - // Declare uv-coordinates for face - pcl::PointXY uv1; pcl::PointXY uv2; pcl::PointXY uv3; - - // Calculate uv-coordinates for face in camera - isFaceProjected(cameras_[cameraIndex], - cameraCloud->points[mesh_->tex_polygons[0][modelFaceIndex].vertices[0]], - cameraCloud->points[mesh_->tex_polygons[0][modelFaceIndex].vertices[1]], - cameraCloud->points[mesh_->tex_polygons[0][modelFaceIndex].vertices[2]], - uv1, uv2, uv3); - - // Update minimum and maximum uv-coordinate value for patch - patch.minu_ = std::min(patch.minu_, std::min(uv1.x, std::min(uv2.x, uv3.x))); - patch.minv_ = std::min(patch.minv_, std::min(uv1.y, std::min(uv2.y, uv3.y))); - patch.maxu_ = std::max(patch.maxu_, std::max(uv1.x, std::max(uv2.x, uv3.x))); - patch.maxv_ = std::max(patch.maxv_, std::max(uv1.y, std::max(uv2.y, uv3.y))); - - // Add modelFaceIndex to patch - patch.faces_.push_back(modelFaceIndex); - - // Add modelFaceIndex from faces to check for neighbors with same optimal camera - addedFaces.push_back(modelFaceIndex); - - // Remove modelFaceIndex from optFaceCameraVector to exclude it from comming iterations - optFaceCameraVector[cameraIndex].erase(optFaceCameraVector[cameraIndex].begin() + i); - } - } - } - } - } - - // Set optimal camera for patch - patch.optimalCameraIndex_ = static_cast(cameraIndex); - - // Add patch to patches_ vector - patches_.push_back(patch); - } - } - patches_.push_back(nonVisibleFaces); -} - -Coords OdmTexturing::recursiveFindCoords(Node &n, float w, float h) -{ - // Coordinates to return and place patch - Coords c; - - if (NULL != n.lft_) - { - c = recursiveFindCoords(*(n.lft_), w, h); - if (c.success_) - { - return c; - } - else - { - return recursiveFindCoords(*(n.rgt_), w, h); - } - } - else - { - // If the patch is to large or occupied return success false for coord - if (n.used_ || w > n.width_ || h > n.height_) - { - c.success_ = false; - return c; - } - - // If the patch matches perfectly, store it - if (w == n.width_ && h == n.height_) - { - n.used_ = true; - c.r_ = n.r_; - c.c_ = n.c_; - c.success_ = true; - - return c; - } - - // Initialize children for node - n.lft_ = new Node(n); - n.rgt_ = new Node(n); - - n.rgt_->used_ = false; - n.lft_->used_ = false; - n.rgt_->rgt_ = NULL; - n.rgt_->lft_ = NULL; - n.lft_->rgt_ = NULL; - n.lft_->lft_ = NULL; - - // Check how to adjust free space - if (n.width_ - w > n.height_ - h) - { - n.lft_->width_ = w; - n.rgt_->c_ = n.c_ + w; - n.rgt_->width_ = n.width_ - w; - } - else - { - n.lft_->height_ = h; - n.rgt_->r_ = n.r_ + h; - n.rgt_->height_ = n.height_ - h; - } - - return recursiveFindCoords(*(n.lft_), w, h); - } -} - -void OdmTexturing::sortPatches() -{ - // Bool to set true when done - bool done = false; - - // Material index - int materialIndex = 0; - - // Number of patches left from last loop - size_t countLeftLastIteration = 0; - - while(!done) - { - // Create container for current material - Node root; - root.width_ = textureResolution_; - root.height_ = textureResolution_; - - // Set done to true - done = true; - - // Number of patches that did not fit in current material - size_t countNotPlacedPatches = 0; - - // Number of patches placed in current material - size_t placed = 0; - - for (size_t patchIndex = 0; patchIndex < patches_.size(); ++patchIndex) - { - if(!patches_[patchIndex].placed_) - { - // Calculate dimensions of the patch - float w = patches_[patchIndex].maxu_ - patches_[patchIndex].minu_ + 2*padding_; - float h = patches_[patchIndex].maxv_ - patches_[patchIndex].minv_ + 2*padding_; - - // Try to place patch in root container for this material - if ( w > 0.0 && h > 0.0) - { - patches_[patchIndex].c_ = recursiveFindCoords(root, w, h); - } - - if (!patches_[patchIndex].c_.success_) - { - ++countNotPlacedPatches; - done = false; - } - else - { - // Set patch material as current material - patches_[patchIndex].materialIndex_ = materialIndex; - - // Set patch as placed - patches_[patchIndex].placed_ = true; - - // Update number of patches placed in current material - placed++; - - // Update patch with padding_ - //patches_[patchIndex].c_.c_ += padding_; - //patches_[patchIndex].c_.r_ += padding_; - patches_[patchIndex].minu_ -= padding_; - patches_[patchIndex].minv_ -= padding_; - patches_[patchIndex].maxu_ = std::min((patches_[patchIndex].maxu_ + padding_), textureResolution_); - patches_[patchIndex].maxv_ = std::min((patches_[patchIndex].maxv_ + padding_), textureResolution_); - } - } - } - - // Update material index - ++materialIndex; - - if (countLeftLastIteration == countNotPlacedPatches && countNotPlacedPatches != 0) - { - done = true; - } - countLeftLastIteration = countNotPlacedPatches; - } - - // Set number of textures - nrTextures_ = materialIndex; - - log_ << "Faces sorted into " << nrTextures_ << " textures.\n"; -} - -void OdmTexturing::createTextures() -{ - // Convert vertices to pcl::PointXYZ cloud - pcl::PointCloud::Ptr meshCloud (new pcl::PointCloud); - pcl::fromPCLPointCloud2 (mesh_->cloud, *meshCloud); - - // Container for faces according to submesh. Used to replace faces in mesh_. - std::vector > faceVector = std::vector >(nrTextures_ + 1); - - // Container for texture coordinates according to submesh. Used to replace texture coordinates in mesh_. - std::vector > > textureCoordinatesVector = std::vector > >(nrTextures_ + 1); - - // Container for materials according to submesh. Used to replace materials in mesh_. - std::vector materialVector = std::vector(nrTextures_ + 1); - - // Setup model according to patches placement - for (int textureIndex = 0; textureIndex < nrTextures_; ++textureIndex) - { - for (size_t patchIndex = 0; patchIndex < patches_.size(); ++patchIndex) - { - // If patch is placed in current mesh add all containing faces to that submesh - if (patches_[patchIndex].materialIndex_ == textureIndex) - { - // Transform mesh into camera - pcl::PointCloud::Ptr cameraCloud (new pcl::PointCloud); - pcl::transformPointCloud (*meshCloud, *cameraCloud, cameras_[patches_[patchIndex].optimalCameraIndex_].pose.inverse()); - - // Loop through all faces in patch - for (size_t faceIndex = 0; faceIndex < patches_[patchIndex].faces_.size(); ++faceIndex) - { - // Setup global face index in mesh_ - size_t globalFaceIndex = patches_[patchIndex].faces_[faceIndex]; - - // Add current face to current submesh - faceVector[textureIndex].push_back(mesh_->tex_polygons[0][globalFaceIndex]); - - // Pixel positions - pcl::PointXY pixelPos0; pcl::PointXY pixelPos1; pcl::PointXY pixelPos2; - - // Get pixel positions in corresponding camera for the vertices of the face - getPixelCoordinates(cameraCloud->points[mesh_->tex_polygons[0][globalFaceIndex].vertices[0]], cameras_[patches_[patchIndex].optimalCameraIndex_], pixelPos0); - getPixelCoordinates(cameraCloud->points[mesh_->tex_polygons[0][globalFaceIndex].vertices[1]], cameras_[patches_[patchIndex].optimalCameraIndex_], pixelPos1); - getPixelCoordinates(cameraCloud->points[mesh_->tex_polygons[0][globalFaceIndex].vertices[2]], cameras_[patches_[patchIndex].optimalCameraIndex_], pixelPos2); - - // Shorthands for patch variables - float c = patches_[patchIndex].c_.c_ + padding_; - float r = patches_[patchIndex].c_.r_ + padding_; - float minu = patches_[patchIndex].minu_ + padding_; - float minv = patches_[patchIndex].minv_ + padding_; - - // Declare uv coordinates - Eigen::Vector2f uv1, uv2, uv3; - - // Set uv coordinates according to patch - uv1(0) = (pixelPos0.x - minu + c)/textureResolution_; - uv1(1) = 1.0f - (pixelPos0.y - minv + r)/textureResolution_; - - uv2(0) = (pixelPos1.x - minu + c)/textureResolution_; - uv2(1) = 1.0f - (pixelPos1.y - minv + r)/textureResolution_; - - uv3(0) = (pixelPos2.x - minu + c)/textureResolution_; - uv3(1) = 1.0f - (pixelPos2.y - minv + r)/textureResolution_; - - // Add uv coordinates to submesh - textureCoordinatesVector[textureIndex].push_back(uv1); - textureCoordinatesVector[textureIndex].push_back(uv2); - textureCoordinatesVector[textureIndex].push_back(uv3); - } - } - } - - // Declare material and setup default values - pcl::TexMaterial meshMaterial; - meshMaterial.tex_Ka.r = 0.0f; meshMaterial.tex_Ka.g = 0.0f; meshMaterial.tex_Ka.b = 0.0f; - meshMaterial.tex_Kd.r = 0.0f; meshMaterial.tex_Kd.g = 0.0f; meshMaterial.tex_Kd.b = 0.0f; - meshMaterial.tex_Ks.r = 0.0f; meshMaterial.tex_Ks.g = 0.0f; meshMaterial.tex_Ks.b = 0.0f; - meshMaterial.tex_d = 1.0f; meshMaterial.tex_Ns = 200.0f; meshMaterial.tex_illum = 2; - std::stringstream tex_name; - tex_name << "texture_" << textureIndex; - tex_name >> meshMaterial.tex_name; - meshMaterial.tex_file = meshMaterial.tex_name + ".jpg"; - materialVector[textureIndex] = meshMaterial; - } - - // Add non visible patches to submesh - for (size_t patchIndex = 0; patchIndex < patches_.size(); ++patchIndex) - { - // If the patch does not have an optimal camera - if (patches_[patchIndex].optimalCameraIndex_ == -1) - { - // Add all faces and set uv coordinates - for (size_t faceIndex = 0; faceIndex < patches_[patchIndex].faces_.size(); ++faceIndex) - { - // Setup global face index in mesh_ - size_t globalFaceIndex = patches_[patchIndex].faces_[faceIndex]; - - // Add current face to current submesh - faceVector[nrTextures_].push_back(mesh_->tex_polygons[0][globalFaceIndex]); - - // Declare uv coordinates - Eigen::Vector2f uv1, uv2, uv3; - - // Set uv coordinates according to patch - uv1(0) = 0.25f;//(pixelPos0.x - minu + c)/textureResolution_; - uv1(1) = 0.25f;//1.0f - (pixelPos0.y - minv + r)/textureResolution_; - - uv2(0) = 0.25f;//(pixelPos1.x - minu + c)/textureResolution_; - uv2(1) = 0.75f;//1.0f - (pixelPos1.y - minv + r)/textureResolution_; - - uv3(0) = 0.75f;//(pixelPos2.x - minu + c)/textureResolution_; - uv3(1) = 0.75f;//1.0f - (pixelPos2.y - minv + r)/textureResolution_; - - // Add uv coordinates to submesh - textureCoordinatesVector[nrTextures_].push_back(uv1); - textureCoordinatesVector[nrTextures_].push_back(uv2); - textureCoordinatesVector[nrTextures_].push_back(uv3); - } - } - } - - // Declare material and setup default values for nonVisibileFaces submesh - pcl::TexMaterial meshMaterial; - meshMaterial.tex_Ka.r = 0.0f; meshMaterial.tex_Ka.g = 0.0f; meshMaterial.tex_Ka.b = 0.0f; - meshMaterial.tex_Kd.r = 0.0f; meshMaterial.tex_Kd.g = 0.0f; meshMaterial.tex_Kd.b = 0.0f; - meshMaterial.tex_Ks.r = 0.0f; meshMaterial.tex_Ks.g = 0.0f; meshMaterial.tex_Ks.b = 0.0f; - meshMaterial.tex_d = 1.0f; meshMaterial.tex_Ns = 200.0f; meshMaterial.tex_illum = 2; - std::stringstream tex_name; - tex_name << "non_visible_faces_texture"; - tex_name >> meshMaterial.tex_name; - meshMaterial.tex_file = meshMaterial.tex_name + ".jpg"; - materialVector[nrTextures_] = meshMaterial; - - // Replace polygons, texture coordinates and materials in mesh_ - mesh_->tex_polygons = faceVector; - mesh_->tex_coordinates = textureCoordinatesVector; - mesh_->tex_materials = materialVector; - - // Containers for image and the resized image used for texturing - cv::Mat image; - cv::Mat resizedImage; - - for (int textureIndex = 0; textureIndex < nrTextures_; ++textureIndex) - { - // Current texture for corresponding material - cv::Mat texture = cv::Mat::zeros(textureResolution_, textureResolution_, CV_8UC3); - - for (int cameraIndex = 0; cameraIndex < static_cast(cameras_.size()); ++cameraIndex) - { - // Load image for current camera - image = cv::imread(cameras_[cameraIndex].texture_file,1); - - // Calculate the resize factor to texturize with textureWithSize_ - double resizeFactor = textureWithSize_ / static_cast(image.cols); - - if (resizeFactor > 1.0f) - { - resizeFactor = 1.0f; - } - - // Resize image to the resolution used to texture with - cv::resize(image, resizedImage, cv::Size(), resizeFactor, resizeFactor, CV_INTER_AREA); - - // Loop through all patches - for (size_t patchIndex = 0; patchIndex < patches_.size(); ++patchIndex) - { - // If the patch has the current camera as optimal camera - if (patches_[patchIndex].materialIndex_ == textureIndex && patches_[patchIndex].optimalCameraIndex_ == cameraIndex) - { - // Pixel coordinates to extract image information from - int extractX = static_cast(floor(patches_[patchIndex].minu_));// + padding_); - int extractY = static_cast(floor(patches_[patchIndex].minv_));// + padding_); - - // Pixel coordinates to insert the image information to - int insertX = static_cast(floor(patches_[patchIndex].c_.c_)); - int insertY = static_cast(floor(patches_[patchIndex].c_.r_)); - - // The size of the image information to use - int width = static_cast(floor(patches_[patchIndex].maxu_)) - extractX - 1; - int height = static_cast(floor(patches_[patchIndex].maxv_)) - extractY - 1; - - // Get image information and add to texture - cv::Mat src = resizedImage(cv::Rect(extractX, extractY, width, height)); - cv::Mat dst = texture(cv::Rect(insertX, insertY, width, height)); - src.copyTo(dst); - } - } - } - log_ <<"Saved " << mesh_->tex_materials[textureIndex].tex_file <<" to file.\n"; - cv::imwrite(outputFolder_ + mesh_->tex_materials[textureIndex].tex_file, texture); - } - - // Create nonVisibleFaces texture and save to file - cv::Mat nonVisibleFacesTexture = cv::Mat::zeros(50, 50, CV_8UC3) + cv::Scalar(255,255,255); - log_ <<"Saved " << mesh_->tex_materials[nrTextures_].tex_file <<" to file.\n"; - cv::imwrite(outputFolder_ + mesh_->tex_materials[nrTextures_].tex_file, nonVisibleFacesTexture); -} - -void OdmTexturing::writeObjFile() -{ - if (saveOBJFile(outputFolder_ + "odm_textured_model.obj", *mesh_.get(), 7) == 0) - { - log_ <<"odm_textured_model.obj successfully saved.\n"; - } - else - { - log_ << "Failed to save model.\n"; - } -} - -void OdmTexturing::printHelp() -{ - log_.setIsPrintingInCout(true); - - log_ << "Purpose:\n"; - log_ << "Create a textured mesh from pmvs output and a corresponding ply-mesh from OpenDroneMap-meshing.\n"; - - log_ << "Usage:\n"; - log_ << "The program requires paths to a bundler.out file, a ply model file, an image list file, an image folder path, an output path and the resized resolution used in the bundler step.\n"; - log_ << "All other input parameters are optional.\n\n"; - - log_ << "The following flags are available:\n"; - log_ << "Call the program with flag \"-help\", or without parameters to print this message, or check any generated log file.\n"; - log_ << "Call the program with flag \"-verbose\", to print log messages in the standard output.\n\n"; - - log_ << "Parameters are specified as: \"- \", (without <>), and the following parameters are configurable:\n"; - log_ << "\"-bundleFile \" (mandatory)\n"; - log_ << "Path to the bundle.out file from pmvs.\n"; - - log_ << "\"-imagesListPath \" (mandatory)\n"; - log_ << "Path to the list containing the image names used in the bundle.out file.\n"; - - log_ << "\"-imagesPath \" (mandatory)\n"; - log_ << "Path to the folder containing full resolution images.\n"; - - log_ << "\"-inputModelPath \" (mandatory)\n"; - log_ << "Path to the ply model to texture.\n"; - - log_ << "\"-outputFolder \" (mandatory)\n"; - log_ << "Path to store the textured model. The folder must exist.\n"; - - log_ << "\"-logFile \" (optional)\n"; - log_ << "Path to save the log file.\n"; - - log_ << "\"-bundleResizedTo \" (mandatory)\n"; - log_ << "The resized resolution used in bundler.\n"; - - log_ << "\"-textureResolution_ \" (optional, default: 4096)\n"; - log_ << "The resolution of the output textures. Must be greater than textureWithSize.\n"; - - log_ << "\"-textureWithSize \" (optional, default: 1200)\n"; - log_ << "The resolution to rescale the images performing the texturing.\n"; - - log_.setIsPrintingInCout(false); - -} diff --git a/modules/odm_texturing/src/OdmTexturing.hpp b/modules/odm_texturing/src/OdmTexturing.hpp deleted file mode 100644 index 1e884d22..00000000 --- a/modules/odm_texturing/src/OdmTexturing.hpp +++ /dev/null @@ -1,211 +0,0 @@ -#pragma once - -// STL -#include -#include - -// PCL -#include -#include -#include - -// OpenCV -#include -#include - -// Modified PCL functions -#include "modifiedPclFunctions.hpp" - -// Logging -#include "Logger.hpp" - -/*! - * \brief The Coords struct Coordinate class used in recursiveFindCoordinates for OdmTexturing::sortPatches(). - */ -struct Coords -{ - // Coordinates for row and column - float r_, c_; - - // If coordinates have been placed - bool success_; - - Coords() - { - r_ = 0.0; - c_ = 0.0; - success_ = false; - } -}; - -/*! - * \brief The Patch struct Struct to hold all faces connected and with the same optimal camera. - */ -struct Patch -{ - std::vector faces_; - float minu_, minv_, maxu_, maxv_; - Coords c_; - bool placed_; - int materialIndex_; - int optimalCameraIndex_; - - Patch() - { - placed_ = false; - faces_ = std::vector(0); - minu_ = std::numeric_limits::infinity(); - minv_ = std::numeric_limits::infinity(); - maxu_ = 0.0; - maxv_ = 0.0; - optimalCameraIndex_ = -1; - materialIndex_ = 0; - } -}; - -/*! - * \brief The Node struct Node class for acceleration structure in OdmTexturing::sortPatches(). - */ -struct Node -{ - float r_, c_, width_, height_; - bool used_; - Node* rgt_; - Node* lft_; - - Node() - { - r_ = 0.0; - c_ = 0.0; - width_ = 1.0; - height_ = 1.0; - used_ = false; - rgt_ = NULL; - lft_ = NULL; - } - - Node(const Node &n) - { - r_ = n.r_; - c_ = n.c_; - used_ = n.used_; - width_ = n.width_; - height_ = n.height_; - rgt_ = n.rgt_; - lft_ = n.lft_; - } -}; - -/*! - * \brief The OdmTexturing class is used to create textures to a welded ply-mesh using the camera - * positions from pmvs as input. The result is stored in an obj-file with corresponding - * mtl-file and the textures saved as jpg. - */ -class OdmTexturing -{ -public: - OdmTexturing(); - ~OdmTexturing(); - - - /*! - * \brief run Runs the texturing functionality using the provided input arguments. - * For a list of the accepted arguments, please see the main page documentation or - * call the program with parameter "-help". - * \param argc Application argument count. - * \param argv Argument values. - * \return 0 if successful. - */ - int run(int argc, char **argv); - -private: - - /*! - * \brief parseArguments Parses command line arguments. - * \param argc Application argument count. - * \param argv Argument values. - */ - void parseArguments(int argc, char** argv); - - /*! - * \brief loadMesh Loads a PLY-file containing vertices and faces. - */ - void loadMesh(); - - /*! - * \brief loadCameras Loads cameras from a bundle.out file with corresponding image list file. - */ - void loadCameras(); - - /*! - * \brief triangleToImageAssignment Assigns optimal camera to faces for the faces that are visible. - */ - void triangleToImageAssignment(); - - /*! - * \brief calculatePatches Arrange faces into patches as a prestep to arranging UV-mapping. - */ - void calculatePatches(); - - /*! - * \brief recursiveFindCoords Recursive function used in sortPatches() to find free area to place patch. - * \param n The container in which to check for free space in. - * \param w The width of the box to place. - * \param h The height of the box to place. - * \return The coordinates where the patch has been placed. - */ - Coords recursiveFindCoords(Node &n, float w, float h); - - /*! - * \brief sortPatches Sorts patches into UV-containers to be used in createTextures() using a rectangle packer approach. - */ - void sortPatches(); - - /*! - * \brief createTextures Creates textures to the mesh. - */ - void createTextures(); - - /*! - * \brief writeObjFile Writes the textured mesh to file on the OBJ format. - */ - void writeObjFile(); - - /*! - * \brief printHelp Prints help, explaining usage. Can be shown by calling the program with arguments: "-help". - */ - void printHelp(); - - Logger log_; /**< Logging object. */ - std::string logFilePath_; /**< Path to store the log file. */ - - std::string bundlePath_; /**< Path to the bundle.out file. */ - std::string imagesPath_; /**< Path to the folder with all images in the image list. */ - std::string imagesListPath_; /**< Path to the image list. */ - std::string inputModelPath_; /**< Path to the ply-file containing the mesh to be textured. */ - std::string outputFolder_; /**< Path to the folder to store the output mesh and textures. */ - - double bundleResizedTo_; /**< The size used in the previous steps to calculate the camera focal_length. */ - double textureWithSize_; /**< The desired size of the images to texture with. */ - double textureResolution_; /**< The resolution of each texture. */ - double padding_; /**< A padding used to handle edge cases. */ - int nrTextures_; /**< The number of textures created. */ - - pcl::TextureMesh::Ptr mesh_; /**< PCL Texture Mesh */ - std::vector patches_; /**< The vector containing all patches */ - pcl::texture_mapping::CameraVector cameras_; /**< The vector containing all cameras. */ - std::vector tTIA_; /**< The vector containing the optimal cameras for all faces. */ -}; - -class OdmTexturingException : public std::exception -{ - -public: - OdmTexturingException() : message("Error in OdmTexturing") {} - OdmTexturingException(std::string msgInit) : message("Error in OdmTexturing:\n" + msgInit) {} - ~OdmTexturingException() throw() {} - virtual const char* what() const throw() {return message.c_str(); } - -private: - std::string message; /**< The error message. */ -}; diff --git a/modules/odm_texturing/src/main.cpp b/modules/odm_texturing/src/main.cpp deleted file mode 100644 index 36f9758e..00000000 --- a/modules/odm_texturing/src/main.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// Include texturing source code -#include "OdmTexturing.hpp" - -/*! - * \mainpage main OpenDroneMap Texturing Module - * - * - * - */ - -int main (int argc, char** argv) -{ - OdmTexturing textureCreator; - return textureCreator.run(argc, argv); -} diff --git a/modules/odm_texturing/src/modifiedPclFunctions.cpp b/modules/odm_texturing/src/modifiedPclFunctions.cpp deleted file mode 100644 index eafa9406..00000000 --- a/modules/odm_texturing/src/modifiedPclFunctions.cpp +++ /dev/null @@ -1,336 +0,0 @@ -/* -* Software License Agreement (BSD License) -* -* Point Cloud Library (PCL) - www.pointclouds.org -* Copyright (c) 2012-, Open Perception, Inc. -* -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* * Redistributions in binary form must reproduce the above -* copyright notice, this list of conditions and the following -* disclaimer in the documentation and/or other materials provided -* with the distribution. -* * Neither the name of the copyright holder(s) nor the names of its -* contributors may be used to endorse or promote products derived -* from this software without specific prior written permission. -* -* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE -* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, -* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT -* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -* POSSIBILITY OF SUCH DAMAGE. -* -*/ - -#include "modifiedPclFunctions.hpp" - -int saveOBJFile(const std::string &file_name, const pcl::TextureMesh &tex_mesh, unsigned precision) -{ - if (tex_mesh.cloud.data.empty ()) - { - PCL_ERROR ("[pcl::io::saveOBJFile] Input point cloud has no data!\n"); - return (-1); - } - - // Open file - std::ofstream fs; - fs.precision (precision); - fs.open (file_name.c_str ()); - - // Define material file - std::string mtl_file_name = file_name.substr (0, file_name.find_last_of (".")) + ".mtl"; - // Strip path for "mtllib" command - std::string mtl_file_name_nopath = mtl_file_name; - //std::cout << mtl_file_name_nopath << std::endl; - mtl_file_name_nopath.erase (0, mtl_file_name.find_last_of ('/') + 1); - - /* Write 3D information */ - // number of points - int nr_points = tex_mesh.cloud.width * tex_mesh.cloud.height; - int point_size = tex_mesh.cloud.data.size () / nr_points; - - // mesh size - int nr_meshes = tex_mesh.tex_polygons.size (); - // number of faces for header - int nr_faces = 0; - for (int m = 0; m < nr_meshes; ++m) - nr_faces += tex_mesh.tex_polygons[m].size (); - - // Write the header information - fs << "####" << std::endl; - fs << "# OBJ dataFile simple version. File name: " << file_name << std::endl; - fs << "# Vertices: " << nr_points << std::endl; - fs << "# Faces: " < 0) - f_idx += tex_mesh.tex_polygons[m-1].size (); - - if(tex_mesh.tex_materials.size() !=0) - { - fs << "# The material will be used for mesh " << m << std::endl; - //TODO pbl here with multi texture and unseen faces - fs << "usemtl " << tex_mesh.tex_materials[m].tex_name << std::endl; - fs << "# Faces" << std::endl; - } - for (size_t i = 0; i < tex_mesh.tex_polygons[m].size(); ++i) - { - // Write faces with "f" - fs << "f"; - size_t j = 0; - // There's one UV per vertex per face, i.e., the same vertex can have - // different UV depending on the face. - for (j = 0; j < tex_mesh.tex_polygons[m][i].vertices.size (); ++j) - { - unsigned int idx = tex_mesh.tex_polygons[m][i].vertices[j] + 1; - fs << " " << idx - << "/" << 3*(i+f_idx) +j+1; - //<< "/" << idx; // vertex index in obj file format starting with 1 - } - fs << std::endl; - } - //PCL_INFO ("%d faces in mesh %d \n", tex_mesh.tex_polygons[m].size () , m); - fs << "# "<< tex_mesh.tex_polygons[m].size() << " faces in mesh " << m << std::endl; - } - fs << "# End of File"; - - // Close obj file - //PCL_INFO ("Closing obj file\n"); - fs.close (); - - /* Write material defination for OBJ file*/ - // Open file - //PCL_INFO ("Writing material files\n"); - //dont do it if no material to write - if(tex_mesh.tex_materials.size() ==0) - return (0); - - std::ofstream m_fs; - m_fs.precision (precision); - m_fs.open (mtl_file_name.c_str ()); - //std::cout << "MTL file is located at_ " << mtl_file_name << std::endl; - // default - m_fs << "#" << std::endl; - m_fs << "# Wavefront material file" << std::endl; - m_fs << "#" << std::endl; - for(int m = 0; m < nr_meshes; ++m) - { - m_fs << "newmtl " << tex_mesh.tex_materials[m].tex_name << std::endl; - m_fs << "Ka "<< tex_mesh.tex_materials[m].tex_Ka.r << " " << tex_mesh.tex_materials[m].tex_Ka.g << " " << tex_mesh.tex_materials[m].tex_Ka.b << std::endl; // defines the ambient color of the material to be (r,g,b). - m_fs << "Kd "<< tex_mesh.tex_materials[m].tex_Kd.r << " " << tex_mesh.tex_materials[m].tex_Kd.g << " " << tex_mesh.tex_materials[m].tex_Kd.b << std::endl; // defines the diffuse color of the material to be (r,g,b). - m_fs << "Ks "<< tex_mesh.tex_materials[m].tex_Ks.r << " " << tex_mesh.tex_materials[m].tex_Ks.g << " " << tex_mesh.tex_materials[m].tex_Ks.b << std::endl; // defines the specular color of the material to be (r,g,b). This color shows up in highlights. - m_fs << "d " << tex_mesh.tex_materials[m].tex_d << std::endl; // defines the transparency of the material to be alpha. - m_fs << "Ns "<< tex_mesh.tex_materials[m].tex_Ns << std::endl; // defines the shininess of the material to be s. - m_fs << "illum "<< tex_mesh.tex_materials[m].tex_illum << std::endl; // denotes the illumination model used by the material. - // illum = 1 indicates a flat material with no specular highlights, so the value of Ks is not used. - // illum = 2 denotes the presence of specular highlights, and so a specification for Ks is required. - m_fs << "map_Kd " << tex_mesh.tex_materials[m].tex_file << std::endl; - m_fs << "###" << std::endl; - } - m_fs.close (); - return (0); -} - -bool getPixelCoordinates(const pcl::PointXYZ &pt, const pcl::TextureMapping::Camera &cam, pcl::PointXY &UV_coordinates) -{ - if (pt.z > 0) - { - // compute image center and dimension - double sizeX = cam.width; - double sizeY = cam.height; - double cx, cy; - if (cam.center_w > 0) - cx = cam.center_w; - else - cx = sizeX / 2.0; - if (cam.center_h > 0) - cy = cam.center_h; - else - cy = sizeY / 2.0; - - double focal_x, focal_y; - if (cam.focal_length_w > 0) - focal_x = cam.focal_length_w; - else - focal_x = cam.focal_length; - if (cam.focal_length_h > 0) - focal_y = cam.focal_length_h; - else - focal_y = cam.focal_length; - - // project point on camera's image plane - UV_coordinates.x = static_cast ((focal_x * (pt.x / pt.z) + cx)); //horizontal - UV_coordinates.y = static_cast ((focal_y * (pt.y / pt.z) + cy)); //vertical - - // point is visible! - if (UV_coordinates.x >= 15.0 && UV_coordinates.x <= (sizeX - 15.0) && UV_coordinates.y >= 15.0 && UV_coordinates.y <= (sizeY - 15.0)) - { - return (true); // point was visible by the camera - } - } - - // point is NOT visible by the camera - UV_coordinates.x = -1.0f; - UV_coordinates.y = -1.0f; - return (false); // point was not visible by the camera -} - -bool isFaceProjected (const pcl::TextureMapping::Camera &camera, const pcl::PointXYZ &p1, const pcl::PointXYZ &p2, const pcl::PointXYZ &p3, pcl::PointXY &proj1, pcl::PointXY &proj2, pcl::PointXY &proj3) -{ - return (getPixelCoordinates(p1, camera, proj1) && getPixelCoordinates(p2, camera, proj2) && getPixelCoordinates(p3, camera, proj3)); -} - -void getTriangleCircumscribedCircleCentroid( const pcl::PointXY &p1, const pcl::PointXY &p2, const pcl::PointXY &p3, pcl::PointXY &circumcenter, double &radius) -{ - // compute centroid's coordinates (translate back to original coordinates) - circumcenter.x = static_cast (p1.x + p2.x + p3.x ) / 3; - circumcenter.y = static_cast (p1.y + p2.y + p3.y ) / 3; - double r1 = (circumcenter.x - p1.x) * (circumcenter.x - p1.x) + (circumcenter.y - p1.y) * (circumcenter.y - p1.y) ; - double r2 = (circumcenter.x - p2.x) * (circumcenter.x - p2.x) + (circumcenter.y - p2.y) * (circumcenter.y - p2.y) ; - double r3 = (circumcenter.x - p3.x) * (circumcenter.x - p3.x) + (circumcenter.y - p3.y) * (circumcenter.y - p3.y) ; - - // radius - radius = std::sqrt( std::max( r1, std::max( r2, r3) )) ; -} - -bool checkPointInsideTriangle(const pcl::PointXY &p1, const pcl::PointXY &p2, const pcl::PointXY &p3, const pcl::PointXY &pt) -{ - // Compute vectors - Eigen::Vector2d v0, v1, v2; - v0(0) = p3.x - p1.x; v0(1) = p3.y - p1.y; // v0= C - A - v1(0) = p2.x - p1.x; v1(1) = p2.y - p1.y; // v1= B - A - v2(0) = pt.x - p1.x; v2(1) = pt.y - p1.y; // v2= P - A - - // Compute dot products - double dot00 = v0.dot(v0); // dot00 = dot(v0, v0) - double dot01 = v0.dot(v1); // dot01 = dot(v0, v1) - double dot02 = v0.dot(v2); // dot02 = dot(v0, v2) - double dot11 = v1.dot(v1); // dot11 = dot(v1, v1) - double dot12 = v1.dot(v2); // dot12 = dot(v1, v2) - - // Compute barycentric coordinates - double invDenom = 1.0 / (dot00*dot11 - dot01*dot01); - double u = (dot11*dot02 - dot01*dot12) * invDenom; - double v = (dot00*dot12 - dot01*dot02) * invDenom; - - // Check if point is in triangle - return ((u >= 0) && (v >= 0) && (u + v < 1)); -} diff --git a/modules/odm_texturing/src/modifiedPclFunctions.hpp b/modules/odm_texturing/src/modifiedPclFunctions.hpp deleted file mode 100644 index 5739df14..00000000 --- a/modules/odm_texturing/src/modifiedPclFunctions.hpp +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -// STL -#include -#include - -// PCL -#include -#include -#include - -int saveOBJFile(const std::string &file_name, const pcl::TextureMesh &tex_mesh, unsigned precision); - -bool getPixelCoordinates(const pcl::PointXYZ &pt, const pcl::TextureMapping::Camera &cam, pcl::PointXY &UV_coordinates); - -bool isFaceProjected (const pcl::TextureMapping::Camera &camera, const pcl::PointXYZ &p1, const pcl::PointXYZ &p2, const pcl::PointXYZ &p3, pcl::PointXY &proj1, pcl::PointXY &proj2, pcl::PointXY &proj3); - -void getTriangleCircumscribedCircleCentroid(const pcl::PointXY &p1, const pcl::PointXY &p2, const pcl::PointXY &p3, pcl::PointXY &circumcenter, double &radius); - -bool checkPointInsideTriangle(const pcl::PointXY &p1, const pcl::PointXY &p2, const pcl::PointXY &p3, const pcl::PointXY &pt);