mkazhdan / PoissonRecon

Poisson Surface Reconstruction
MIT License
1.51k stars 422 forks source link

Envelope Generation in PoissonRecon Integration with CloudCompare #293

Open Matozinho opened 3 months ago

Matozinho commented 3 months ago

Hi @mkazhdan,

I'm currently working on upgrading the integration of your PoissonRecon library with the CloudCompare PoissonRecon plugin. This work is part of my undergraduate research at UNIOESTE (Brazil), where we aim to validate whether updating the library version leads to improved reconstructions for our datasets, which consist of point clouds obtained via drone-based LiDAR technology.

In our use case, users only have access to the point cloud data and not the range scans required for generating the depth hull, as explained in your SGP 2020 presentation. To address this, I've been attempting to create an envelope that is a quadrilateral encompassing the extreme points of the cloud. However, I've encountered the Leaf node is unknown error, which seems to originate from the SetUnknownDesignatorsFromChildren function within _GetGeometryNodeDesignators.

I have a few questions regarding this issue:

Does this approach of using a quadrilateral envelope for point clouds make sense in the absence of range scans? If this approach is valid, is there a different method I should use to generate the envelope? Could you provide some insight into what the Leaf node is unknown error signifies and how I might resolve it? Any guidance or suggestions you can provide would be greatly appreciated, as it would help us advance our research and improve the utility of the PoissonRecon integration in CloudCompare for our specific needs.

Thank you for your time and assistance.

mkazhdan commented 3 months ago

When you say "quadrilateral envelope" what do you mean? Is this a bounding box? Is it water-tight? If the envelope is sufficiently "loose" (i.e. it is not tight and encompasses the entire point-set) it seems like the results should be similar to what you would get reconstructing using Dirichlet boundary conditions (instead of the default Neumann).

Matozinho commented 3 months ago

Yes, the envelope I referred to is indeed a bounding box. I initially thought that using a bounding box would yield similar results to a standard reconstruction. I intended to use this as a preliminary step in incorporating the envelope feature into the reconstruction process within CloudCompare. However, I encountered this error and uncertainties that have stalled my progress.

mkazhdan commented 3 months ago

It might be easier if you could share your point set and envelope. That way I could try to reproduce the error here.

Matozinho commented 2 months ago

I'm sorry for the delay @mkazhdan.

I generate the envelope bounding box as follows:

The wrapper:

  // define the envelope
  typename Reconstructor::Poisson::EnvelopeMesh<Real, Dim> *envelopeMesh = NULL;
  {
    envelopeMesh =
        new typename Reconstructor::Poisson::EnvelopeMesh<Real, Dim>();

    Confia::generateMesh<PositionFactory<Real, Dim>, Real, Dim>(
        PositionFactory<Real, Dim>(), inCloud, envelopeMesh);

    // print all the vertices of the envelopeMesh
    for (size_t i = 0; i < envelopeMesh->vertices.size(); i++) {
      std::cout << "Vertex[" << i << "]: " << envelopeMesh->vertices[i]
                << std::endl;
    }
    std::cout << "Simplicies[0] " << envelopeMesh->simplices[0][0] << " "
              << envelopeMesh->simplices[0][1] << " "
              << envelopeMesh->simplices[0][2] << std::endl;
  }

Bounding Box Generation:

template <typename Real>
void findBoundingBox(const PoissonReconLib::ICloud<Real> &inCloud,
                     Real bbox[8][3]) {
  // Initialize min and max values to the first point's coordinates
  Real minX, minY, minZ, maxX, maxY, maxZ;
  Real firstPoint[3];
  inCloud.getPoint(0, firstPoint);
  minX = maxX = firstPoint[0];
  minY = maxY = firstPoint[1];
  minZ = maxZ = firstPoint[2];

  // Iterate through all points to find min and max values
  for (size_t i = 1; i < inCloud.size(); ++i) {
    Real coords[3];
    inCloud.getPoint(i, coords);

    if (coords[0] < minX)
      minX = coords[0];
    if (coords[0] > maxX)
      maxX = coords[0];
    if (coords[1] < minY)
      minY = coords[1];
    if (coords[1] > maxY)
      maxY = coords[1];
    if (coords[2] < minZ)
      minZ = coords[2];
    if (coords[2] > maxZ)
      maxZ = coords[2];
  }

  // Assign the 8 bounding box points
  bbox[0][0] = minX;
  bbox[0][1] = minY;
  bbox[0][2] = minZ; // Min corner
  bbox[1][0] = maxX;
  bbox[1][1] = minY;
  bbox[1][2] = minZ;
  bbox[2][0] = minX;
  bbox[2][1] = maxY;
  bbox[2][2] = minZ;
  bbox[3][0] = maxX;
  bbox[3][1] = maxY;
  bbox[3][2] = minZ;
  bbox[4][0] = minX;
  bbox[4][1] = minY;
  bbox[4][2] = maxZ;
  bbox[5][0] = maxX;
  bbox[5][1] = minY;
  bbox[5][2] = maxZ;
  bbox[6][0] = minX;
  bbox[6][1] = maxY;
  bbox[6][2] = maxZ;
  bbox[7][0] = maxX;
  bbox[7][1] = maxY;
  bbox[7][2] = maxZ; // Max corner
}

template <typename VertexFactory, class Real, int Dim>
void generateMesh(
    const VertexFactory &vFactory, const PoissonReconLib::ICloud<Real> &inCloud,
    Reconstructor::Poisson::EnvelopeMesh<Real, Dim> *envelopeMesh) {

  Real bbox[8][3];

  findBoundingBox(inCloud, bbox);

  typename VertexFactory::VertexType vertex = vFactory();

  for (size_t i = 0; i < 8; i++) {
    char *buffer = reinterpret_cast<char *>(&bbox[i]);

    vFactory.fromBuffer(buffer, vertex);
    envelopeMesh->vertices.push_back(vertex);
  }

  std::vector<std::vector<int>> simplices = {
      {0, 1, 2}, {0, 2, 3}, {4, 5, 6}, {4, 6, 7}, {0, 1, 5}, {0, 5, 4},
      {2, 3, 7}, {2, 7, 6}, {1, 2, 6}, {1, 6, 5}, {0, 3, 7}, {0, 7, 4}};

  for (size_t i = 0; i < simplices.size(); i++) {
    envelopeMesh->simplices.resize(simplices.size());
    for (size_t j = 0; j < simplices[i].size(); j++) {
      envelopeMesh->simplices[i][j] = simplices[i][j];
    }
  }
}

After making some changes to the implementation, I started receiving the following error:

[ERROR] /home/operador/Dev/unioeste/CloudCompare/plugins/core/Standard/qPoissonRecon/extern/PoissonRecon/Src_CC_wrap/../Src/Rasterizer.inl (Line 59)
        _RegularGridIndex
        Simplex is not in unit cube: ( 0.355635 , 0.289911 , 0.0454546 ) , ( 0.644365 , 0.289911 , 0.0454546 ) , ( 0.355635 , 0.710089 , 0.0454546 )

This error occurs when I'm testing with the torso.points.ply dataset (the example from your repo).

Thank you for your assistance.