10 #include <Eigen/Dense>
25 #pragma warning(disable: 4701 4703 4245 4189)
31 #include "PoissonRecon/Src/PreProcessor.h"
32 #include "PoissonRecon/Src/MyMiscellany.h"
33 #include "PoissonRecon/Src/CmdLineParser.h"
34 #include "PoissonRecon/Src/FEMTree.h"
35 #include "PoissonRecon/Src/PPolynomial.h"
36 #include "PoissonRecon/Src/PointStreamData.h"
88 template <
typename Real>
90 :
public InputPointStreamWithData<Real, DIMENSION, CloudViewerData> {
93 : pcd_(pcd), xform_(nullptr), current_(0) {}
94 void reset(
void) { current_ = 0; }
96 if (current_ >= pcd_->size()) {
99 p.coords[0] =
static_cast<Real
>(pcd_->getEigenPoint(current_)(0));
100 p.coords[1] =
static_cast<Real
>(pcd_->getEigenPoint(current_)(1));
101 p.coords[2] =
static_cast<Real
>(pcd_->getEigenPoint(current_)(2));
103 if (xform_ !=
nullptr) {
107 if (pcd_->hasNormals()) {
108 d.
normal_ = pcd_->getEigenNormal(current_);
110 d.
normal_ = Eigen::Vector3d(0, 0, 0);
113 if (pcd_->hasColors()) {
114 d.
color_ = pcd_->getEigenColor(current_);
116 d.
color_ = Eigen::Vector3d(0, 0, 0);
129 template <
typename _Real>
136 : point(point), normal_(0, 0, 0), color_(0, 0, 0), w_(0) {}
171 template <
unsigned int Dim,
class Real>
178 t = Time(), FEMTree<Dim, Real>::ResetLocalMemoryUsage();
181 FEMTree<Dim, Real>::MemoryUsage();
185 FEMTree<Dim, Real>::LocalMemoryUsage(),
186 FEMTree<Dim, Real>::MaxMemoryUsage(),
187 MemoryInfo::PeakMemoryUsageMB());
190 FEMTree<Dim, Real>::LocalMemoryUsage(),
191 FEMTree<Dim, Real>::MaxMemoryUsage(),
192 MemoryInfo::PeakMemoryUsageMB());
197 template <
class Real,
unsigned int Dim>
199 Point<Real, Dim> max,
201 Point<Real, Dim> center = (max + min) / 2;
202 Real scale = max[0] - min[0];
203 for (
unsigned int d = 1; d < Dim; d++) {
204 scale = std::max<Real>(scale, max[d] - min[d]);
206 scale *= scaleFactor;
207 for (
unsigned int i = 0; i < Dim; i++) {
208 center[i] -= scale / 2;
210 XForm<Real, Dim + 1> tXForm = XForm<Real, Dim + 1>::Identity(),
211 sXForm = XForm<Real, Dim + 1>::Identity();
212 for (
unsigned int i = 0; i < Dim; i++) {
213 sXForm(i, i) = (Real)(1. / scale), tXForm(Dim, i) = -center[i];
215 return sXForm * tXForm;
218 template <
class Real,
unsigned int Dim>
220 Point<Real, Dim> max,
225 Real resolution = (max[0] - min[0]) /
width;
226 for (
unsigned int d = 1; d < Dim; d++) {
227 resolution = std::max<Real>(resolution, (max[d] - min[d]) /
width);
229 resolution *= scaleFactor;
231 while ((1 << depth) < resolution) {
235 Point<Real, Dim> center = (max + min) / 2;
236 Real scale = (1 << depth) *
width;
238 for (
unsigned int i = 0; i < Dim; i++) {
239 center[i] -= scale / 2;
241 XForm<Real, Dim + 1> tXForm = XForm<Real, Dim + 1>::Identity(),
242 sXForm = XForm<Real, Dim + 1>::Identity();
243 for (
unsigned int i = 0; i < Dim; i++) {
244 sXForm(i, i) = (Real)(1. / scale), tXForm(Dim, i) = -center[i];
246 return sXForm * tXForm;
249 template <
class Real,
unsigned int Dim>
254 Point<Real, Dim> min, max;
255 stream.boundingBox(min, max);
259 template <
class Real,
unsigned int Dim>
262 Point<Real, Dim> min, max;
263 stream.boundingBox(min, max);
267 template <
unsigned int Dim,
typename Real>
272 const Point<Real, Dim>& p)
const {
273 return CumulativeDerivativeValues<Real, Dim, 0>(target * weight);
277 template <
unsigned int Dim,
typename Real>
282 const Point<Real, Dim>& p,
283 const CumulativeDerivativeValues<Real, Dim, 0>& dValues)
const {
284 return dValues * weight;
287 const Point<Real, Dim>& p,
288 const CumulativeDerivativeValues<double, Dim, 0>& dValues)
const {
289 return dValues * weight;
293 template <
unsigned int Dim>
299 const Point<Real, Dim>& p,
300 const CumulativeDerivativeValues<Real, Dim, 0>& dValues)
const {
301 return dValues * weight;
305 template <
typename Vertex,
307 typename SetVertexFunction,
308 unsigned int... FEMSigs,
309 typename... SampleData>
313 UIntPack<FEMSigs...>,
314 std::tuple<SampleData...>,
315 FEMTree<
sizeof...(FEMSigs), Real>& tree,
316 const DenseNodeData<Real, UIntPack<FEMSigs...>>& solution,
318 const std::vector<
typename FEMTree<
sizeof...(FEMSigs),
319 Real>::PointSample>* samples,
320 std::vector<CloudViewerData>* sampleData,
321 const typename FEMTree<
sizeof...(FEMSigs),
322 Real>::
template DensityEstimator<WEIGHT_DEGREE>*
324 const SetVertexFunction& SetVertex,
325 XForm<Real,
sizeof...(FEMSigs) + 1> iXForm,
326 std::shared_ptr<ccMesh>& out_mesh,
327 std::vector<double>& out_densities) {
328 static const int Dim =
sizeof...(FEMSigs);
329 typedef UIntPack<FEMSigs...> Sigs;
330 static const unsigned int DataSig =
331 FEMDegreeAndBType<DATA_DEGREE, BOUNDARY_FREE>::Signature;
332 typedef typename FEMTree<Dim,
333 Real>::template DensityEstimator<WEIGHT_DEGREE>
338 CoredMeshData<Vertex, node_index_type>* mesh;
339 mesh =
new CoredVectorMeshData<Vertex, node_index_type>();
341 bool non_manifold =
true;
342 bool polygon_mesh =
false;
345 typename IsoSurfaceExtractor<Dim, Real, Vertex>::IsoStats isoStats;
347 SparseNodeData<ProjectiveData<CloudViewerData, Real>,
348 IsotropicUIntPack<Dim, DataSig>>
350 tree.template setMultiDepthDataField<DataSig, false>(
351 *samples, *sampleData, (DensityEstimator*)
NULL);
352 for (
const RegularTreeNode<Dim, FEMTreeNodeData, depth_and_offset_type>*
353 n = tree.tree().nextNode();
354 n; n = tree.tree().nextNode(n)) {
355 ProjectiveData<CloudViewerData, Real>* clr = _sampleData(n);
356 if (clr) (*clr) *= (Real)pow(datax, tree.depth(n));
358 isoStats = IsoSurfaceExtractor<Dim, Real, Vertex>::template
Extract<
360 Sigs(), UIntPack<WEIGHT_DEGREE>(), UIntPack<DataSig>(), tree,
361 density, &_sampleData, solution, isoValue, *mesh, SetVertex,
362 !linear_fit, !non_manifold, polygon_mesh,
false);
364 isoStats = IsoSurfaceExtractor<Dim, Real, Vertex>::template
Extract<
366 Sigs(), UIntPack<WEIGHT_DEGREE>(), UIntPack<DataSig>(), tree,
367 density,
NULL, solution, isoValue, *mesh, SetVertex,
368 !linear_fit, !non_manifold, polygon_mesh,
false);
371 mesh->resetIterator();
372 out_densities.clear();
377 "[poisson::ExtractMesh] ccMesh should set associated cloud "
382 static_cast<unsigned>(mesh->outOfCorePointCount()))) {
384 "[poisson::ExtractMesh] reserve points failed, not enough "
391 "[poisson::ExtractMesh] reserve normals failed, not enough "
398 "[poisson::ExtractMesh] reserve rgbs failed, not enough "
403 for (
size_t vidx = 0; vidx < mesh->outOfCorePointCount(); ++vidx) {
405 mesh->nextOutOfCorePoint(v);
412 out_densities.push_back(v.w_);
415 if (!out_mesh->reserve(mesh->polygonCount())) {
417 "[poisson::ExtractMesh] reserve triangles failed, not enough "
422 for (
size_t tidx = 0; tidx < mesh->polygonCount(); ++tidx) {
423 std::vector<CoredVertexIndex<node_index_type>> triangle;
424 mesh->nextPolygon(triangle);
425 if (triangle.size() != 3) {
429 triangle[0].idx, triangle[1].idx, triangle[2].idx));
436 template <
class Real,
typename... SampleData,
unsigned int... FEMSigs>
438 std::shared_ptr<ccMesh>& out_mesh,
439 std::vector<double>& out_densities,
445 float samples_per_node,
446 UIntPack<FEMSigs...>) {
447 static const int Dim =
sizeof...(FEMSigs);
448 typedef UIntPack<FEMSigs...> Sigs;
449 typedef UIntPack<FEMSignature<FEMSigs>::Degree...> Degrees;
450 typedef UIntPack<FEMDegreeAndBType<
451 NORMAL_DEGREE, DerivativeBoundary<FEMSignature<FEMSigs>::BType,
452 1>::BType>::Signature...>
454 typedef typename FEMTree<Dim,
455 Real>::template DensityEstimator<WEIGHT_DEGREE>
457 typedef typename FEMTree<Dim, Real>::template InterpolationInfo<Real, 0>
460 XForm<Real, Dim + 1> xForm, iXForm;
461 xForm = XForm<Real, Dim + 1>::Identity();
465 int base_v_cycles = 1;
466 float confidence = 0.f;
469 float confidence_bias = 0.f;
470 float cg_solver_accuracy = 1e-3f;
473 bool exact_interpolation =
false;
475 double startTime = Time();
478 FEMTree<Dim, Real> tree(MEMORY_ALLOCATOR_BLOCK_SIZE);
484 std::vector<typename FEMTree<Dim, Real>::PointSample> samples;
485 std::vector<CloudViewerData> sampleData;
486 DensityEstimator* density =
NULL;
487 SparseNodeData<Point<Real, Dim>, NormalSigs>* normalInfo =
NULL;
488 Real targetValue = (Real)0.5;
495 xForm = GetPointXForm<Real, Dim>(pointStream, (Real)
width,
496 (Real)(scale > 0 ? scale : 1.),
500 xForm = scale > 0 ? GetPointXForm<Real, Dim>(pointStream,
506 pointStream.
xform_ = &xForm;
509 auto ProcessDataWithConfidence = [&](
const Point<Real, Dim>& p,
511 Real l = (Real)d.normal_.norm();
512 if (!l || l != l)
return (Real)-1.;
513 return (Real)pow(l, confidence);
515 auto ProcessData = [](
const Point<Real, Dim>& p,
517 Real l = (Real)d.normal_.norm();
518 if (!l || l != l)
return (Real)-1.;
522 if (confidence > 0) {
523 pointCount = FEMTreeInitializer<Dim, Real>::template Initialize<
525 tree.spaceRoot(), pointStream, depth, samples,
526 sampleData,
true, tree.nodeAllocators[0],
527 tree.initializer(), ProcessDataWithConfidence);
529 pointCount = FEMTreeInitializer<Dim, Real>::template Initialize<
531 samples, sampleData,
true,
532 tree.nodeAllocators[0],
533 tree.initializer(), ProcessData);
536 iXForm = xForm.inverse();
542 int kernelDepth = depth - 2;
543 if (kernelDepth < 0) {
545 "[CreateFromPointCloudPoisson] depth (={}) has to be >= 2",
549 DenseNodeData<Real, Sigs> solution;
551 DenseNodeData<Real, Sigs> constraints;
552 InterpolationInfo* iInfo =
NULL;
553 int solveDepth = depth;
555 tree.resetNodeIndices();
560 density = tree.template setDensityEstimator<WEIGHT_DEGREE>(
561 samples, kernelDepth, samples_per_node, 1);
568 normalInfo =
new SparseNodeData<Point<Real, Dim>, NormalSigs>();
573 Point<Real, Dim> n(in.normal_(0), in.normal_(1),
575 Real l = (Real)Length(n);
579 if (!l)
return false;
585 Point<Real, Dim>& out,
588 Point<Real, Dim> n(in.normal_(0), in.normal_(1),
590 Real l = (Real)Length(n);
594 if (!l)
return false;
596 bias = (Real)(log(l) * confidence_bias /
597 log(1 << (Dim - 1)));
600 if (confidence_bias > 0) {
601 *normalInfo = tree.setDataField(
602 NormalSigs(), samples, sampleData, density,
603 pointWeightSum, ConversionAndBiasFunction);
605 *normalInfo = tree.setDataField(
606 NormalSigs(), samples, sampleData, density,
607 pointWeightSum, ConversionFunction);
609 ThreadPool::Parallel_for(0, normalInfo->size(),
610 [&](
unsigned int,
size_t i) {
611 (*normalInfo)[i] *= (Real)-1.;
615 pointWeightSum, pointCount * pointWeightSum);
624 tree.template finalizeForMultigrid<MAX_DEGREE>(
626 typename FEMTree<Dim, Real>::template HasNormalDataFunctor<
627 NormalSigs>(*normalInfo),
628 normalInfo, density);
635 constraints = tree.initDenseNodeData(Sigs());
636 typename FEMIntegrator::template Constraint<
637 Sigs, IsotropicUIntPack<Dim, 1>, NormalSigs,
638 IsotropicUIntPack<Dim, 0>, Dim>
640 unsigned int derivatives2[Dim];
641 for (
unsigned int d = 0; d < Dim; d++) derivatives2[d] = 0;
642 typedef IsotropicUIntPack<Dim, 1> Derivatives1;
643 typedef IsotropicUIntPack<Dim, 0> Derivatives2;
644 for (
unsigned int d = 0; d < Dim; d++) {
645 unsigned int derivatives1[Dim];
646 for (
unsigned int dd = 0; dd < Dim; dd++)
647 derivatives1[dd] = dd == d ? 1 : 0;
653 tree.addFEMConstraints(F, *normalInfo, constraints, solveDepth);
654 profiler.
dumpOutput(
"# Set FEM constraints:");
658 delete normalInfo, normalInfo =
NULL;
661 if (point_weight > 0) {
663 if (exact_interpolation) {
664 iInfo = FEMTree<Dim, Real>::
665 template InitializeExactPointInterpolationInfo<Real, 0>(
669 (Real)point_weight * pointWeightSum),
674 iInfo = FEMTree<Dim, Real>::
675 template InitializeApproximatePointInterpolationInfo<
680 (Real)point_weight * pointWeightSum),
685 tree.addInterpolationConstraints(constraints, solveDepth, *iInfo);
686 profiler.
dumpOutput(
"#Set point constraints:");
690 "Leaf Nodes / Active Nodes / Ghost Nodes: {} / {} / {}",
691 tree.leaves(), tree.nodes(), tree.ghostNodes());
693 float(MemoryInfo::Usage()) / (1 << 20));
698 typename FEMTree<Dim, Real>::SolverInfo sInfo;
699 sInfo.cgDepth = 0, sInfo.cascadic =
true, sInfo.vCycles = 1,
700 sInfo.iters = iters, sInfo.cgAccuracy = cg_solver_accuracy,
705 sInfo.showGlobalResidual = SHOW_GLOBAL_RESIDUAL_NONE,
706 sInfo.sliceBlockSize = 1;
707 sInfo.baseDepth = base_depth, sInfo.baseVCycles = base_v_cycles;
708 typename FEMIntegrator::template System<Sigs,
709 IsotropicUIntPack<Dim, 1>>
711 solution = tree.solveSystem(Sigs(), F, constraints, solveDepth,
713 profiler.
dumpOutput(
"# Linear system solved:");
723 double valueSum = 0, weightSum = 0;
724 typename FEMTree<Dim, Real>::template MultiThreadedEvaluator<Sigs, 0>
725 evaluator(&tree, solution);
728 ThreadPool::Parallel_for(
729 0, samples.size(), [&](
unsigned int thread,
size_t j) {
730 ProjectiveData<Point<Real, Dim>, Real>& sample =
732 Real w = sample.weight;
734 weightSums[thread] += w,
736 evaluator.values(sample.data / sample.weight,
737 thread, samples[j].node)[0] *
740 for (
size_t t = 0; t < valueSums.size(); t++)
741 valueSum += valueSums[t], weightSum += weightSums[t];
742 isoValue = (Real)(valueSum / weightSum);
755 ExtractMesh<CloudViewerVertex<Real>, Real>(
756 datax, linear_fit, UIntPack<FEMSigs...>(),
757 std::tuple<SampleData...>(), tree, solution, isoValue, &samples,
758 &sampleData, density, SetVertex, iXForm, out_mesh, out_densities);
760 if (density)
delete density, density =
NULL;
762 Time() - startTime, FEMTree<Dim, Real>::MaxMemoryUsage());
767 std::tuple<std::shared_ptr<ccMesh>, std::vector<double>>
774 float samples_per_node,
781 if (n_threads <= 0) {
782 n_threads = (int)std::thread::hardware_concurrency();
786 ThreadPool::Init((ThreadPool::ParallelType)(
int)ThreadPool::OPEN_MP,
789 ThreadPool::Init((ThreadPool::ParallelType)(
int)ThreadPool::THREAD_POOL,
793 auto mesh = std::make_shared<ccMesh>();
794 if (!mesh->CreateInternalCloud()) {
796 "[CreateFromPointCloudPoisson] creating internal cloud "
800 std::vector<double> densities;
801 const BoundaryType BType = (BoundaryType)boundary_type;
803 case BoundaryType::BOUNDARY_FREE:
804 typedef IsotropicUIntPack<
807 BoundaryType::BOUNDARY_FREE>::Signature>
809 poisson::Execute<float>(
810 pcd, mesh, densities,
static_cast<int>(depth),
width, scale,
811 linear_fit, point_weight, samples_per_node, FEMSigsFree());
813 case BoundaryType::BOUNDARY_DIRICHLET:
814 typedef IsotropicUIntPack<
818 BoundaryType::BOUNDARY_DIRICHLET>::Signature>
820 poisson::Execute<float>(pcd, mesh, densities,
821 static_cast<int>(depth),
width, scale,
822 linear_fit, point_weight, samples_per_node,
825 case BoundaryType::BOUNDARY_NEUMANN:
826 typedef IsotropicUIntPack<
830 BoundaryType::BOUNDARY_NEUMANN>::Signature>
832 poisson::Execute<float>(pcd, mesh, densities,
833 static_cast<int>(depth),
width, scale,
834 linear_fit, point_weight, samples_per_node,
837 case BoundaryType::BOUNDARY_COUNT:
838 typedef IsotropicUIntPack<
841 BoundaryType::BOUNDARY_COUNT>::Signature>
843 poisson::Execute<float>(
844 pcd, mesh, densities,
static_cast<int>(depth),
width, scale,
845 linear_fit, point_weight, samples_per_node, FEMSigsCount());
852 ThreadPool::Terminate();
854 return std::make_tuple(mesh, densities);
static bool Execute(PointStream< Real > &pointStream, PoissonReconLib::IMesh< Real > &out_mesh, const PoissonReconLib::Parameters ¶ms, UIntPack< FEMSigs... >)
void ExtractMesh(const PoissonReconLib::Parameters ¶ms, UIntPack< FEMSigs... >, std::tuple< SampleData... >, FEMTree< sizeof...(FEMSigs), Real > &tree, const DenseNodeData< Real, UIntPack< FEMSigs... >> &solution, Real isoValue, const std::vector< typename FEMTree< sizeof...(FEMSigs), Real >::PointSample > *samples, std::vector< PointData< Real >> *sampleData, const typename FEMTree< sizeof...(FEMSigs), Real >::template DensityEstimator< WEIGHT_DEGREE > *density, const SetVertexFunction &SetVertex, XForm< Real, sizeof...(FEMSigs)+1 > iXForm, PoissonReconLib::IMesh< Real > &out_mesh)
static ccPointCloud * ToPointCloud(ccHObject *obj, bool *isLockedVertices=nullptr)
Converts current object to 'equivalent' ccPointCloud.
static std::tuple< std::shared_ptr< ccMesh >, std::vector< double > > CreateFromPointCloudPoisson(const ccPointCloud &pcd, size_t depth=8, size_t width=0, float scale=1.1f, bool linear_fit=false, float point_weight=2.f, float samples_per_node=1.5f, int boundary_type=2, int n_threads=-1)
Function that computes a triangle mesh from a oriented PointCloud pcd. This implements the Screened P...
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
void addEigenNorm(const Eigen::Vector3d &N)
void addEigenColor(const Eigen::Vector3d &color)
bool hasNormals() const override
Returns whether normals are enabled or not.
bool reserveTheNormsTable()
Reserves memory to store the compressed normals.
bool reserveTheRGBTable()
Reserves memory to store the RGB colors.
bool reserveThePointsTable(unsigned _numberOfPoints)
Reserves memory to store the points coordinates.
void addEigenPoint(const Eigen::Vector3d &point)
size_t NumThreads() const
CloudViewerData operator*(double s) const
CloudViewerData(const Eigen::Vector3d &normal, const Eigen::Vector3d &color)
CloudViewerData operator/(double s) const
CloudViewerData & operator+=(const CloudViewerData &d)
CloudViewerData & operator*=(double s)
XForm< Real, 4 > * xform_
bool nextPoint(Point< Real, 3 > &p, CloudViewerData &d)
CloudViewerPointStream(const ccPointCloud *pcd)
const ccPointCloud * pcd_
CloudViewerVertex(Point< Real, 3 > point)
CloudViewerVertex & operator*=(Real s)
CloudViewerVertex & operator/=(Real s)
CloudViewerVertex & operator+=(const CloudViewerVertex &p)
void Extract(const std::string &file_path, const std::string &extract_dir)
Function to extract compressed files.
VerbosityLevel GetVerbosityLevel()
Get global verbosity level of CloudViewer.
Generic file read and write utility for python interface.
Eigen::Matrix< Index, 3, 1 > Vector3i
Eigen::MatrixXd::Index Index
static const int DEFAULT_FEM_DEGREE
XForm< Real, Dim+1 > GetBoundingBoxXForm(Point< Real, Dim > min, Point< Real, Dim > max, Real width, Real scaleFactor, int &depth)
static const int WEIGHT_DEGREE
static const int DATA_DEGREE
static const int DIMENSION
static const int NORMAL_DEGREE
static const BoundaryType DEFAULT_FEM_BOUNDARY
XForm< Real, Dim+1 > GetPointXForm(InputPointStream< Real, Dim > &stream, Real scaleFactor)
ConstraintDual(Real t, Real w)
CumulativeDerivativeValues< Real, Dim, 0 > operator()(const Point< Real, Dim > &p) const
void dumpOutput(const char *header) const
FEMTree< Dim, Real > & tree
FEMTreeProfiler(FEMTree< Dim, Real > &t)
CumulativeDerivativeValues< Real, Dim, 0 > operator()(const Point< Real, Dim > &p, const CumulativeDerivativeValues< Real, Dim, 0 > &dValues) const
CumulativeDerivativeValues< double, Dim, 0 > operator()(const Point< Real, Dim > &p, const CumulativeDerivativeValues< double, Dim, 0 > &dValues) const
CumulativeDerivativeValues< Real, Dim, 0 > operator()(const Point< Real, Dim > &p, const CumulativeDerivativeValues< Real, Dim, 0 > &dValues) const