Program Listing for File LargeScaleReconstruction.hpp
↰ Return to documentation for file (include/lvr2/reconstruction/LargeScaleReconstruction.hpp)
#ifndef LAS_VEGAS_LARGESCALERECONSTRUCTION_HPP
#define LAS_VEGAS_LARGESCALERECONSTRUCTION_HPP
#include "lvr2/types/ScanTypes.hpp"
#include "lvr2/algorithm/ChunkHashGrid.hpp"
#include "lvr2/algorithm/HLODTree.hpp"
#include "lvr2/reconstruction/BigGrid.hpp"
#include "lvr2/reconstruction/FastBox.hpp"
#include "lvr2/reconstruction/PointsetGrid.hpp"
#if defined CUDA_FOUND
#define GPU_FOUND
#include "lvr2/reconstruction/cuda/CudaSurface.hpp"
typedef lvr2::CudaSurface GpuSurface;
#elif defined OPENCL_FOUND
#define GPU_FOUND
#include "lvr2/reconstruction/opencl/ClSurface.hpp"
typedef lvr2::ClSurface GpuSurface;
#endif
namespace lvr2
{
enum class LSROutput
{
BigMesh,
ChunksPly,
ChunksHdf5,
#ifdef LVR2_USE_3DTILES
Tiles3d,
#endif
};
struct LSROptions
{
std::unordered_set<LSROutput> output{LSROutput::BigMesh};
bool hasOutput(LSROutput o) const
{
return output.find(o) != output.end();
}
fs::path outputDir;
fs::path tempDir;
bool useGPU = false;
bool useGPUDistances = false;
std::vector<float> voxelSizes{0.1};
float bgVoxelSize = 10;
float scale = 1;
uint nodeSize = 1000000;
uint partMethod = 1;
uint ki = 20;
uint kd = 20;
uint kn = 20;
bool useRansac = false;
std::vector<float> flipPoint{10000000, 10000000, 10000000};
bool extrude = true;
uint removeDanglingArtifacts = 0;
uint cleanContours = 0;
uint fillHoles = 0;
bool optimizePlanes = false;
float planeNormalThreshold = 0.85;
uint planeIterations = 3;
uint minPlaneSize = 7;
uint smallRegionThreshold = 0;
bool retesselate = false;
float lineFusionThreshold = 0.01;
bool mergeChunkBorders = true;
bool tiles3dCompress = false;
AllowedMemoryUsage tiles3dMemUsage = AllowedMemoryUsage::Moderate;
void ensureCorrectness()
{
LSROptions defaultOptions;
#define CHECK_OPTION(option, condition, message) \
if (condition) \
{ \
std::cout << timestamp << "Warning: " << message << " Reverting to default value." << std::endl; \
option = defaultOptions.option; \
}
if (partMethod != 1)
{
if (hasOutput(LSROutput::ChunksPly))
{
std::cout << timestamp << "Warning: Output ChunksPly requires partMethod == 1." << std::endl;
output.erase(LSROutput::ChunksPly);
}
if (hasOutput(LSROutput::ChunksHdf5))
{
std::cout << timestamp << "Warning: Output ChunksHdf5 requires partMethod == 1." << std::endl;
output.erase(LSROutput::ChunksHdf5);
}
#ifdef LVR2_USE_3DTILES
if (hasOutput(LSROutput::Tiles3d))
{
std::cout << timestamp << "Warning: Output Tiles3d requires partMethod == 1." << std::endl;
output.erase(LSROutput::Tiles3d);
}
#endif
}
CHECK_OPTION(output, output.empty(), "No output specified.");
if (outputDir.empty())
{
std::stringstream ss;
time_t now = time(0);
ss << "./" << std::put_time(std::localtime(&now), "%Y-%m-%d_%H-%M-%S") << "/";
outputDir = ss.str();
std::cout << timestamp << "LargeScaleReconstruction: Output directory set to " << outputDir << std::endl;
}
fs::create_directories(outputDir);
if (tempDir.empty())
{
tempDir = outputDir / "temp/";
}
fs::create_directories(tempDir);
#ifndef GPU_FOUND
if (useGPU || useGPUDistances)
{
std::cout << timestamp << "Warning: No GPU found. Falling back to CPU." << std::endl;
useGPU = useGPUDistances = false;
}
#endif
CHECK_OPTION(voxelSizes, voxelSizes.empty(), "No voxel sizes specified.");
if (voxelSizes[0] <= 0)
{
throw std::invalid_argument("voxelSizes must be positive.");
}
CHECK_OPTION(bgVoxelSize, bgVoxelSize <= 0, "bgVoxelSize has to be greater than 0.");
auto correctedVoxelSize = std::ceil(bgVoxelSize / voxelSizes[0]) * voxelSizes[0];
if (correctedVoxelSize != bgVoxelSize)
{
std::cout << timestamp << "Warning: bgVoxelSize is not a multiple of voxelSizes[0]. Correcting to " << correctedVoxelSize << std::endl;
bgVoxelSize = correctedVoxelSize;
}
auto it = voxelSizes.begin() + 1;
while (it != voxelSizes.end())
{
if (*it <= 0)
{
std::cout << timestamp << "Warning: voxelSizes cannot be negative. Ignoring " << *it << std::endl;
it = voxelSizes.erase(it);
}
else if (std::abs(bgVoxelSize - std::ceil(bgVoxelSize / *it) * *it) > std::numeric_limits<float>::epsilon())
{
std::cout << timestamp << "Warning: all voxelSizes have to divide bgVoxelSize. Ignoring " << *it << std::endl;
it = voxelSizes.erase(it);
}
else
{
++it;
}
}
CHECK_OPTION(voxelSizes, voxelSizes.empty(), "No voxel sizes specified.");
CHECK_OPTION(partMethod, partMethod > 1, "partMethod has to be 0 or 1.");
CHECK_OPTION(kd, kd <= 0, "kd has to be greater than 0.");
CHECK_OPTION(kn, kn <= 0, "kn has to be greater than 0.");
CHECK_OPTION(flipPoint, flipPoint.size() != 3, "flipPoint has to be of size 3.");
if (retesselate)
{
optimizePlanes = true;
}
#ifdef LVR2_USE_3DTILES
if (tiles3dCompress && !hasOutput(LSROutput::Tiles3d))
{
std::cout << timestamp << "Warning: tiles3dCompress is only supported for LSROutput::Tiles3d." << std::endl;
tiles3dCompress = false;
}
#else
if (tiles3dCompress)
{
std::cout << timestamp << "Warning: tiles3dCompress is only supported when compiling with 3D Tiles support." << std::endl;
tiles3dCompress = false;
}
#endif
}
};
template <typename BaseVecT>
class LargeScaleReconstruction
{
public:
using BoxT = FastBox<BaseVecT>;
LargeScaleReconstruction(LSROptions options = LSROptions());
void chunkAndReconstruct(ScanProjectEditMarkPtr project, BoundingBox<BaseVecT>& newChunksBB, std::shared_ptr<ChunkHashGrid> chunkManager = nullptr)
{
m_options.ensureCorrectness();
if (m_options.partMethod == 0)
{
chunkAndReconstructKDTree(project, newChunksBB);
}
else
{
if (!chunkManager)
{
throw std::invalid_argument("chunkManager is required for VGrid partition method.");
}
chunkAndReconstructVGrid(project, newChunksBB, chunkManager);
}
}
int trueMpiAndReconstructMaster(ScanProjectEditMarkPtr project, BoundingBox<BaseVecT>& newChunksBB, std::shared_ptr<ChunkHashGrid> chunkManager, int size);
int trueMpiAndReconstructSlave();
HalfEdgeMesh<BaseVecT> getPartialReconstruct(BoundingBox<BaseVecT> newChunksBB, std::shared_ptr<ChunkHashGrid> chunkHashGrid, float voxelSize);
private:
void chunkAndReconstructKDTree(ScanProjectEditMarkPtr project, BoundingBox<BaseVecT>& newChunksBB);
void chunkAndReconstructVGrid(ScanProjectEditMarkPtr project, BoundingBox<BaseVecT>& newChunksBB, std::shared_ptr<ChunkHashGrid> chunkManager);
using GridPtr = std::shared_ptr<HashGrid<BaseVecT, BoxT>>;
GridPtr createChunk(const BigGrid<BaseVecT>& bg,
const BoundingBox<BaseVecT>& bb,
float voxelSize,
size_t minPointsPerChunk, size_t& maxPointsPerChunk,
bool& retry);
void processChunk(GridPtr ps_grid,
const Vector3i& coord,
const fs::path& chunkDirPly,
std::shared_ptr<HighFive::File> chunkFileHdf5,
std::shared_ptr<HighFive::File> chunkFile3dTiles,
typename HLODTree<BaseVecT>::ChunkMap& chunkMap);
void createAndSaveBigMesh(GridPtr hg, size_t voxelSizeIndex);
uint* mpiScheduler(const std::vector<BoundingBox<BaseVecT>>& partitionBoxes, BigGrid<BaseVecT>& bg, BoundingBox<BaseVecT>& cbb, std::shared_ptr<ChunkHashGrid> chunkManager);
void mpiCollector(const std::vector<BoundingBox<BaseVecT>>& partitionBoxes, BoundingBox<BaseVecT>& cbb, std::shared_ptr<ChunkHashGrid> chunkManager, uint* partitionBoxesSkipped);
LSROptions m_options;
};
} // namespace lvr2
#include "LargeScaleReconstruction.tcc"
#endif // LAS_VEGAS_LARGESCALERECONSTRUCTION_HPP