traveller59 / spconv

Spatial Sparse Convolution Library
Apache License 2.0
1.85k stars 362 forks source link

Point2Voxel generated coordinates out of range? #691

Open Kazawaryu opened 6 months ago

Kazawaryu commented 6 months ago

I'm using VoxelGenerator.point_to_voxel(), to get the voxelized points. But I fond the return value of coordinates out of range. Did I miss some procedure or wrong understanding the function? Please let me understand, thank you. Here's my code.

import numpy as np
from skimage import transform
from pcdet.models.backbones_3d.spconv_backbone import VoxelBackBone8x
import torch
import torchvision
import spconv
tv = None
try:
    import cumm.tensorview as tv
except:
    pass
class voxelgenerator():
    def __init__(self,vsize_xyz, coors_range_xyz, num_point_features, max_num_points_per_voxel, max_num_voxels):
        print(vsize_xyz, coors_range_xyz, num_point_features, max_num_points_per_voxel, max_num_voxels)
        try:
            from spconv.utils import VoxelGeneratorV2 as VoxelGenerator
            self.spconv_ver = 1
        except:
            try:
                from spconv.utils import VoxelGenerator
                self.spconv_ver = 1
            except:
                from spconv.utils import Point2VoxelCPU3d as VoxelGenerator
                self.spconv_ver = 2

        if self.spconv_ver == 1:
            self._voxel_generator = VoxelGenerator(
                voxel_size=vsize_xyz,
                point_cloud_range=coors_range_xyz,
                max_num_points=max_num_points_per_voxel,
                max_voxels=max_num_voxels
            )
        else:
            self._voxel_generator = VoxelGenerator(
                vsize_xyz=vsize_xyz,
                coors_range_xyz=coors_range_xyz,
                num_point_features=num_point_features,
                max_num_points_per_voxel=max_num_points_per_voxel,
                max_num_voxels=max_num_voxels
            )

    def generate(self, points):
        if self.spconv_ver == 1:
            voxel_output = self._voxel_generator.generate(points)
            if isinstance(voxel_output, dict):
                voxels, coordinates, num_points = \
                    voxel_output['voxels'], voxel_output['coordinates'], voxel_output['num_points_per_voxel']
            else:
                voxels, coordinates, num_points = voxel_output
        else:
            assert tv is not None, f"Unexpected error, library: 'cumm' wasn't imported properly."
            voxel_output = self._voxel_generator.point_to_voxel(tv.from_numpy(points))
            tv_voxels, tv_coordinates, tv_num_points = voxel_output
            # make copy with numpy(), since numpy_view() will disappear as soon as the generator is deleted
            voxels = tv_voxels.numpy()
            coordinates = tv_coordinates.numpy()
            num_points = tv_num_points.numpy()
        return voxels, coordinates, num_points

    def meanVFE(self,voxel_features, voxel_num_points):
        points_mean = voxel_features[:, :, :].sum(dim=1, keepdim=False) # Use sum() instead of _sum()
        normalizer = torch.clamp_min(voxel_num_points.view(-1, 1), min=1.0).type_as(voxel_features)
        points_mean = points_mean / normalizer 
        return points_mean.contiguous()

voxel_size = dataset_processor_cfg[2].VOXEL_SIZE
points_range = cfg.DATA_CONFIG.POINT_CLOUD_RANGE
num_point_features = cfg.DATA_CONFIG.DATA_AUGMENTOR.AUG_CONFIG_LIST[0].NUM_POINT_FEATURES
max_number_per_voxel = dataset_processor_cfg[2].MAX_POINTS_PER_VOXEL
max_number_of_voxels = dataset_processor_cfg[2].MAX_NUMBER_OF_VOXELS['train']
#grid_size = cfg.MODEL.ROI_HEAD.ROI_GRID_POOL.GRID_SIZE

grid_size = points_range[3:6] - points_range[0:3] / np.array(voxel_size)
grid_size = np.round(grid_size).astype(np.int64)
print(grid_size)

voxel_generator = voxelgenerator(voxel_size, points_range, num_point_features, max_number_per_voxel, max_number_of_voxels)
points = np.fromfile(data_path, dtype=np.float32).reshape(-1, 4)
# only use the points in points range
# print('origin', len(points))
# points = points[(points[:, 0] >= points_range[0]) & (points[:, 0] < points_range[3]) &
#                 (points[:, 1] >= points_range[1]) & (points[:, 1] < points_range[4]) &
#                 (points[:, 2] >= points_range[2]) & (points[:, 2] < points_range[5])]
# print('after', len(points))

voxels, coordinates, num_points = voxel_generator.generate(points)

voxels = torch.from_numpy(voxels)
coordinates = torch.from_numpy(coordinates)
num_points = torch.from_numpy(num_points)

# print max of coordinates
print(coordinates.max(0), coordinates.min(0))

mean_voxel = voxel_generator.meanVFE(voxels, num_points)
print(mean_voxel.shape, coordinates.shape, num_points.shape)

# 2. load the voxelbackbone
backbone = VoxelBackBone8x(model_cfg=cfg, input_channels=num_point_features, grid_size=grid_size)
# [batch_idx, z_idx, y_idx, x_idx]
coordinates = torch.cat([torch.zeros_like(coordinates[:, :1]), coordinates], dim=1)
for i in range(len(coordinates)):
    coordinates[i, 0] = i

# mean_voxels, coordinates, num_points to cuda
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
torch.cuda.set_device(0)
mean_voxel = mean_voxel.to(0)
coordinates = coordinates.to(0)
num_points = num_points.to(0)

sp_input_res = backbone.get_input_layer_result(voxel_features=mean_voxel, voxel_coords=coordinates,batch_size=1)

And the input parameters of voxelgenerator are [0.05, 0.05, 0.1] [-70.4, -40, -3, 70.4, 40, 1] 4 5 16000, grid size is [1478 840 31]. But the max and min of coordinates are

print(max(indices[:,1]), min(indices[:,1])) # 39 0
print(max(indices[:,2]), min(indices[:,2])) # 1599 0
print(max(indices[:,3]), min(indices[:,3])) # 2813 0
Kazawaryu commented 6 months ago

I thought the max of indices should less than grid size