Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pointcloud sampling #2696

Open
Frq-F opened this issue May 7, 2024 · 4 comments
Open

pointcloud sampling #2696

Frq-F opened this issue May 7, 2024 · 4 comments
Assignees

Comments

@Frq-F
Copy link

Frq-F commented May 7, 2024

Hello ,I use the method pointGridSampling to downsample the pointcloud. Which python method can be used to check the number of points in the downsampled point cloud? And how to convert the downsampled point coordinates into numpy array

@Fedr Fedr self-assigned this May 7, 2024
@Fedr
Copy link
Contributor

Fedr commented May 7, 2024

Hello,

The function pointGridSampling in python returns an object of VertBitSet type. You can use count() method of it to find the number of samples.

If you want the result as numpy array, then you can export all points (before sampling) and sample mask:

from meshlib import mrmesh
from meshlib import mrmeshnumpy 

# Start from numpy arrays
u, v = np.mgrid[0 : 2 * np.pi : 100j, 0 : np.pi : 100j]
x = np.cos(u) * np.sin(v)
y = np.sin(u) * np.sin(v)
z = np.cos(v)

# Prepare for MeshLib PointCloud
verts = np.stack((x.flatten(), y.flatten(), z.flatten()), axis=-1).reshape(-1, 3)
# Create MeshLib PointCloud from np ndarray
pc = mrmeshnumpy.pointCloudFromPoints(verts)
assert(pc.validPoints.count() == 10000)
# Sample points
samples = mrmesh.pointGridSampling(pc, 0.1)
assert(samples.count() == 1524)

# Convert all points (before downsampling) in numpy array
pts = mrmeshnumpy.toNumpyArray(pc.points)

# Convert sample mask in numpy array of True/False
mrmeshnumpy.getNumpyBitSet(samples)

@Frq-F
Copy link
Author

Frq-F commented May 8, 2024

Thank you for your suggestion, which has solved my problem. By the way, I want to know if there is a method to downsample the point cloud to a fixed number. for example, after sampling, the number of points in the point cloud is 5000.

@Frq-F
Copy link
Author

Frq-F commented May 8, 2024

I am trying to use a loop to downsample the point cloud to 5000 points. Here is my code:

def prepare(mesh):

verts = mesh.points
pc = mn.pointCloudFromPoints(verts)

while True:
    samples = mm.pointGridSampling(pc, 0.99)

    # Convert all points (before downsampling) in numpy array
    pts = mn.toNumpyArray(pc.points)
    # Convert sample mask in numpy array of True/False
    samples_mask = mn.getNumpyBitSet(samples)
    result = pts[np.where(samples_mask)[0]]
    print(len(result))       
    tmp = len(result)
    if  tmp <= 5000:
        break
    pc = mn.pointCloudFromPoints(result)

But it only dropped to around 10000 and no longer undergoes downsampling. How to solve the problem?
屏幕截图 2024-05-08 142239

@Fedr
Copy link
Contributor

Fedr commented May 8, 2024

The second parameter in pointGridSampling is voxel size (or 3d box size), and the function leaves only one sample per voxel. If you run the function several times, then the voxels are the same and they already contain one point each, so the function does nothing. The only exception is the second run, which still removes some points because the bounding box of the whole point cloud changes after the first invocation, so the distribution of voxels changes as well.

In short, one has to increase voxelSize to get smaller number of output samples.

As to receiving exactly specified number of samples, we have such option for meshes (see decimation), but not for point clouds yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants