mkazhdan / PoissonRecon

Poisson Surface Reconstruction
MIT License
1.59k stars 431 forks source link

Input from memory (positions + normals + colors) #254

Open AybarsManav opened 1 year ago

AybarsManav commented 1 year ago

Hello Professor,

I have been trying to read a point cloud from memory (positions, normal and colors) and construct MemoryInputDataStream object accordingly. I firstly called a slightly changed Execute function this way Execute< Real >( FEMSigs() , VertexFactory::RGBColorFactory<Real>(), point_cloud_mesh); , this function simply also includes a point cloud mesh so that we can populate necessary vectors. I have read the related issues like #90 and written my code like this similarly:

if (true)
{
  std::vector<double> pos = point_cloud_mesh.getPointsFlattened();
  std::vector<double> nor = point_cloud_mesh.getNormalsFlattened();
  std::vector<double> cols = point_cloud_mesh.getNormalsFlattened();
  for (int mv = 0; mv < pos.size()/3; mv++)
  {
    const int mv3 = mv*3;
    InputSampleType pointAndNormalAndColor;
    pointAndNormalAndColor.get<0>() = Point< Real, Dim >(pos[mv3], pos[mv3+1], pos[mv3+2]);
    pointAndNormalAndColor.get<1>().get<0>() = Point< Real, Dim >(nor[mv3], nor[mv3 + 1], nor[mv3 + 2]);
    pointAndNormalAndColor.get<1>().get<1>() = Point<Real, 3>(cols[mv3], cols[mv3+1], cols[mv3+2]);
    inCorePoints.push_back(pointAndNormalAndColors);
  }
  pointStream = new MemoryInputDataStream< InputSampleType >(inCorePoints.size(), &inCorePoints[0]);  
  printf("here we go!\n");
}

But when I do this, I get this compiler error : binary '=': no operator found which takes a right-hand operand of type 'Point<unsigned char,3>' (or there is no acceptable conversion) at line pointAndNormalAndColor.get<1>().get<1>() = Point<Real, 3>(cols[mv3], cols[mv3+1], cols[mv3+2]);.

After seeing this, I commented the problematic line and printed the type of pointAndNormalAndColor.get<1>().get<1>() via std::cout << typeid(pointAndNormalAndColor.get<1>().get<1>()).name() << std::endl; it was struct Point<float,3> as expected. Then I tried to use coords member of the Point struct like this just see: pointAndNormalAndColor.get<1>().get<1>().coords[0] = col[mv3]; However, when I did this the compiler told me: 'coords': is not a member of 'EmptyVectorType<Real>'.

I have also checked std::cout << "Vertex type: " << typeid(typename AuxDataFactory::VertexType).name() << std::endl; std::cout << "Vertex type: " << typeid(typename InputSampleFactory::VertexType).name() << std::endl; and outputs were

Vertex type: struct Point<float,3>
Vertex type: struct VectorTypeUnion<float,struct Point<float,3>,struct VectorTypeUnion<float,struct Point<float,3>,struct Point<float,3> > >

Similary I have also checked std::cout << "Vertex type: " << typeid(typename InputSampleType).name() << std::endl; std::cout << "Vertex type: " << typeid(typename InputSampleDataType).name() << std::endl; the outputs were

Vertex type: struct VectorTypeUnion<float,struct Point<float,3>,struct VectorTypeUnion<float,struct Point<float,3>,struct Point<float,3> > >
Vertex type: struct VectorTypeUnion<float,struct Point<float,3>,struct Point<float,3> >

I do not know why the second element of InputSampleDataType object is thought as EmptyVectorType during compile time. Could you please enlighten me?

mkazhdan commented 1 year ago

Given what I see of your code, I am confused like you. Would it be possible to see more of the context. By all accounts the error is strange since the RHS is of type Point< Real , 3 > while the compiler believes it to be of type Point< unsigned char , 3 >. (I'm assuming that if you print out the type of "Real" it will be "float"?)

AybarsManav commented 1 year ago

Thank you for your quick response, I updated the code to be this way:

if (true) {
            std::vector<double> pos;
            std::vector<double> nor;
            std::vector<float> col;
            pos = point_cloud_mesh.getPointsFlattened();
            nor = point_cloud_mesh.getNormalsFlattened();
            col = point_cloud_mesh.getPointColorsFlattened();
            for (int mv = 0; mv < pos.size() / 3; mv++) {
                const int mv3 = mv * 3;
                InputSampleType pointAndNormalAndColor;
                Point<Real, Dim> position(pos[mv3], pos[mv3 + 1], pos[mv3 + 2]);
                Point<Real, Dim> normal(nor[mv3], nor[mv3 + 1], nor[mv3 + 2]);
                Point<Real, Dim> color(col[mv3], col[mv3 + 1], col[mv3 + 2]);
                pointAndNormalAndColor.get<0>() = position;
                pointAndNormalAndColor.get<1>().get<0>() = normal;
                pointAndNormalAndColor.get<1>().get<1>() = color;

                inCorePoints.push_back(pointAndNormalAndColor);
            }
            pointStream = new MemoryInputDataStream< InputSampleType >(inCorePoints.size(), &inCorePoints[0]);
       }

You are right Real is type float. I believe the confusion stems from that I accidentally shared the wrong code, the correct code is the one I have given above. I updated the getPointColors() and it returns a std::vector<float> now. Now I get a similar compiler error binary '=': no operator found which takes a right-hand operand of type 'Point<Real,3>' (or there is no acceptable conversion). I believe now the compiler now understands the right hand side is Point <Real,3>, however, even though the left hand side is also supposed to be Point <Real,3> it apparently is not seen so by the compiler. When I comment out the pointAndNormalAndColor.get<1>().get<1>() = color; line and add std::cout << typeid(pointAndNormalAndColor.get<1>().get<1>()).name() << std::endl; I can run the code with Colors.set = 1 and InCore.set=0 and the printed type for pointAndNormalAndColor.get<1>().get<1>() is struct Point<float,3> indeed. From this, I don't think there should have been any problems.

On the other hand, I believe the compiler error indicates that left hand side is not actually struct Point<float,3>, to see what it is, I tried to assign a value using the coords member of the pointAndNormalAndColor.get<1>().get<1>() by pointAndNormalAndColor.get<1>().get<1>().coords[0] = color[0]; and I received the following compiler error C2039 'coords': is not a member of 'EmptyVectorType<Real>'. I guess that means the compiler thinks the LHS as EmptyVectorType even though when that line is commented and its type is printed it says Point<float,3>.

I can provide more information about the context but I am not sure which part of the context would be useful. Since I am not reading from a .ply file and the received error is during compile time I don't think it has anything to do with a .ply file that has no color information or additional auxiliary data. If you could tell me what things might be affecting the template parameter instantiation I can share those parts.

mkazhdan commented 1 year ago

I'm wondering what the function signature looks like and what the invocation looks like as well. (Concretely, I'm wondering if your code supports a template option without color, even though you are calling it with Colors.set. If so, the problem is with compilation, not execution. The code fails to compile when the line is commented out since for some set of allowable template parameters the point doesn't have colors so trying to access the .get<1>().get<1>() might not be valid.)

AybarsManav commented 1 year ago

Hello professor, yes my code works without colors, in main function I call the Execute this way

if(Colors.set) last_mesh = Execute< Real >( FEMSigs() , VertexFactory::RGBColorFactory<Real>(), point_cloud_mesh);
    else             last_mesh = Execute< Real >( FEMSigs() , VertexFactory::EmptyFactory< Real >(), point_cloud_mesh);

and the signature looks like this

template< class Real , typename AuxDataFactory , unsigned int ... FEMSigs >
Mesh Execute( UIntPack< FEMSigs ... > , const AuxDataFactory &auxDataFactory, Mesh& mesh )

I can run the code without issues

if (!Colors.set)
        {
            std::vector<double> pos;
            std::vector<double> nor;
            pos =  point_cloud_mesh.getPointsFlattened();
            nor =  point_cloud_mesh.getNormalsFlattened();
            std::cout << "[PoissonRecon]pos size " << pos.size() << std::endl;
            std::cout << "[PoissonRecon]nor size " << nor.size() << std::endl;
            for (int mv = 0; mv < pos.size() / 3; mv++)
            {
                const int mv3 = mv * 3;
                InputSampleType pointAndNormal;
                pointAndNormal.get<0>() = Point< Real, Dim >(pos[mv3], pos[mv3 + 1], pos[mv3 + 2]);
                pointAndNormal.get<1>().get<0>() = Point< Real, Dim >(nor[mv3], nor[mv3 + 1], nor[mv3 + 2]);
                inCorePoints.push_back(pointAndNormal);
            }
            pointStream = new MemoryInputDataStream< InputSampleType >(inCorePoints.size(), &inCorePoints[0]);
        }

I do not understand why point would not have colors even though I instantiate the AuxDataFactory as RGBColorFactory. Also the code complies when I comment out the line with pointAndNormalAndColor.get<1>().get<1>() and I can see the inputSampleType is of correct one having a Point<Real,Dim> as the second element of the inner VectorTypeUnion. I hope I was able to provide you some useful information, I had hardship understanding your previous response.

Thank you so much.

mkazhdan commented 1 year ago

I think the problem may be with how you are invoking the function in the "if( Color.set ) ... else ..." clause.

You implementation of the "else" clause has the compiler trying to generate a version of "Execute" where Factory type is an EmptyFactory. This will cause a compilation error because when you invoke "pointAndNormalAndColor.get<1>().get<1>()" you are trying to access a tuple element that does not exist.

What you are seeing when you comment out code and print out the type is happening at run-time, when Color.set==true, and you are only running the "if" part of the branch, not the "else".

If my hunch is right, commenting out the "else" part of the branch should also compile.