Skip to content

Instantly share code, notes, and snippets.

@justanhduc
Last active March 8, 2023 20:00
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save justanhduc/514ed66db6a3bcc953151cf4a4c391b2 to your computer and use it in GitHub Desktop.
Save justanhduc/514ed66db6a3bcc953151cf4a4c391b2 to your computer and use it in GitHub Desktop.
PyTorch pointcloud to voxel
import neuralnet_pytorch as nnt
import torch as T
from torch_scatter import scatter_add
def pointcloud2voxel_fast(pc: T.Tensor, voxel_size: int, grid_size=1., filter_outlier=True):
b, n, _ = pc.shape
half_size = grid_size / 2.
valid = (pc >= -half_size) & (pc <= half_size)
valid = T.all(valid, 2)
pc_grid = (pc + half_size) * (voxel_size - 1.) / grid_size # thanks @heathentw
indices_floor = T.floor(pc_grid)
indices = indices_floor.long()
batch_indices = T.arange(b, device=pc.device)
batch_indices = nnt.utils.shape_padright(batch_indices)
batch_indices = nnt.utils.tile(batch_indices, (1, n))
batch_indices = nnt.utils.shape_padright(batch_indices)
indices = T.cat((batch_indices, indices), 2)
indices = T.reshape(indices, (-1, 4))
r = pc_grid - indices_floor
rr = (1. - r, r)
if filter_outlier:
valid = valid.flatten()
indices = indices[valid]
def interpolate_scatter3d(pos):
updates_raw = rr[pos[0]][..., 0] * rr[pos[1]][..., 1] * rr[pos[2]][..., 2]
updates = updates_raw.flatten()
if filter_outlier:
updates = updates[valid]
indices_shift = T.tensor([[0] + pos]).to(pc.device)
indices_loc = indices + indices_shift
out_shape = (b,) + (voxel_size,) * 3
out = T.zeros(*out_shape).to(pc.device).flatten()
voxels = scatter_add(updates, nnt.utils.ravel_index(indices_loc.t(), out_shape), out=out).view(*out_shape)
return voxels
voxels = [interpolate_scatter3d([k, j, i]) for k in range(2) for j in range(2) for i in range(2)]
voxels = sum(voxels)
voxels = T.clamp(voxels, 0., 1.)
return voxels
def voxelize(pc, vox_size=32):
vox = pointcloud2voxel_fast(pc, vox_size)
vox = T.squeeze(vox)
return vox
def iou(pred, gt, th=.5):
pred = pred > th
gt = gt > th
intersect = T.sum(pred & gt).float()
union = T.sum(pred | gt).float()
iou_score = intersect / (union + 1e-8)
return iou_score
def batch_iou(bpc1, bpc2, voxsize=32, thres=.4):
def _iou(pc1, pc2):
pc1 = pc1 - T.mean(pc1, -2, keepdim=True)
pc1 = voxelize(pc1[None], voxsize)
pc2 = pc2 - T.mean(pc2, -2, keepdim=True)
pc2 = voxelize(pc2[None], voxsize)
return iou(pc1, pc2, thres)
total = map(_iou, bpc1, bpc2)
return sum(total) / len(bpc1)
@heathentw
Copy link

heathentw commented Jun 24, 2022

I think it should / grid_size in line 11

@justanhduc
Copy link
Author

Hey @heathentw. Nice catch! I have never tested the code with any size other than one, so wasn't aware of that problem. Thanks for pointing out.

@heathentw
Copy link

No problem, thank you for sharing this good stuff. BTW are you still using it when voxelization? or there are useful library for replacement... cuz I can't find something off the shield base, at least not in pytorch3d. If you no longer maintaining related work it's totally fine. Thx again.

@justanhduc
Copy link
Author

Hi @heathentw. I'm not working with voxelization anymore, but of course I will use this code if I need. I remember Pytorch3d does have a differntiable voxelization function. I think it is here. Cheers!

@dengchengxifrank
Copy link

thanks for your wonderful work.But when I run you code,I find an error
`DGQ XV4JA(J1 U%5J44S4L

should I change neuralnet_pytorch.utils to T ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment