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);