LiangliangNan / Easy3D

A lightweight, easy-to-use, and efficient C++ library for processing and rendering 3D data
GNU General Public License v3.0
1.37k stars 245 forks source link

Is there a way to extract a "plane" data structure from PrimitivesRansac::detect() ?? #121

Closed KenKenhehe closed 2 years ago

KenKenhehe commented 2 years ago

In file Tutorial_603_PlaneExtraction/viewer.cpp line 70

The PrimitivesRansac::detect() method only returns the number of primitive extracted, is there a way to access or retrive a "plane" data structure such that I can get the equation of the plane or get the x1y1, x2y2,x3y3 of a plane??

Appreciate the help

LiangliangNan commented 2 years ago

No, the current implementation doesn't provide a "PlanePrimitive" data structure, but the plane equation can be easily obtained by least-squares fitting of the points of a plane.

You can use the PrincipalAxes in easy3d/core/principal_axes.h to do the least-squares fitting. Something like:

            PrincipalAxes<3, float> pca;
            pca.begin();
            for each point p belonging to a plane: {
                pca.add(p);
            }
            pca.end();

            // the eigen vector corresponding to the smallest eigen value gives you the normal of the plane.
            plane_normal = pca.axis(2);
            // the centroid of the points is a point on the plane
            plane_point = pca.center();

            // then the plane can be constructed by
       Plane3 plane(vec3(0, 0, 0), normal);
            // and now you can get the plane parameters, please refer to `easy3d/core/plane.h`
LiangliangNan commented 2 years ago

I believe your question has been answered and thus I am closing this issue. Feel free to re-open it if this is not the case.

KenKenhehe commented 2 years ago

The Normal of the plane is different when I apply a positional translation to all of this point(for example when apply P(x, y, z) =>P(x = 1000, y+ 1000, z) for all the points in plane), is there a way for me to get the same normal no matter what the translation is?

KenKenhehe commented 2 years ago

For example:

PrincipalAxes<3, float> pca;
PrincipalAxes<3, float> pca2;
pca.begin();
for (auto v : plane_point_could->vertices()) {
        pca.add(plane_point_could->position(v));
    }
    pca.end();

    vec3 plane_normal = pca.axis(2);
    vec3 plane_point = pca.center();

//modify the translation of all point
pca2.begin();
for (auto v : plane_point_could->vertices()) {
vec3 pos = plane_point_could->position(v);
pos.x += 1000;
pos.y += 1000;
        pca2.add(pos);
    }
    pca2.end();

    vec3 plane_normal2 = pca2.axis(2);
    vec3 plane_point2 = pca2.center();

//plane_normal and plane_normal2 should be equal but is not???
LiangliangNan commented 2 years ago

How did you know the normals are different? Can you provide your computed normals? And if possible, please also attached your points in a file (preferably XYZ format).

KenKenhehe commented 2 years ago

I found out by simply printing out the normal in console:

vec3 plane_normal = pca.center();
std::cout << plane_normal << std::endl;

output normal for this model when it sits in (0,0,0) in blender(the yellow mesh is the plane I have extracted): image image

but when model is moved with y + 3000 and x + 3000: image We can see the plane is no longer aligned with the point cloud data and the normal is: image

LiangliangNan commented 2 years ago

Can you attach your point cloud file here?

KenKenhehe commented 2 years ago

The point could is converted by a .obj file taken just the x,y,z from each vertex github doesn't seem to support uploading obj file

Try making a simple plane in blender, and convert to point cloud by taking the xyz, and you should see similar behaviour when the location is x+3000, y+3000 and when it's (0,0,0)

LiangliangNan commented 2 years ago

The simplest would be the "XYZ" file, so each line simply 3 floating-point numbers representing the x, y, and z coordinates, e..g,,

2.3       3.322   32.98
123.2   67.77    72.24
...
KenKenhehe commented 2 years ago

Yes, but again the xyz file isn't the initial input, the .obj is, the point cloud is internally converted by this .obj file so I can not provide any xyz file

LiangliangNan commented 2 years ago

So how can I help? I want to help, but I need your problem data. So please save it in any format and send it to me (xyz is just the simplest format to look at).

LiangliangNan commented 2 years ago

Can you try PrincipalAxes<3, double> pca; , i.e., use double instead of float. I can imagine that when using float, if your object coordinates are very close to the origin, adding 1000 to each coordinate and then summing up those for hundreds/thousands/millions of points could accumulate huge errors.

KenKenhehe commented 2 years ago

Sorry I won't be able to provide the actual obj due to company policy, I will have a try to see if it's really the double vs float issue, thanks