<filename>3D-SMNet-toolings/get_mp3d_training_data_stats.py
import open3d as o3d
import os
import sys
sys.path.append('mp3d')
from model_util_mp3d import MP3DDatasetConfig
import h5py
from tqdm import tqdm

import trimesh
import numpy as np

import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim import lr_scheduler
from torch.utils.data import DataLoader

DC = MP3DDatasetConfig()
DATASET_CONFIG = MP3DDatasetConfig()

MAX_NUM_OBJ = 256
data_type = 'complete_pc'

if data_type =='complete_pc':
    root_data_path = os.path.join('mp3d',
                                  'votenet_training_data_complete_pc/')
 
data_path = os.path.join(root_data_path,
                         'train',
                         'votenet_inputs')
 

files = os.listdir(data_path)


# -- from pc_utils.py write_oriented_bbox
def heading2rotmat(heading_angle):
    rotmat = np.zeros((3,3))
    rotmat[2,2] = 1
    cosval = np.cos(heading_angle)
    sinval = np.sin(heading_angle)
    rotmat[0:2,0:2] = np.array([[cosval, -sinval],[sinval, cosval]])
    return rotmat

def convert_oriented_box_to_trimesh_fmt(box):
    ctr = box[:3]
    lengths = box[3:6]
    trns = np.eye(4)
    trns[0:3, 3] = ctr
    trns[3,3] = 1.0
    trns[0:3,0:3] = heading2rotmat(box[6])
    box_trimesh_fmt = trimesh.creation.box(lengths, trns)
    return box_trimesh_fmt

X = []
Y = []
Z = []
pcd = []
points_per_box_per_class = {}
box_dimensions_per_class = {}

num_objects_per_scene = []

for idx in tqdm(range(len(files))):
    
    file = files[idx]

    h5file = h5py.File(os.path.join(data_path, file), 'r')
    mesh_vertices = np.array(h5file['point_cloud'], dtype=np.float32)
    instance_labels = np.array(h5file['instance'], dtype=np.int32)
    semantic_labels = np.array(h5file['semantic'], dtype=np.int32)
    instance_bboxes = np.array(h5file['bboxes'], dtype=np.float32)
    instance_bboxes = instance_bboxes[:,:8]
    h5file.close()

    mesh_vertices[:,[0,1,2]] = mesh_vertices[:,[0,2,1]]

    num_point = mesh_vertices.shape[0]
    
    # convert annotations to z is up.
    instance_bboxes[:,[0,1,2]] = instance_bboxes[:,[0,2,1]]
    instance_bboxes[:,[3,4,5]] = instance_bboxes[:,[3,5,4]]

    point_cloud = mesh_vertices[:,0:3] # do not use color for now

    floor_height = np.percentile(point_cloud[:,2],0.99)
    height = point_cloud[:,2] - floor_height
    point_cloud = np.concatenate([point_cloud, np.expand_dims(height, 1)],1)

    # ------------------------------- LABELS ------------------------------
    target_bboxes = np.zeros((MAX_NUM_OBJ, 6))
    target_bboxes_mask = np.zeros((MAX_NUM_OBJ))
    angle_classes = np.zeros((MAX_NUM_OBJ,))
    angle_residuals = np.zeros((MAX_NUM_OBJ,))
    size_classes = np.zeros((MAX_NUM_OBJ,))
    size_residuals = np.zeros((MAX_NUM_OBJ, 3))

    target_bboxes_mask[0:instance_bboxes.shape[0]] = 1
    target_bboxes[0:instance_bboxes.shape[0],:] = instance_bboxes[:,0:6]


    # NOTE: set size class as semantic class. Consider use size2class.
    size_classes[0:instance_bboxes.shape[0]] = instance_bboxes[:,-1]
    instance_bboxes_sids = instance_bboxes[:,-1]
    instance_bboxes_sids = instance_bboxes_sids.astype(np.int)
    size_residuals[0:instance_bboxes.shape[0], :] = \
        target_bboxes[0:instance_bboxes.shape[0], 3:6] - DC.mean_size_arr[instance_bboxes_sids,:]

    #TODO: update angle_classes + residuals
    angle_residuals[0:instance_bboxes.shape[0]] = instance_bboxes[:,6]


    ### == == STATS
    num_objects_per_scene.append(np.sum(target_bboxes_mask))

    #batch_data_label[key] = batch_data_label[key].to(device)
    #X += point_cloud[:,0].tolist()
    #Y += point_cloud[:,1].tolist()
    #Z += point_cloud[:,2].tolist()

    #pc = o3d.geometry.PointCloud()
    #pc.points = o3d.utility.Vector3dVector(point_cloud[:,:3])
    #pc_dist = pc.compute_nearest_neighbor_distance()
    #pc_dist = np.asarray(pc_dist)
    #pcd += pc_dist.tolist()

    # Dump GT bounding boxes
    target_bboxes_semcls = np.zeros((MAX_NUM_OBJ))
    target_bboxes_semcls[0:instance_bboxes.shape[0]] = instance_bboxes[:,-1]
    gt_semantic_label = target_bboxes_semcls
    gt_center = target_bboxes 
    gt_mask = target_bboxes_mask
    gt_heading_class = angle_classes
    gt_heading_residual = angle_residuals
    gt_size_class = size_classes
    gt_size_residual = size_residuals
    obbs = []
    for j in range(gt_center.shape[0]):
        if gt_mask[j] == 0: continue
        semantic_id = gt_semantic_label[j].item()
        obb = DATASET_CONFIG.param2obb(gt_center[j,0:3],
                                       gt_heading_class[j],
                                       gt_heading_residual[j],
                                       gt_size_class[j],
                                       gt_size_residual[j])

        trimesh_box = convert_oriented_box_to_trimesh_fmt(obb)

        inside_points_mask = trimesh_box.contains(point_cloud[:,:3])

        num_points_inside_box = np.sum(inside_points_mask)

        if semantic_id not in points_per_box_per_class:
            points_per_box_per_class[semantic_id] = []

        points_per_box_per_class[semantic_id].append(num_points_inside_box/num_point * 100)

        bounds = trimesh_box.bounds
        dist = bounds[1] - bounds[0]

        if semantic_id not in box_dimensions_per_class:
            box_dimensions_per_class[semantic_id] = []

        box_dimensions_per_class[semantic_id].append(dist)
    
#print(' ')
#print(' Mean objects number per scene')
#print(np.mean(num_objects_per_scene))
#print(np.std(num_objects_per_scene))
#
#mean_X = np.mean(X)
#mean_Y = np.mean(Y)
#mean_Z = np.mean(Z)
#print(' ')
#print('Average PC xyz values: ')
#print(mean_X, mean_Y, mean_Z)
#
#std_X = np.std(X)
#std_Y = np.std(Y)
#std_Z = np.std(Z)
#
#print(std_X, std_Y, std_Z)

#print(' ')
#print('Average distance btween points in PC: ')
#mean_pcd = np.mean(pcd)
#std_pcd = np.std(pcd)
#print(mean_pcd, ' +/ ', std_pcd)

print(' ')
print('Average number of points per boxes per class: ')
tmp = []
for k,v in points_per_box_per_class.items():
    tmp += v
    mean_pts = np.mean(v)
    std_pts = np.std(v)

    print(k, mean_pts, std_pts)
    print(k, np.min(v))

print(' ')
print('Overall number of points per boxes: ')
print(np.mean(tmp), ' +/- ', np.std(tmp))
print(np.min(tmp))

#print(' ')
#print('Average boxes dimensions per class: ')
#tmp = []
#for k,v in box_dimensions_per_class.items():
#    tmp += v
#    mean_dims = np.mean(np.array(v), axis=0)
#    std_dims = np.std(np.array(v), axis=0)
#
#    print(k, mean_dims, std_dims)
#
#print(' ')
#print('Overall boxes dimensions: ')
#print(np.mean(np.array(tmp), axis=0), ' +/- ', np.std(np.array(tmp), axis=0))




<filename>3D-SMNet-toolings/get_mp3d_training_data_stats.py
import open3d as o3d
import os
import sys
sys.path.append('mp3d')
from model_util_mp3d import MP3DDatasetConfig
import h5py
from tqdm import tqdm

import trimesh
import numpy as np

import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim import lr_scheduler
from torch.utils.data import DataLoader

DC = MP3DDatasetConfig()
DATASET_CONFIG = MP3DDatasetConfig()

MAX_NUM_OBJ = 256
data_type = 'complete_pc'

if data_type =='complete_pc':
    root_data_path = os.path.join('mp3d',
                                  'votenet_training_data_complete_pc/')
 
data_path = os.path.join(root_data_path,
                         'train',
                         'votenet_inputs')
 

files = os.listdir(data_path)


# -- from pc_utils.py write_oriented_bbox
def heading2rotmat(heading_angle):
    rotmat = np.zeros((3,3))
    rotmat[2,2] = 1
    cosval = np.cos(heading_angle)
    sinval = np.sin(heading_angle)
    rotmat[0:2,0:2] = np.array([[cosval, -sinval],[sinval, cosval]])
    return rotmat

def convert_oriented_box_to_trimesh_fmt(box):
    ctr = box[:3]
    lengths = box[3:6]
    trns = np.eye(4)
    trns[0:3, 3] = ctr
    trns[3,3] = 1.0
    trns[0:3,0:3] = heading2rotmat(box[6])
    box_trimesh_fmt = trimesh.creation.box(lengths, trns)
    return box_trimesh_fmt

X = []
Y = []
Z = []
pcd = []
points_per_box_per_class = {}
box_dimensions_per_class = {}

num_objects_per_scene = []

for idx in tqdm(range(len(files))):
    
    file = files[idx]

    h5file = h5py.File(os.path.join(data_path, file), 'r')
    mesh_vertices = np.array(h5file['point_cloud'], dtype=np.float32)
    instance_labels = np.array(h5file['instance'], dtype=np.int32)
    semantic_labels = np.array(h5file['semantic'], dtype=np.int32)
    instance_bboxes = np.array(h5file['bboxes'], dtype=np.float32)
    instance_bboxes = instance_bboxes[:,:8]
    h5file.close()

    mesh_vertices[:,[0,1,2]] = mesh_vertices[:,[0,2,1]]

    num_point = mesh_vertices.shape[0]
    
    # convert annotations to z is up.
    instance_bboxes[:,[0,1,2]] = instance_bboxes[:,[0,2,1]]
    instance_bboxes[:,[3,4,5]] = instance_bboxes[:,[3,5,4]]

    point_cloud = mesh_vertices[:,0:3] # do not use color for now

    floor_height = np.percentile(point_cloud[:,2],0.99)
    height = point_cloud[:,2] - floor_height
    point_cloud = np.concatenate([point_cloud, np.expand_dims(height, 1)],1)

    # ------------------------------- LABELS ------------------------------
    target_bboxes = np.zeros((MAX_NUM_OBJ, 6))
    target_bboxes_mask = np.zeros((MAX_NUM_OBJ))
    angle_classes = np.zeros((MAX_NUM_OBJ,))
    angle_residuals = np.zeros((MAX_NUM_OBJ,))
    size_classes = np.zeros((MAX_NUM_OBJ,))
    size_residuals = np.zeros((MAX_NUM_OBJ, 3))

    target_bboxes_mask[0:instance_bboxes.shape[0]] = 1
    target_bboxes[0:instance_bboxes.shape[0],:] = instance_bboxes[:,0:6]


    # NOTE: set size class as semantic class. Consider use size2class.
    size_classes[0:instance_bboxes.shape[0]] = instance_bboxes[:,-1]
    instance_bboxes_sids = instance_bboxes[:,-1]
    instance_bboxes_sids = instance_bboxes_sids.astype(np.int)
    size_residuals[0:instance_bboxes.shape[0], :] = \
        target_bboxes[0:instance_bboxes.shape[0], 3:6] - DC.mean_size_arr[instance_bboxes_sids,:]

    #TODO: update angle_classes + residuals
    angle_residuals[0:instance_bboxes.shape[0]] = instance_bboxes[:,6]


    ### == == STATS
    num_objects_per_scene.append(np.sum(target_bboxes_mask))

    #batch_data_label[key] = batch_data_label[key].to(device)
    #X += point_cloud[:,0].tolist()
    #Y += point_cloud[:,1].tolist()
    #Z += point_cloud[:,2].tolist()

    #pc = o3d.geometry.PointCloud()
    #pc.points = o3d.utility.Vector3dVector(point_cloud[:,:3])
    #pc_dist = pc.compute_nearest_neighbor_distance()
    #pc_dist = np.asarray(pc_dist)
    #pcd += pc_dist.tolist()

    # Dump GT bounding boxes
    target_bboxes_semcls = np.zeros((MAX_NUM_OBJ))
    target_bboxes_semcls[0:instance_bboxes.shape[0]] = instance_bboxes[:,-1]
    gt_semantic_label = target_bboxes_semcls
    gt_center = target_bboxes 
    gt_mask = target_bboxes_mask
    gt_heading_class = angle_classes
    gt_heading_residual = angle_residuals
    gt_size_class = size_classes
    gt_size_residual = size_residuals
    obbs = []
    for j in range(gt_center.shape[0]):
        if gt_mask[j] == 0: continue
        semantic_id = gt_semantic_label[j].item()
        obb = DATASET_CONFIG.param2obb(gt_center[j,0:3],
                                       gt_heading_class[j],
                                       gt_heading_residual[j],
                                       gt_size_class[j],
                                       gt_size_residual[j])

        trimesh_box = convert_oriented_box_to_trimesh_fmt(obb)

        inside_points_mask = trimesh_box.contains(point_cloud[:,:3])

        num_points_inside_box = np.sum(inside_points_mask)

        if semantic_id not in points_per_box_per_class:
            points_per_box_per_class[semantic_id] = []

        points_per_box_per_class[semantic_id].append(num_points_inside_box/num_point * 100)

        bounds = trimesh_box.bounds
        dist = bounds[1] - bounds[0]

        if semantic_id not in box_dimensions_per_class:
            box_dimensions_per_class[semantic_id] = []

        box_dimensions_per_class[semantic_id].append(dist)
    
#print(' ')
#print(' Mean objects number per scene')
#print(np.mean(num_objects_per_scene))
#print(np.std(num_objects_per_scene))
#
#mean_X = np.mean(X)
#mean_Y = np.mean(Y)
#mean_Z = np.mean(Z)
#print(' ')
#print('Average PC xyz values: ')
#print(mean_X, mean_Y, mean_Z)
#
#std_X = np.std(X)
#std_Y = np.std(Y)
#std_Z = np.std(Z)
#
#print(std_X, std_Y, std_Z)

#print(' ')
#print('Average distance btween points in PC: ')
#mean_pcd = np.mean(pcd)
#std_pcd = np.std(pcd)
#print(mean_pcd, ' +/ ', std_pcd)

print(' ')
print('Average number of points per boxes per class: ')
tmp = []
for k,v in points_per_box_per_class.items():
    tmp += v
    mean_pts = np.mean(v)
    std_pts = np.std(v)

    print(k, mean_pts, std_pts)
    print(k, np.min(v))

print(' ')
print('Overall number of points per boxes: ')
print(np.mean(tmp), ' +/- ', np.std(tmp))
print(np.min(tmp))

#print(' ')
#print('Average boxes dimensions per class: ')
#tmp = []
#for k,v in box_dimensions_per_class.items():
#    tmp += v
#    mean_dims = np.mean(np.array(v), axis=0)
#    std_dims = np.std(np.array(v), axis=0)
#
#    print(k, mean_dims, std_dims)
#
#print(' ')
#print('Overall boxes dimensions: ')
#print(np.mean(np.array(tmp), axis=0), ' +/- ', np.std(np.array(tmp), axis=0))




# -- from pc_utils.py write_oriented_bbox # convert annotations to z is up. # do not use color for now # ------------------------------- LABELS ------------------------------ # NOTE: set size class as semantic class. Consider use size2class. #TODO: update angle_classes + residuals ### == == STATS #batch_data_label[key] = batch_data_label[key].to(device) #X += point_cloud[:,0].tolist() #Y += point_cloud[:,1].tolist() #Z += point_cloud[:,2].tolist() #pc = o3d.geometry.PointCloud() #pc.points = o3d.utility.Vector3dVector(point_cloud[:,:3]) #pc_dist = pc.compute_nearest_neighbor_distance() #pc_dist = np.asarray(pc_dist) #pcd += pc_dist.tolist() # Dump GT bounding boxes #print(' ') #print(' Mean objects number per scene') #print(np.mean(num_objects_per_scene)) #print(np.std(num_objects_per_scene)) # #mean_X = np.mean(X) #mean_Y = np.mean(Y) #mean_Z = np.mean(Z) #print(' ') #print('Average PC xyz values: ') #print(mean_X, mean_Y, mean_Z) # #std_X = np.std(X) #std_Y = np.std(Y) #std_Z = np.std(Z) # #print(std_X, std_Y, std_Z) #print(' ') #print('Average distance btween points in PC: ') #mean_pcd = np.mean(pcd) #std_pcd = np.std(pcd) #print(mean_pcd, ' +/ ', std_pcd) #print(' ') #print('Average boxes dimensions per class: ') #tmp = [] #for k,v in box_dimensions_per_class.items(): #    tmp += v #    mean_dims = np.mean(np.array(v), axis=0) #    std_dims = np.std(np.array(v), axis=0) # #    print(k, mean_dims, std_dims) # #print(' ') #print('Overall boxes dimensions: ') #print(np.mean(np.array(tmp), axis=0), ' +/- ', np.std(np.array(tmp), axis=0))