├── README.md ├── models ├── __init__.py ├── deformnet.py ├── losses.py ├── meshnet.py ├── pointnet │ ├── __init__.py │ ├── model.py │ ├── model_cpu.py │ ├── model_emd.py │ ├── model_fc_upconv.py │ ├── model_hierachy.py │ ├── model_pointnet2.py │ ├── model_seg.py │ ├── model_upconv.py │ ├── model_vae.py │ ├── model_withtransform.py │ ├── pointnet2_cls_msg.py │ ├── pointnet2_part_seg.py │ └── transform_nets.py ├── pointnet_util.py ├── tf_ops │ ├── 3d_interpolation │ │ ├── interpolate.cpp │ │ ├── tf_interpolate.cpp │ │ ├── tf_interpolate.py │ │ ├── tf_interpolate_compile.sh │ │ ├── tf_interpolate_op_test.py │ │ └── visu_interpolation.py │ ├── __init__.py │ ├── approxmatch │ │ ├── __init__.py │ │ ├── tf_approxmatch.cpp │ │ ├── tf_approxmatch.py │ │ ├── tf_approxmatch_compile.sh │ │ └── tf_approxmatch_g.cu │ ├── compile.sh │ ├── grouping │ │ ├── test │ │ │ ├── compile.sh │ │ │ ├── query_ball_point.cpp │ │ │ ├── query_ball_point.cu │ │ │ ├── query_ball_point_block.cu │ │ │ ├── query_ball_point_grid.cu │ │ │ ├── selection_sort.cpp │ │ │ ├── selection_sort.cu │ │ │ └── selection_sort_const.cu │ │ ├── tf_grouping.cpp │ │ ├── tf_grouping.py │ │ ├── tf_grouping_compile.sh │ │ ├── tf_grouping_g.cu │ │ └── tf_grouping_op_test.py │ ├── mesh_laplacian │ │ ├── __init__.py │ │ ├── tf_meshlaplacian.cpp │ │ ├── tf_meshlaplacian.py │ │ ├── tf_meshlaplacian_compile.sh │ │ └── tf_meshlaplacian_g.cu │ ├── mesh_sampling │ │ ├── __init__.py │ │ ├── tf_meshsampling.cpp │ │ ├── tf_meshsampling.h │ │ ├── tf_meshsampling.py │ │ ├── tf_meshsampling_compile.sh │ │ └── tf_meshsampling_g.cu │ ├── nn_distance │ │ ├── README.md │ │ ├── __init__.py │ │ ├── tf_nndistance.cpp │ │ ├── tf_nndistance.py │ │ ├── tf_nndistance_compile.sh │ │ ├── tf_nndistance_cpu.py │ │ └── tf_nndistance_g.cu │ ├── sampling │ │ ├── tf_sampling.cpp │ │ ├── tf_sampling.py │ │ ├── tf_sampling_compile.sh │ │ └── tf_sampling_g.cu │ └── test.py └── tf_util.py ├── shapenet ├── 2D │ ├── demo_2D.py │ ├── model_vgg.py │ ├── test.py │ └── train_vgg.py ├── 3D │ ├── demo.py │ ├── model.py │ ├── test.py │ └── train.py └── data │ ├── data_h5.py │ ├── data_h5_mp.py │ ├── data_h5_template.py │ ├── data_img.py │ ├── data_obj.py │ ├── data_off.py │ ├── data_pc.py │ ├── data_rendered_img.py │ ├── data_rendered_img_template.py │ └── obj.py └── utils ├── __init__.py ├── output_utils.py ├── part_color_mapping.json ├── test_utils.py └── tf_util.py /README.md: -------------------------------------------------------------------------------- 1 | ### 3DN: 3D Deformation Network [Arxiv] 2 | 3 | ### Installation 4 | Install Tensorflow (1.10.0), PyMesh. 5 | 6 | The mesh sampling and mesh laplacian operations are under folder `models/tf_ops`. To build them, simply use `cd models/tf_ops` and `sh compile.sh` to compile. You may need to set CUDA path in each subfolder. 7 | 8 | ### Training 9 | 10 | ```bash 11 | cd shapenet/3D 12 | python train.py 13 | ``` 14 | ```bash 15 | cd shapenet/2D 16 | python train_vgg.py 17 | ``` 18 | Pretrained Model can be found here. 19 | ### Testing 20 | 21 | ```bash 22 | cd shapenet/3D 23 | python test.py 24 | ``` 25 | ```bash 26 | cd shapenet/2D 27 | python test.py 28 | ``` 29 | 30 | ### Citation 31 | If you find this work useful, please consider citing: 32 | 33 | @inproceedings{wang20193dn, 34 | title={3DN: 3D Deformation Network}, 35 | author={Wang, Weiyue and Ceylan, Duygu and Mech, Radomir and Neumann, Ulrich}, 36 | booktitle={CVPR}, 37 | year={2019} 38 | } 39 | 40 | 41 | ### Acknowledgemets 42 | - PointNet 43 | - PointNet AutoEncoder 44 | - Point Set Generation 45 | 46 | 47 | -------------------------------------------------------------------------------- /models/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laughtervv/3DN/81e3651d780478139c3b8dee5e737ce565813900/models/__init__.py -------------------------------------------------------------------------------- /models/deformnet.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import tf_util 3 | from pointnet_util import pointnet_sa_module, pointnet_fp_module 4 | 5 | def displacement_decoder(net, batch_size, is_training, bn=True, bn_decay=None, scope = '', outputdim=3): 6 | 7 | net2 = tf_util.conv2d(net, 512, [1,1], padding='VALID', stride=[1,1], bn_decay=bn_decay, bn=bn, is_training=is_training, scope=scope+'decoder/conv1') 8 | net2 = tf_util.conv2d(net2, 256, [1,1], padding='VALID', stride=[1,1], bn_decay=bn_decay, bn=bn, is_training=is_training, scope=scope+'decoder/conv2') 9 | net2 = tf_util.conv2d(net2, outputdim, [1,1], padding='VALID', stride=[1,1], activation_fn=None, bn=False, scope=scope+'decoder/conv5') 10 | 11 | net2 = tf.reshape(net2, [batch_size, -1, outputdim]) 12 | return net2 13 | 14 | def get_pred_foldenet_basic(src_pc, src_feats, ref_feats, is_training, batch_size, num_point, bn, bn_decay): 15 | ##TODO: Symmetry 16 | 17 | globalfeats = tf.concat([src_feats, ref_feats], axis=1) 18 | 19 | globalfeats = tf.reshape(globalfeats, [batch_size, 1, 1, -1]) 20 | globalfeats_expand = tf.tile(globalfeats, [1, src_pc.get_shape()[1], 1, 1]) 21 | 22 | concat = tf.concat(axis=3, values=[tf.expand_dims(src_pc,2), globalfeats_expand]) 23 | displacement = displacement_decoder(concat, batch_size, is_training, bn=bn, bn_decay=bn_decay) 24 | 25 | concat = tf.concat(axis=3, values=[tf.expand_dims(displacement,2), globalfeats_expand]) 26 | displacement = displacement_decoder(concat, batch_size, is_training, bn=bn, bn_decay=bn_decay, scope='fold2/') 27 | 28 | concat2 = tf.concat(axis=3, values=[tf.expand_dims(displacement,2), concat]) 29 | displacement = displacement_decoder(concat2, batch_size, is_training, bn=bn, bn_decay=bn_decay, scope='fold3/') 30 | 31 | pred = src_pc + displacement 32 | 33 | return pred, displacement 34 | 35 | -------------------------------------------------------------------------------- /models/meshnet.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import math 4 | import os 5 | import sys 6 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 7 | sys.path.append(os.path.join(BASE_DIR)) 8 | ROOT_DIR = os.path.dirname(BASE_DIR) 9 | sys.path.append(os.path.join(ROOT_DIR)) 10 | try: 11 | import models.tf_ops.mesh_sampling.tf_meshsampling as tf_meshsampling 12 | except: 13 | import models.tf_ops_server.mesh_sampling.tf_meshsampling as tf_meshsampling 14 | 15 | 16 | def mesh_sample(src_verts, src_nverts, src_tris, src_ntris, batch_size, num_point, feats=None, scope='', random=None): 17 | 18 | with tf.variable_scope(scope) as sc: 19 | if random is not None: 20 | r1, r2, r = random 21 | # r1 = r1.initialized_value() 22 | # r2 = r2.initialized_value() 23 | # r = r.initialized_value() 24 | else: 25 | r1 = tf.random_uniform([batch_size, num_point], dtype=tf.float32) 26 | r2 = tf.random_uniform([batch_size, num_point], dtype=tf.float32) 27 | r = tf.random_uniform([batch_size, num_point], dtype=tf.float32) 28 | # print (scope,'r', r.get_shape()) 29 | # print (scope,'feats', feats.get_shape()) 30 | 31 | if feats == None: 32 | src_pc, src_pc_feats_from_verts, correspondingface = tf_meshsampling.mesh_sampling(src_verts, src_nverts, src_tris, src_ntris, src_verts, r, r1, r2) 33 | else: 34 | src_pc, src_pc_feats_from_verts, correspondingface = tf_meshsampling.mesh_sampling(src_verts, src_nverts, src_tris, src_ntris, feats, r, r1, r2) 35 | 36 | src_pc_feats_from_verts = tf.expand_dims(src_pc_feats_from_verts, 2) 37 | correspondingface = tf.expand_dims(correspondingface, 2) 38 | # print (scope,'src_pc_feats_from_verts', src_pc_feats_from_verts.get_shape()) 39 | 40 | return src_pc, src_pc_feats_from_verts, correspondingface, r1, r2, r -------------------------------------------------------------------------------- /models/pointnet/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laughtervv/3DN/81e3651d780478139c3b8dee5e737ce565813900/models/pointnet/__init__.py -------------------------------------------------------------------------------- /models/pointnet/model.py: -------------------------------------------------------------------------------- 1 | """ TF model for point cloud autoencoder. PointNet encoder, FC decoder.import tensorflow as tf 2 | import numpy as np 3 | import math 4 | import os 5 | import sys 6 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 7 | ROOT_DIR = os.path.dirname(BASE_DIR) 8 | sys.path.append(os.path.join(ROOT_DIR)) 9 | import models.pointnet.model as pointnet 10 | from models.ffd import * 11 | try: 12 | import models.tf_ops.approxmatch.tf_approxmatch as tf_approxmatch 13 | import models.tf_ops.nn_distance.tf_nndistance as tf_nndistance 14 | except: 15 | import models.tf_ops_server.approxmatch.tf_approxmatch as tf_approxmatch 16 | import models.tf_ops_server.nn_distance.tf_nndistance as tf_nndistance 17 | Using GPU Chamfer's distance loss. 18 | 19 | Author: Charles R. Qi 20 | Date: May 2018 21 | """ 22 | import tensorflow as tf 23 | import numpy as np 24 | import math 25 | import sys 26 | import os 27 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 28 | ROOT_DIR = os.path.dirname(BASE_DIR) 29 | sys.path.append(os.path.join(ROOT_DIR)) 30 | import tf_util 31 | # sys.path.append(os.path.join(ROOT_DIR, 'tf_ops/nn_distance')) 32 | # import tf_nndistance 33 | 34 | def placeholder_inputs(batch_size, num_point): 35 | pointclouds_pl = tf.placeholder(tf.float32, shape=(batch_size, num_point, 3)) 36 | labels_pl = tf.placeholder(tf.float32, shape=(batch_size, num_point, 3)) 37 | return pointclouds_pl, labels_pl 38 | 39 | 40 | def get_model(point_cloud, is_training, scope='', num_point=None, bn_decay=None, ifglobal=False, bn=True): 41 | """ Autoencoder for point clouds. 42 | Input: 43 | point_cloud: TF tensor BxNx3 44 | is_training: boolean 45 | bn_decay: float between 0 and 1 46 | Output: 47 | net: TF tensor BxNx3, reconstructed point clouds 48 | end_points: dict 49 | """ 50 | batch_size = point_cloud.get_shape()[0].value 51 | if num_point is None: 52 | num_point = point_cloud.get_shape()[1].value 53 | point_dim = point_cloud.get_shape()[2].value 54 | end_points = {} 55 | 56 | with tf.variable_scope(scope) as sc: 57 | 58 | input_image = tf.expand_dims(point_cloud, -1) 59 | 60 | # Encoder 61 | net = tf_util.conv2d(input_image, 64, [1,point_dim], 62 | padding='VALID', stride=[1,1], 63 | bn=bn, is_training=is_training, 64 | scope='conv1', bn_decay=bn_decay) 65 | print('pointnet shape', net.get_shape()) 66 | net = tf_util.conv2d(net, 64, [1,1], 67 | padding='VALID', stride=[1,1], 68 | bn=bn, is_training=is_training, 69 | scope='conv2', bn_decay=bn_decay) 70 | point_feat = tf_util.conv2d(net, 64, [1,1], 71 | padding='VALID', stride=[1,1], 72 | bn=bn, is_training=is_training, 73 | scope='conv3', bn_decay=bn_decay) 74 | net = tf_util.conv2d(point_feat, 128, [1,1], 75 | padding='VALID', stride=[1,1], 76 | bn=bn, is_training=is_training, 77 | scope='conv4', bn_decay=bn_decay) 78 | pointwise = tf_util.conv2d(net, 1024, [1,1], 79 | padding='VALID', stride=[1,1], 80 | bn=bn, is_training=is_training, 81 | scope='conv5', bn_decay=bn_decay) 82 | # global_feat = tf_util.max_pool2d(pointwise, [num_point,1], 83 | # padding='VALID', scope='maxpool') 84 | 85 | global_feat = tf.reduce_max(pointwise, axis = 1, keep_dims=True) 86 | 87 | print('maxpoolglobal_feat', global_feat.get_shape()) 88 | 89 | feat0 = tf.reshape(global_feat, [batch_size, 1024]) 90 | 91 | # FC Decoder 92 | net = None 93 | # if ifglobal: 94 | feat = tf_util.fully_connected(feat0, 1024, bn=bn, is_training=is_training, scope='fc1', bn_decay=bn_decay) 95 | feat = tf_util.fully_connected(feat, 1024, bn=bn, is_training=is_training, scope='fc2', bn_decay=bn_decay) 96 | # if num_point is not None: 97 | # net = tf_util.fully_connected(feat, num_point * 3, activation_fn=None, scope='fc3') 98 | # net = tf.reshape(net, (batch_size, num_point, 3)) 99 | # end_points['pc'] = net 100 | end_points['embedding'] = feat 101 | end_points['pointwise'] = pointwise 102 | 103 | return net, end_points 104 | 105 | # def get_loss(pred, label, end_points): 106 | # """ pred: BxNx3, 107 | # label: BxNx3, """ 108 | # dists_forward,_,dists_backward,_ = tf_nndistance.nn_distance(pred, label) 109 | # loss = tf.reduce_mean(dists_forward+dists_backward) 110 | # end_points['pcloss'] = loss 111 | # return loss*100, end_points 112 | 113 | def get_decoder(embedding, is_training, scope='', bn_decay=None, bn=True): 114 | 115 | batch_size = embedding.get_shape()[0].value 116 | print(embedding.shape) 117 | net = tf_util.fully_connected(embedding, 512, bn=True, is_training=is_training, scope='fc1', bn_decay=bn_decay) 118 | net = tf_util.fully_connected(net, 512, bn=True, is_training=is_training, scope='fc2', bn_decay=bn_decay) 119 | net = tf_util.fully_connected(net, 1024*3, activation_fn=None, scope='fc3') 120 | pc_fc = tf.reshape(net, (batch_size, -1, 3)) 121 | 122 | # UPCONV Decoder 123 | net = tf.reshape(embedding, [batch_size, 1, 1, -1]) 124 | net = tf_util.conv2d_transpose(net, 512, kernel_size=[2,2], stride=[1,1], padding='VALID', scope='upconv1', bn=True, bn_decay=bn_decay, is_training=is_training) 125 | net = tf_util.conv2d_transpose(net, 256, kernel_size=[3,3], stride=[1,1], padding='VALID', scope='upconv2', bn=True, bn_decay=bn_decay, is_training=is_training) 126 | net = tf_util.conv2d_transpose(net, 256, kernel_size=[4,4], stride=[2,2], padding='VALID', scope='upconv3', bn=True, bn_decay=bn_decay, is_training=is_training) 127 | net = tf_util.conv2d_transpose(net, 128, kernel_size=[5,5], stride=[3,3], padding='VALID', scope='upconv4', bn=True, bn_decay=bn_decay, is_training=is_training) 128 | net = tf_util.conv2d_transpose(net, 3, kernel_size=[1,1], stride=[1,1], padding='VALID', scope='upconv5', activation_fn=None) 129 | 130 | pc_upconv = tf.reshape(net, [batch_size, -1, 3]) 131 | 132 | # Set union 133 | reconst_pc = tf.concat(values=[pc_fc,pc_upconv], axis=1) 134 | 135 | return reconst_pc 136 | 137 | if __name__=='__main__': 138 | with tf.Graph().as_default(): 139 | inputs = tf.zeros((32,1024,3)) 140 | outputs = get_model(inputs, tf.constant(True)) 141 | print(outputs) 142 | loss = get_loss(outputs[0], tf.zeros((32,1024,3)), outputs[1]) 143 | -------------------------------------------------------------------------------- /models/pointnet/model_cpu.py: -------------------------------------------------------------------------------- 1 | """ TF model for point cloud autoencoder. PointNet encoder, FC decoder. 2 | Using CPU Chamfer's distance loss. 3 | 4 | Author: Charles R. Qi 5 | Date: May 2018 6 | """ 7 | import tensorflow as tf 8 | import numpy as np 9 | import math 10 | import sys 11 | import os 12 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 13 | ROOT_DIR = os.path.dirname(BASE_DIR) 14 | sys.path.append(os.path.join(ROOT_DIR, 'utils')) 15 | import tf_util 16 | sys.path.append(os.path.join(ROOT_DIR, 'tf_ops/nn_distance')) 17 | import tf_nndistance_cpu 18 | 19 | def placeholder_inputs(batch_size, num_point): 20 | pointclouds_pl = tf.placeholder(tf.float32, shape=(batch_size, num_point, 3)) 21 | labels_pl = tf.placeholder(tf.float32, shape=(batch_size, num_point, 3)) 22 | return pointclouds_pl, labels_pl 23 | 24 | 25 | def get_model(point_cloud, is_training, bn_decay=None): 26 | """ Autoencoder for point clouds. 27 | Input: 28 | point_cloud: TF tensor BxNx3 29 | is_training: boolean 30 | bn_decay: float between 0 and 1 31 | Output: 32 | net: TF tensor BxNx3, reconstructed point clouds 33 | end_points: dict 34 | """ 35 | 36 | batch_size = point_cloud.get_shape()[0].value 37 | num_point = point_cloud.get_shape()[1].value 38 | point_dim = point_cloud.get_shape()[2].value 39 | end_points = {} 40 | 41 | input_image = tf.expand_dims(point_cloud, -1) 42 | 43 | # Encoder 44 | net = tf_util.conv2d(input_image, 64, [1,point_dim], 45 | padding='VALID', stride=[1,1], 46 | bn=True, is_training=is_training, 47 | scope='conv1', bn_decay=bn_decay) 48 | net = tf_util.conv2d(net, 64, [1,1], 49 | padding='VALID', stride=[1,1], 50 | bn=True, is_training=is_training, 51 | scope='conv2', bn_decay=bn_decay) 52 | point_feat = tf_util.conv2d(net, 64, [1,1], 53 | padding='VALID', stride=[1,1], 54 | bn=True, is_training=is_training, 55 | scope='conv3', bn_decay=bn_decay) 56 | net = tf_util.conv2d(point_feat, 128, [1,1], 57 | padding='VALID', stride=[1,1], 58 | bn=True, is_training=is_training, 59 | scope='conv4', bn_decay=bn_decay) 60 | net = tf_util.conv2d(net, 1024, [1,1], 61 | padding='VALID', stride=[1,1], 62 | bn=True, is_training=is_training, 63 | scope='conv5', bn_decay=bn_decay) 64 | global_feat = tf_util.max_pool2d(net, [num_point,1], 65 | padding='VALID', scope='maxpool') 66 | 67 | net = tf.reshape(global_feat, [batch_size, -1]) 68 | end_points['embedding'] = net 69 | 70 | # FC Decoder 71 | net = tf_util.fully_connected(net, 1024, bn=True, is_training=is_training, scope='fc1', bn_decay=bn_decay) 72 | net = tf_util.fully_connected(net, 1024, bn=True, is_training=is_training, scope='fc2', bn_decay=bn_decay) 73 | net = tf_util.fully_connected(net, num_point*3, activation_fn=None, scope='fc3') 74 | net = tf.reshape(net, (batch_size, num_point, 3)) 75 | 76 | return net, end_points 77 | 78 | def get_loss(pred, label, end_points): 79 | """ pred: BxNx3, 80 | label: BxNx3, """ 81 | dists_forward,_,dists_backward,_ = tf_nndistance_cpu.nn_distance_cpu(pred, label) 82 | loss = tf.reduce_mean(dists_forward+dists_backward) 83 | end_points['pcloss'] = loss 84 | return loss*100, end_points 85 | 86 | 87 | if __name__=='__main__': 88 | with tf.Graph().as_default(): 89 | inputs = tf.zeros((32,1024,3)) 90 | outputs = get_model(inputs, tf.constant(True)) 91 | print(outputs) 92 | loss = get_loss(outputs[0], tf.zeros((32,1024,3)), outputs[1]) 93 | -------------------------------------------------------------------------------- /models/pointnet/model_emd.py: -------------------------------------------------------------------------------- 1 | """ TF model for point cloud autoencoder. PointNet encoder, FC decoder. 2 | Using GPU Earth Mover's distance loss. 3 | 4 | Author: Charles R. Qi 5 | Date: May 2018 6 | """ 7 | import tensorflow as tf 8 | import numpy as np 9 | import math 10 | import sys 11 | import os 12 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 13 | ROOT_DIR = os.path.dirname(BASE_DIR) 14 | sys.path.append(os.path.join(ROOT_DIR, 'utils')) 15 | import tf_util 16 | sys.path.append(os.path.join(ROOT_DIR, 'tf_ops/nn_distance')) 17 | import tf_nndistance 18 | sys.path.append(os.path.join(ROOT_DIR, 'tf_ops/approxmatch')) 19 | import tf_approxmatch 20 | 21 | def placeholder_inputs(batch_size, num_point): 22 | pointclouds_pl = tf.placeholder(tf.float32, shape=(batch_size, num_point, 3)) 23 | labels_pl = tf.placeholder(tf.float32, shape=(batch_size, num_point, 3)) 24 | return pointclouds_pl, labels_pl 25 | 26 | 27 | def get_model(point_cloud, is_training, bn_decay=None): 28 | """ Autoencoder for point clouds. 29 | Input: 30 | point_cloud: TF tensor BxNxC 31 | is_training: boolean 32 | bn_decay: float between 0 and 1 33 | Output: 34 | net: TF tensor BxNxC, reconstructed point clouds 35 | end_points: dict 36 | """ 37 | batch_size = point_cloud.get_shape()[0].value 38 | num_point = point_cloud.get_shape()[1].value 39 | point_dim = point_cloud.get_shape()[2].value 40 | end_points = {} 41 | 42 | input_image = tf.expand_dims(point_cloud, -1) 43 | 44 | # Encoder 45 | net = tf_util.conv2d(input_image, 64, [1,point_dim], 46 | padding='VALID', stride=[1,1], 47 | bn=True, is_training=is_training, 48 | scope='conv1', bn_decay=bn_decay) 49 | net = tf_util.conv2d(net, 64, [1,1], 50 | padding='VALID', stride=[1,1], 51 | bn=True, is_training=is_training, 52 | scope='conv2', bn_decay=bn_decay) 53 | point_feat = tf_util.conv2d(net, 64, [1,1], 54 | padding='VALID', stride=[1,1], 55 | bn=True, is_training=is_training, 56 | scope='conv3', bn_decay=bn_decay) 57 | net = tf_util.conv2d(point_feat, 128, [1,1], 58 | padding='VALID', stride=[1,1], 59 | bn=True, is_training=is_training, 60 | scope='conv4', bn_decay=bn_decay) 61 | net = tf_util.conv2d(net, 1024, [1,1], 62 | padding='VALID', stride=[1,1], 63 | bn=True, is_training=is_training, 64 | scope='conv5', bn_decay=bn_decay) 65 | global_feat = tf_util.max_pool2d(net, [num_point,1], 66 | padding='VALID', scope='maxpool') 67 | 68 | net = tf.reshape(global_feat, [batch_size, -1]) 69 | end_points['embedding'] = net 70 | 71 | # FC Decoder 72 | net = tf_util.fully_connected(net, 1024, bn=True, is_training=is_training, scope='fc1', bn_decay=bn_decay) 73 | net = tf_util.fully_connected(net, 1024, bn=True, is_training=is_training, scope='fc2', bn_decay=bn_decay) 74 | net = tf_util.fully_connected(net, num_point*3, activation_fn=None, scope='fc3') 75 | net = tf.reshape(net, (batch_size, num_point, 3)) 76 | 77 | return net, end_points 78 | 79 | def get_loss(pred, label, end_points): 80 | """ pred: BxNx3, 81 | label: BxNx3, """ 82 | dists_forward,_,dists_backward,_ = tf_nndistance.nn_distance(pred, label) 83 | pc_loss = tf.reduce_mean(dists_forward+dists_backward) 84 | end_points['pcloss'] = pc_loss 85 | 86 | match = tf_approxmatch.approx_match(label, pred) 87 | loss = tf.reduce_mean(tf_approxmatch.match_cost(label, pred, match)) 88 | tf.summary.scalar('loss', loss) 89 | return loss, end_points 90 | 91 | 92 | if __name__=='__main__': 93 | with tf.Graph().as_default(): 94 | inputs = tf.zeros((32,1024,3)) 95 | outputs = get_model(inputs, tf.constant(True)) 96 | print outputs 97 | loss = get_loss(outputs[0], tf.zeros((32,1024,3)), outputs[1]) 98 | -------------------------------------------------------------------------------- /models/pointnet/model_fc_upconv.py: -------------------------------------------------------------------------------- 1 | """ TF model for point cloud autoencoder. PointNet encoder, FC and UPCONV decoder. 2 | Using GPU Chamfer's distance loss. Required to have 2048 points. 3 | 4 | Author: Charles R. Qi 5 | Date: May 2018 6 | """ 7 | import tensorflow as tf 8 | import numpy as np 9 | import math 10 | import sys 11 | import os 12 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 13 | ROOT_DIR = os.path.dirname(BASE_DIR) 14 | sys.path.append(os.path.join(ROOT_DIR)) 15 | import tf_util 16 | # sys.path.append(os.path.join(ROOT_DIR, 'tf_ops/nn_distance')) 17 | # import tf_nndistance 18 | 19 | def placeholder_inputs(batch_size, num_point): 20 | pointclouds_pl = tf.placeholder(tf.float32, shape=(batch_size, num_point, 3)) 21 | labels_pl = tf.placeholder(tf.float32, shape=(batch_size, num_point, 3)) 22 | return pointclouds_pl, labels_pl 23 | 24 | 25 | def get_model(point_cloud, is_training, bn_decay=None): 26 | """ Autoencoder for point clouds. 27 | Input: 28 | point_cloud: TF tensor BxNx3 29 | is_training: boolean 30 | bn_decay: float between 0 and 1 31 | Output: 32 | net: TF tensor BxNx3, reconstructed point clouds 33 | end_points: dict 34 | """ 35 | batch_size = point_cloud.get_shape()[0].value 36 | num_point = point_cloud.get_shape()[1].value 37 | # assert(num_point==2048) 38 | point_dim = point_cloud.get_shape()[2].value 39 | end_points = {} 40 | 41 | input_image = tf.expand_dims(point_cloud, -1) 42 | 43 | # Encoder 44 | net = tf_util.conv2d(input_image, 64, [1, point_dim], 45 | padding='VALID', stride=[1,1], 46 | bn=True, is_training=is_training, 47 | scope='conv1', bn_decay=bn_decay) 48 | net = tf_util.conv2d(net, 64, [1,1], 49 | padding='VALID', stride=[1,1], 50 | bn=True, is_training=is_training, 51 | scope='conv2', bn_decay=bn_decay) 52 | point_feat = tf_util.conv2d(net, 64, [1,1], 53 | padding='VALID', stride=[1,1], 54 | bn=True, is_training=is_training, 55 | scope='conv3', bn_decay=bn_decay) 56 | net = tf_util.conv2d(point_feat, 128, [1,1], 57 | padding='VALID', stride=[1,1], 58 | bn=True, is_training=is_training, 59 | scope='conv4', bn_decay=bn_decay) 60 | net = tf_util.conv2d(net, 1024, [1,1], 61 | padding='VALID', stride=[1,1], 62 | bn=True, is_training=is_training, 63 | scope='conv5', bn_decay=bn_decay) 64 | end_points['pointwise'] = net 65 | # global_feat = tf_util.max_pool2d(net, [num_point,1], 66 | # padding='VALID', scope='maxpool') 67 | global_feat = tf.reduce_max(net, axis = 1, keep_dims=True) 68 | 69 | net = tf.reshape(global_feat, [batch_size, -1]) 70 | net = tf_util.fully_connected(net, 512, bn=True, is_training=is_training, scope='fc00', bn_decay=bn_decay) 71 | embedding = tf.reshape(net, [batch_size, -1]) 72 | end_points['embedding'] = embedding 73 | 74 | # FC Decoder 75 | net = tf_util.fully_connected(embedding, 512, bn=True, is_training=is_training, scope='fc1', bn_decay=bn_decay) 76 | net = tf_util.fully_connected(net, 512, bn=True, is_training=is_training, scope='fc2', bn_decay=bn_decay) 77 | net = tf_util.fully_connected(net, 1024*3, activation_fn=None, scope='fc3') 78 | pc_fc = tf.reshape(net, (batch_size, -1, 3)) 79 | 80 | # UPCONV Decoder 81 | net = tf.reshape(embedding, [batch_size, 1, 1, -1]) 82 | print net.shape 83 | net = tf_util.conv2d_transpose(net, 512, kernel_size=[2,2], stride=[1,1], padding='VALID', scope='upconv1', bn=True, bn_decay=bn_decay, is_training=is_training) 84 | print net.shape 85 | net = tf_util.conv2d_transpose(net, 256, kernel_size=[3,3], stride=[1,1], padding='VALID', scope='upconv2', bn=True, bn_decay=bn_decay, is_training=is_training) 86 | print net.shape 87 | net = tf_util.conv2d_transpose(net, 256, kernel_size=[4,4], stride=[2,2], padding='VALID', scope='upconv3', bn=True, bn_decay=bn_decay, is_training=is_training) 88 | print net.shape 89 | net = tf_util.conv2d_transpose(net, 128, kernel_size=[5,5], stride=[3,3], padding='VALID', scope='upconv4', bn=True, bn_decay=bn_decay, is_training=is_training) 90 | print net.shape 91 | net = tf_util.conv2d_transpose(net, 3, kernel_size=[1,1], stride=[1,1], padding='VALID', scope='upconv5', activation_fn=None) 92 | end_points['xyzmap'] = net 93 | pc_upconv = tf.reshape(net, [batch_size, -1, 3]) 94 | 95 | 96 | # Set union 97 | net = tf.concat(values=[pc_fc,pc_upconv], axis=1) 98 | 99 | return net, end_points 100 | 101 | # def get_loss(pred, label, end_points): 102 | # """ pred: BxNx3, 103 | # label: BxNx3, """ 104 | # dists_forward,_,dists_backward,_ = tf_nndistance.nn_distance(pred, label) 105 | # loss = tf.reduce_mean(dists_forward+dists_backward) 106 | # end_points['pcloss'] = loss 107 | # return loss*100, end_points 108 | 109 | 110 | if __name__=='__main__': 111 | with tf.Graph().as_default(): 112 | inputs = tf.zeros((32,2048,3)) 113 | outputs = get_model(inputs, tf.constant(True)) 114 | print(outputs) 115 | # loss = get_loss(outputs[0], tf.zeros((32,2048,3)), outputs[1]) 116 | -------------------------------------------------------------------------------- /models/pointnet/model_hierachy.py: -------------------------------------------------------------------------------- 1 | """ TF model for point cloud autoencoder. PointNet encoder, *hierachical* FC decoder. 2 | Using GPU Chamfer's distance loss. 3 | 4 | Author: Charles R. Qi 5 | Date: May 2018 6 | """ 7 | import tensorflow as tf 8 | import numpy as np 9 | import math 10 | import sys 11 | import os 12 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 13 | ROOT_DIR = os.path.dirname(BASE_DIR) 14 | sys.path.append(os.path.join(ROOT_DIR, 'utils')) 15 | import tf_util 16 | sys.path.append(os.path.join(ROOT_DIR, 'tf_ops/nn_distance')) 17 | import tf_nndistance 18 | 19 | def placeholder_inputs(batch_size, num_point): 20 | pointclouds_pl = tf.placeholder(tf.float32, shape=(batch_size, num_point, 3)) 21 | labels_pl = tf.placeholder(tf.float32, shape=(batch_size, num_point, 3)) 22 | return pointclouds_pl, labels_pl 23 | 24 | 25 | def get_model(point_cloud, is_training, bn_decay=None): 26 | """ Autoencoder for point clouds. 27 | Input: 28 | point_cloud: TF tensor BxNxC 29 | is_training: boolean 30 | bn_decay: float between 0 and 1 31 | Output: 32 | pc_xyz: TF tensor BxNxC, reconstructed point clouds 33 | end_points: dict 34 | """ 35 | batch_size = point_cloud.get_shape()[0].value 36 | num_point = point_cloud.get_shape()[1].value 37 | point_dim = point_cloud.get_shape()[2].value 38 | end_points = {} 39 | 40 | input_image = tf.expand_dims(point_cloud, -1) 41 | 42 | # Encoder 43 | net = tf_util.conv2d(input_image, 64, [1,point_dim], 44 | padding='VALID', stride=[1,1], 45 | bn=True, is_training=is_training, 46 | scope='conv1', bn_decay=bn_decay) 47 | net = tf_util.conv2d(net, 64, [1,1], 48 | padding='VALID', stride=[1,1], 49 | bn=True, is_training=is_training, 50 | scope='conv2', bn_decay=bn_decay) 51 | point_feat = tf_util.conv2d(net, 64, [1,1], 52 | padding='VALID', stride=[1,1], 53 | bn=True, is_training=is_training, 54 | scope='conv3', bn_decay=bn_decay) 55 | net = tf_util.conv2d(point_feat, 128, [1,1], 56 | padding='VALID', stride=[1,1], 57 | bn=True, is_training=is_training, 58 | scope='conv4', bn_decay=bn_decay) 59 | net = tf_util.conv2d(net, 1024, [1,1], 60 | padding='VALID', stride=[1,1], 61 | bn=True, is_training=is_training, 62 | scope='conv5', bn_decay=bn_decay) 63 | global_feat = tf_util.max_pool2d(net, [num_point,1], 64 | padding='VALID', scope='maxpool') 65 | 66 | net = tf.reshape(global_feat, [batch_size, -1]) 67 | net = tf_util.fully_connected(net, 512, bn=True, is_training=is_training, scope='fc00', bn_decay=bn_decay) 68 | net = tf_util.fully_connected(net, 512, bn=True, is_training=is_training, scope='fc01', bn_decay=bn_decay) 69 | end_points['embedding'] = net 70 | 71 | # Hierarchical FC decoder 72 | # Firstly predict 64 points with their XYZs and features 73 | # Then from feature of each of the 64 points, predict XYZs for NUM_POINT/64 subpoints with their *local* XYZs 74 | # At last, local XYZs are translated to their global XYZs 75 | pc1_feat = tf_util.fully_connected(net, 64*256, bn=True, is_training=is_training, scope='fc1', bn_decay=bn_decay) 76 | pc1_xyz = tf_util.fully_connected(net, 64*3, activation_fn=None, scope='fc1_xyz') 77 | pc1_feat = tf.reshape(pc1_feat, [batch_size, 64, 256]) 78 | pc1_xyz = tf.reshape(pc1_xyz, [batch_size, 64, 3]) 79 | end_points['pc1_xyz'] = pc1_xyz 80 | 81 | pc2 = tf_util.conv1d(pc1_feat, 256, 1, padding='VALID', stride=1, bn=True, is_training=is_training, scope='fc_conv1', bn_decay=bn_decay) 82 | pc2_xyz = tf_util.conv1d(pc2, (num_point/64)*3, 1, padding='VALID', stride=1, activation_fn=None, scope='fc_conv3') # B,64,32*3 83 | pc2_xyz = tf.reshape(pc2_xyz, [batch_size, 64, num_point/64, 3]) 84 | pc1_xyz_expand = tf.expand_dims(pc1_xyz, 2) # B,64,1,3 85 | # Translate local XYZs to global XYZs 86 | pc2_xyz = pc2_xyz + pc1_xyz_expand 87 | pc_xyz = tf.reshape(pc2_xyz, [batch_size, num_point, 3]) 88 | 89 | return pc_xyz, end_points 90 | 91 | def get_loss(pred, label, end_points): 92 | """ pred: BxNx3, 93 | label: BxNx3, """ 94 | dists_forward,_,dists_backward,_ = tf_nndistance.nn_distance(pred, label) 95 | pc_loss = tf.reduce_mean(dists_forward+dists_backward) 96 | end_points['pcloss'] = pc_loss 97 | tf.summary.scalar('pcloss', pc_loss) 98 | 99 | d1,_,d2,_ = tf_nndistance.nn_distance(end_points['pc1_xyz'], label) 100 | pc1_loss = tf.reduce_mean(d1) + tf.reduce_mean(d2) 101 | tf.summary.scalar('pc1loss', pc1_loss) 102 | loss = pc_loss + 0.1*pc1_loss 103 | 104 | return loss*100, end_points 105 | 106 | 107 | if __name__=='__main__': 108 | with tf.Graph().as_default(): 109 | inputs = tf.zeros((32,1024,3)) 110 | outputs = get_model(inputs, tf.constant(True)) 111 | print(outputs) 112 | loss = get_loss(outputs[0], tf.zeros((32,1024,3)), outputs[1]) 113 | -------------------------------------------------------------------------------- /models/pointnet/model_pointnet2.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | BASE_DIR = os.path.dirname(__file__) 4 | sys.path.append(BASE_DIR) 5 | sys.path.append(os.path.join(BASE_DIR, '..')) 6 | import tensorflow as tf 7 | import numpy as np 8 | import tf_util 9 | from pointnet_util import pointnet_sa_module, pointnet_fp_module 10 | 11 | def placeholder_inputs(batch_size, num_point): 12 | pointclouds_pl = tf.placeholder(tf.float32, shape=(batch_size, num_point, 3)) 13 | labels_pl = tf.placeholder(tf.int32, shape=(batch_size, num_point)) 14 | smpws_pl = tf.placeholder(tf.float32, shape=(batch_size, num_point)) 15 | return pointclouds_pl, labels_pl, smpws_pl 16 | 17 | 18 | def get_model(point_cloud, is_training, scope='', num_point=None, bn_decay=None, ifglobal=False, bn=True, end_points={}): 19 | """ Semantic segmentation PointNet, input is BxNx3, output Bxnum_class """ 20 | batch_size = point_cloud.get_shape()[0].value 21 | num_point = point_cloud.get_shape()[1].value 22 | end_points = {} 23 | l0_xyz = point_cloud 24 | l0_points = None 25 | end_points['l0_xyz'] = l0_xyz 26 | 27 | # Layer 1 28 | l1_xyz, l1_points, l1_indices = pointnet_sa_module(l0_xyz, l0_points, npoint=1024, radius=0.1, nsample=32, mlp=[32,32,64], mlp2=None, group_all=False, is_training=is_training, bn_decay=bn_decay, scope='layer1') 29 | l2_xyz, l2_points, l2_indices = pointnet_sa_module(l1_xyz, l1_points, npoint=256, radius=0.2, nsample=32, mlp=[64,64,128], mlp2=None, group_all=False, is_training=is_training, bn_decay=bn_decay, scope='layer2') 30 | l3_xyz, l3_points, l3_indices = pointnet_sa_module(l2_xyz, l2_points, npoint=64, radius=0.4, nsample=32, mlp=[128,128,256], mlp2=None, group_all=False, is_training=is_training, bn_decay=bn_decay, scope='layer3') 31 | l4_xyz, l4_points, l4_indices = pointnet_sa_module(l3_xyz, l3_points, npoint=16, radius=0.8, nsample=32, mlp=[256,256,512], mlp2=None, group_all=False, is_training=is_training, bn_decay=bn_decay, scope='layer4') 32 | 33 | # Feature Propagation layers 34 | l3_points = pointnet_fp_module(l3_xyz, l4_xyz, l3_points, l4_points, [256,256], is_training, bn_decay, scope='fa_layer1') 35 | l2_points = pointnet_fp_module(l2_xyz, l3_xyz, l2_points, l3_points, [256,256], is_training, bn_decay, scope='fa_layer2') 36 | l1_points = pointnet_fp_module(l1_xyz, l2_xyz, l1_points, l2_points, [256,128], is_training, bn_decay, scope='fa_layer3') 37 | l0_points = pointnet_fp_module(l0_xyz, l1_xyz, l0_points, l1_points, [128,128,128], is_training, bn_decay, scope='fa_layer4') 38 | 39 | # FC layers 40 | net = tf_util.conv1d(l0_points, 256, 1, padding='VALID', bn=True, is_training=is_training, scope='fc1', bn_decay=bn_decay) 41 | end_points['embedding'] = net 42 | # net = tf_util.dropout(net, keep_prob=0.5, is_training=is_training, scope='dp1') 43 | # net = tf_util.conv1d(net, num_class, 1, padding='VALID', activation_fn=None, scope='fc2') 44 | 45 | return net, end_points 46 | 47 | 48 | def get_loss(pred, label, smpw): 49 | """ pred: BxNxC, 50 | label: BxN, 51 | smpw: BxN """ 52 | classify_loss = tf.losses.sparse_softmax_cross_entropy(labels=label, logits=pred, weights=smpw) 53 | tf.summary.scalar('classify loss', classify_loss) 54 | tf.add_to_collection('losses', classify_loss) 55 | return classify_loss 56 | 57 | if __name__=='__main__': 58 | with tf.Graph().as_default(): 59 | inputs = tf.zeros((32,2048,3)) 60 | net, _ = get_model(inputs, tf.constant(True), 10) 61 | print(net) 62 | -------------------------------------------------------------------------------- /models/pointnet/model_seg.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import math 4 | import sys 5 | import os 6 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 7 | sys.path.append(BASE_DIR) 8 | sys.path.append(os.path.join(BASE_DIR, '../utils')) 9 | import tf_util 10 | from transform_nets import input_transform_net, feature_transform_net 11 | 12 | def placeholder_inputs(batch_size, num_point): 13 | pointclouds_pl = tf.placeholder(tf.float32, 14 | shape=(batch_size, num_point, 3)) 15 | labels_pl = tf.placeholder(tf.int32, 16 | shape=(batch_size, num_point)) 17 | return pointclouds_pl, labels_pl 18 | 19 | 20 | def get_model(point_cloud, is_training, bn_decay=None): 21 | """ Classification PointNet, input is BxNx3, output BxNx50 """ 22 | batch_size = point_cloud.get_shape()[0].value 23 | num_point = point_cloud.get_shape()[1].value 24 | end_points = {} 25 | 26 | with tf.variable_scope('transform_net1') as sc: 27 | transform = input_transform_net(point_cloud, is_training, bn_decay, K=3) 28 | point_cloud_transformed = tf.matmul(point_cloud, transform) 29 | input_image = tf.expand_dims(point_cloud_transformed, -1) 30 | 31 | net = tf_util.conv2d(input_image, 64, [1,3], 32 | padding='VALID', stride=[1,1], 33 | bn=True, is_training=is_training, 34 | scope='conv1', bn_decay=bn_decay) 35 | net = tf_util.conv2d(net, 64, [1,1], 36 | padding='VALID', stride=[1,1], 37 | bn=True, is_training=is_training, 38 | scope='conv2', bn_decay=bn_decay) 39 | 40 | with tf.variable_scope('transform_net2') as sc: 41 | transform = feature_transform_net(net, is_training, bn_decay, K=64) 42 | end_points['transform'] = transform 43 | net_transformed = tf.matmul(tf.squeeze(net, axis=[2]), transform) 44 | point_feat = tf.expand_dims(net_transformed, [2]) 45 | print(point_feat) 46 | 47 | net = tf_util.conv2d(point_feat, 64, [1,1], 48 | padding='VALID', stride=[1,1], 49 | bn=True, is_training=is_training, 50 | scope='conv3', bn_decay=bn_decay) 51 | net = tf_util.conv2d(net, 128, [1,1], 52 | padding='VALID', stride=[1,1], 53 | bn=True, is_training=is_training, 54 | scope='conv4', bn_decay=bn_decay) 55 | net = tf_util.conv2d(net, 1024, [1,1], 56 | padding='VALID', stride=[1,1], 57 | bn=True, is_training=is_training, 58 | scope='conv5', bn_decay=bn_decay) 59 | global_feat = tf_util.max_pool2d(net, [num_point,1], 60 | padding='VALID', scope='maxpool') 61 | end_points['embedding'] = global_feat 62 | print(global_feat) 63 | 64 | global_feat_expand = tf.tile(global_feat, [1, num_point, 1, 1]) 65 | print('global_feat_expand', global_feat_expand) 66 | print('point_feat', point_feat) 67 | concat_feat = tf.concat([point_feat, global_feat_expand], axis=3) 68 | print(concat_feat) 69 | 70 | net = tf_util.conv2d(concat_feat, 512, [1,1], 71 | padding='VALID', stride=[1,1], 72 | bn=True, is_training=is_training, 73 | scope='conv6', bn_decay=bn_decay) 74 | net = tf_util.conv2d(net, 256, [1,1], 75 | padding='VALID', stride=[1,1], 76 | bn=True, is_training=is_training, 77 | scope='conv7', bn_decay=bn_decay) 78 | net = tf_util.conv2d(net, 128, [1,1], 79 | padding='VALID', stride=[1,1], 80 | bn=True, is_training=is_training, 81 | scope='conv8', bn_decay=bn_decay) 82 | net = tf_util.conv2d(net, 128, [1,1], 83 | padding='VALID', stride=[1,1], 84 | bn=True, is_training=is_training, 85 | scope='conv9', bn_decay=bn_decay) 86 | 87 | net = tf_util.conv2d(net, 50, [1,1], 88 | padding='VALID', stride=[1,1], activation_fn=None, 89 | scope='conv10') 90 | net = tf.squeeze(net, [2]) # BxNxC 91 | 92 | return net, end_points 93 | 94 | 95 | def get_loss(pred, label, end_points, reg_weight=0.001): 96 | """ pred: BxNxC, 97 | label: BxN, """ 98 | loss = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=pred, labels=label) 99 | classify_loss = tf.reduce_mean(loss) 100 | tf.summary.scalar('classify loss', classify_loss) 101 | 102 | # Enforce the transformation as orthogonal matrix 103 | transform = end_points['transform'] # BxKxK 104 | K = transform.get_shape()[1].value 105 | mat_diff = tf.matmul(transform, tf.transpose(transform, perm=[0,2,1])) 106 | mat_diff -= tf.constant(np.eye(K), dtype=tf.float32) 107 | mat_diff_loss = tf.nn.l2_loss(mat_diff) 108 | tf.summary.scalar('mat_loss', mat_diff_loss) 109 | 110 | return classify_loss + mat_diff_loss * reg_weight 111 | 112 | 113 | if __name__=='__main__': 114 | with tf.Graph().as_default(): 115 | inputs = tf.zeros((32,1024,3)) 116 | outputs = get_model(inputs, tf.constant(True)) 117 | print(outputs) 118 | -------------------------------------------------------------------------------- /models/pointnet/model_upconv.py: -------------------------------------------------------------------------------- 1 | """ TF model for point cloud autoencoder. PointNet encoder, UPCONV decoder. 2 | Using GPU Chamfer's distance loss. Required to have 2048 points. 3 | 4 | Author: Charles R. Qi 5 | Date: May 2018 6 | """ 7 | import tensorflow as tf 8 | import numpy as np 9 | import math 10 | import sys 11 | import os 12 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 13 | ROOT_DIR = os.path.dirname(BASE_DIR) 14 | sys.path.append(ROOT_DIR) 15 | sys.path.append(os.path.join(ROOT_DIR, 'utils')) 16 | import tf_util 17 | # sys.path.append(os.path.join(ROOT_DIR, 'tf_ops/nn_distance')) 18 | # import tf_nndistance 19 | 20 | def placeholder_inputs(batch_size, num_point): 21 | pointclouds_pl = tf.placeholder(tf.float32, shape=(batch_size, num_point, 3)) 22 | labels_pl = tf.placeholder(tf.float32, shape=(batch_size, num_point, 3)) 23 | return pointclouds_pl, labels_pl 24 | 25 | 26 | def get_model(point_cloud, is_training, bn_decay=None): 27 | """ Autoencoder for point clouds. 28 | Input: 29 | point_cloud: TF tensor BxNx3 30 | is_training: boolean 31 | bn_decay: float between 0 and 1 32 | Output: 33 | net: TF tensor BxNx3, reconstructed point clouds 34 | end_points: dict 35 | """ 36 | batch_size = point_cloud.get_shape()[0].value 37 | num_point = point_cloud.get_shape()[1].value 38 | assert(num_point==2048) 39 | point_dim = point_cloud.get_shape()[2].value 40 | end_points = {} 41 | 42 | input_image = tf.expand_dims(point_cloud, -1) 43 | 44 | # Encoder 45 | net = tf_util.conv2d(input_image, 64, [1,point_dim], 46 | padding='VALID', stride=[1,1], 47 | bn=True, is_training=is_training, 48 | scope='conv1', bn_decay=bn_decay) 49 | net = tf_util.conv2d(net, 64, [1,1], 50 | padding='VALID', stride=[1,1], 51 | bn=True, is_training=is_training, 52 | scope='conv2', bn_decay=bn_decay) 53 | point_feat = tf_util.conv2d(net, 64, [1,1], 54 | padding='VALID', stride=[1,1], 55 | bn=True, is_training=is_training, 56 | scope='conv3', bn_decay=bn_decay) 57 | net = tf_util.conv2d(point_feat, 128, [1,1], 58 | padding='VALID', stride=[1,1], 59 | bn=True, is_training=is_training, 60 | scope='conv4', bn_decay=bn_decay) 61 | net = tf_util.conv2d(net, 1024, [1,1], 62 | padding='VALID', stride=[1,1], 63 | bn=True, is_training=is_training, 64 | scope='conv5', bn_decay=bn_decay) 65 | global_feat = tf_util.max_pool2d(net, [num_point,1], 66 | padding='VALID', scope='maxpool') 67 | 68 | net = tf.reshape(global_feat, [batch_size, -1]) 69 | # net = tf_util.fully_connected(net, 1024, bn=True, is_training=is_training, scope='fc00', bn_decay=bn_decay) 70 | # 71 | net = tf.reshape(net, [batch_size, -1]) 72 | end_points['embedding'] = net 73 | # z_log_sigma_sq = tf_util.fully_connected(z_mu, 1024, scope='enc_fc4_sigma', activation_fn=None) 74 | # eps = tf.random_normal(shape=tf.shape(z_log_sigma_sq), 75 | # mean=0, stddev=1, dtype=tf.float32) 76 | # net = net + tf.sqrt(tf.exp(z_log_sigma_sq)) * eps 77 | 78 | 79 | # latent_loss = -0.5 * tf.reduce_sum(1 + z_log_sigma_sq - tf.square(z_mu) - tf.exp(z_log_sigma_sq), axis=1) 80 | # end_points['latent_loss'] = tf.reduce_mean(latent_loss) 81 | 82 | # UPCONV Decoder 83 | net = tf.reshape(net, [batch_size, 1, 2, -1]) 84 | net = tf_util.conv2d_transpose(net, 512, kernel_size=[2,2], stride=[2,2], padding='VALID', scope='upconv1', bn=True, bn_decay=bn_decay, is_training=is_training) 85 | net = tf_util.conv2d_transpose(net, 256, kernel_size=[3,3], stride=[1,1], padding='VALID', scope='upconv2', bn=True, bn_decay=bn_decay, is_training=is_training) 86 | net = tf_util.conv2d_transpose(net, 256, kernel_size=[4,5], stride=[2,3], padding='VALID', scope='upconv3', bn=True, bn_decay=bn_decay, is_training=is_training) 87 | net = tf_util.conv2d_transpose(net, 128, kernel_size=[5,7], stride=[3,3], padding='VALID', scope='upconv4', bn=True, bn_decay=bn_decay, is_training=is_training) 88 | net = tf_util.conv2d_transpose(net, 3, kernel_size=[1,1], stride=[1,1], padding='VALID', scope='upconv5', activation_fn=None) 89 | end_points['xyzmap'] = net 90 | net = tf.reshape(net, [batch_size, -1, 3]) 91 | 92 | return net, end_points 93 | 94 | def get_loss(pred, label, end_points): 95 | """ pred: BxNx3, 96 | label: BxNx3, """ 97 | dists_forward,_,dists_backward,_ = tf_nndistance.nn_distance(pred, label) 98 | loss = tf.reduce_mean(dists_forward+dists_backward) 99 | end_points['pcloss'] = loss 100 | return loss*100, end_points 101 | 102 | 103 | if __name__=='__main__': 104 | with tf.Graph().as_default(): 105 | inputs = tf.zeros((32,2048,3)) 106 | outputs = get_model(inputs, tf.constant(True)) 107 | print(outputs) 108 | loss = get_loss(outputs[0], tf.zeros((32,2048,3)), outputs[1]) 109 | -------------------------------------------------------------------------------- /models/pointnet/model_vae.py: -------------------------------------------------------------------------------- 1 | """ TF model for point cloud autoencoder. PointNet encoder, UPCONV decoder. 2 | Using GPU Chamfer's distance loss. Required to have 2048 points. 3 | 4 | Author: Charles R. Qi 5 | Date: May 2018 6 | """ 7 | import tensorflow as tf 8 | import numpy as np 9 | import math 10 | import sys 11 | import os 12 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 13 | ROOT_DIR = os.path.dirname(BASE_DIR) 14 | sys.path.append(ROOT_DIR) 15 | sys.path.append(os.path.join(ROOT_DIR, 'utils')) 16 | import tf_util 17 | # sys.path.append(os.path.join(ROOT_DIR, 'tf_ops/nn_distance')) 18 | # import tf_nndistance 19 | 20 | def placeholder_inputs(batch_size, num_point): 21 | pointclouds_pl = tf.placeholder(tf.float32, shape=(batch_size, num_point, 3)) 22 | labels_pl = tf.placeholder(tf.float32, shape=(batch_size, num_point, 3)) 23 | return pointclouds_pl, labels_pl 24 | 25 | 26 | def get_model(point_cloud, is_training, bn_decay=None): 27 | """ Autoencoder for point clouds. 28 | Input: 29 | point_cloud: TF tensor BxNx3 30 | is_training: boolean 31 | bn_decay: float between 0 and 1 32 | Output: 33 | net: TF tensor BxNx3, reconstructed point clouds 34 | end_points: dict 35 | """ 36 | batch_size = point_cloud.get_shape()[0].value 37 | num_point = point_cloud.get_shape()[1].value 38 | assert(num_point==2048) 39 | point_dim = point_cloud.get_shape()[2].value 40 | end_points = {} 41 | 42 | input_image = tf.expand_dims(point_cloud, -1) 43 | 44 | # Encoder 45 | net = tf_util.conv2d(input_image, 64, [1,point_dim], 46 | padding='VALID', stride=[1,1], 47 | bn=True, is_training=is_training, 48 | scope='conv1', bn_decay=bn_decay) 49 | net = tf_util.conv2d(net, 64, [1,1], 50 | padding='VALID', stride=[1,1], 51 | bn=True, is_training=is_training, 52 | scope='conv2', bn_decay=bn_decay) 53 | point_feat = tf_util.conv2d(net, 64, [1,1], 54 | padding='VALID', stride=[1,1], 55 | bn=True, is_training=is_training, 56 | scope='conv3', bn_decay=bn_decay) 57 | net = tf_util.conv2d(point_feat, 128, [1,1], 58 | padding='VALID', stride=[1,1], 59 | bn=True, is_training=is_training, 60 | scope='conv4', bn_decay=bn_decay) 61 | net = tf_util.conv2d(net, 1024, [1,1], 62 | padding='VALID', stride=[1,1], 63 | bn=True, is_training=is_training, 64 | scope='conv5', bn_decay=bn_decay) 65 | global_feat = tf_util.max_pool2d(net, [num_point,1], 66 | padding='VALID', scope='maxpool') 67 | 68 | net = tf.reshape(global_feat, [batch_size, -1]) 69 | net = tf_util.fully_connected(net, 1024, bn=True, is_training=is_training, scope='fc00', bn_decay=bn_decay) 70 | # 71 | z_mu = tf.reshape(net, [batch_size, -1]) 72 | end_points['embedding'] = z_mu 73 | z_log_sigma_sq = tf_util.fully_connected(z_mu, 1024, scope='enc_fc4_sigma', activation_fn=None) 74 | eps = tf.random_normal(shape=tf.shape(z_log_sigma_sq), 75 | mean=0, stddev=1, dtype=tf.float32) 76 | net = net + tf.sqrt(tf.exp(z_log_sigma_sq)) * eps 77 | 78 | 79 | # latent_loss = -0.5 * tf.reduce_sum(1 + z_log_sigma_sq - tf.square(z_mu) - tf.exp(z_log_sigma_sq), axis=1) 80 | # end_points['latent_loss'] = tf.reduce_mean(latent_loss) 81 | 82 | # UPCONV Decoder 83 | net = tf.reshape(net, [batch_size, 1, 2, -1]) 84 | net = tf_util.conv2d_transpose(net, 512, kernel_size=[2,2], stride=[2,2], padding='VALID', scope='upconv1', bn=True, bn_decay=bn_decay, is_training=is_training) 85 | net = tf_util.conv2d_transpose(net, 256, kernel_size=[3,3], stride=[1,1], padding='VALID', scope='upconv2', bn=True, bn_decay=bn_decay, is_training=is_training) 86 | net = tf_util.conv2d_transpose(net, 256, kernel_size=[4,5], stride=[2,3], padding='VALID', scope='upconv3', bn=True, bn_decay=bn_decay, is_training=is_training) 87 | net = tf_util.conv2d_transpose(net, 128, kernel_size=[5,7], stride=[3,3], padding='VALID', scope='upconv4', bn=True, bn_decay=bn_decay, is_training=is_training) 88 | net = tf_util.conv2d_transpose(net, 3, kernel_size=[1,1], stride=[1,1], padding='VALID', scope='upconv5', activation_fn=None) 89 | end_points['xyzmap'] = net 90 | net = tf.reshape(net, [batch_size, -1, 3]) 91 | 92 | return net, end_points 93 | 94 | def get_loss(pred, label, end_points): 95 | """ pred: BxNx3, 96 | label: BxNx3, """ 97 | dists_forward,_,dists_backward,_ = tf_nndistance.nn_distance(pred, label) 98 | loss = tf.reduce_mean(dists_forward+dists_backward) 99 | end_points['pcloss'] = loss 100 | return loss*100, end_points 101 | 102 | 103 | if __name__=='__main__': 104 | with tf.Graph().as_default(): 105 | inputs = tf.zeros((32,2048,3)) 106 | outputs = get_model(inputs, tf.constant(True)) 107 | print(outputs) 108 | loss = get_loss(outputs[0], tf.zeros((32,2048,3)), outputs[1]) 109 | -------------------------------------------------------------------------------- /models/pointnet/model_withtransform.py: -------------------------------------------------------------------------------- 1 | """ TF model for point cloud autoencoder. PointNet encoder, FC decoder.import tensorflow as tf 2 | import numpy as np 3 | import math 4 | import os 5 | import sys 6 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 7 | ROOT_DIR = os.path.dirname(BASE_DIR) 8 | sys.path.append(os.path.join(ROOT_DIR)) 9 | import models.pointnet.model as pointnet 10 | from models.ffd import * 11 | try: 12 | import models.tf_ops.approxmatch.tf_approxmatch as tf_approxmatch 13 | import models.tf_ops.nn_distance.tf_nndistance as tf_nndistance 14 | except: 15 | import models.tf_ops_server.approxmatch.tf_approxmatch as tf_approxmatch 16 | import models.tf_ops_server.nn_distance.tf_nndistance as tf_nndistance 17 | Using GPU Chamfer's distance loss. 18 | 19 | Author: Charles R. Qi 20 | Date: May 2018 21 | """ 22 | import tensorflow as tf 23 | import numpy as np 24 | import math 25 | import sys 26 | import os 27 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 28 | ROOT_DIR = os.path.dirname(BASE_DIR) 29 | sys.path.append(os.path.join(ROOT_DIR)) 30 | import tf_util 31 | from transform_nets import input_transform_net, feature_transform_net 32 | # sys.path.append(os.path.join(ROOT_DIR, 'tf_ops/nn_distance')) 33 | # import tf_nndistance 34 | 35 | def placeholder_inputs(batch_size, num_point): 36 | pointclouds_pl = tf.placeholder(tf.float32, shape=(batch_size, num_point, 3)) 37 | labels_pl = tf.placeholder(tf.float32, shape=(batch_size, num_point, 3)) 38 | return pointclouds_pl, labels_pl 39 | 40 | 41 | def get_model(point_cloud, is_training, scope='', num_point=None, bn_decay=None, ifglobal=False, bn=True, end_points={}): 42 | """ Autoencoder for point clouds. 43 | Input: 44 | point_cloud: TF tensor BxNx3 45 | is_training: boolean 46 | bn_decay: float between 0 and 1 47 | Output: 48 | net: TF tensor BxNx3, reconstructed point clouds 49 | end_points: dict 50 | """ 51 | """ Classification PointNet, input is BxNx3, output BxNx50 """ 52 | batch_size = point_cloud.get_shape()[0].value 53 | num_point = point_cloud.get_shape()[1].value 54 | end_points = {} 55 | 56 | with tf.variable_scope('transform_net1') as sc: 57 | transform = input_transform_net(point_cloud, is_training, bn_decay, K=3) 58 | point_cloud_transformed = tf.matmul(point_cloud, transform) 59 | input_image = tf.expand_dims(point_cloud_transformed, -1) 60 | 61 | net = tf_util.conv2d(input_image, 64, [1,3], 62 | padding='VALID', stride=[1,1], 63 | bn=True, is_training=is_training, 64 | scope='conv1', bn_decay=bn_decay) 65 | net = tf_util.conv2d(net, 64, [1,1], 66 | padding='VALID', stride=[1,1], 67 | bn=True, is_training=is_training, 68 | scope='conv2', bn_decay=bn_decay) 69 | 70 | with tf.variable_scope('transform_net2') as sc: 71 | transform = feature_transform_net(net, is_training, bn_decay, K=64) 72 | end_points['transform'] = transform 73 | net_transformed = tf.matmul(tf.squeeze(net, axis=[2]), transform) 74 | point_feat = tf.expand_dims(net_transformed, [2]) 75 | print(point_feat) 76 | 77 | net = tf_util.conv2d(point_feat, 64, [1,1], 78 | padding='VALID', stride=[1,1], 79 | bn=True, is_training=is_training, 80 | scope='conv3', bn_decay=bn_decay) 81 | net = tf_util.conv2d(net, 128, [1,1], 82 | padding='VALID', stride=[1,1], 83 | bn=True, is_training=is_training, 84 | scope='conv4', bn_decay=bn_decay) 85 | pointwise = tf_util.conv2d(net, 1024, [1,1], 86 | padding='VALID', stride=[1,1], 87 | bn=True, is_training=is_training, 88 | scope='conv5', bn_decay=bn_decay) 89 | 90 | 91 | global_feat = tf.reduce_max(pointwise, axis = 1, keep_dims=True) 92 | 93 | print('maxpoolglobal_feat', global_feat.get_shape()) 94 | 95 | feat0 = tf.reshape(global_feat, [batch_size, 1024]) 96 | 97 | # FC Decoder 98 | net = None 99 | # if ifglobal: 100 | feat = tf_util.fully_connected(feat0, 1024, bn=bn, is_training=is_training, scope='fc1', bn_decay=bn_decay) 101 | feat = tf_util.fully_connected(feat, 1024, bn=bn, is_training=is_training, scope='fc2', bn_decay=bn_decay) 102 | # if num_point is not None: 103 | # net = tf_util.fully_connected(feat, num_point * 3, activation_fn=None, scope='fc3') 104 | # net = tf.reshape(net, (batch_size, num_point, 3)) 105 | # end_points['pc'] = net 106 | end_points['embedding'] = feat 107 | end_points['pointwise'] = pointwise 108 | 109 | return net, end_points 110 | 111 | # def get_loss(pred, label, end_points): 112 | # """ pred: BxNx3, 113 | # label: BxNx3, """ 114 | # dists_forward,_,dists_backward,_ = tf_nndistance.nn_distance(pred, label) 115 | # loss = tf.reduce_mean(dists_forward+dists_backward) 116 | # end_points['pcloss'] = loss 117 | # return loss*100, end_points 118 | 119 | def get_decoder(embedding, is_training, scope='', bn_decay=None, bn=True): 120 | 121 | batch_size = embedding.get_shape()[0].value 122 | net = tf_util.fully_connected(embedding, 512, bn=True, is_training=is_training, scope='fc1', bn_decay=bn_decay) 123 | net = tf_util.fully_connected(net, 512, bn=True, is_training=is_training, scope='fc2', bn_decay=bn_decay) 124 | net = tf_util.fully_connected(net, 1024*3, activation_fn=None, scope='fc3') 125 | pc_fc = tf.reshape(net, (batch_size, -1, 3)) 126 | 127 | # UPCONV Decoder 128 | net = tf.reshape(embedding, [batch_size, 1, 1, -1]) 129 | net = tf_util.conv2d_transpose(net, 512, kernel_size=[2,2], stride=[1,1], padding='VALID', scope='upconv1', bn=True, bn_decay=bn_decay, is_training=is_training) 130 | net = tf_util.conv2d_transpose(net, 256, kernel_size=[3,3], stride=[1,1], padding='VALID', scope='upconv2', bn=True, bn_decay=bn_decay, is_training=is_training) 131 | net = tf_util.conv2d_transpose(net, 256, kernel_size=[4,4], stride=[2,2], padding='VALID', scope='upconv3', bn=True, bn_decay=bn_decay, is_training=is_training) 132 | net = tf_util.conv2d_transpose(net, 128, kernel_size=[5,5], stride=[3,3], padding='VALID', scope='upconv4', bn=True, bn_decay=bn_decay, is_training=is_training) 133 | net = tf_util.conv2d_transpose(net, 3, kernel_size=[1,1], stride=[1,1], padding='VALID', scope='upconv5', activation_fn=None) 134 | 135 | pc_upconv = tf.reshape(net, [batch_size, -1, 3]) 136 | 137 | # Set union 138 | reconst_pc = tf.concat(values=[pc_fc,pc_upconv], axis=1) 139 | 140 | return reconst_pc 141 | 142 | if __name__=='__main__': 143 | with tf.Graph().as_default(): 144 | inputs = tf.zeros((32,1024,3)) 145 | outputs = get_model(inputs, tf.constant(True)) 146 | print(outputs) 147 | loss = get_loss(outputs[0], tf.zeros((32,1024,3)), outputs[1]) 148 | -------------------------------------------------------------------------------- /models/pointnet/pointnet2_cls_msg.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | BASE_DIR = os.path.dirname(__file__) 4 | sys.path.append(BASE_DIR) 5 | sys.path.append(os.path.join(BASE_DIR, '../utils')) 6 | import tensorflow as tf 7 | import numpy as np 8 | import tf_util 9 | from pointnet_util import pointnet_sa_module, pointnet_sa_module_msg 10 | from pointnet_util import pointnet_sa_module, pointnet_fp_module 11 | 12 | 13 | def placeholder_inputs(batch_size, num_point): 14 | pointclouds_pl = tf.placeholder(tf.float32, shape=(batch_size, num_point, 3)) 15 | labels_pl = tf.placeholder(tf.int32, shape=(batch_size)) 16 | return pointclouds_pl, labels_pl 17 | 18 | 19 | def get_model(point_cloud, is_training, scope='', num_point=None, bn_decay=None, ifglobal=False, bn=True, end_points={}): 20 | """ Classification PointNet, input is BxNx3, output Bx40 """ 21 | batch_size = point_cloud.get_shape()[0].value 22 | num_point = point_cloud.get_shape()[1].value 23 | end_points = {} 24 | 25 | l0_xyz = point_cloud 26 | l0_points = None 27 | 28 | # Set abstraction layers 29 | l1_xyz, l1_points = pointnet_sa_module_msg(l0_xyz, l0_points, 512, [0.1,0.2,0.4], [16,32,128], [[32,32,64], [64,64,128], [64,96,128]], is_training, bn_decay, scope='layer1', use_nchw=True, bn = bn) 30 | l2_xyz, l2_points = pointnet_sa_module_msg(l1_xyz, l1_points, 128, [0.2,0.4,0.8], [32,64,128], [[64,64,128], [128,128,256], [128,128,256]], is_training, bn_decay, scope='layer2', bn = bn) 31 | l3_xyz, l3_points, _ = pointnet_sa_module(l2_xyz, l2_points, npoint=None, radius=None, nsample=None, mlp=[256,512,1024], mlp2=None, group_all=True, is_training=is_training, bn_decay=bn_decay, scope='layer3', bn = bn) 32 | 33 | # Fully connected layers 34 | net = tf.reshape(l3_points, [batch_size, -1]) 35 | net = tf_util.fully_connected(net, 512, bn=bn, is_training=is_training, scope='fc1', bn_decay=bn_decay) 36 | end_points['embedding'] = net 37 | # net = tf_util.dropout(net, keep_prob=0.4, is_training=is_training, scope='dp1') 38 | # net = tf_util.fully_connected(net, 256, bn=True, is_training=is_training, scope='fc2', bn_decay=bn_decay) 39 | # net = tf_util.dropout(net, keep_prob=0.4, is_training=is_training, scope='dp2') 40 | # net = tf_util.fully_connected(net, 40, activation_fn=None, scope='fc3') 41 | end_points['l2_xyz'] = l2_xyz 42 | end_points['l3_xyz'] = l3_xyz 43 | end_points['l1_xyz'] = l1_xyz 44 | end_points['l0_xyz'] = l0_xyz 45 | end_points['l2_points'] = l2_points 46 | end_points['l3_points'] = l3_points 47 | end_points['l1_points'] = l1_points 48 | end_points['l0_points'] = l0_points 49 | 50 | return net, end_points 51 | 52 | def get_decoder(embedding, is_training, scope='pointnet2_decoder', bn_decay=None, bn=True, end_points = {}): 53 | with tf.name_scope(scope) as sc: 54 | l2_xyz = end_points['l2_xyz'] 55 | l3_xyz = end_points['l3_xyz'] 56 | l1_xyz = end_points['l1_xyz'] 57 | l0_xyz = end_points['l0_xyz'] 58 | l2_points = end_points['l2_points'] 59 | l3_points = end_points['l3_points'] 60 | l1_points = end_points['l1_points'] 61 | l0_points = end_points['l0_points'] 62 | 63 | batch_size = embedding.get_shape()[0].value 64 | # net = tf_util.fully_connected(embedding, 512, bn=True, is_training=is_training, scope='fc1', bn_decay=bn_decay) 65 | # net = tf_util.fully_connected(net, 512, bn=True, is_training=is_training, scope='fc2', bn_decay=bn_decay) 66 | # net = tf_util.fully_connected(net, 1024*3, activation_fn=None, scope='fc3') 67 | # pc_fc = tf.reshape(net, (batch_size, -1, 3)) 68 | 69 | embedding = tf.expand_dims(embedding, axis=1) 70 | l3_points = tf.concat([embedding, l3_points], axis = -1) 71 | 72 | # Feature Propagation layers 73 | l2_points = pointnet_fp_module(l2_xyz, l3_xyz, l2_points, l3_points, [256,256], is_training, bn_decay, scope='fa_layer1') 74 | l1_points = pointnet_fp_module(l1_xyz, l2_xyz, l1_points, l2_points, [256,128], is_training, bn_decay, scope='fa_layer2') 75 | l0_points = pointnet_fp_module(l0_xyz, l1_xyz, l0_points, l1_points, [128,128,128], is_training, bn_decay, scope='fa_layer3') 76 | 77 | # FC layers 78 | net = tf_util.conv1d(l0_points, 128, 1, padding='VALID', bn=True, is_training=is_training, scope='decoder_fc1', bn_decay=bn_decay) 79 | net = tf_util.conv1d(l0_points, 3, 1, padding='VALID', bn=False, is_training=is_training, scope='decoder_fc2', bn_decay=None, activation_fn=None) 80 | # net = tf_util.conv2d_transpose(net, 3, kernel_size=[1,1], stride=[1,1], padding='VALID', scope='fc2', activation_fn=None) 81 | 82 | reconst_pc = tf.reshape(net, [batch_size, -1, 3]) 83 | 84 | 85 | return reconst_pc 86 | 87 | def get_loss(pred, label, end_points): 88 | """ pred: B*NUM_CLASSES, 89 | label: B, """ 90 | loss = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=pred, labels=label) 91 | classify_loss = tf.reduce_mean(loss) 92 | tf.summary.scalar('classify loss', classify_loss) 93 | tf.add_to_collection('losses', classify_loss) 94 | return classify_loss 95 | 96 | 97 | if __name__=='__main__': 98 | with tf.Graph().as_default(): 99 | inputs = tf.zeros((32,1024,3)) 100 | net, _ = get_model(inputs, tf.constant(True)) 101 | print(net) 102 | -------------------------------------------------------------------------------- /models/pointnet/pointnet2_part_seg.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | BASE_DIR = os.path.dirname(__file__) 4 | sys.path.append(BASE_DIR) 5 | sys.path.append(os.path.join(BASE_DIR, '..')) 6 | import tensorflow as tf 7 | import numpy as np 8 | import tf_util 9 | from pointnet_util import pointnet_sa_module, pointnet_fp_module 10 | 11 | def placeholder_inputs(batch_size, num_point): 12 | pointclouds_pl = tf.placeholder(tf.float32, shape=(batch_size, num_point, 6)) 13 | labels_pl = tf.placeholder(tf.int32, shape=(batch_size, num_point)) 14 | return pointclouds_pl, labels_pl 15 | 16 | 17 | def get_model(point_cloud, is_training, scope='', num_point=None, bn_decay=None, ifglobal=False, bn=True, end_points={}): 18 | """ Part segmentation PointNet, input is BxNx6 (XYZ NormalX NormalY NormalZ), output Bx50 """ 19 | batch_size = point_cloud.get_shape()[0].value 20 | num_point = point_cloud.get_shape()[1].value 21 | end_points = {} 22 | l0_xyz = tf.slice(point_cloud, [0,0,0], [-1,-1,3]) 23 | l0_points = None#tf.slice(point_cloud, [0,0,3], [-1,-1,3]) 24 | 25 | # Set Abstraction layers 26 | l1_xyz, l1_points, l1_indices = pointnet_sa_module(l0_xyz, l0_points, npoint=512, radius=0.2, nsample=64, mlp=[64,64,128], mlp2=None, group_all=False, is_training=is_training, bn_decay=bn_decay, scope='layer1') 27 | l2_xyz, l2_points, l2_indices = pointnet_sa_module(l1_xyz, l1_points, npoint=128, radius=0.4, nsample=64, mlp=[128,128,256], mlp2=None, group_all=False, is_training=is_training, bn_decay=bn_decay, scope='layer2') 28 | l3_xyz, l3_points, l3_indices = pointnet_sa_module(l2_xyz, l2_points, npoint=None, radius=None, nsample=None, mlp=[256,512,1024], mlp2=None, group_all=True, is_training=is_training, bn_decay=bn_decay, scope='layer3') 29 | 30 | # Feature Propagation layers 31 | l2_points = pointnet_fp_module(l2_xyz, l3_xyz, l2_points, l3_points, [256,256], is_training, bn_decay, scope='fa_layer1') 32 | l1_points = pointnet_fp_module(l1_xyz, l2_xyz, l1_points, l2_points, [256,128], is_training, bn_decay, scope='fa_layer2') 33 | l0_points = pointnet_fp_module(l0_xyz, l1_xyz, tf.concat([l0_xyz,l0_points],axis=-1), l1_points, [128,128,128], is_training, bn_decay, scope='fa_layer3') 34 | 35 | # FC layers 36 | net = tf_util.conv1d(l0_points, 128, 1, padding='VALID', bn=True, is_training=is_training, scope='fc1', bn_decay=bn_decay) 37 | end_points['embedding'] = net 38 | net = tf_util.dropout(net, keep_prob=0.5, is_training=is_training, scope='dp1') 39 | net = tf_util.conv1d(net, 50, 1, padding='VALID', activation_fn=None, scope='fc2') 40 | 41 | return net, end_points 42 | 43 | 44 | def get_loss(pred, label): 45 | """ pred: BxNxC, 46 | label: BxN, """ 47 | loss = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=pred, labels=label) 48 | classify_loss = tf.reduce_mean(loss) 49 | tf.summary.scalar('classify loss', classify_loss) 50 | tf.add_to_collection('losses', classify_loss) 51 | return classify_loss 52 | 53 | if __name__=='__main__': 54 | with tf.Graph().as_default(): 55 | inputs = tf.zeros((32,2048,6)) 56 | net, _ = get_model(inputs, tf.constant(True)) 57 | print(net) 58 | -------------------------------------------------------------------------------- /models/pointnet/transform_nets.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import sys 4 | import os 5 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 6 | sys.path.append(BASE_DIR) 7 | sys.path.append(os.path.join(BASE_DIR, '../utils')) 8 | import tf_util 9 | 10 | def input_transform_net(point_cloud, is_training, bn_decay=None, K=3): 11 | """ Input (XYZ) Transform Net, input is BxNx3 gray image 12 | Return: 13 | Transformation matrix of size 3xK """ 14 | batch_size = point_cloud.get_shape()[0].value 15 | num_point = point_cloud.get_shape()[1].value 16 | 17 | input_image = tf.expand_dims(point_cloud, -1) 18 | net = tf_util.conv2d(input_image, 64, [1,3], 19 | padding='VALID', stride=[1,1], 20 | bn=True, is_training=is_training, 21 | scope='tconv1', bn_decay=bn_decay) 22 | net = tf_util.conv2d(net, 128, [1,1], 23 | padding='VALID', stride=[1,1], 24 | bn=True, is_training=is_training, 25 | scope='tconv2', bn_decay=bn_decay) 26 | net = tf_util.conv2d(net, 1024, [1,1], 27 | padding='VALID', stride=[1,1], 28 | bn=True, is_training=is_training, 29 | scope='tconv3', bn_decay=bn_decay) 30 | net = tf_util.max_pool2d(net, [num_point,1], 31 | padding='VALID', scope='tmaxpool') 32 | 33 | net = tf.reshape(net, [batch_size, -1]) 34 | net = tf_util.fully_connected(net, 512, bn=True, is_training=is_training, 35 | scope='tfc1', bn_decay=bn_decay) 36 | net = tf_util.fully_connected(net, 256, bn=True, is_training=is_training, 37 | scope='tfc2', bn_decay=bn_decay) 38 | 39 | with tf.variable_scope('transform_XYZ') as sc: 40 | assert(K==3) 41 | weights = tf.get_variable('weights', [256, 3*K], 42 | initializer=tf.constant_initializer(0.0), 43 | dtype=tf.float32) 44 | biases = tf.get_variable('biases', [3*K], 45 | initializer=tf.constant_initializer(0.0), 46 | dtype=tf.float32) 47 | biases += tf.constant([1,0,0,0,1,0,0,0,1], dtype=tf.float32) 48 | transform = tf.matmul(net, weights) 49 | transform = tf.nn.bias_add(transform, biases) 50 | 51 | transform = tf.reshape(transform, [batch_size, 3, K]) 52 | return transform 53 | 54 | 55 | def feature_transform_net(inputs, is_training, bn_decay=None, K=64): 56 | """ Feature Transform Net, input is BxNx1xK 57 | Return: 58 | Transformation matrix of size KxK """ 59 | batch_size = inputs.get_shape()[0].value 60 | num_point = inputs.get_shape()[1].value 61 | 62 | net = tf_util.conv2d(inputs, 64, [1,1], 63 | padding='VALID', stride=[1,1], 64 | bn=True, is_training=is_training, 65 | scope='tconv1', bn_decay=bn_decay) 66 | net = tf_util.conv2d(net, 128, [1,1], 67 | padding='VALID', stride=[1,1], 68 | bn=True, is_training=is_training, 69 | scope='tconv2', bn_decay=bn_decay) 70 | net = tf_util.conv2d(net, 1024, [1,1], 71 | padding='VALID', stride=[1,1], 72 | bn=True, is_training=is_training, 73 | scope='tconv3', bn_decay=bn_decay) 74 | net = tf_util.max_pool2d(net, [num_point,1], 75 | padding='VALID', scope='tmaxpool') 76 | 77 | net = tf.reshape(net, [batch_size, -1]) 78 | net = tf_util.fully_connected(net, 512, bn=True, is_training=is_training, 79 | scope='tfc1', bn_decay=bn_decay) 80 | net = tf_util.fully_connected(net, 256, bn=True, is_training=is_training, 81 | scope='tfc2', bn_decay=bn_decay) 82 | 83 | with tf.variable_scope('transform_feat') as sc: 84 | weights = tf.get_variable('weights', [256, K*K], 85 | initializer=tf.constant_initializer(0.0), 86 | dtype=tf.float32) 87 | biases = tf.get_variable('biases', [K*K], 88 | initializer=tf.constant_initializer(0.0), 89 | dtype=tf.float32) 90 | biases += tf.constant(np.eye(K).flatten(), dtype=tf.float32) 91 | transform = tf.matmul(net, weights) 92 | transform = tf.nn.bias_add(transform, biases) 93 | 94 | transform = tf.reshape(transform, [batch_size, K, K]) 95 | return transform 96 | -------------------------------------------------------------------------------- /models/tf_ops/3d_interpolation/interpolate.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include // memset 4 | #include // rand, RAND_MAX 5 | #include // sqrtf 6 | #include 7 | #include 8 | using namespace std; 9 | float randomf(){ 10 | return (rand()+0.5)/(RAND_MAX+1.0); 11 | } 12 | static double get_time(){ 13 | timespec tp; 14 | clock_gettime(CLOCK_MONOTONIC,&tp); 15 | return tp.tv_sec+tp.tv_nsec*1e-9; 16 | } 17 | 18 | // Find three nearest neigbors with square distance 19 | // input: xyz1 (b,n,3), xyz2(b,m,3) 20 | // output: dist (b,n,3), idx (b,n,3) 21 | void threenn_cpu(int b, int n, int m, const float *xyz1, const float *xyz2, float *dist, int *idx) { 22 | for (int i=0;i 2 | #include 3 | #include // memset 4 | #include // rand, RAND_MAX 5 | #include // sqrtf 6 | #include 7 | #include 8 | using namespace std; 9 | float randomf(){ 10 | return (rand()+0.5)/(RAND_MAX+1.0); 11 | } 12 | static double get_time(){ 13 | timespec tp; 14 | clock_gettime(CLOCK_MONOTONIC,&tp); 15 | return tp.tv_sec+tp.tv_nsec*1e-9; 16 | } 17 | // input: radius (1), nsample (1), xyz1 (b,n,3), xyz2 (b,m,3) 18 | // output: idx (b,m,nsample) 19 | void query_ball_point_cpu(int b, int n, int m, float radius, int nsample, const float *xyz1, const float *xyz2, int *idx) { 20 | for (int i=0;i 2 | #include 3 | #include // memset 4 | #include // rand, RAND_MAX 5 | #include // sqrtf 6 | #include 7 | #include 8 | using namespace std; 9 | float randomf(){ 10 | return (rand()+0.5)/(RAND_MAX+1.0); 11 | } 12 | static double get_time(){ 13 | timespec tp; 14 | clock_gettime(CLOCK_MONOTONIC,&tp); 15 | return tp.tv_sec+tp.tv_nsec*1e-9; 16 | } 17 | // input: radius (1), nsample (1), xyz1 (b,n,3), xyz2 (b,m,3) 18 | // output: idx (b,m,nsample) 19 | __global__ void query_ball_point_gpu(int b, int n, int m, float radius, int nsample, const float *xyz1, const float *xyz2, int *idx) { 20 | for (int i=0;i>>(b,n,m,radius,nsample,xyz1,xyz2,idx); 113 | cudaDeviceSynchronize(); 114 | printf("query_ball_point gpu time %f\n",get_time()-t0); 115 | 116 | t0=get_time(); 117 | group_point_gpu<<<1,1>>>(b,n,c,m,nsample,points,idx,out); 118 | cudaDeviceSynchronize(); 119 | printf("grou_point gpu time %f\n",get_time()-t0); 120 | 121 | t0=get_time(); 122 | group_point_grad_gpu<<<1,1>>>(b,n,c,m,nsample,grad_out,idx,grad_points); 123 | cudaDeviceSynchronize(); 124 | printf("grou_point_grad gpu time %f\n",get_time()-t0); 125 | 126 | cudaFree(xyz1); 127 | cudaFree(xyz2); 128 | cudaFree(points); 129 | cudaFree(idx); 130 | cudaFree(out); 131 | cudaFree(grad_out); 132 | cudaFree(grad_points); 133 | return 0; 134 | } 135 | -------------------------------------------------------------------------------- /models/tf_ops/grouping/test/query_ball_point_block.cu: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include // memset 4 | #include // rand, RAND_MAX 5 | #include // sqrtf 6 | #include 7 | #include 8 | using namespace std; 9 | float randomf(){ 10 | return (rand()+0.5)/(RAND_MAX+1.0); 11 | } 12 | static double get_time(){ 13 | timespec tp; 14 | clock_gettime(CLOCK_MONOTONIC,&tp); 15 | return tp.tv_sec+tp.tv_nsec*1e-9; 16 | } 17 | // input: radius (1), nsample (1), xyz1 (b,n,3), xyz2 (b,m,3) 18 | // output: idx (b,m,nsample) 19 | __global__ void query_ball_point_gpu(int b, int n, int m, float radius, int nsample, const float *xyz1, const float *xyz2, int *idx) { 20 | int index = threadIdx.x; 21 | xyz1 += n*3*index; 22 | xyz2 += m*3*index; 23 | idx += m*nsample*index; 24 | 25 | for (int j=0;j>>(b,n,m,radius,nsample,xyz1,xyz2,idx); 113 | cudaDeviceSynchronize(); 114 | printf("query_ball_point gpu time %f\n",get_time()-t0); 115 | 116 | t0=get_time(); 117 | group_point_gpu<<<1,b>>>(b,n,c,m,nsample,points,idx,out); 118 | cudaDeviceSynchronize(); 119 | printf("grou_point gpu time %f\n",get_time()-t0); 120 | 121 | t0=get_time(); 122 | group_point_grad_gpu<<<1,b>>>(b,n,c,m,nsample,grad_out,idx,grad_points); 123 | cudaDeviceSynchronize(); 124 | printf("grou_point_grad gpu time %f\n",get_time()-t0); 125 | 126 | cudaFree(xyz1); 127 | cudaFree(xyz2); 128 | cudaFree(points); 129 | cudaFree(idx); 130 | cudaFree(out); 131 | cudaFree(grad_out); 132 | cudaFree(grad_points); 133 | return 0; 134 | } 135 | -------------------------------------------------------------------------------- /models/tf_ops/grouping/test/query_ball_point_grid.cu: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include // memset 4 | #include // rand, RAND_MAX 5 | #include // sqrtf 6 | #include 7 | #include 8 | using namespace std; 9 | float randomf(){ 10 | return (rand()+0.5)/(RAND_MAX+1.0); 11 | } 12 | static double get_time(){ 13 | timespec tp; 14 | clock_gettime(CLOCK_MONOTONIC,&tp); 15 | return tp.tv_sec+tp.tv_nsec*1e-9; 16 | } 17 | // input: radius (1), nsample (1), xyz1 (b,n,3), xyz2 (b,m,3) 18 | // output: idx (b,m,nsample) 19 | __global__ void query_ball_point_gpu(int b, int n, int m, float radius, int nsample, const float *xyz1, const float *xyz2, int *idx) { 20 | int batch_index = blockIdx.x; 21 | xyz1 += n*3*batch_index; 22 | xyz2 += m*3*batch_index; 23 | idx += m*nsample*batch_index; 24 | 25 | int index = threadIdx.x; 26 | int stride = blockDim.x; 27 | 28 | for (int j=index;j>>(b,n,m,radius,nsample,xyz1,xyz2,idx); 123 | cudaDeviceSynchronize(); 124 | printf("query_ball_point gpu time %f\n",get_time()-t0); 125 | 126 | t0=get_time(); 127 | group_point_gpu<<>>(b,n,c,m,nsample,points,idx,out); 128 | cudaDeviceSynchronize(); 129 | printf("grou_point gpu time %f\n",get_time()-t0); 130 | 131 | t0=get_time(); 132 | group_point_grad_gpu<<>>(b,n,c,m,nsample,grad_out,idx,grad_points); 133 | cudaDeviceSynchronize(); 134 | printf("grou_point_grad gpu time %f\n",get_time()-t0); 135 | 136 | cudaFree(xyz1); 137 | cudaFree(xyz2); 138 | cudaFree(points); 139 | cudaFree(idx); 140 | cudaFree(out); 141 | cudaFree(grad_out); 142 | cudaFree(grad_points); 143 | return 0; 144 | } 145 | -------------------------------------------------------------------------------- /models/tf_ops/grouping/test/selection_sort.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include // memset 4 | #include // rand, RAND_MAX 5 | #include // sqrtf 6 | #include 7 | #include 8 | using namespace std; 9 | float randomf(){ 10 | return (rand()+0.5)/(RAND_MAX+1.0); 11 | } 12 | static double get_time(){ 13 | timespec tp; 14 | clock_gettime(CLOCK_MONOTONIC,&tp); 15 | return tp.tv_sec+tp.tv_nsec*1e-9; 16 | } 17 | 18 | // input: k (1), distance matrix dist (b,m,n) 19 | // output: idx (b,m,n), val (b,m,n) 20 | void selection_sort_cpu(int b, int n, int m, int k, const float *dist, int *idx, float *val) { 21 | float *p_dist; 22 | float tmp; 23 | int tmpi; 24 | for (int i=0;i 2 | #include 3 | #include // memset 4 | #include // rand, RAND_MAX 5 | #include // sqrtf 6 | #include 7 | #include 8 | using namespace std; 9 | float randomf(){ 10 | return (rand()+0.5)/(RAND_MAX+1.0); 11 | } 12 | static double get_time(){ 13 | timespec tp; 14 | clock_gettime(CLOCK_MONOTONIC,&tp); 15 | return tp.tv_sec+tp.tv_nsec*1e-9; 16 | } 17 | 18 | // input: k (1), distance matrix dist (b,m,n) 19 | // output: idx (b,m,k), val (b,m,k) 20 | __global__ void selection_sort_gpu(int b, int n, int m, int k, float *dist, int *idx, float *val) { 21 | int batch_index = blockIdx.x; 22 | dist+=m*n*batch_index; 23 | idx+=m*k*batch_index; 24 | val+=m*k*batch_index; 25 | 26 | int index = threadIdx.x; 27 | int stride = blockDim.x; 28 | 29 | float *p_dist; 30 | for (int j=index;j>>(b,n,m,k,dist,idx,val); 68 | cudaDeviceSynchronize(); 69 | printf("selection sort cpu time %f\n",get_time()-t0); 70 | 71 | return 0; 72 | } 73 | -------------------------------------------------------------------------------- /models/tf_ops/grouping/test/selection_sort_const.cu: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include // memset 4 | #include // rand, RAND_MAX 5 | #include // sqrtf 6 | #include 7 | #include 8 | using namespace std; 9 | float randomf(){ 10 | return (rand()+0.5)/(RAND_MAX+1.0); 11 | } 12 | static double get_time(){ 13 | timespec tp; 14 | clock_gettime(CLOCK_MONOTONIC,&tp); 15 | return tp.tv_sec+tp.tv_nsec*1e-9; 16 | } 17 | 18 | // input: k (1), distance matrix dist (b,m,n) 19 | // output: idx (b,m,n), dist_out (b,m,n) 20 | __global__ void selection_sort_gpu(int b, int n, int m, int k, const float *dist, int *outi, float *out) { 21 | int batch_index = blockIdx.x; 22 | dist+=m*n*batch_index; 23 | outi+=m*n*batch_index; 24 | out+=m*n*batch_index; 25 | 26 | int index = threadIdx.x; 27 | int stride = blockDim.x; 28 | 29 | // copy from dist to dist_out 30 | for (int j=index;j>>(b,n,m,k,dist,idx,dist_out); 84 | cudaDeviceSynchronize(); 85 | printf("selection sort cpu time %f\n",get_time()-t0); 86 | 87 | //for (int i=0;i>>(b,n,m,radius,nsample,xyz1,xyz2,idx,pts_cnt); 127 | //cudaDeviceSynchronize(); 128 | } 129 | void selectionSortLauncher(int b, int n, int m, int k, const float *dist, int *outi, float *out) { 130 | selection_sort_gpu<<>>(b,n,m,k,dist,outi,out); 131 | //cudaDeviceSynchronize(); 132 | } 133 | void groupPointLauncher(int b, int n, int c, int m, int nsample, const float *points, const int *idx, float *out){ 134 | group_point_gpu<<>>(b,n,c,m,nsample,points,idx,out); 135 | //cudaDeviceSynchronize(); 136 | } 137 | void groupPointGradLauncher(int b, int n, int c, int m, int nsample, const float *grad_out, const int *idx, float *grad_points){ 138 | group_point_grad_gpu<<>>(b,n,c,m,nsample,grad_out,idx,grad_points); 139 | //group_point_grad_gpu<<<1,1>>>(b,n,c,m,nsample,grad_out,idx,grad_points); 140 | //cudaDeviceSynchronize(); 141 | } 142 | -------------------------------------------------------------------------------- /models/tf_ops/grouping/tf_grouping_op_test.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | from tf_grouping import query_ball_point, group_point 4 | 5 | class GroupPointTest(tf.test.TestCase): 6 | def test(self): 7 | pass 8 | 9 | def test_grad(self): 10 | with tf.device('/gpu:0'): 11 | points = tf.constant(np.random.random((1,128,16)).astype('float32')) 12 | print points 13 | xyz1 = tf.constant(np.random.random((1,128,3)).astype('float32')) 14 | xyz2 = tf.constant(np.random.random((1,8,3)).astype('float32')) 15 | radius = 0.3 16 | nsample = 32 17 | idx, pts_cnt = query_ball_point(radius, nsample, xyz1, xyz2) 18 | grouped_points = group_point(points, idx) 19 | print grouped_points 20 | 21 | with self.test_session(): 22 | print "---- Going to compute gradient error" 23 | err = tf.test.compute_gradient_error(points, (1,128,16), grouped_points, (1,8,32,16)) 24 | print err 25 | self.assertLess(err, 1e-4) 26 | 27 | if __name__=='__main__': 28 | tf.test.main() 29 | -------------------------------------------------------------------------------- /models/tf_ops/mesh_laplacian/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laughtervv/3DN/81e3651d780478139c3b8dee5e737ce565813900/models/tf_ops/mesh_laplacian/__init__.py -------------------------------------------------------------------------------- /models/tf_ops/mesh_laplacian/tf_meshlaplacian.py: -------------------------------------------------------------------------------- 1 | """ 2 | Mesh laplacian Operator 3 | Weiyue Wang 4 | """ 5 | 6 | import tensorflow as tf 7 | from tensorflow.python.framework import ops 8 | import sys 9 | import os 10 | import time 11 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 12 | mesh_laplacian_module=tf.load_op_library(os.path.join(BASE_DIR, 'tf_meshlaplacian_so.so')) 13 | 14 | def mesh_laplacian(verts,nverts,tris,ntris): 15 | ''' 16 | .Input("verts: float32") 17 | .Input("nverts: int32") 18 | .Input("tris: int32") 19 | .Input("ntris: int32") 20 | .Output("laplacian: float32") 21 | .Output("count: int32") 22 | .Output("nb: int32"); 23 | ''' 24 | return mesh_laplacian_module.mesh_laplacian(verts,nverts,tris,ntris) 25 | 26 | @ops.RegisterGradient('MeshLaplacian') 27 | def _mesh_laplacian_grad(op, grad_laplacian, grad_count, grad_nb): 28 | ''' 29 | .Input("nverts: int32") 30 | .Input("count: int32") 31 | .Input("nb: int32") 32 | .Input("grad_laplacian: float32") 33 | .Output("grad_verts: float32"); 34 | ''' 35 | 36 | nverts = op.inputs[1] 37 | # global count 38 | count = op.outputs[1] 39 | # global nb 40 | nb = op.outputs[2] 41 | # global aaa 42 | # aaa = grad_laplacian 43 | grad_verts = mesh_laplacian_module.mesh_laplacian_grad(nverts,count,nb,grad_laplacian) 44 | 45 | return [grad_verts,None,None,None] 46 | 47 | 48 | if __name__=='__main__': 49 | import numpy as np 50 | import random 51 | import time 52 | from tensorflow.python.ops.gradient_checker import compute_gradient 53 | random.seed(100) 54 | np.random.seed(100) 55 | 56 | 57 | def write_off(fn, verts, faces): 58 | file = open(fn, 'w') 59 | file.write('OFF\n') 60 | file.write('%d %d %d\n' % (len(verts), len(faces), 0)) 61 | for vert in verts: 62 | file.write('%f %f %f\n' % (vert[0], vert[1], vert[2])) 63 | # verts.append([float(s) for s in readline().strip().split(' ')]) 64 | for face in faces: 65 | file.write('3 %f %f %f\n' % (face[0], face[1], face[2])) 66 | # faces.append([int(s) for s in readline().strip().split(' ')][1:]) 67 | file.close() 68 | return 69 | 70 | def read_off(fn): 71 | file = open(fn, 'r') 72 | if 'OFF' != file.readline().strip(): 73 | print ('Not a valid OFF header') 74 | return 75 | n_verts, n_faces, n_dontknow = tuple([int(s) for s in file.readline().strip().split(' ')]) 76 | verts = [] 77 | for i_vert in range(n_verts): 78 | verts.append([float(s) for s in file.readline().strip().split(' ')]) 79 | faces = [] 80 | for i_face in range(n_faces): 81 | faces.append([int(s) for s in file.readline().strip().split(' ')][1:]) 82 | file.close() 83 | return np.asarray(verts,dtype=np.float32), np.asarray(faces, dtype=np.int32) 84 | 85 | 86 | test1 = True 87 | test2 = False 88 | test1 = False 89 | test2 = True 90 | 91 | with tf.Session('') as sess: 92 | 93 | vertices, faces = read_off('bunny.off') 94 | 95 | if test1: 96 | verts=tf.expand_dims(tf.constant(vertices),0) 97 | tris=tf.expand_dims(tf.constant(faces),0) 98 | nverts = tf.constant([[len(vertices)]],dtype=tf.int32) 99 | ntris = tf.constant([[len(faces)]],dtype=tf.int32) 100 | 101 | laplacian,_,_ = mesh_laplacian(verts, nverts, tris, ntris) 102 | loss = tf.nn.l2_loss(laplacian - 0) 103 | verts1_grad = tf.gradients(loss, [verts])[0] 104 | laplacian_val, old_count_val, old_nb_val = sess.run([laplacian, count, nb]) 105 | for i in range(10): 106 | laplacian_val, count_val, nb_val, verts_val = sess.run([laplacian, count, nb, verts]) 107 | 108 | verts_val += 0.3* laplacian_val 109 | verts=tf.constant(verts_val) 110 | laplacian,_,_ = mesh_laplacian(verts, nverts, tris, ntris) 111 | 112 | color = np.squeeze(laplacian_val) 113 | color = 255*(color - np.min(color))/(np.max(color)-np.min(color)) 114 | color[:,0]=0 115 | np.savetxt('verts_val.xyz', np.concatenate((vertices, color.astype(np.int8)), axis=1)) 116 | 117 | write_off('out.off', np.squeeze(verts_val), faces) 118 | if test2: 119 | 120 | verts1=tf.expand_dims(tf.constant(vertices),0) 121 | tris1=tf.expand_dims(tf.constant(faces),0) 122 | nverts1 = tf.constant([[len(vertices)]],dtype=tf.int32) 123 | ntris1 = tf.constant([[len(faces)]],dtype=tf.int32) 124 | 125 | laplacian1,_,_ = mesh_laplacian(verts1, nverts1, tris1, ntris1) 126 | 127 | vertices[:,1] *= 2 128 | old_verts2 = tf.expand_dims(tf.constant(vertices),0) 129 | verts2=tf.Variable(old_verts2) 130 | tris2=tf.expand_dims(tf.constant(faces),0) 131 | nverts2 = tf.constant([[len(vertices)]],dtype=tf.int32) 132 | ntris2 = tf.constant([[len(faces)]],dtype=tf.int32) 133 | 134 | laplacian2,_,_ = mesh_laplacian(verts2, nverts2, tris2, ntris2) 135 | 136 | # 137 | loss = 10*tf.nn.l2_loss(laplacian2 - laplacian1) 138 | verts2_grad = tf.gradients(loss, [verts2])[0] 139 | # 140 | train=tf.train.GradientDescentOptimizer(learning_rate=0.05).minimize(loss) 141 | 142 | sess.run(tf.initialize_all_variables()) 143 | # 144 | old_lossval = 10000 145 | for i in range(500): 146 | _, loss_val, verts2_val, verts1_val, verts2_grad_val,count_val,grad_laplasian_val,old_verts2_val =sess.run([train, loss, verts2, verts1, verts2_grad, count, aaa,old_verts2])#, feed_dict=feed_dict) 147 | 148 | np.savetxt('verts2.xyz', np.squeeze(verts2_val)) 149 | np.savetxt('verts1.xyz', np.squeeze(verts1_val)) 150 | 151 | write_off('out2.off', np.squeeze(verts2_val), faces) 152 | write_off('old_out2.off', np.squeeze(old_verts2_val), faces) 153 | 154 | write_off('out1.off', np.squeeze(verts1_val), faces) -------------------------------------------------------------------------------- /models/tf_ops/mesh_laplacian/tf_meshlaplacian_compile.sh: -------------------------------------------------------------------------------- 1 | /usr/local/cuda/bin/nvcc tf_meshlaplacian_g.cu -o tf_meshlaplacian_g.cu.o -c -O2 -DGOOGLE_CUDA=1 -x cu -Xcompiler -fPIC 2 | g++ -std=c++11 tf_meshlaplacian.cpp tf_meshlaplacian_g.cu.o -o tf_meshlaplacian_so.so -shared -fPIC -I /usr/local/lib/python2.7/dist-packages/tensorflow/include -I /usr/local/cuda/include -I /usr/local/lib/python2.7/dist-packages/tensorflow/include/external/nsync/public -lcudart -L /usr/local/cuda/lib64/ -L/usr/local/lib/python2.7/dist-packages/tensorflow -ltensorflow_framework -O2 -D_GLIBCXX_USE_CXX11_ABI=0 3 | 4 | -------------------------------------------------------------------------------- /models/tf_ops/mesh_laplacian/tf_meshlaplacian_g.cu: -------------------------------------------------------------------------------- 1 | //Mesh Laplacian 2 | //Author: Weiyue Wang 3 | //Reference: https://github.com/charlesq34/pointnet-autoencoder/blob/master/tf_ops/nn_distance/tf_nndistance_g.cu 4 | // https://github.com/PointCloudLibrary/pcl/blob/master/tools/mesh_sampling.cpp 5 | 6 | #if GOOGLE_CUDA 7 | #define EIGEN_USE_GPU 8 | #include 9 | #include 10 | 11 | 12 | __device__ void getPoint(const float *vertices, int v_id, float *p){ 13 | p[0] = vertices[3* v_id]; 14 | p[1] = vertices[3* v_id+1]; 15 | p[2] = vertices[3* v_id+2]; 16 | } 17 | 18 | __device__ void getTriangle(const int *triangles, int t_id, int &v1, int &v2, int &v3){ 19 | v1 = triangles[3 * t_id]; 20 | v2 = triangles[3 * t_id + 1]; 21 | v3 = triangles[3 * t_id + 2]; 22 | } 23 | 24 | __host__ void getTriangle_cpu(const int *triangles, int t_id, int &v1, int &v2, int &v3){ 25 | v1 = triangles[3 * t_id]; 26 | v2 = triangles[3 * t_id + 1]; 27 | v3 = triangles[3 * t_id + 2]; 28 | } 29 | 30 | __host__ bool findnb_cpu(const int *nb, int v_id){ 31 | bool flag = false; 32 | for (int i=0; i<20; i++) 33 | if (nb[i] == v_id){ 34 | flag = true; 35 | break; 36 | } 37 | return flag; 38 | } 39 | __device__ bool findnb(const int *nb, int v_id){ 40 | bool flag = false; 41 | for (int i=0; i<20; i++) 42 | if (nb[i] == v_id){ 43 | flag = true; 44 | break; 45 | } 46 | return flag; 47 | } 48 | 49 | __device__ void setLaplacian(float *laplacian, int *count, int v_id1, int v_id2, float * p1, float * p2){ 50 | 51 | atomicAdd(&laplacian[3 * v_id1], p2[0] - p1[0]); 52 | atomicAdd(&laplacian[3 * v_id1+1], p2[1] - p1[1]); 53 | atomicAdd(&laplacian[3 * v_id1+2], p2[2] - p1[2]); 54 | 55 | atomicAdd(&count[v_id1], 1); 56 | 57 | 58 | atomicAdd(&laplacian[3 * v_id2], p1[0] - p2[0]); 59 | atomicAdd(&laplacian[3 * v_id2+1], p1[1] - p2[1]); 60 | atomicAdd(&laplacian[3 * v_id2+2], p1[2] - p2[2]); 61 | 62 | atomicAdd(&count[v_id2], 1); 63 | } 64 | 65 | 66 | __global__ void InitMeshLaplacianKernel(const int b, const int maxnverts, float* laplacian, int* count){ 67 | for (int i=blockIdx.x;i>>(b, maxn_verts, laplacian, count); 128 | cudaMemset(nb, -1, b*maxn_verts*20*sizeof(int)); 129 | MeshLaplacianKernel<<<64,512>>>(b, n_verts, maxn_verts, vertices, n_triangles, maxn_triangles, triangles, laplacian, nb, count); 130 | AvgMeshLaplacianKernel<<>>(b, maxn_verts, laplacian, count); 131 | 132 | 133 | } 134 | 135 | /****************** Gradient ******************/ 136 | __device__ void setLaplaciangrad (const float * grad_laplacian, float *grad_verts, int v_id1, int v_id2){ 137 | 138 | atomicAdd(&grad_verts[3 * v_id1], - 1 * grad_laplacian[3 * v_id1]); 139 | atomicAdd(&grad_verts[3 * v_id1+1], - 1 * grad_laplacian[3 * v_id1+1]); 140 | atomicAdd(&grad_verts[3 * v_id1+2], - 1 * grad_laplacian[3 * v_id1+2]); 141 | 142 | atomicAdd(&grad_verts[3 * v_id2], grad_laplacian[3 * v_id1]); 143 | atomicAdd(&grad_verts[3 * v_id2+1], grad_laplacian[3 * v_id1+1]); 144 | atomicAdd(&grad_verts[3 * v_id2+2], grad_laplacian[3 * v_id1+2]); 145 | } 146 | 147 | 148 | __global__ void MeshLaplacianGradKernel(const int b, const int maxnverts, const int *nverts, const int * nb, const float * grad_laplacian, float* grad_verts){ 149 | for (int i=blockIdx.x;i>>(b, maxnverts, nverts, nb, grad_laplacian, grad_verts); 179 | AvgGradKernel<<>>(b, maxnverts, grad_verts, count); 180 | } 181 | 182 | #endif 183 | 184 | -------------------------------------------------------------------------------- /models/tf_ops/mesh_sampling/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laughtervv/3DN/81e3651d780478139c3b8dee5e737ce565813900/models/tf_ops/mesh_sampling/__init__.py -------------------------------------------------------------------------------- /models/tf_ops/mesh_sampling/tf_meshsampling.h: -------------------------------------------------------------------------------- 1 | #ifndef TF_MESHSAMPLING_H_ 2 | #define TF_MESHSAMPLING_H_ 3 | 4 | 5 | void randomPointTriangle (float a1, float a2, float a3, float b1, float b2, float b3, float c1, float c2, float c3, 6 | float r1, float r2, float p[3]) 7 | { 8 | float r1sqr = std::sqrt (r1); 9 | float OneMinR1Sqr = (1 - r1sqr); 10 | float OneMinR2 = (1 - r2); 11 | a1 *= OneMinR1Sqr; 12 | a2 *= OneMinR1Sqr; 13 | a3 *= OneMinR1Sqr; 14 | b1 *= OneMinR2; 15 | b2 *= OneMinR2; 16 | b3 *= OneMinR2; 17 | c1 = r1sqr * (r2 * c1 + b1) + a1; 18 | c2 = r1sqr * (r2 * c2 + b2) + a2; 19 | c3 = r1sqr * (r2 * c3 + b3) + a3; 20 | p[0] = c1; 21 | p[1] = c2; 22 | p[2] = c3; 23 | } 24 | 25 | #endif// TF_MESHSAMPLING_H_ -------------------------------------------------------------------------------- /models/tf_ops/mesh_sampling/tf_meshsampling_compile.sh: -------------------------------------------------------------------------------- 1 | /usr/local/cuda/bin/nvcc tf_meshsampling_g.cu -o tf_meshsampling_g.cu.o -c -O2 -DGOOGLE_CUDA=1 -x cu -Xcompiler -fPIC 2 | g++ -std=c++11 tf_meshsampling.cpp tf_meshsampling_g.cu.o -o tf_meshsampling_so.so -shared -fPIC -I /usr/local/lib/python2.7/dist-packages/tensorflow/include -I /usr/local/cuda/include -I /usr/local/lib/python2.7/dist-packages/tensorflow/include/external/nsync/public -lcudart -L /usr/local/cuda/lib64/ -L/usr/local/lib/python2.7/dist-packages/tensorflow -ltensorflow_framework -O2 -D_GLIBCXX_USE_CXX11_ABI=0 3 | 4 | -------------------------------------------------------------------------------- /models/tf_ops/nn_distance/README.md: -------------------------------------------------------------------------------- 1 | From https://github.com/fanhqme/PointSetGeneration/tree/master/depthestimate 2 | -------------------------------------------------------------------------------- /models/tf_ops/nn_distance/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laughtervv/3DN/81e3651d780478139c3b8dee5e737ce565813900/models/tf_ops/nn_distance/__init__.py -------------------------------------------------------------------------------- /models/tf_ops/nn_distance/tf_nndistance.py: -------------------------------------------------------------------------------- 1 | """ Compute Chamfer's Distance. 2 | 3 | Original author: Haoqiang Fan. 4 | Modified by Charles R. Qi 5 | """ 6 | 7 | import tensorflow as tf 8 | from tensorflow.python.framework import ops 9 | import sys 10 | import os 11 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 12 | nn_distance_module=tf.load_op_library(os.path.join(BASE_DIR, 'tf_nndistance_so.so')) 13 | 14 | def nn_distance(xyz1,xyz2): 15 | ''' 16 | Computes the distance of nearest neighbors for a pair of point clouds 17 | input: xyz1: (batch_size,#points_1,3) the first point cloud 18 | input: xyz2: (batch_size,#points_2,3) the second point cloud 19 | output: dist1: (batch_size,#point_1) distance from first to second 20 | output: idx1: (batch_size,#point_1) nearest neighbor from first to second 21 | output: dist2: (batch_size,#point_2) distance from second to first 22 | output: idx2: (batch_size,#point_2) nearest neighbor from second to first 23 | ''' 24 | return nn_distance_module.nn_distance(xyz1,xyz2) 25 | #@tf.RegisterShape('NnDistance') 26 | #def _nn_distance_shape(op): 27 | #shape1=op.inputs[0].get_shape().with_rank(3) 28 | #shape2=op.inputs[1].get_shape().with_rank(3) 29 | #return [tf.TensorShape([shape1.dims[0],shape1.dims[1]]),tf.TensorShape([shape1.dims[0],shape1.dims[1]]), 30 | #tf.TensorShape([shape2.dims[0],shape2.dims[1]]),tf.TensorShape([shape2.dims[0],shape2.dims[1]])] 31 | @ops.RegisterGradient('NnDistance') 32 | def _nn_distance_grad(op,grad_dist1,grad_idx1,grad_dist2,grad_idx2): 33 | xyz1=op.inputs[0] 34 | xyz2=op.inputs[1] 35 | idx1=op.outputs[1] 36 | idx2=op.outputs[3] 37 | return nn_distance_module.nn_distance_grad(xyz1,xyz2,grad_dist1,idx1,grad_dist2,idx2) 38 | 39 | 40 | if __name__=='__main__': 41 | import numpy as np 42 | import random 43 | import time 44 | from tensorflow.python.ops.gradient_checker import compute_gradient 45 | random.seed(100) 46 | np.random.seed(100) 47 | with tf.Session('') as sess: 48 | xyz1=np.random.randn(32,16384,3).astype('float32') 49 | xyz2=np.random.randn(32,1024,3).astype('float32') 50 | #with tf.device('/gpu:0'): 51 | if True: 52 | inp1=tf.Variable(xyz1) 53 | inp2=tf.constant(xyz2) 54 | reta,retb,retc,retd=nn_distance(inp1,inp2) 55 | loss=tf.reduce_sum(reta)+tf.reduce_sum(retc) 56 | train=tf.train.GradientDescentOptimizer(learning_rate=0.05).minimize(loss) 57 | sess.run(tf.initialize_all_variables()) 58 | t0=time.time() 59 | t1=t0 60 | best=1e100 61 | for i in xrange(100): 62 | trainloss,_=sess.run([loss,train]) 63 | newt=time.time() 64 | best=min(best,newt-t1) 65 | print (i,trainloss,(newt-t0)/(i+1),best) 66 | t1=newt 67 | #print sess.run([inp1,retb,inp2,retd]) 68 | #grads=compute_gradient([inp1,inp2],[(16,32,3),(16,32,3)],loss,(1,),[xyz1,xyz2]) 69 | #for i,j in grads: 70 | #print i.shape,j.shape,np.mean(np.abs(i-j)),np.mean(np.abs(i)),np.mean(np.abs(j)) 71 | #for i in xrange(10): 72 | #t0=time.time() 73 | #a,b,c,d=sess.run([reta,retb,retc,retd],feed_dict={inp1:xyz1,inp2:xyz2}) 74 | #print 'time',time.time()-t0 75 | #print a.shape,b.shape,c.shape,d.shape 76 | #print a.dtype,b.dtype,c.dtype,d.dtype 77 | #samples=np.array(random.sample(range(xyz2.shape[1]),100),dtype='int32') 78 | #dist1=((xyz1[:,samples,None,:]-xyz2[:,None,:,:])**2).sum(axis=-1).min(axis=-1) 79 | #idx1=((xyz1[:,samples,None,:]-xyz2[:,None,:,:])**2).sum(axis=-1).argmin(axis=-1) 80 | #print np.abs(dist1-a[:,samples]).max() 81 | #print np.abs(idx1-b[:,samples]).max() 82 | #dist2=((xyz2[:,samples,None,:]-xyz1[:,None,:,:])**2).sum(axis=-1).min(axis=-1) 83 | #idx2=((xyz2[:,samples,None,:]-xyz1[:,None,:,:])**2).sum(axis=-1).argmin(axis=-1) 84 | #print np.abs(dist2-c[:,samples]).max() 85 | #print np.abs(idx2-d[:,samples]).max() 86 | 87 | 88 | -------------------------------------------------------------------------------- /models/tf_ops/nn_distance/tf_nndistance_compile.sh: -------------------------------------------------------------------------------- 1 | /usr/local/cuda/bin/nvcc tf_nndistance_g.cu -o tf_nndistance_g.cu.o -c -O2 -DGOOGLE_CUDA=1 -x cu -Xcompiler -fPIC 2 | g++ -std=c++11 tf_nndistance.cpp tf_nndistance_g.cu.o -o tf_nndistance_so.so -shared -fPIC -I /usr/local/lib/python2.7/dist-packages/tensorflow/include -I /usr/local/cuda/include -I /usr/local/lib/python2.7/dist-packages/tensorflow/include/external/nsync/public -lcudart -L /usr/local/cuda/lib64/ -L/usr/local/lib/python2.7/dist-packages/tensorflow -ltensorflow_framework -O2 -D_GLIBCXX_USE_CXX11_ABI=0 3 | 4 | -------------------------------------------------------------------------------- /models/tf_ops/nn_distance/tf_nndistance_cpu.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | 4 | def nn_distance_cpu(pc1, pc2): 5 | ''' 6 | Input: 7 | pc1: float TF tensor in shape (B,N,C) the first point cloud 8 | pc2: float TF tensor in shape (B,M,C) the second point cloud 9 | Output: 10 | dist1: float TF tensor in shape (B,N) distance from first to second 11 | idx1: int32 TF tensor in shape (B,N) nearest neighbor from first to second 12 | dist2: float TF tensor in shape (B,M) distance from second to first 13 | idx2: int32 TF tensor in shape (B,M) nearest neighbor from second to first 14 | ''' 15 | N = pc1.get_shape()[1].value 16 | M = pc2.get_shape()[1].value 17 | pc1_expand_tile = tf.tile(tf.expand_dims(pc1,2), [1,1,M,1]) 18 | pc2_expand_tile = tf.tile(tf.expand_dims(pc2,1), [1,N,1,1]) 19 | pc_diff = pc1_expand_tile - pc2_expand_tile # B,N,M,C 20 | pc_dist = tf.reduce_sum(pc_diff ** 2, axis=-1) # B,N,M 21 | dist1 = tf.reduce_min(pc_dist, axis=2) # B,N 22 | idx1 = tf.argmin(pc_dist, axis=2) # B,N 23 | dist2 = tf.reduce_min(pc_dist, axis=1) # B,M 24 | idx2 = tf.argmin(pc_dist, axis=1) # B,M 25 | return dist1, idx1, dist2, idx2 26 | 27 | 28 | def verify_nn_distance_cup(): 29 | np.random.seed(0) 30 | sess = tf.Session() 31 | pc1arr = np.random.random((1,5,3)) 32 | pc2arr = np.random.random((1,6,3)) 33 | pc1 = tf.constant(pc1arr) 34 | pc2 = tf.constant(pc2arr) 35 | dist1, idx1, dist2, idx2 = nn_distance_cpu(pc1, pc2) 36 | print(sess.run(dist1)) 37 | print(sess.run(idx1)) 38 | print(sess.run(dist2)) 39 | print(sess.run(idx2)) 40 | 41 | dist = np.zeros((5,6)) 42 | for i in range(5): 43 | for j in range(6): 44 | dist[i,j] = np.sum((pc1arr[0,i,:] - pc2arr[0,j,:]) ** 2) 45 | print(dist) 46 | 47 | if __name__ == '__main__': 48 | verify_nn_distance_cup() 49 | -------------------------------------------------------------------------------- /models/tf_ops/nn_distance/tf_nndistance_g.cu: -------------------------------------------------------------------------------- 1 | #if GOOGLE_CUDA 2 | #define EIGEN_USE_GPU 3 | //#include "third_party/eigen3/unsupported/Eigen/CXX11/Tensor" 4 | 5 | __global__ void NmDistanceKernel(int b,int n,const float * xyz,int m,const float * xyz2,float * result,int * result_i){ 6 | const int batch=512; 7 | __shared__ float buf[batch*3]; 8 | for (int i=blockIdx.x;ibest){ 120 | result[(i*n+j)]=best; 121 | result_i[(i*n+j)]=best_i; 122 | } 123 | } 124 | __syncthreads(); 125 | } 126 | } 127 | } 128 | void NmDistanceKernelLauncher(int b,int n,const float * xyz,int m,const float * xyz2,float * result,int * result_i,float * result2,int * result2_i){ 129 | NmDistanceKernel<<>>(b,n,xyz,m,xyz2,result,result_i); 130 | NmDistanceKernel<<>>(b,m,xyz2,n,xyz,result2,result2_i); 131 | } 132 | __global__ void NmDistanceGradKernel(int b,int n,const float * xyz1,int m,const float * xyz2,const float * grad_dist1,const int * idx1,float * grad_xyz1,float * grad_xyz2){ 133 | for (int i=blockIdx.x;i>>(b,n,xyz1,m,xyz2,grad_dist1,idx1,grad_xyz1,grad_xyz2); 156 | NmDistanceGradKernel<<>>(b,m,xyz2,n,xyz1,grad_dist2,idx2,grad_xyz2,grad_xyz1); 157 | } 158 | 159 | #endif 160 | 161 | -------------------------------------------------------------------------------- /models/tf_ops/sampling/tf_sampling.py: -------------------------------------------------------------------------------- 1 | ''' Furthest point sampling 2 | Original author: Haoqiang Fan 3 | Modified by Charles R. Qi 4 | All Rights Reserved. 2017. 5 | ''' 6 | import tensorflow as tf 7 | from tensorflow.python.framework import ops 8 | import sys 9 | import os 10 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 11 | sys.path.append(BASE_DIR) 12 | sampling_module=tf.load_op_library(os.path.join(BASE_DIR, 'tf_sampling_so.so')) 13 | def prob_sample(inp,inpr): 14 | ''' 15 | input: 16 | batch_size * ncategory float32 17 | batch_size * npoints float32 18 | returns: 19 | batch_size * npoints int32 20 | ''' 21 | return sampling_module.prob_sample(inp,inpr) 22 | ops.NoGradient('ProbSample') 23 | # TF1.0 API requires set shape in C++ 24 | #@tf.RegisterShape('ProbSample') 25 | #def _prob_sample_shape(op): 26 | # shape1=op.inputs[0].get_shape().with_rank(2) 27 | # shape2=op.inputs[1].get_shape().with_rank(2) 28 | # return [tf.TensorShape([shape2.dims[0],shape2.dims[1]])] 29 | def gather_point(inp,idx): 30 | ''' 31 | input: 32 | batch_size * ndataset * 3 float32 33 | batch_size * npoints int32 34 | returns: 35 | batch_size * npoints * 3 float32 36 | ''' 37 | return sampling_module.gather_point(inp,idx) 38 | #@tf.RegisterShape('GatherPoint') 39 | #def _gather_point_shape(op): 40 | # shape1=op.inputs[0].get_shape().with_rank(3) 41 | # shape2=op.inputs[1].get_shape().with_rank(2) 42 | # return [tf.TensorShape([shape1.dims[0],shape2.dims[1],shape1.dims[2]])] 43 | @tf.RegisterGradient('GatherPoint') 44 | def _gather_point_grad(op,out_g): 45 | inp=op.inputs[0] 46 | idx=op.inputs[1] 47 | return [sampling_module.gather_point_grad(inp,idx,out_g),None] 48 | def farthest_point_sample(npoint,inp): 49 | ''' 50 | input: 51 | int32 52 | batch_size * ndataset * 3 float32 53 | returns: 54 | batch_size * npoint int32 55 | ''' 56 | return sampling_module.farthest_point_sample(inp, npoint) 57 | ops.NoGradient('FarthestPointSample') 58 | 59 | 60 | if __name__=='__main__': 61 | import numpy as np 62 | np.random.seed(100) 63 | triangles=np.random.rand(1,5,3,3).astype('float32') 64 | with tf.device('/gpu:1'): 65 | inp=tf.constant(triangles) 66 | tria=inp[:,:,0,:] 67 | trib=inp[:,:,1,:] 68 | tric=inp[:,:,2,:] 69 | areas=tf.sqrt(tf.reduce_sum(tf.cross(trib-tria,tric-tria)**2,2)+1e-9) 70 | randomnumbers=tf.random_uniform((1,8192)) 71 | triids=prob_sample(areas,randomnumbers) 72 | tria_sample=gather_point(tria,triids) 73 | trib_sample=gather_point(trib,triids) 74 | tric_sample=gather_point(tric,triids) 75 | us=tf.random_uniform((1,8192)) 76 | vs=tf.random_uniform((1,8192)) 77 | uplusv=1-tf.abs(us+vs-1) 78 | uminusv=us-vs 79 | us=(uplusv+uminusv)*0.5 80 | vs=(uplusv-uminusv)*0.5 81 | pt_sample=tria_sample+(trib_sample-tria_sample)*tf.expand_dims(us,-1)+(tric_sample-tria_sample)*tf.expand_dims(vs,-1) 82 | print 'pt_sample: ', pt_sample 83 | reduced_sample=gather_point(pt_sample,farthest_point_sample(1024,pt_sample)) 84 | print reduced_sample 85 | with tf.Session('') as sess: 86 | ret=sess.run(reduced_sample) 87 | print ret.shape,ret.dtype 88 | import cPickle as pickle 89 | pickle.dump(ret,open('1.pkl','wb'),-1) 90 | -------------------------------------------------------------------------------- /models/tf_ops/sampling/tf_sampling_compile.sh: -------------------------------------------------------------------------------- 1 | #/bin/bash 2 | /usr/local/cuda/bin/nvcc tf_sampling_g.cu -o tf_sampling_g.cu.o -c -O2 -DGOOGLE_CUDA=1 -x cu -Xcompiler -fPIC 3 | 4 | # TF1.2 5 | #g++ -std=c++11 tf_sampling.cpp tf_sampling_g.cu.o -o tf_sampling_so.so -shared -fPIC -I /usr/local/lib/python2.7/dist-packages/tensorflow/include -I /usr/local/cuda-8.0/include -lcudart -L /usr/local/cuda-8.0/lib64/ -O2 -D_GLIBCXX_USE_CXX11_ABI=0 6 | 7 | # TF1.4 8 | g++ -std=c++11 tf_sampling.cpp tf_sampling_g.cu.o -o tf_sampling_so.so -shared -fPIC -I /usr/local/lib/python2.7/dist-packages/tensorflow/include -I /usr/local/cuda/include -I /usr/local/lib/python2.7/dist-packages/tensorflow/include/external/nsync/public -lcudart -L /usr/local/cuda/lib64/ -L/usr/local/lib/python2.7/dist-packages/tensorflow -ltensorflow_framework -O2 -D_GLIBCXX_USE_CXX11_ABI=0 9 | -------------------------------------------------------------------------------- /models/tf_ops/sampling/tf_sampling_g.cu: -------------------------------------------------------------------------------- 1 | /* Furthest point sampling GPU implementation 2 | * Original author: Haoqiang Fan 3 | * Modified by Charles R. Qi 4 | * All Rights Reserved. 2017. 5 | */ 6 | 7 | __global__ void cumsumKernel(int b,int n,const float * __restrict__ inp,float * __restrict__ out){ 8 | const int BlockSize=2048; 9 | const int paddingLevel=5; 10 | __shared__ float buffer4[BlockSize*4]; 11 | __shared__ float buffer[BlockSize+(BlockSize>>paddingLevel)]; 12 | for (int i=blockIdx.x;i>2; 18 | for (int k=threadIdx.x*4;k>2)+(k>>(2+paddingLevel))]=v4; 33 | }else{ 34 | float v=0; 35 | for (int k2=k;k2>2)+(k>>(2+paddingLevel))]=v; 43 | } 44 | } 45 | int u=0; 46 | for (;(2<>(u+1));k+=blockDim.x){ 49 | int i1=(((k<<1)+2)<>paddingLevel; 52 | i2+=i2>>paddingLevel; 53 | buffer[i1]+=buffer[i2]; 54 | } 55 | } 56 | u--; 57 | for (;u>=0;u--){ 58 | __syncthreads(); 59 | for (int k=threadIdx.x;k>(u+1));k+=blockDim.x){ 60 | int i1=(((k<<1)+3)<>paddingLevel; 63 | i2+=i2>>paddingLevel; 64 | buffer[i1]+=buffer[i2]; 65 | } 66 | } 67 | __syncthreads(); 68 | for (int k=threadIdx.x*4;k>2)-1)+(((k>>2)-1)>>paddingLevel); 71 | buffer4[k]+=buffer[k2]; 72 | buffer4[k+1]+=buffer[k2]; 73 | buffer4[k+2]+=buffer[k2]; 74 | buffer4[k+3]+=buffer[k2]; 75 | } 76 | } 77 | __syncthreads(); 78 | for (int k=threadIdx.x;k>paddingLevel)]+runningsum2; 82 | float r2=runningsum+t; 83 | runningsum2=t-(r2-runningsum); 84 | runningsum=r2; 85 | __syncthreads(); 86 | } 87 | } 88 | } 89 | 90 | __global__ void binarysearchKernel(int b,int n,int m,const float * __restrict__ dataset,const float * __restrict__ query, int * __restrict__ result){ 91 | int base=1; 92 | while (base=1;k>>=1) 99 | if (r>=k && dataset[i*n+r-k]>=q) 100 | r-=k; 101 | result[i*m+j]=r; 102 | } 103 | } 104 | } 105 | __global__ void farthestpointsamplingKernel(int b,int n,int m,const float * __restrict__ dataset,float * __restrict__ temp,int * __restrict__ idxs){ 106 | if (m<=0) 107 | return; 108 | const int BlockSize=512; 109 | __shared__ float dists[BlockSize]; 110 | __shared__ int dists_i[BlockSize]; 111 | const int BufferSize=3072; 112 | __shared__ float buf[BufferSize*3]; 113 | for (int i=blockIdx.x;ibest){ 147 | best=d2; 148 | besti=k; 149 | } 150 | } 151 | dists[threadIdx.x]=best; 152 | dists_i[threadIdx.x]=besti; 153 | for (int u=0;(1<>(u+1))){ 156 | int i1=(threadIdx.x*2)<>>(b,n,inp,out); 196 | } 197 | //require b*n working space 198 | void probsampleLauncher(int b,int n,int m,const float * inp_p,const float * inp_r,float * temp,int * out){ 199 | cumsumKernel<<<32,512>>>(b,n,inp_p,temp); 200 | binarysearchKernel<<>>(b,n,m,temp,inp_r,out); 201 | } 202 | //require 32*n working space 203 | void farthestpointsamplingLauncher(int b,int n,int m,const float * inp,float * temp,int * out){ 204 | farthestpointsamplingKernel<<<32,512>>>(b,n,m,inp,temp,out); 205 | } 206 | void gatherpointLauncher(int b,int n,int m,const float * inp,const int * idx,float * out){ 207 | gatherpointKernel<<>>(b,n,m,inp,idx,out); 208 | } 209 | void scatteraddpointLauncher(int b,int n,int m,const float * out_g,const int * idx,float * inp_g){ 210 | scatteraddpointKernel<<>>(b,n,m,out_g,idx,inp_g); 211 | } 212 | 213 | -------------------------------------------------------------------------------- /models/tf_ops/test.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import tensorflow as tf 3 | import approxmatch.tf_approxmatch as tf_approxmatch 4 | import nn_distance.tf_nndistance as tf_nndistance 5 | import mesh_sampling.tf_meshsampling as tf_meshsampling 6 | import mesh_laplacian.tf_meshlaplacian as tf_meshlaplacian 7 | import os 8 | import sys 9 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 10 | ROOT_DIR = os.path.dirname(BASE_DIR) 11 | sys.path.append(os.path.join(ROOT_DIR)) 12 | import tf_util 13 | 14 | if __name__=='__main__': 15 | import numpy as np 16 | import random 17 | import time 18 | from tensorflow.python.ops.gradient_checker import compute_gradient 19 | random.seed(100) 20 | np.random.seed(100) 21 | 22 | 23 | def write_off(fn, verts, faces): 24 | file = open(fn, 'w') 25 | file.write('OFF\n') 26 | file.write('%d %d %d\n' % (len(verts), len(faces), 0)) 27 | for vert in verts: 28 | file.write('%f %f %f\n' % (vert[0], vert[1], vert[2])) 29 | # verts.append([float(s) for s in readline().strip().split(' ')]) 30 | for face in faces: 31 | file.write('3 %f %f %f\n' % (face[0], face[1], face[2])) 32 | # faces.append([int(s) for s in readline().strip().split(' ')][1:]) 33 | file.close() 34 | return 35 | 36 | def read_off(fn): 37 | file = open(fn, 'r') 38 | if 'OFF' != file.readline().strip(): 39 | print ('Not a valid OFF header') 40 | return 41 | n_verts, n_faces, n_dontknow = tuple([int(s) for s in file.readline().strip().split(' ')]) 42 | verts = [] 43 | for i_vert in range(n_verts): 44 | verts.append([float(s) for s in file.readline().strip().split(' ')]) 45 | faces = [] 46 | for i_face in range(n_faces): 47 | faces.append([int(s) for s in file.readline().strip().split(' ')][1:]) 48 | file.close() 49 | return np.asarray(verts,dtype=np.float32), np.asarray(faces, dtype=np.int32) 50 | 51 | 52 | test1 = False 53 | test2 = True 54 | 55 | with tf.Session('') as sess: 56 | # xyz1=np.random.randn(32,16384,3).astype('float32') 57 | # xyz2=np.random.randn(32,1024,3).astype('float32') 58 | src_vertices, src_faces = read_off('1bf710535121b17cf453cc5da9731a22.off') 59 | dst_vertices, dst_faces = read_off('/mnt/ilcompf8d0/user/weiyuewa/dataset/shapenet/part_mesh/Models/Chair/1bcec47c5dc259ea95ca4adb70946a21.off') 60 | 61 | 62 | np.random.seed(int(time.time())) 63 | # r1 = tf.constant(np.random.random_sample((1, 40000)),dtype=tf.float32) 64 | # r2 = tf.constant(np.random.random_sample((1, 40000)),dtype=tf.float32) 65 | # r = tf.constant(np.random.random_sample((1, 40000)),dtype=tf.float32) 66 | r1 = tf.random_uniform([1, 40000],dtype=tf.float32) 67 | r2 = tf.random_uniform([1, 40000],dtype=tf.float32) 68 | r = tf.random_uniform([1, 40000],dtype=tf.float32) 69 | 70 | 71 | ##target 72 | dst_verts=tf.expand_dims(tf.constant(dst_vertices),0) 73 | dst_tris=tf.expand_dims(tf.constant(dst_faces),0) 74 | dst_feats=tf.expand_dims(tf.constant(dst_vertices),0) 75 | dst_nverts = tf.constant([[len(dst_vertices)]],dtype=tf.int32) 76 | dst_ntris = tf.constant([[len(dst_faces)]],dtype=tf.int32) 77 | dst_points, outfeats, correspondingfaces = tf_meshsampling.mesh_sampling(dst_verts, dst_nverts, dst_tris, dst_ntris, dst_feats, r, r1, r2) 78 | dst_points_val, dst_verts_val = sess.run([dst_points, dst_verts]) 79 | np.savetxt('dst_points.xyz', np.squeeze(dst_points_val)) 80 | 81 | # dst_points_val = np.concatenate((dst_points_val, dst_verts_val), axis =1) 82 | targetpoints = tf.constant(dst_points_val) 83 | 84 | ##source 85 | src_verts=tf.expand_dims(tf.constant(src_vertices),0) 86 | src_tris=tf.expand_dims(tf.constant(src_faces),0) 87 | src_feats=tf.expand_dims(tf.constant(src_vertices),0) 88 | src_nverts = tf.constant([[len(src_vertices)]],dtype=tf.int32) 89 | src_ntris = tf.constant([[len(src_faces)]],dtype=tf.int32) 90 | src_points, outfeats, correspondingfaces = tf_meshsampling.mesh_sampling(src_verts, src_nverts, src_tris, src_ntris, src_feats, r, r1, r2) 91 | src_points_val, src_verts_val = sess.run([src_points, src_verts]) 92 | np.savetxt('src_points.xyz', np.squeeze(src_points_val)) 93 | 94 | # src_feats = tf.concat([src_feats]*100, axis=2) 95 | feats = tf.Variable(src_feats) 96 | print src_feats.get_shape() 97 | points, outfeats, correspondingfaces = tf_meshsampling.mesh_sampling(src_verts, src_nverts, src_tris, src_ntris, feats, r, r1, r2) 98 | laplacian1, _, _ = tf_meshlaplacian.mesh_laplacian(src_verts, src_nverts, src_tris, src_ntris) 99 | # feats1 = tf.slice(feats, [0, 0, 0], [1, -1, 3]) 100 | laplacian2, _, _ = tf_meshlaplacian.mesh_laplacian(feats, src_nverts, src_tris, src_ntris) 101 | laplacian_loss = 10*tf.nn.l2_loss(laplacian1 - laplacian2) 102 | # outfeats = tf.concat([outfeats, feats], axis=1) 103 | 104 | #loss 105 | 106 | # outfeats = tf.expand_dims(outfeats, 2) 107 | 108 | # Encoder 109 | # net = tf_util.conv2d(outfeats, 3, [1,6], 110 | # padding='VALID', stride=[1,1], 111 | # bn=False, 112 | # scope='conv1') 113 | # net = tf.squeeze(outfeats, 2) 114 | # print net.get_shape() 115 | outfeats = tf.slice(outfeats, [0, 0, 0], [1, -1, 3]) 116 | dists_forward, _, dists_backward, _ = tf_nndistance.nn_distance(outfeats, targetpoints) 117 | loss = 10000*tf.reduce_mean(dists_forward) + 10000*tf.reduce_mean(dists_backward)+laplacian_loss 118 | 119 | feats_grad = tf.gradients(loss, [feats])[0] 120 | # 121 | train=tf.train.GradientDescentOptimizer(learning_rate=0.05).minimize(loss) 122 | 123 | sess.run(tf.initialize_all_variables()) 124 | # 125 | old_lossval = 10000 126 | for i in range(100): 127 | # feed_dict = {feats_ph: feats_val} 128 | _, loss_val, feats_val, points_val, dst_points_val, outfeats_val, feats_grad_val,correspondingfaces_val2,r_val =sess.run([train, loss, feats, points, targetpoints, outfeats, feats_grad, correspondingfaces,r])#, feed_dict=feed_dict) 129 | # print feats_val 130 | # feats_val -= feats_grad_val*0.005 131 | # if loss_val= self.data_num: 63 | i = 0 64 | 65 | if tgt_single_mesh == None or src_single_mesh == None: 66 | continue 67 | 68 | src_verts, src_tris = src_single_mesh 69 | tgt_verts, tgt_tris = tgt_single_mesh 70 | 71 | src_batch_verts[cnt,:len(src_verts),:] = src_verts 72 | src_batch_tris[cnt,:len(src_tris),:] = src_tris 73 | src_batch_nverts[cnt, 0] = len(src_verts) 74 | src_batch_ntris[cnt, 0] = len(src_tris) 75 | tgt_batch_verts[cnt,:len(tgt_verts),:] = tgt_verts 76 | tgt_batch_tris[cnt,:len(tgt_tris),:] = tgt_tris 77 | tgt_batch_nverts[cnt, 0] = len(tgt_verts) 78 | tgt_batch_ntris[cnt, 0] = len(tgt_tris) 79 | 80 | cnt += 1 81 | 82 | src_batch_data = {} 83 | src_batch_data['verts'] = src_batch_verts 84 | src_batch_data['nverts'] = src_batch_nverts 85 | src_batch_data['tris'] = src_batch_tris 86 | src_batch_data['ntris'] = src_batch_ntris 87 | tgt_batch_data = {} 88 | tgt_batch_data['verts'] = tgt_batch_verts 89 | tgt_batch_data['nverts'] = tgt_batch_nverts 90 | tgt_batch_data['tris'] = tgt_batch_tris 91 | tgt_batch_data['ntris'] = tgt_batch_ntris 92 | 93 | return src_batch_data, tgt_batch_data 94 | 95 | def pc_normalize(self, pc, centroid=None): 96 | 97 | """ pc: NxC, return NxC """ 98 | l = pc.shape[0] 99 | 100 | if centroid is None: 101 | centroid = np.mean(pc, axis=0) 102 | 103 | pc = pc - centroid 104 | m = np.max(np.sqrt(np.sum(pc ** 2, axis=1))) 105 | 106 | pc = pc / m 107 | 108 | return pc, centroid 109 | 110 | def get_one(self, path, subsamplemesh=False): 111 | if path in self.cache: 112 | return self.cache[path] 113 | else: 114 | try: 115 | h5_f = h5py.File(path) 116 | if (self.maxnverts != -1 and h5_f['verts'].shape[0] > self.maxnverts) or (self.maxntris != -1 and h5_f['tris'].shape[0] > self.maxntris): 117 | raise Exception() 118 | 119 | verts, tris = h5_f['verts'][:], h5_f['tris'][:] 120 | except: 121 | h5_f.close() 122 | self.cache[path] = None 123 | return None 124 | 125 | if self.normalize: 126 | centroid = None 127 | verts, _ = self.pc_normalize(verts, centroid) 128 | 129 | if subsamplemesh: 130 | mesh = pymesh.form_mesh(verts, tris) 131 | mesh, _ = pymesh.split_long_edges(mesh, 0.05) 132 | verts, tris = mesh.vertices, mesh.faces 133 | if (self.maxnverts != -1 and verts.shape[0] > self.maxnverts) or (self.maxntris != -1 and tris.shape[0] > self.maxntris): 134 | return None 135 | 136 | if len(self.cache) < self.cache_size: 137 | self.cache[path] = (verts, tris) 138 | h5_f.close() 139 | 140 | return verts, tris 141 | 142 | 143 | def __len__(self): 144 | return self.data_num 145 | 146 | if __name__ == '__main__': 147 | MAX_NVERTS = MAX_NTRIS = 5000 148 | d = H5Dataset('/media/hdd2/data/ShapeNet/filelists/ShapeNetCore.v2.h5/03001627_obj_5000.lst', maxnverts=MAX_NVERTS, maxntris=MAX_NTRIS) 149 | 150 | batch_size = 20 151 | tic = time.time() 152 | for i in range(10): 153 | i = i * batch_size 154 | batch = d.get_batch(i) 155 | print (time.time() - tic) 156 | 157 | 158 | 159 | -------------------------------------------------------------------------------- /shapenet/data/data_img.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Dataset for shapenet part segmentaion. 3 | ''' 4 | 5 | import os 6 | import json 7 | import numpy as np 8 | import sys 9 | import time 10 | import random 11 | from PIL import Image 12 | import tensorflow as tf 13 | import numpy as np 14 | import h5py 15 | import cv2 16 | 17 | 18 | def pc_normalize(pc): 19 | """ pc: NxC, return NxC """ 20 | l = pc.shape[0] 21 | centroid = np.mean(pc, axis=0) 22 | pc = pc - centroid 23 | m = np.max(np.sqrt(np.sum(pc ** 2, axis=1))) 24 | pc = pc / m 25 | centroid = np.mean(pc, axis=0) 26 | pc = pc - centroid 27 | return pc 28 | 29 | 30 | def rotate_point_cloud(batch_data): 31 | """ Randomly rotate the point clouds to augument the dataset 32 | rotation is per shape based along up direction 33 | Input: 34 | BxNx3 array, original batch of point clouds 35 | Return: 36 | BxNx3 array, rotated batch of point clouds 37 | """ 38 | rotated_data = np.zeros(batch_data.shape, dtype=np.float32) 39 | for k in np.arange(batch_data.shape[0]): 40 | rotation_angle = np.random.uniform() * 2 * np.pi 41 | cosval = np.cos(rotation_angle) 42 | sinval = np.sin(rotation_angle) 43 | rotation_matrix = np.array([[cosval, 0, sinval], 44 | [0, 1, 0], 45 | [-sinval, 0, cosval]]) 46 | shape_pc = batch_data[k, ...] 47 | rotated_data[k, ...] = np.dot(shape_pc.reshape((-1, 3)), rotation_matrix) 48 | return rotated_data 49 | 50 | class ImgDataset_test(): 51 | def __init__(self, listfile): 52 | 53 | self.inputlistfile = listfile 54 | 55 | if isinstance(self.inputlistfile, str): 56 | with open(self.inputlistfile, 'r') as f: 57 | lines = f.read().splitlines() 58 | self.datapath = [line.strip() for line in lines] 59 | else: 60 | self.datapath = listfile 61 | 62 | self.order = list(range(len(self.datapath))) 63 | 64 | def __getitem__(self, index): 65 | 66 | batch_img = np.ones([1, 600, 600, 3], dtype=np.float32) 67 | img = Image.open(self.datapath[index])# 68 | 69 | if img.size[0] > img.size[1]: 70 | img.thumbnail((400, int(400.*img.size[0]/img.size[1])), Image.ANTIALIAS) 71 | else: 72 | img.thumbnail((int(400.*img.size[1]/img.size[0]), 400), Image.ANTIALIAS) 73 | 74 | img = np.asarray(img, dtype=np.float32) 75 | print(img.shape) 76 | if len(img.shape) == 2: 77 | img = np.transpose(np.asarray([img,img,img]), (1,2,0)) 78 | 79 | if img.shape[2] == 4: 80 | mask = img[:,:,3] 81 | img = img[:,:,:3] / 255. 82 | img[mask==0,:] = 1. 83 | else: 84 | img /= 255. 85 | offsetx = int((600. - img.shape[0]) / 2) 86 | offsety = int((600. - img.shape[1]) / 2) 87 | batch_img[:,offsetx:offsetx+img.shape[0],offsety:offsety+img.shape[1], :] = img 88 | 89 | return batch_img 90 | 91 | 92 | def __len__(self): 93 | return len(self.datapath) 94 | 95 | 96 | if __name__ == '__main__': 97 | path = '/mnt/ilcompf8d0/user/weiyuewa/dataset/shapenet/ShapeNetCore.v2.render_img/03001627/a06c400e070343cfd8a56a98f4d239c3/image/r_000.png' 98 | img = np.asarray(Image.open(path), dtype=np.float32) 99 | mask = img[:,:,3] 100 | img = img[:,:,:3] / 255. 101 | img[mask==0,:] = 1. 102 | cv2.imwrite('tmp.png', (img * 255).astype(np.uint8)) 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /shapenet/data/data_obj.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Dataset for shapenet part segmentaion. 3 | ''' 4 | 5 | import os 6 | import os.path 7 | import json 8 | import numpy as np 9 | import sys 10 | import tensorflow as tf 11 | import numpy as np 12 | import obj 13 | 14 | 15 | def pc_normalize(pc): 16 | """ pc: NxC, return NxC """ 17 | l = pc.shape[0] 18 | centroid = np.mean(pc, axis=0) 19 | pc = pc - centroid 20 | m = np.max(np.sqrt(np.sum(pc ** 2, axis=1))) 21 | pc = pc / m 22 | centroid = np.mean(pc, axis=0) 23 | pc = pc - centroid 24 | return pc 25 | 26 | def write_obj(filepath, verts, tris): 27 | with open(filepath, 'w') as f: 28 | f.write("# OBJ file\n") 29 | for v in verts: 30 | f.write("v %.4f %.4f %.4f\n" % (v[0], v[1], v[2])) 31 | for p in tris: 32 | f.write("f") 33 | for i in p: 34 | f.write(" %d" % (i + 1)) 35 | f.write("\n") 36 | 37 | def rotate_point_cloud(batch_data): 38 | """ Randomly rotate the point clouds to augument the dataset 39 | rotation is per shape based along up direction 40 | Input: 41 | BxNx3 array, original batch of point clouds 42 | Return: 43 | BxNx3 array, rotated batch of point clouds 44 | """ 45 | rotated_data = np.zeros(batch_data.shape, dtype=np.float32) 46 | for k in np.arange(batch_data.shape[0]): 47 | rotation_angle = np.random.uniform() * 2 * np.pi 48 | cosval = np.cos(rotation_angle) 49 | sinval = np.sin(rotation_angle) 50 | rotation_matrix = np.array([[cosval, 0, sinval], 51 | [0, 1, 0], 52 | [-sinval, 0, cosval]]) 53 | shape_pc = batch_data[k, ...] 54 | rotated_data[k, ...] = np.dot(shape_pc.reshape((-1, 3)), rotation_matrix) 55 | return rotated_data 56 | 57 | class ObjDataset(): 58 | def __init__(self, listfile, maxnverts=10000, maxntris=10000, normalize = True, texture=0): 59 | self.maxnverts = maxnverts 60 | self.maxntris = maxntris 61 | self.inputlistfile = listfile 62 | self.normalize = normalize 63 | self.texture = texture 64 | 65 | if isinstance(self.inputlistfile, basestring): 66 | with open(self.inputlistfile, 'r') as f: 67 | lines = f.read().splitlines() 68 | self.datapath = [line.strip() for line in lines] 69 | else: 70 | self.datapath = listfile 71 | 72 | self.cache = {} # from index to (point_set, cls, seg) tuple 73 | self.cache_size = 18000 74 | 75 | def __getitem__(self, index): 76 | 77 | if self.texture == 0: 78 | if index in self.cache: 79 | verts, tris = self.cache[index] 80 | else: 81 | obj_fn = self.datapath[index]+'.obj' 82 | try: 83 | loadobj = obj.load_obj(obj_fn, maxnverts=self.maxnverts, maxntris=self.maxntris) 84 | except: 85 | loadobj = None 86 | 87 | if loadobj == None: 88 | if (index + 1) < len(self.datapath): 89 | return self.__getitem__(index+1) 90 | else: 91 | return self.__getitem__(0) 92 | 93 | verts, tris = loadobj 94 | if self.normalize: 95 | verts = pc_normalize(verts) 96 | 97 | if len(self.cache) < self.cache_size: 98 | self.cache[index] = (verts, tris) 99 | 100 | return verts, tris 101 | else: 102 | if index in self.cache: 103 | verts, tris, textures = self.cache[index] 104 | else: 105 | obj_fn = self.datapath[index]+'.obj' 106 | try: 107 | loadobj = obj.load_obj(obj_fn, texture_size=self.texture, load_texture=True, maxnverts=self.maxnverts, maxntris=self.maxntris) 108 | except: 109 | loadobj = None 110 | if loadobj == None: 111 | if (index + 1) < len(self.datapath): 112 | return self.__getitem__(index+1) 113 | else: 114 | return self.__getitem__(0) 115 | 116 | verts, tris, textures = loadobj 117 | if self.normalize: 118 | verts = pc_normalize(verts) 119 | 120 | if len(self.cache) < self.cache_size: 121 | self.cache[index] = (verts, tris, textures) 122 | 123 | return verts, tris, textures 124 | 125 | 126 | def __len__(self): 127 | return len(self.datapath) 128 | 129 | 130 | if __name__ == '__main__': 131 | 132 | d = ObjDataset('/mnt/ilcompf8d0/user/weiyuewa/dataset/shapenet/part_mesh/Models/filelists/chair.lst') 133 | 134 | -------------------------------------------------------------------------------- /shapenet/data/data_pc.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Dataset for shapenet part segmentaion. 3 | ''' 4 | 5 | import os 6 | import os.path 7 | import json 8 | import numpy as np 9 | import sys 10 | import tensorflow as tf 11 | # import matplotlib.pyplot as plt 12 | import numpy as np 13 | # from matplotlib import colors 14 | # from matplotlib.ticker import PercentFormatter 15 | 16 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 17 | ROOT_DIR = os.path.dirname(BASE_DIR) 18 | sys.path.append(os.path.join(ROOT_DIR)) 19 | sys.path.append(os.path.join(ROOT_DIR,'..')) 20 | try: 21 | import models.tf_ops.approxmatch.tf_approxmatch as tf_approxmatch 22 | import models.tf_ops.nn_distance.tf_nndistance as tf_nndistance 23 | import models.tf_ops.mesh_sampling.tf_meshsampling as tf_meshsampling 24 | import models.tf_ops.mesh_laplacian.tf_meshlaplacian as tf_meshlaplacian 25 | except: 26 | import models.tf_ops_server.approxmatch.tf_approxmatch as tf_approxmatch 27 | import models.tf_ops_server.nn_distance.tf_nndistance as tf_nndistance 28 | import models.tf_ops_server.mesh_sampling.tf_meshsampling as tf_meshsampling 29 | import models.tf_ops_server.mesh_laplacian.tf_meshlaplacian as tf_meshlaplacian 30 | 31 | 32 | def pc_normalize(pc): 33 | """ pc: NxC, return NxC """ 34 | l = pc.shape[0] 35 | centroid = np.mean(pc, axis=0) 36 | pc = pc - centroid 37 | m = np.max(np.sqrt(np.sum(pc ** 2, axis=1))) 38 | pc = pc / m 39 | return pc 40 | 41 | 42 | def rotate_point_cloud(batch_data): 43 | """ Randomly rotate the point clouds to augument the dataset 44 | rotation is per shape based along up direction 45 | Input: 46 | BxNx3 array, original batch of point clouds 47 | Return: 48 | BxNx3 array, rotated batch of point clouds 49 | """ 50 | rotated_data = np.zeros(batch_data.shape, dtype=np.float32) 51 | for k in np.arange(batch_data.shape[0]): 52 | rotation_angle = np.random.uniform() * 2 * np.pi 53 | cosval = np.cos(rotation_angle) 54 | sinval = np.sin(rotation_angle) 55 | rotation_matrix = np.array([[cosval, 0, sinval], 56 | [0, 1, 0], 57 | [-sinval, 0, cosval]]) 58 | shape_pc = batch_data[k, ...] 59 | rotated_data[k, ...] = np.dot(shape_pc.reshape((-1, 3)), rotation_matrix) 60 | return rotated_data 61 | 62 | 63 | 64 | class PartPcDataset(): 65 | def __init__(self, listfile, npoints, normalize = True): 66 | self.inputlistfile = listfile 67 | self.normalize = normalize 68 | 69 | with open(self.inputlistfile, 'r') as f: 70 | lines = f.read().splitlines() 71 | self.datapath = [line.strip() for line in lines] 72 | 73 | self.cache = {} # from index to (point_set, cls, seg) tuple 74 | self.cache_size = 18000 75 | self.npoints = npoints 76 | 77 | def __getitem__(self, index): 78 | if index in self.cache: 79 | points, label = self.cache[index] 80 | else: 81 | fn = self.datapath[index]+'.pts' 82 | points = np.loadtxt(fn) 83 | fn_label = self.datapath[index].replace("points", "points_label")+'.seg' 84 | label = np.loadtxt(fn_label) - 1 85 | choice = np.random.choice(len(points), self.npoints, replace=True) 86 | # resample 87 | try: 88 | points = points[choice, :] 89 | label = label[choice] 90 | except: 91 | if (index + 1) < len(self.datapath): 92 | # print 'exceed max nverts', index+1 93 | return self.__getitem__(index+1) 94 | else: 95 | return self.__getitem__(0) 96 | if self.normalize: 97 | points = pc_normalize(points) 98 | 99 | if len(self.cache) < self.cache_size: 100 | self.cache[index] = (points, label) 101 | 102 | return points, label#, index 103 | 104 | def __len__(self): 105 | return len(self.datapath) 106 | -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/laughtervv/3DN/81e3651d780478139c3b8dee5e737ce565813900/utils/__init__.py -------------------------------------------------------------------------------- /utils/output_utils.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import sys 4 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 5 | sys.path.append(os.path.dirname(os.path.abspath(__file__))) # model 6 | import numpy as np 7 | import matplotlib as mpl 8 | import matplotlib.pyplot as plt 9 | mpl.use('Agg') 10 | ############################ 11 | ## Visualize Results ## 12 | ############################ 13 | 14 | color_map = json.load(open(os.path.join(BASE_DIR, 'part_color_mapping.json'), 'r')) 15 | 16 | def output_bounding_box_withcorners(box_corners, seg, out_file): 17 | # ############## 0 1 2 3 4 5 6 7 18 | corner_indexes = [[0, 1, 2], [0, 1, 5], [0, 4, 2], [0, 4, 5], [3, 1, 2], [3, 1, 5], [3, 4, 2], [3, 4, 5]] 19 | line_indexes = [[0, 1], [0, 2], [0, 4], [1, 3], [1, 5], [2, 3], [2, 6], [3, 7], [4, 5], [4, 6], [5, 7], [6, 7]] 20 | with open(out_file, 'w') as f: 21 | l = box_corners.shape[0] 22 | for i in range(l): 23 | box = box_corners[i] 24 | color = color_map[seg[i]] 25 | for line_index in line_indexes: 26 | corner0 = box[line_index[0]] 27 | corner1 = box[line_index[1]] 28 | print corner0.shape 29 | dist = np.linalg.norm(corner0 - corner1) 30 | dot_num = int(dist / 0.005) 31 | delta = (corner1 - corner0) / dot_num 32 | for idot in range(dot_num): 33 | plotdot = corner0 + idot * delta 34 | f.write( 35 | 'v %f %f %f %f %f %f\n' % (plotdot[0], plotdot[1], plotdot[2], color[0], color[1], color[2])) 36 | 37 | 38 | def output_bounding_box(boxes, seg, out_file): 39 | # ############## 0 1 2 3 4 5 6 7 40 | #box:nx8x3 41 | corner_indexes = [[0, 1, 2], [0, 1, 5], [0, 4, 2], [0, 4, 5], [3, 1, 2], [3, 1, 5], [3, 4, 2], [3, 4, 5]] 42 | line_indexes = [[0, 1], [0, 2], [0, 4], [1, 3], [1, 5], [2, 3], [2, 6], [3, 7], [4, 5], [4, 6], [5, 7], [6, 7]] 43 | with open(out_file, 'w') as f: 44 | l = boxes.shape[0] 45 | for i in range(l): 46 | box = boxes[i] 47 | color = color_map[seg[i]] 48 | for line_index in line_indexes: 49 | corner0 = box[corner_indexes[line_index[0]]] 50 | corner1 = box[corner_indexes[line_index[1]]] 51 | dist = np.linalg.norm(corner0 - corner1) 52 | dot_num = int(dist / 0.005) 53 | delta = (corner1 - corner0) / dot_num 54 | for idot in range(dot_num): 55 | plotdot = corner0 + idot * delta 56 | f.write( 57 | 'v %f %f %f %f %f %f\n' % (plotdot[0], plotdot[1], plotdot[2], color[0], color[1], color[2])) 58 | 59 | 60 | def output_color_point_cloud(data, seg, out_file): 61 | with open(out_file, 'w') as f: 62 | l = len(seg) 63 | for i in range(l): 64 | color = color_map[seg[i]] 65 | f.write('v %f %f %f %f %f %f\n' % (data[i][0], data[i][1], data[i][2], color[0], color[1], color[2])) 66 | 67 | 68 | def output_point_cloud_rgb(data, rgb, out_file): 69 | with open(out_file, 'w') as f: 70 | l = len(data) 71 | for i in range(l): 72 | f.write('v %f %f %f %f %f %f\n' % (data[i][0], data[i][1], data[i][2], rgb[i][0], rgb[i][1], rgb[i][2])) 73 | 74 | 75 | def output_color_point_cloud_red_blue(data, seg, out_file): 76 | with open(out_file, 'w') as f: 77 | l = len(seg) 78 | for i in range(l): 79 | if seg[i] == 1: 80 | color = [0, 0, 1] 81 | elif seg[i] == 0: 82 | color = [1, 0, 0] 83 | else: 84 | color = [0, 0, 0] 85 | f.write('v %f %f %f %f %f %f\n' % (data[i][0], data[i][1], data[i][2], color[0], color[1], color[2])) 86 | 87 | 88 | ##define color heat map 89 | norm = mpl.colors.Normalize(vmin=0, vmax=255) 90 | magma_cmap = plt.cm.get_cmap('magma') 91 | magma_rgb = [] 92 | for i in range(0, 255): 93 | k = mpl.colors.colorConverter.to_rgb(magma_cmap(norm(i))) 94 | magma_rgb.append(k) 95 | 96 | 97 | def output_scale_point_cloud(data, scales, out_file): 98 | with open(out_file, 'w') as f: 99 | l = len(scales) 100 | for i in range(l): 101 | scale = int(scales[i]*254) 102 | if scale > 254: 103 | scale = 254 104 | color = magma_rgb[scale] 105 | f.write('v %f %f %f %f %f %f\n' % (data[i][0], data[i][1], data[i][2], color[0], color[1], color[2])) 106 | -------------------------------------------------------------------------------- /utils/part_color_mapping.json: -------------------------------------------------------------------------------- 1 | [[0.57, 0.15, 0.43], [0.85, 0.57, 0.29], [0.7100000000000001, 0.7100000000000001, 0.01], [0.01, 0.7100000000000001, 0.15], [0.01, 0.57, 0.85], [0.43, 0.01, 0.7100000000000001], [0.43, 0.7100000000000001, 0.57], [0.29, 0.29, 0.29], [0.29, 0.7100000000000001, 0.7100000000000001], [0.57, 0.57, 0.29], [0.57, 0.7100000000000001, 0.7100000000000001], [0.01, 0.01, 0.29], [0.29, 0.57, 0.7100000000000001], [0.29, 0.15, 0.57], [0.29, 0.7100000000000001, 0.43], [0.57, 0.29, 0.01], [0.29, 0.15, 0.15], [0.7100000000000001, 0.29, 0.01], [0.01, 0.85, 0.15], [0.85, 0.01, 0.01], [0.29, 0.15, 0.7100000000000001], [0.7100000000000001, 0.15, 0.43], [0.29, 0.43, 0.7100000000000001], [0.43, 0.43, 0.7100000000000001], [0.29, 0.57, 0.01], [0.57, 0.29, 0.29], [0.57, 0.85, 0.15], [0.15, 0.29, 0.29], [0.15, 0.7100000000000001, 0.15], [0.85, 0.01, 0.29], [0.43, 0.85, 0.29], [0.43, 0.29, 0.85], [0.57, 0.85, 0.85], [0.15, 0.57, 0.01], [0.57, 0.29, 0.15], [0.7100000000000001, 0.85, 0.57], [0.57, 0.01, 0.57], [0.01, 0.85, 0.43], [0.01, 0.01, 0.01], [0.85, 0.01, 0.43], [0.57, 0.43, 0.57], [0.85, 0.01, 0.57], [0.01, 0.43, 0.43], [0.01, 0.29, 0.85], [0.57, 0.57, 0.7100000000000001], [0.7100000000000001, 0.29, 0.57], [0.57, 0.7100000000000001, 0.43], [0.29, 0.15, 0.01], [0.57, 0.15, 0.15], [0.85, 0.57, 0.85], [0.85, 0.29, 0.85], [0.85, 0.15, 0.01], [0.85, 0.7100000000000001, 0.01], [0.01, 0.57, 0.15], [0.43, 0.01, 0.43], [0.57, 0.15, 0.85], [0.01, 0.29, 0.57], [0.29, 0.85, 0.43], [0.57, 0.29, 0.43], [0.43, 0.01, 0.29], [0.15, 0.85, 0.7100000000000001], [0.85, 0.57, 0.43], [0.01, 0.15, 0.57], [0.7100000000000001, 0.7100000000000001, 0.29], [0.7100000000000001, 0.15, 0.57], [0.43, 0.43, 0.29], [0.7100000000000001, 0.43, 0.43], [0.01, 0.43, 0.57], [0.57, 0.01, 0.15], [0.57, 0.57, 0.01], [0.29, 0.01, 0.29], [0.7100000000000001, 0.01, 0.29], [0.85, 0.85, 0.7100000000000001], [0.85, 0.15, 0.29], [0.43, 0.29, 0.57], [0.43, 0.43, 0.85], [0.85, 0.15, 0.85], [0.57, 0.85, 0.29], [0.57, 0.7100000000000001, 0.01], [0.7100000000000001, 0.85, 0.15], [0.85, 0.7100000000000001, 0.43], [0.01, 0.15, 0.01], [0.85, 0.29, 0.43], [0.43, 0.85, 0.15], [0.15, 0.01, 0.15], [0.7100000000000001, 0.7100000000000001, 0.85], [0.43, 0.29, 0.01], [0.15, 0.43, 0.29], [0.7100000000000001, 0.57, 0.15], [0.29, 0.85, 0.29], [0.29, 0.7100000000000001, 0.57], [0.57, 0.85, 0.7100000000000001], [0.15, 0.01, 0.85], [0.43, 0.15, 0.57], [0.57, 0.57, 0.15], [0.01, 0.57, 0.01], [0.15, 0.29, 0.57], [0.29, 0.57, 0.43], [0.15, 0.7100000000000001, 0.01], [0.15, 0.15, 0.15], [0.43, 0.29, 0.15], [0.7100000000000001, 0.29, 0.7100000000000001], [0.7100000000000001, 0.85, 0.43], [0.15, 0.29, 0.7100000000000001], [0.15, 0.43, 0.57], [0.01, 0.7100000000000001, 0.01], [0.85, 0.29, 0.01], [0.15, 0.01, 0.57], [0.29, 0.29, 0.7100000000000001], [0.15, 0.7100000000000001, 0.29], [0.01, 0.15, 0.43], [0.7100000000000001, 0.01, 0.15], [0.57, 0.43, 0.01], [0.85, 0.43, 0.01], [0.43, 0.85, 0.7100000000000001], [0.85, 0.43, 0.43], [0.85, 0.01, 0.15], [0.01, 0.43, 0.85], [0.15, 0.15, 0.7100000000000001], [0.29, 0.57, 0.85], [0.43, 0.15, 0.15], [0.29, 0.85, 0.85], [0.15, 0.57, 0.29], [0.85, 0.85, 0.85], [0.29, 0.43, 0.43], [0.01, 0.43, 0.29], [0.43, 0.15, 0.7100000000000001], [0.7100000000000001, 0.01, 0.57], [0.7100000000000001, 0.43, 0.15], [0.01, 0.85, 0.01], [0.85, 0.01, 0.7100000000000001], [0.57, 0.43, 0.43], [0.57, 0.85, 0.01], [0.01, 0.57, 0.43], [0.15, 0.15, 0.01], [0.85, 0.43, 0.85], [0.57, 0.15, 0.29], [0.7100000000000001, 0.7100000000000001, 0.57], [0.57, 0.01, 0.85], [0.29, 0.43, 0.15], [0.7100000000000001, 0.57, 0.7100000000000001], [0.43, 0.7100000000000001, 0.85], [0.01, 0.15, 0.15], [0.85, 0.85, 0.57], [0.43, 0.85, 0.01], [0.15, 0.15, 0.85], [0.29, 0.29, 0.43], [0.29, 0.43, 0.57], [0.7100000000000001, 0.29, 0.85], [0.15, 0.15, 0.43], [0.85, 0.7100000000000001, 0.85], [0.85, 0.15, 0.43], [0.43, 0.43, 0.15], [0.57, 0.7100000000000001, 0.15], [0.7100000000000001, 0.43, 0.57], [0.7100000000000001, 0.43, 0.01], [0.85, 0.29, 0.29], [0.85, 0.15, 0.15], [0.43, 0.57, 0.85], [0.01, 0.85, 0.29], [0.29, 0.7100000000000001, 0.15], [0.57, 0.85, 0.57], [0.43, 0.43, 0.57], [0.01, 0.7100000000000001, 0.7100000000000001], [0.57, 0.15, 0.57], [0.57, 0.57, 0.43], [0.85, 0.57, 0.57], [0.85, 0.7100000000000001, 0.7100000000000001], [0.57, 0.7100000000000001, 0.85], [0.15, 0.85, 0.85], [0.29, 0.57, 0.57], [0.15, 0.7100000000000001, 0.85], [0.57, 0.01, 0.29], [0.29, 0.7100000000000001, 0.01], [0.7100000000000001, 0.29, 0.15], [0.85, 0.01, 0.85], [0.29, 0.01, 0.57], [0.29, 0.01, 0.7100000000000001], [0.7100000000000001, 0.85, 0.29], [0.85, 0.29, 0.7100000000000001], [0.43, 0.15, 0.43], [0.01, 0.01, 0.15], [0.01, 0.7100000000000001, 0.57], [0.7100000000000001, 0.15, 0.01], [0.7100000000000001, 0.15, 0.15], [0.29, 0.29, 0.85], [0.01, 0.43, 0.7100000000000001], [0.57, 0.15, 0.01], [0.85, 0.15, 0.7100000000000001], [0.43, 0.43, 0.01], [0.29, 0.85, 0.57], [0.01, 0.29, 0.43], [0.57, 0.43, 0.29], [0.43, 0.29, 0.43], [0.85, 0.7100000000000001, 0.29], [0.7100000000000001, 0.85, 0.85], [0.43, 0.43, 0.43], [0.43, 0.29, 0.7100000000000001], [0.7100000000000001, 0.57, 0.57], [0.57, 0.29, 0.85], [0.01, 0.15, 0.7100000000000001], [0.7100000000000001, 0.7100000000000001, 0.15], [0.15, 0.85, 0.01], [0.43, 0.7100000000000001, 0.7100000000000001], [0.43, 0.57, 0.43], [0.7100000000000001, 0.01, 0.85], [0.29, 0.43, 0.29], [0.57, 0.15, 0.7100000000000001], [0.29, 0.57, 0.15], [0.15, 0.29, 0.43], [0.43, 0.85, 0.57], [0.43, 0.57, 0.57], [0.7100000000000001, 0.01, 0.01], [0.85, 0.85, 0.29], [0.15, 0.01, 0.29], [0.85, 0.29, 0.15], [0.15, 0.01, 0.01], [0.01, 0.01, 0.57], [0.15, 0.57, 0.15], [0.15, 0.43, 0.85], [0.01, 0.01, 0.7100000000000001], [0.85, 0.15, 0.57], [0.29, 0.15, 0.29], [0.15, 0.29, 0.15], [0.43, 0.85, 0.43], [0.01, 0.15, 0.29], [0.85, 0.7100000000000001, 0.15], [0.01, 0.01, 0.85], [0.7100000000000001, 0.57, 0.85], [0.01, 0.85, 0.57], [0.29, 0.85, 0.7100000000000001], [0.15, 0.01, 0.7100000000000001], [0.85, 0.57, 0.15], [0.15, 0.57, 0.85], [0.15, 0.43, 0.15], [0.15, 0.85, 0.57], [0.7100000000000001, 0.85, 0.01], [0.7100000000000001, 0.01, 0.7100000000000001], [0.15, 0.43, 0.43], [0.01, 0.57, 0.7100000000000001], [0.43, 0.01, 0.57], [0.01, 0.57, 0.57], [0.57, 0.43, 0.7100000000000001], [0.7100000000000001, 0.29, 0.29], [0.15, 0.43, 0.7100000000000001], [0.57, 0.43, 0.15], [0.01, 0.7100000000000001, 0.29], [0.7100000000000001, 0.57, 0.01], [0.01, 0.29, 0.15], [0.29, 0.85, 0.01], [0.57, 0.29, 0.57], [0.85, 0.43, 0.29], [0.7100000000000001, 0.43, 0.29], [0.29, 0.7100000000000001, 0.85], [0.85, 0.57, 0.01], [0.01, 0.29, 0.7100000000000001], [0.15, 0.57, 0.7100000000000001], [0.85, 0.57, 0.7100000000000001], [0.85, 0.43, 0.7100000000000001], [0.15, 0.57, 0.43], [0.15, 0.85, 0.29], [0.15, 0.29, 0.85], [0.7100000000000001, 0.29, 0.43], [0.15, 0.15, 0.29], [0.43, 0.7100000000000001, 0.01], [0.29, 0.7100000000000001, 0.29], [0.7100000000000001, 0.7100000000000001, 0.43], [0.29, 0.85, 0.15], [0.43, 0.15, 0.29], [0.29, 0.01, 0.15], [0.57, 0.01, 0.01], [0.85, 0.85, 0.15], [0.43, 0.7100000000000001, 0.15], [0.43, 0.7100000000000001, 0.29], [0.7100000000000001, 0.57, 0.43], [0.29, 0.29, 0.57], [0.29, 0.01, 0.43], [0.85, 0.7100000000000001, 0.57], [0.57, 0.29, 0.7100000000000001], [0.43, 0.29, 0.29], [0.7100000000000001, 0.43, 0.7100000000000001], [0.43, 0.57, 0.29], [0.43, 0.01, 0.15], [0.15, 0.7100000000000001, 0.57], [0.01, 0.29, 0.29], [0.29, 0.01, 0.01], [0.7100000000000001, 0.15, 0.85], [0.57, 0.7100000000000001, 0.29], [0.57, 0.7100000000000001, 0.57], [0.15, 0.29, 0.01], [0.29, 0.43, 0.01], [0.7100000000000001, 0.15, 0.7100000000000001], [0.85, 0.85, 0.43], [0.7100000000000001, 0.15, 0.29], [0.7100000000000001, 0.7100000000000001, 0.7100000000000001], [0.29, 0.57, 0.29], [0.85, 0.43, 0.57], [0.01, 0.57, 0.29], [0.57, 0.01, 0.43], [0.01, 0.29, 0.01], [0.29, 0.01, 0.85], [0.43, 0.57, 0.15], [0.85, 0.85, 0.01], [0.29, 0.15, 0.43], [0.29, 0.29, 0.15], [0.01, 0.43, 0.01], [0.43, 0.85, 0.85], [0.15, 0.7100000000000001, 0.7100000000000001], [0.15, 0.85, 0.43], [0.7100000000000001, 0.85, 0.7100000000000001], [0.7100000000000001, 0.01, 0.43], [0.15, 0.43, 0.01], [0.43, 0.57, 0.01], [0.7100000000000001, 0.57, 0.29], [0.01, 0.85, 0.85], [0.01, 0.85, 0.7100000000000001], [0.01, 0.7100000000000001, 0.85], [0.43, 0.7100000000000001, 0.43], [0.43, 0.15, 0.01], [0.57, 0.85, 0.43], [0.85, 0.43, 0.15], [0.01, 0.15, 0.85], [0.85, 0.29, 0.57], [0.01, 0.01, 0.43], [0.57, 0.01, 0.7100000000000001], [0.29, 0.29, 0.01], [0.57, 0.43, 0.85], [0.43, 0.15, 0.85], [0.01, 0.7100000000000001, 0.43], [0.15, 0.57, 0.57], [0.15, 0.15, 0.57], [0.29, 0.43, 0.85], [0.43, 0.01, 0.01], [0.57, 0.57, 0.85], [0.15, 0.7100000000000001, 0.43], [0.43, 0.01, 0.85], [0.15, 0.01, 0.43], [0.43, 0.57, 0.7100000000000001], [0.29, 0.15, 0.85], [0.15, 0.85, 0.15], [0.7100000000000001, 0.43, 0.85], [0.01, 0.43, 0.15], [0.57, 0.57, 0.57]] 2 | -------------------------------------------------------------------------------- /utils/test_utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import os 3 | import pymesh 4 | 5 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 6 | 7 | def iou_pymesh(mesh1, mesh2, dim=110): 8 | # mesh1 = (vertices1, triangles1) 9 | # mesh2 = (vertices2, triangles2) 10 | 11 | mesh1 = pymesh.form_mesh(mesh1[0], mesh1[1]) 12 | grid1 = pymesh.VoxelGrid(2./dim) 13 | grid1.insert_mesh(mesh1) 14 | grid1.create_grid() 15 | 16 | ind1 = ((grid1.mesh.vertices + 1.1) / 2.4 * dim).astype(np.int) 17 | v1 = np.zeros([dim, dim, dim]) 18 | v1[ind1[:,0], ind1[:,1], ind1[:,2]] = 1 19 | 20 | 21 | mesh2 = pymesh.form_mesh(mesh2[0], mesh2[1]) 22 | grid2 = pymesh.VoxelGrid(2./dim) 23 | grid2.insert_mesh(mesh2) 24 | grid2.create_grid() 25 | 26 | ind2 = ((grid2.mesh.vertices + 1.1) / 2.4 * dim).astype(np.int) 27 | v2 = np.zeros([dim, dim, dim]) 28 | v2[ind2[:,0], ind2[:,1], ind2[:,2]] = 1 29 | 30 | intersection = np.sum(np.logical_and(v1, v2)) 31 | union = np.sum(np.logical_or(v1, v2)) 32 | return float(intersection) / union 33 | 34 | def iou_binvox(off_path1, off_path2): 35 | 36 | solidbinvoxpath1 = off_path1[:-4] + '.binvox' 37 | if not os.path.exists(solidbinvoxpath1): 38 | os.system("%s/binvox -cb -dc -aw -bb -1. -1. -1. 1. 1. 1. -d 128 %s -pb 2>&1 >/dev/null" % (BASE_DIR, off_path1)) 39 | with open(solidbinvoxpath1, 'rb') as f: 40 | v1 = binvox_rw.read_as_3d_array(f)#.data 41 | pc1 = process_binvox(v1) 42 | 43 | solidbinvoxpath2 = off_path2[:-4] + '.binvox' 44 | if not os.path.exists(solidbinvoxpath2): 45 | os.system("%s/binvox -cb -dc -aw -bb -1. -1. -1. 1. 1. 1. -d 128 %s -pb 2>&1 >/dev/null" % (BASE_DIR, off_path2)) 46 | with open(solidbinvoxpath2, 'rb') as f: 47 | v2 = binvox_rw.read_as_3d_array(f)#.data 48 | pc2 = process_binvox(v2) 49 | 50 | intersection = np.sum(np.logical_and(v1.data, v2.data)) 51 | union = np.sum(np.logical_or(v1.data, v2.data)) 52 | return float(intersection) / union 53 | 54 | 55 | if __name__ == "__main__": 56 | 57 | off_path1 = '/media/ssd/projects/Deformation/Sources/3DN/shapenet/3D/checkpoint/3DN_allcategories_ft/test_results/0_deformmesh.obj' 58 | off_path2 = '/media/ssd/projects/Deformation/Sources/3DN/shapenet/3D/checkpoint/3DN_allcategories_ft/test_results/0_refmesh.obj' 59 | 60 | mesh1 = pymesh.load_mesh('/media/ssd/projects/Deformation/Sources/3DN/shapenet/3D/checkpoint/3DN_allcategories_ft/test_results/0_deformmesh.obj'); 61 | mesh2 = pymesh.load_mesh('/media/ssd/projects/Deformation/Sources/3DN/shapenet/3D/checkpoint/3DN_allcategories_ft/test_results/0_refmesh.obj'); 62 | print(iou_pymesh((mesh1.vertices, mesh1.faces), (mesh2.vertices, mesh2.faces))) 63 | # grid = pymesh.VoxelGrid(0.01); 64 | # grid.insert_mesh(mesh); 65 | # grid.create_grid(); 66 | # out_mesh = grid.mesh; 67 | # print(out_mesh.vertices) 68 | # pymesh.save_mesh('tmp.obj', out_mesh); 69 | # print(iou_off(off_path1, off_path2)) 70 | --------------------------------------------------------------------------------