├── IMGAN ├── checkpoint │ └── put checkpoint folder here.txt ├── data │ └── put data here.txt ├── main.py ├── model.py ├── modelz.py └── ops.py ├── IMSVR ├── checkpoint │ └── put checkpoint folder here.txt ├── data │ └── put data here.txt ├── main.py ├── model.py └── ops.py ├── LICENSE ├── README.md ├── img ├── car.gif ├── chair.gif ├── font.gif ├── plane.gif ├── rifle.gif ├── table.gif └── teaser.png └── point_sampling ├── README.md ├── binvox_rw.py ├── data └── samplechair │ ├── 1.binvox │ ├── 2.binvox │ └── 3.binvox ├── samplechair ├── 0_16.dae ├── 0_16_1.png ├── 0_16_2.png ├── 0_16_3.png ├── 0_32.dae ├── 0_32_1.png ├── 0_32_2.png ├── 0_32_3.png ├── 0_64.dae ├── 0_64_1.png ├── 0_64_2.png ├── 0_64_3.png ├── 0_vox.dae ├── 0_vox_1.png ├── 0_vox_2.png ├── 0_vox_3.png ├── samplechair_vox.hdf5 ├── samplechair_vox.txt └── statistics.txt ├── test_vox.py ├── vox2pointvaluepair_from_binvox.py └── vox2pointvaluepair_from_hsp.py /IMGAN/checkpoint/put checkpoint folder here.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/IMGAN/checkpoint/put checkpoint folder here.txt -------------------------------------------------------------------------------- /IMGAN/data/put data here.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/IMGAN/data/put data here.txt -------------------------------------------------------------------------------- /IMGAN/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import scipy.misc 3 | import numpy as np 4 | 5 | from model import IMAE 6 | from modelz import ZGAN 7 | 8 | import tensorflow as tf 9 | import h5py 10 | 11 | flags = tf.app.flags 12 | flags.DEFINE_integer("epoch", 10000, "Epoch to train [25]") 13 | flags.DEFINE_float("learning_rate", 0.00005, "Learning rate of for adam [0.0002]") 14 | flags.DEFINE_float("beta1", 0.5, "Momentum term of adam [0.5]") 15 | flags.DEFINE_string("dataset", "03001627_vox", "The name of dataset") 16 | flags.DEFINE_integer("real_size", 64, "output point-value voxel grid size in training [64]") 17 | flags.DEFINE_integer("batch_size_input", 32768, "training batch size (virtual, batch_size is the real batch_size) [32768]") 18 | flags.DEFINE_string("checkpoint_dir", "checkpoint", "Directory name to save the checkpoints [checkpoint]") 19 | flags.DEFINE_string("data_dir", "./data", "Root directory of dataset [data]") 20 | flags.DEFINE_string("sample_dir", "samples", "Directory name to save the image samples [samples]") 21 | flags.DEFINE_boolean("train", False, "True for training, False for testing [False]") 22 | flags.DEFINE_boolean("ae", False, "True for AE, False for zGAN [False]") 23 | FLAGS = flags.FLAGS 24 | 25 | def main(_): 26 | if not os.path.exists(FLAGS.checkpoint_dir): 27 | os.makedirs(FLAGS.checkpoint_dir) 28 | if not os.path.exists(FLAGS.sample_dir): 29 | os.makedirs(FLAGS.sample_dir) 30 | 31 | #gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.5) 32 | #run_config = tf.ConfigProto(gpu_options=gpu_options) 33 | run_config = tf.ConfigProto() 34 | run_config.gpu_options.allow_growth=True 35 | 36 | if FLAGS.ae: 37 | with tf.Session(config=run_config) as sess: 38 | imae = IMAE( 39 | sess, 40 | FLAGS.real_size, 41 | FLAGS.batch_size_input, 42 | is_training = FLAGS.train, 43 | dataset_name=FLAGS.dataset, 44 | checkpoint_dir=FLAGS.checkpoint_dir, 45 | sample_dir=FLAGS.sample_dir, 46 | data_dir=FLAGS.data_dir) 47 | 48 | if FLAGS.train: 49 | imae.train(FLAGS) 50 | else: 51 | imae.get_z(FLAGS) 52 | #imae.test_interp(FLAGS) 53 | #imae.test(FLAGS) 54 | else: 55 | if FLAGS.train: 56 | with tf.Session(config=run_config) as sess_z: 57 | zgan = ZGAN( 58 | sess_z, 59 | is_training = FLAGS.train, 60 | dataset_name=FLAGS.dataset, 61 | checkpoint_dir=FLAGS.checkpoint_dir, 62 | sample_dir=FLAGS.sample_dir, 63 | data_dir=FLAGS.data_dir) 64 | zgan.train(FLAGS) 65 | else: 66 | 67 | #option 1 generate z 68 | with tf.Session(config=run_config) as sess_z: 69 | zgan = ZGAN( 70 | sess_z, 71 | is_training = FLAGS.train, 72 | dataset_name=FLAGS.dataset, 73 | checkpoint_dir=FLAGS.checkpoint_dir, 74 | sample_dir=FLAGS.sample_dir, 75 | data_dir=FLAGS.data_dir) 76 | generated_z = zgan.get_z(FLAGS, 16) 77 | tf.reset_default_graph() 78 | ''' 79 | hdf5_file = h5py.File("temp_z.hdf5", mode='w') 80 | hdf5_file.create_dataset("zs", generated_z.shape, np.float32) 81 | hdf5_file["zs"][...] = generated_z 82 | hdf5_file.close() 83 | ''' 84 | with tf.Session(config=run_config) as sess: 85 | imae = IMAE( 86 | sess, 87 | FLAGS.real_size, 88 | FLAGS.batch_size_input, 89 | is_training = FLAGS.train, 90 | dataset_name=FLAGS.dataset, 91 | checkpoint_dir=FLAGS.checkpoint_dir, 92 | sample_dir=FLAGS.sample_dir, 93 | data_dir=FLAGS.data_dir) 94 | imae.test_z(FLAGS, generated_z, 128) 95 | 96 | ''' 97 | #option 2 use filtered z 98 | hdf5_file = h5py.File("temp_z.hdf5", mode='r') 99 | generated_z = hdf5_file["zs"][:] 100 | hdf5_file.close() 101 | z_num = generated_z.shape[0] 102 | filtered_z = np.copy(generated_z) 103 | t = 0 104 | for tt in range(z_num): 105 | if (os.path.exists(FLAGS.sample_dir+'/'+str(tt)+'_1t.png')): 106 | filtered_z[t] = generated_z[tt] 107 | t += 1 108 | filtered_z = filtered_z[:t] 109 | print('filtered',t) 110 | 111 | with tf.Session(config=run_config) as sess: 112 | imae = IMAE( 113 | sess, 114 | is_training = FLAGS.train, 115 | dataset_name=FLAGS.dataset, 116 | checkpoint_dir=FLAGS.checkpoint_dir, 117 | sample_dir=FLAGS.sample_dir, 118 | data_dir=FLAGS.data_dir) 119 | imae.test_z(FLAGS, filtered_z, 256) 120 | ''' 121 | 122 | if __name__ == '__main__': 123 | tf.app.run() 124 | -------------------------------------------------------------------------------- /IMGAN/model.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import math 4 | from glob import glob 5 | import tensorflow as tf 6 | import numpy as np 7 | import h5py 8 | import cv2 9 | import mcubes 10 | 11 | from ops import * 12 | 13 | class IMAE(object): 14 | def __init__(self, sess, real_size, batch_size_input, is_training = False, z_dim=128, ef_dim=32, gf_dim=128, dataset_name='default', checkpoint_dir=None, sample_dir=None, data_dir='./data'): 15 | """ 16 | Args: 17 | too lazy to explain 18 | """ 19 | self.sess = sess 20 | 21 | #progressive training 22 | #1-- (16, 16*16*16) 23 | #2-- (32, 16*16*16*2) 24 | #3-- (64, 32*32*32) 25 | #4-- (128, 32*32*32*4) 26 | self.real_size = real_size #output point-value voxel grid size in training 27 | self.batch_size_input = batch_size_input #training batch size (virtual, batch_size is the real batch_size) 28 | 29 | self.batch_size = 16*16*16*4 #adjust batch_size according to gpu memory size in training 30 | if self.batch_size_inputz_height or slot<0: print("error slot") 149 | z_counter[slot,j] += 1 150 | 151 | maxz = 50#np.max(z_counter) 152 | for i in range(z_height): 153 | for j in range(self.z_dim): 154 | x = int(z_counter[i,j]*256/maxz) 155 | if (x>255): x=255 156 | z_img[i,j] = x 157 | 158 | cv2.imwrite("z_train.png", z_img) 159 | 160 | #generated z 161 | z_height = 64 162 | z_counter = np.zeros([z_height,self.z_vector_dim],np.int32) 163 | z_img = np.zeros([z_height,self.z_vector_dim],np.uint8) 164 | 165 | batch_z = np.random.normal(0, 0.2, [batch_index_num, self.z_dim]).astype(np.float32) 166 | z_vector = self.sess.run(self.sG, 167 | feed_dict={ 168 | self.z: batch_z, 169 | } 170 | ) 171 | for i in range(batch_index_num): 172 | for j in range(self.z_dim): 173 | slot = int(z_vector[i,j]*(z_height-0.0001)) 174 | if slot>z_height or slot<0: print("error slot") 175 | z_counter[slot,j] += 1 176 | 177 | for i in range(z_height): 178 | for j in range(self.z_dim): 179 | x = int(z_counter[i,j]*256/maxz) 180 | if (x>255): x=255 181 | z_img[i,j] = x 182 | 183 | cv2.imwrite("z_gen.png", z_img) 184 | 185 | print("[Visualized Z]") 186 | 187 | def get_z(self, config, num): 188 | could_load, checkpoint_counter = self.load(self.checkpoint_dir) 189 | if could_load: 190 | print(" [*] Load SUCCESS") 191 | else: 192 | print(" [!] Load failed...") 193 | return 194 | 195 | #generated z 196 | batch_z = np.random.normal(0, 0.2, [num, self.z_dim]).astype(np.float32) 197 | z_vector = self.sess.run(self.sG, 198 | feed_dict={ 199 | self.z: batch_z, 200 | } 201 | ) 202 | return z_vector 203 | 204 | @property 205 | def model_dir(self): 206 | return "{}_{}_{}".format( 207 | self.dataset_namez, self.z_dim, self.z_vector_dim) 208 | 209 | def save(self, checkpoint_dir, step): 210 | model_name = "ZGAN.model" 211 | checkpoint_dir = os.path.join(checkpoint_dir, self.model_dir) 212 | 213 | if not os.path.exists(checkpoint_dir): 214 | os.makedirs(checkpoint_dir) 215 | 216 | self.saver.save(self.sess, 217 | os.path.join(checkpoint_dir, model_name), 218 | global_step=step) 219 | 220 | def load(self, checkpoint_dir): 221 | import re 222 | print(" [*] Reading checkpoints...") 223 | checkpoint_dir = os.path.join(checkpoint_dir, self.model_dir) 224 | 225 | ckpt = tf.train.get_checkpoint_state(checkpoint_dir) 226 | if ckpt and ckpt.model_checkpoint_path: 227 | ckpt_name = os.path.basename(ckpt.model_checkpoint_path) 228 | self.saver.restore(self.sess, os.path.join(checkpoint_dir, ckpt_name)) 229 | counter = int(next(re.finditer("(\d+)(?!.*\d)",ckpt_name)).group(0)) 230 | print(" [*] Success to read {}".format(ckpt_name)) 231 | return True, counter 232 | else: 233 | print(" [*] Failed to find a checkpoint") 234 | return False, 0 235 | -------------------------------------------------------------------------------- /IMGAN/ops.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import tensorflow as tf 3 | 4 | def init_weights(shape, name): 5 | return tf.get_variable(name, shape=shape, initializer=tf.contrib.layers.xavier_initializer()) 6 | 7 | def init_biases(shape): 8 | return tf.Variable(tf.zeros(shape)) 9 | 10 | def lrelu(x, leak=0.02): 11 | return tf.maximum(x, leak*x) 12 | 13 | def batch_norm(input, phase_train): 14 | return tf.contrib.layers.batch_norm(input, decay=0.999, updates_collections=None, epsilon=1e-5, scale=True, is_training=phase_train) 15 | # better using instance normalization since the batch size is 1 16 | #return tf.contrib.layers.instance_norm(input) 17 | 18 | def linear(input_, output_size, scope): 19 | shape = input_.get_shape().as_list() 20 | with tf.variable_scope(scope): 21 | matrix = tf.get_variable("Matrix", [shape[1], output_size], tf.float32, tf.random_normal_initializer(stddev=0.02)) 22 | bias = tf.get_variable("bias", [output_size], initializer=tf.zeros_initializer()) 23 | print("linear","in",shape,"out",(shape[0],output_size)) 24 | return tf.matmul(input_, matrix) + bias 25 | 26 | def conv2d(input_, shape, strides, scope, padding="SAME"): 27 | with tf.variable_scope(scope): 28 | matrix = tf.get_variable('Matrix', shape, initializer=tf.truncated_normal_initializer(stddev=0.02)) 29 | bias = tf.get_variable('bias', [shape[-1]], initializer=tf.zeros_initializer()) 30 | conv = tf.nn.conv2d(input_, matrix, strides=strides, padding=padding) 31 | conv = tf.nn.bias_add(conv, bias) 32 | print("conv2d","in",input_.shape,"out",conv.shape) 33 | return conv 34 | 35 | def conv3d(input_, shape, strides, scope, padding="SAME"): 36 | with tf.variable_scope(scope): 37 | matrix = tf.get_variable("Matrix", shape, initializer=tf.contrib.layers.xavier_initializer()) 38 | bias = tf.get_variable("bias", [shape[-1]], initializer=tf.zeros_initializer()) 39 | conv = tf.nn.conv3d(input_, matrix, strides=strides, padding=padding) 40 | conv = tf.nn.bias_add(conv, bias) 41 | print("conv3d","in",input_.shape,"out",conv.shape) 42 | return conv 43 | 44 | def deconv3d(input_, shape, out_shape, strides, scope, padding="SAME"): 45 | with tf.variable_scope(scope): 46 | matrix = tf.get_variable("Matrix", shape, initializer=tf.contrib.layers.xavier_initializer()) 47 | bias = tf.get_variable("bias", [shape[-2]], initializer=tf.zeros_initializer()) 48 | conv = tf.nn.conv3d_transpose(input_, matrix, out_shape, strides=strides, padding=padding) 49 | conv = tf.nn.bias_add(conv, bias) 50 | print("deconv3d","in",input_.shape,"out",conv.shape) 51 | return conv 52 | 53 | 54 | -------------------------------------------------------------------------------- /IMSVR/checkpoint/put checkpoint folder here.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/IMSVR/checkpoint/put checkpoint folder here.txt -------------------------------------------------------------------------------- /IMSVR/data/put data here.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/IMSVR/data/put data here.txt -------------------------------------------------------------------------------- /IMSVR/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import scipy.misc 3 | import numpy as np 4 | 5 | from model import IMSVR 6 | 7 | import tensorflow as tf 8 | 9 | flags = tf.app.flags 10 | flags.DEFINE_integer("epoch", 1500, "Epoch to train [25]") 11 | flags.DEFINE_float("learning_rate", 0.00005, "Learning rate of for adam [0.0002]") 12 | flags.DEFINE_float("beta1", 0.5, "Momentum term of adam [0.5]") 13 | flags.DEFINE_string("dataset", "02691156_hsp_vox", "The name of dataset") 14 | flags.DEFINE_string("checkpoint_dir", "checkpoint", "Directory name to save the checkpoints [checkpoint]") 15 | flags.DEFINE_string("data_dir", "./data", "Root directory of dataset [data]") 16 | flags.DEFINE_string("pretrained_model_dir", "./checkpoint/02691156_hsp_vox_only_train_64", "Root directory of pretrained_model") 17 | flags.DEFINE_string("pretrained_z_dir", "./data/02691156_hsp_vox_only_train_z.hdf5", "Root directory of pretrained_model_z") 18 | flags.DEFINE_string("sample_dir", "samples", "Directory name to save the image samples [samples]") 19 | flags.DEFINE_boolean("train", False, "True for training, False for testing [False]") 20 | FLAGS = flags.FLAGS 21 | 22 | def main(_): 23 | if not os.path.exists(FLAGS.checkpoint_dir): 24 | os.makedirs(FLAGS.checkpoint_dir) 25 | if not os.path.exists(FLAGS.sample_dir): 26 | os.makedirs(FLAGS.sample_dir) 27 | 28 | #gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.333) 29 | run_config = tf.ConfigProto() 30 | run_config.gpu_options.allow_growth=True 31 | 32 | with tf.Session(config=run_config) as sess: 33 | imsvr = IMSVR( 34 | sess, 35 | is_training = FLAGS.train, 36 | dataset_name=FLAGS.dataset, 37 | checkpoint_dir=FLAGS.checkpoint_dir, 38 | pretrained_z_dir=FLAGS.pretrained_z_dir, 39 | sample_dir=FLAGS.sample_dir, 40 | data_dir=FLAGS.data_dir) 41 | 42 | #show_all_variables() 43 | 44 | if FLAGS.train: 45 | imsvr.train(FLAGS) 46 | else: 47 | imsvr.test(FLAGS) 48 | 49 | if __name__ == '__main__': 50 | tf.app.run() 51 | -------------------------------------------------------------------------------- /IMSVR/model.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import math 4 | from glob import glob 5 | import tensorflow as tf 6 | import numpy as np 7 | import h5py 8 | import cv2 9 | import mcubes 10 | 11 | from ops import * 12 | 13 | class IMSVR(object): 14 | def __init__(self, sess, is_training = False, z_dim=128, ef_dim=64, gf_dim=128, dataset_name='default', checkpoint_dir=None, pretrained_z_dir=None, sample_dir=None, data_dir='./data'): 15 | """ 16 | Args: 17 | too lazy to explain 18 | """ 19 | self.sess = sess 20 | 21 | #progressive training 22 | #1-- (16, 16*16*16) 23 | #2-- (32, 16*16*16*2) 24 | #3-- (64, 32*32*32) 25 | #4-- (128, 32*32*32*4) 26 | 27 | self.real_size = 64 28 | self.batch_size_input = 32*32*32 29 | self.batch_size = 16*16*16 30 | self.z_batch_size = 64 31 | 32 | self.view_size = 137 33 | self.crop_size = 128 34 | self.view_num = 20 35 | self.crop_edge = self.view_size-self.crop_size 36 | 37 | self.z_dim = z_dim 38 | 39 | self.ef_dim = ef_dim 40 | self.gf_dim = gf_dim 41 | 42 | self.dataset_name = dataset_name 43 | self.dataset_load = dataset_name + '_train' 44 | self.checkpoint_dir = checkpoint_dir 45 | self.data_dir = data_dir 46 | 47 | if not is_training: 48 | self.test_size = 16 49 | self.batch_size = self.test_size*self.test_size*self.test_size 50 | self.dataset_load = dataset_name + '_test' 51 | 52 | if os.path.exists(self.data_dir+'/'+self.dataset_load+'.hdf5'): 53 | self.data_dict = h5py.File(self.data_dir+'/'+self.dataset_load+'.hdf5', 'r') 54 | self.data_points = self.data_dict['points_'+str(self.real_size)][:] 55 | self.data_values = self.data_dict['values_'+str(self.real_size)][:] 56 | self.data_pixel = self.data_dict['pixels'][:] 57 | data_dict_z = h5py.File(pretrained_z_dir, 'r') 58 | self.data_z = data_dict_z['zs'][:] 59 | if self.batch_size_input!=self.data_points.shape[1]: 60 | print("error: batch_size!=data_points.shape") 61 | exit(0) 62 | if self.view_num!=self.data_pixel.shape[1] or self.view_size!=self.data_pixel.shape[2]: 63 | print("error: view_size!=self.data_pixel.shape") 64 | exit(0) 65 | else: 66 | if is_training: 67 | print("error: cannot load "+self.data_dir+'/'+self.dataset_load+'.hdf5') 68 | exit(0) 69 | else: 70 | print("warning: cannot load "+self.data_dir+'/'+self.dataset_load+'.hdf5') 71 | 72 | self.build_model() 73 | 74 | def build_model(self): 75 | #for test 76 | self.point_coord = tf.placeholder(shape=[self.batch_size,3], dtype=tf.float32) 77 | self.z_vector_test = tf.placeholder(shape=[1,self.z_dim], dtype=tf.float32) 78 | self.view_test = tf.placeholder(shape=[1,self.crop_size,self.crop_size,1], dtype=tf.float32) 79 | 80 | #for train 81 | self.view = tf.placeholder(shape=[self.z_batch_size,self.crop_size,self.crop_size,1], dtype=tf.float32) 82 | self.z_vector = tf.placeholder(shape=[self.z_batch_size,self.z_dim], dtype=tf.float32) 83 | 84 | self.E = self.encoder(self.view, phase_train=True, reuse=False) 85 | 86 | self.sE = self.encoder(self.view_test, phase_train=False, reuse=True) 87 | self.zG = self.generator(self.point_coord, self.z_vector_test, phase_train=False, reuse=False) 88 | 89 | self.loss = tf.reduce_mean(tf.square(self.z_vector - self.E)) 90 | self.vars = tf.trainable_variables() 91 | self.g_vars = [var for var in self.vars if 'simple_net' in var.name] 92 | self.e_vars = [var for var in self.vars if 'encoder' in var.name] 93 | 94 | 95 | 96 | def generator(self, points, z, phase_train=True, reuse=False): 97 | with tf.variable_scope("simple_net") as scope: 98 | if reuse: 99 | scope.reuse_variables() 100 | 101 | zs = tf.tile(z, [self.batch_size,1]) 102 | pointz = tf.concat([points,zs],1) 103 | print("pointz",pointz.shape) 104 | 105 | h1 = lrelu(linear(pointz, self.gf_dim*16, 'h1_lin')) 106 | h1 = tf.concat([h1,pointz],1) 107 | 108 | h2 = lrelu(linear(h1, self.gf_dim*8, 'h4_lin')) 109 | h2 = tf.concat([h2,pointz],1) 110 | 111 | h3 = lrelu(linear(h2, self.gf_dim*4, 'h5_lin')) 112 | h3 = tf.concat([h3,pointz],1) 113 | 114 | h4 = lrelu(linear(h3, self.gf_dim*2, 'h6_lin')) 115 | h4 = tf.concat([h4,pointz],1) 116 | 117 | h5 = lrelu(linear(h4, self.gf_dim, 'h7_lin')) 118 | h6 = tf.nn.sigmoid(linear(h5, 1, 'h8_lin')) 119 | 120 | return tf.reshape(h6, [self.batch_size,1]) 121 | 122 | def encoder(self, view, phase_train=True, reuse=False): 123 | with tf.variable_scope("encoder") as scope: 124 | if reuse: 125 | scope.reuse_variables() 126 | 127 | #mimic resnet 128 | def resnet_block(input, dim_in, dim_out, scope): 129 | if dim_in == dim_out: 130 | output = conv2d_nobias(input, shape=[3, 3, dim_out, dim_out], strides=[1,1,1,1], scope=scope+'_1') 131 | output = batch_norm(output, phase_train) 132 | output = lrelu(output) 133 | output = conv2d_nobias(output, shape=[3, 3, dim_out, dim_out], strides=[1,1,1,1], scope=scope+'_2') 134 | output = batch_norm(output, phase_train) 135 | output = output + input 136 | output = lrelu(output) 137 | else: 138 | output = conv2d_nobias(input, shape=[3, 3, dim_in, dim_out], strides=[1,2,2,1], scope=scope+'_1') 139 | output = batch_norm(output, phase_train) 140 | output = lrelu(output) 141 | output = conv2d_nobias(output, shape=[3, 3, dim_out, dim_out], strides=[1,1,1,1], scope=scope+'_2') 142 | output = batch_norm(output, phase_train) 143 | input_ = conv2d_nobias(input, shape=[1, 1, dim_in, dim_out], strides=[1,2,2,1], scope=scope+'_3') 144 | input_ = batch_norm(input_, phase_train) 145 | output = output + input_ 146 | output = lrelu(output) 147 | return output 148 | 149 | view = 1.0 - view 150 | layer_0 = conv2d_nobias(view, shape=[7, 7, 1, self.ef_dim], strides=[1,2,2,1], scope='conv0') 151 | layer_0 = batch_norm(layer_0, phase_train) 152 | layer_0 = lrelu(layer_0) 153 | #no maxpool 154 | 155 | layer_1 = resnet_block(layer_0, self.ef_dim, self.ef_dim, 'conv1') 156 | layer_2 = resnet_block(layer_1, self.ef_dim, self.ef_dim, 'conv2') 157 | 158 | layer_3 = resnet_block(layer_2, self.ef_dim, self.ef_dim*2, 'conv3') 159 | layer_4 = resnet_block(layer_3, self.ef_dim*2, self.ef_dim*2, 'conv4') 160 | 161 | layer_5 = resnet_block(layer_4, self.ef_dim*2, self.ef_dim*4, 'conv5') 162 | layer_6 = resnet_block(layer_5, self.ef_dim*4, self.ef_dim*4, 'conv6') 163 | 164 | layer_7 = resnet_block(layer_6, self.ef_dim*4, self.ef_dim*8, 'conv7') 165 | layer_8 = resnet_block(layer_7, self.ef_dim*8, self.ef_dim*8, 'conv8') 166 | 167 | layer_9 = conv2d_nobias(layer_8, shape=[4, 4, self.ef_dim*8, self.ef_dim*8], strides=[1,2,2,1], scope='conv9') 168 | layer_9 = batch_norm(layer_9, phase_train) 169 | layer_9 = lrelu(layer_9) 170 | 171 | layer_10 = conv2d(layer_9, shape=[4, 4, self.ef_dim*8, self.z_dim], strides=[1,1,1,1], scope='conv10', padding="VALID") 172 | layer_10 = tf.nn.sigmoid(layer_10) 173 | 174 | return tf.reshape(layer_10, [-1,self.z_dim]) 175 | 176 | def train(self, config): 177 | ''' 178 | #resume training 179 | ae_optim = tf.train.AdamOptimizer(config.learning_rate, beta1=config.beta1).minimize(self.loss, var_list=self.e_vars) 180 | self.sess.run(tf.global_variables_initializer()) 181 | self.saver = tf.train.Saver(max_to_keep=10) 182 | 183 | batch_index_list = np.arange(len(self.data_points)) 184 | batch_idxs = int(len(self.data_points)/self.z_batch_size) 185 | batch_num = int(self.batch_size_input/self.batch_size) 186 | if self.batch_size_input%self.batch_size != 0: 187 | print("batch_size_input % batch_size != 0") 188 | exit(0) 189 | 190 | counter = 0 191 | could_load, checkpoint_counter = self.load(self.checkpoint_dir) 192 | if could_load: 193 | counter = checkpoint_counter+1 194 | print(" [*] Load SUCCESS") 195 | else: 196 | print(" [!] Load failed...") 197 | start_time = time.time() 198 | ''' 199 | #first time run 200 | ae_optim = tf.train.AdamOptimizer(config.learning_rate, beta1=config.beta1, ).minimize(self.loss, var_list=self.e_vars) 201 | self.sess.run(tf.global_variables_initializer()) 202 | 203 | self.saver = tf.train.Saver(self.g_vars) 204 | could_load, checkpoint_counter = self.load_pretrained(config.pretrained_model_dir) 205 | if could_load: 206 | print(" [*] Load SUCCESS") 207 | else: 208 | print(" [!] Load failed...") 209 | exit(0) 210 | 211 | batch_index_list = np.arange(len(self.data_points)) 212 | batch_idxs = int(len(self.data_points)/self.z_batch_size) 213 | batch_num = int(self.batch_size_input/self.batch_size) 214 | if self.batch_size_input%self.batch_size != 0: 215 | print("batch_size_input % batch_size != 0") 216 | exit(0) 217 | self.saver = tf.train.Saver(max_to_keep=10) 218 | counter = 0 219 | start_time = time.time() 220 | 221 | 222 | batch_view = np.zeros([self.z_batch_size,self.crop_size,self.crop_size,1], np.float32) 223 | for epoch in range(counter, config.epoch): 224 | np.random.shuffle(batch_index_list) 225 | avg_loss = 0 226 | avg_num = 0 227 | for idx in range(0, batch_idxs): 228 | for t in range(self.z_batch_size): 229 | dxb = batch_index_list[idx*self.z_batch_size+t] 230 | which_view = np.random.randint(self.view_num) 231 | batch_view_ = self.data_pixel[dxb,which_view] 232 | offset_x = np.random.randint(self.crop_edge) 233 | offset_y = np.random.randint(self.crop_edge) 234 | if np.random.randint(2)==0: 235 | batch_view_ = batch_view_[offset_y:offset_y+self.crop_size, offset_x:offset_x+self.crop_size] 236 | else: 237 | batch_view_ = np.flip(batch_view_[offset_y:offset_y+self.crop_size, offset_x:offset_x+self.crop_size], 1) 238 | batch_view[t] = np.reshape(batch_view_/255.0, [self.crop_size,self.crop_size,1]) 239 | batch_z = self.data_z[batch_index_list[idx*self.z_batch_size:(idx+1)*self.z_batch_size]] 240 | 241 | # Update AE network 242 | _, errAE = self.sess.run([ae_optim, self.loss], 243 | feed_dict={ 244 | self.view: batch_view, 245 | self.z_vector: batch_z, 246 | }) 247 | 248 | avg_loss += errAE 249 | avg_num += 1 250 | 251 | if idx==batch_idxs-1: 252 | print("Epoch: [%2d/%2d] [%4d/%4d] time: %4.4f, loss: %.8f, avgloss: %.8f" % (epoch, config.epoch, idx, batch_idxs, time.time() - start_time, errAE, avg_loss/avg_num)) 253 | 254 | if epoch%10 == 0: 255 | 256 | sample_z = self.sess.run(self.sE, 257 | feed_dict={ 258 | self.view_test: batch_view[0:1], 259 | }) 260 | 261 | model_float = np.zeros([self.real_size,self.real_size,self.real_size],np.float32) 262 | real_model_float = np.zeros([self.real_size,self.real_size,self.real_size],np.float32) 263 | dxb = batch_index_list[idx*self.z_batch_size] 264 | for minib in range(batch_num): 265 | batch_points_int = self.data_points[dxb,minib*self.batch_size:(minib+1)*self.batch_size] 266 | batch_points = (batch_points_int+0.5)/self.real_size*2.0-1.0 267 | batch_values = self.data_values[dxb,minib*self.batch_size:(minib+1)*self.batch_size] 268 | 269 | model_out = self.sess.run(self.zG, 270 | feed_dict={ 271 | self.z_vector_test: sample_z, 272 | self.point_coord: batch_points, 273 | }) 274 | model_float[batch_points_int[:,0],batch_points_int[:,1],batch_points_int[:,2]] = np.reshape(model_out, [self.batch_size]) 275 | real_model_float[batch_points_int[:,0],batch_points_int[:,1],batch_points_int[:,2]] = np.reshape(batch_values, [self.batch_size]) 276 | img1 = np.clip(np.amax(model_float, axis=0)*256, 0,255).astype(np.uint8) 277 | img2 = np.clip(np.amax(model_float, axis=1)*256, 0,255).astype(np.uint8) 278 | img3 = np.clip(np.amax(model_float, axis=2)*256, 0,255).astype(np.uint8) 279 | cv2.imwrite(config.sample_dir+"/"+str(epoch)+"_1t.png",img1) 280 | cv2.imwrite(config.sample_dir+"/"+str(epoch)+"_2t.png",img2) 281 | cv2.imwrite(config.sample_dir+"/"+str(epoch)+"_3t.png",img3) 282 | img1 = np.clip(np.amax(real_model_float, axis=0)*256, 0,255).astype(np.uint8) 283 | img2 = np.clip(np.amax(real_model_float, axis=1)*256, 0,255).astype(np.uint8) 284 | img3 = np.clip(np.amax(real_model_float, axis=2)*256, 0,255).astype(np.uint8) 285 | cv2.imwrite(config.sample_dir+"/"+str(epoch)+"_1i.png",img1) 286 | cv2.imwrite(config.sample_dir+"/"+str(epoch)+"_2i.png",img2) 287 | cv2.imwrite(config.sample_dir+"/"+str(epoch)+"_3i.png",img3) 288 | img1 = (np.reshape(batch_view[0:1], [self.crop_size,self.crop_size])*255).astype(np.uint8) 289 | cv2.imwrite(config.sample_dir+"/"+str(epoch)+"_v.png",img1) 290 | print("[sample]") 291 | 292 | self.save(config.checkpoint_dir, epoch) 293 | 294 | def test_interp(self, config): 295 | self.saver = tf.train.Saver() 296 | could_load, checkpoint_counter = self.load(self.checkpoint_dir) 297 | if could_load: 298 | print(" [*] Load SUCCESS") 299 | else: 300 | print(" [!] Load failed...") 301 | return 302 | 303 | interp_size = 8 304 | 305 | idx1 = 0 306 | idx2 = 1 307 | 308 | thres = 0.6 309 | 310 | add_out = "./out/" 311 | 312 | dim = 128 313 | dima = self.test_size 314 | multiplier = int(dim/dima) 315 | multiplier2 = multiplier*multiplier 316 | multiplier3 = multiplier*multiplier*multiplier 317 | 318 | #get coords 64 319 | aux_x = np.zeros([dima,dima,dima],np.int32) 320 | aux_y = np.zeros([dima,dima,dima],np.int32) 321 | aux_z = np.zeros([dima,dima,dima],np.int32) 322 | for i in range(dima): 323 | for j in range(dima): 324 | for k in range(dima): 325 | aux_x[i,j,k] = i*multiplier 326 | aux_y[i,j,k] = j*multiplier 327 | aux_z[i,j,k] = k*multiplier 328 | coords = np.zeros([multiplier3,dima,dima,dima,3],np.float32) 329 | for i in range(multiplier): 330 | for j in range(multiplier): 331 | for k in range(multiplier): 332 | coords[i*multiplier2+j*multiplier+k,:,:,:,0] = aux_x+i 333 | coords[i*multiplier2+j*multiplier+k,:,:,:,1] = aux_y+j 334 | coords[i*multiplier2+j*multiplier+k,:,:,:,2] = aux_z+k 335 | coords = (coords+0.5)/dim*2.0-1.0 336 | coords = np.reshape(coords,[multiplier3,self.batch_size,3]) 337 | 338 | offset_x = int(self.crop_edge/2) 339 | offset_y = int(self.crop_edge/2) 340 | batch_view1 = self.data_pixel[idx1,0] 341 | batch_view1 = batch_view1[offset_y:offset_y+self.crop_size, offset_x:offset_x+self.crop_size] 342 | batch_view1 = np.reshape(batch_view1/255.0, [1,self.crop_size,self.crop_size,1]) 343 | batch_view2 = self.data_pixel[idx2,0] 344 | batch_view2 = batch_view2[offset_y:offset_y+self.crop_size, offset_x:offset_x+self.crop_size] 345 | batch_view2 = np.reshape(batch_view2/255.0, [1,self.crop_size,self.crop_size,1]) 346 | 347 | model_z1 = self.sess.run(self.sE, 348 | feed_dict={ 349 | self.view_test: batch_view1, 350 | }) 351 | model_z2 = self.sess.run(self.sE, 352 | feed_dict={ 353 | self.view_test: batch_view2, 354 | }) 355 | 356 | batch_z = np.zeros([interp_size,self.z_dim], np.float32) 357 | for i in range(interp_size): 358 | batch_z[i] = model_z2*i/(interp_size-1) + model_z1*(interp_size-1-i)/(interp_size-1) 359 | 360 | for t in range(interp_size): 361 | model_float = np.zeros([dim+2,dim+2,dim+2],np.float32) 362 | for i in range(multiplier): 363 | for j in range(multiplier): 364 | for k in range(multiplier): 365 | minib = i*multiplier2+j*multiplier+k 366 | model_out = self.sess.run(self.zG, 367 | feed_dict={ 368 | self.z_vector_test: batch_z[t], 369 | self.point_coord: coords[minib], 370 | }) 371 | model_float[aux_x+i+1,aux_y+j+1,aux_z+k+1] = np.reshape(model_out, [dima,dima,dima]) 372 | 373 | vertices, triangles = mcubes.marching_cubes(model_float, thres) 374 | mcubes.export_mesh(vertices, triangles, add_out+str(t)+".dae", str(t)) 375 | print("[sample]") 376 | 377 | def test(self, config): 378 | self.saver = tf.train.Saver() 379 | could_load, checkpoint_counter = self.load(self.checkpoint_dir) 380 | if could_load: 381 | print(" [*] Load SUCCESS") 382 | else: 383 | print(" [!] Load failed...") 384 | return 385 | 386 | thres = 0.6 387 | 388 | add_out = "./out/" 389 | add_image = "./image/" 390 | 391 | dim = 128 392 | dima = self.test_size 393 | multiplier = int(dim/dima) 394 | multiplier2 = multiplier*multiplier 395 | multiplier3 = multiplier*multiplier*multiplier 396 | 397 | #get coords 64 398 | aux_x = np.zeros([dima,dima,dima],np.int32) 399 | aux_y = np.zeros([dima,dima,dima],np.int32) 400 | aux_z = np.zeros([dima,dima,dima],np.int32) 401 | for i in range(dima): 402 | for j in range(dima): 403 | for k in range(dima): 404 | aux_x[i,j,k] = i*multiplier 405 | aux_y[i,j,k] = j*multiplier 406 | aux_z[i,j,k] = k*multiplier 407 | coords = np.zeros([multiplier3,dima,dima,dima,3],np.float32) 408 | for i in range(multiplier): 409 | for j in range(multiplier): 410 | for k in range(multiplier): 411 | coords[i*multiplier2+j*multiplier+k,:,:,:,0] = aux_x+i 412 | coords[i*multiplier2+j*multiplier+k,:,:,:,1] = aux_y+j 413 | coords[i*multiplier2+j*multiplier+k,:,:,:,2] = aux_z+k 414 | coords = (coords+0.5)/dim*2.0-1.0 415 | coords = np.reshape(coords,[multiplier3,self.batch_size,3]) 416 | 417 | offset_x = int(self.crop_edge/2) 418 | offset_y = int(self.crop_edge/2) 419 | 420 | #test_num = self.data_pixel.shape[0] 421 | test_num = 16 422 | for t in range(test_num): 423 | print(t,test_num) 424 | 425 | batch_view = self.data_pixel[t,0] 426 | batch_view = batch_view[offset_y:offset_y+self.crop_size, offset_x:offset_x+self.crop_size] 427 | batch_view = np.reshape(batch_view/255.0, [1,self.crop_size,self.crop_size,1]) 428 | 429 | model_z = self.sess.run(self.sE, 430 | feed_dict={ 431 | self.view_test: batch_view, 432 | }) 433 | 434 | model_float = np.zeros([dim+2,dim+2,dim+2],np.float32) 435 | for i in range(multiplier): 436 | for j in range(multiplier): 437 | for k in range(multiplier): 438 | minib = i*multiplier2+j*multiplier+k 439 | model_out = self.sess.run(self.zG, 440 | feed_dict={ 441 | self.z_vector_test: model_z, 442 | self.point_coord: coords[minib], 443 | }) 444 | model_float[aux_x+i+1,aux_y+j+1,aux_z+k+1] = np.reshape(model_out, [dima,dima,dima]) 445 | ''' 446 | img1 = np.clip(np.amax(model_float, axis=0)*256, 0,255).astype(np.uint8) 447 | img2 = np.clip(np.amax(model_float, axis=1)*256, 0,255).astype(np.uint8) 448 | img3 = np.clip(np.amax(model_float, axis=2)*256, 0,255).astype(np.uint8) 449 | cv2.imwrite(config.sample_dir+"/"+str(t)+"_1t.png",img1) 450 | cv2.imwrite(config.sample_dir+"/"+str(t)+"_2t.png",img2) 451 | cv2.imwrite(config.sample_dir+"/"+str(t)+"_3t.png",img3) 452 | img1 = (np.reshape(batch_view, [self.crop_size,self.crop_size])*255).astype(np.uint8) 453 | cv2.imwrite(config.sample_dir+"/"+str(t)+"_v.png",img1) 454 | ''' 455 | vertices, triangles = mcubes.marching_cubes(model_float, thres) 456 | mcubes.export_mesh(vertices, triangles, add_out+str(t)+".dae", str(t)) 457 | 458 | cv2.imwrite(add_image+str(t)+".png", self.data_pixel[t,0]) 459 | 460 | print("[sample]") 461 | 462 | def test_image(self, config): 463 | self.saver = tf.train.Saver() 464 | could_load, checkpoint_counter = self.load(self.checkpoint_dir) 465 | if could_load: 466 | print(" [*] Load SUCCESS") 467 | else: 468 | print(" [!] Load failed...") 469 | return 470 | 471 | thres = 0.6 472 | 473 | add_out = "./out/" 474 | add_image = "./image/" 475 | 476 | dim = 128 477 | dima = self.test_size 478 | multiplier = int(dim/dima) 479 | multiplier2 = multiplier*multiplier 480 | multiplier3 = multiplier*multiplier*multiplier 481 | 482 | #get coords 64 483 | aux_x = np.zeros([dima,dima,dima],np.int32) 484 | aux_y = np.zeros([dima,dima,dima],np.int32) 485 | aux_z = np.zeros([dima,dima,dima],np.int32) 486 | for i in range(dima): 487 | for j in range(dima): 488 | for k in range(dima): 489 | aux_x[i,j,k] = i*multiplier 490 | aux_y[i,j,k] = j*multiplier 491 | aux_z[i,j,k] = k*multiplier 492 | coords = np.zeros([multiplier3,dima,dima,dima,3],np.float32) 493 | for i in range(multiplier): 494 | for j in range(multiplier): 495 | for k in range(multiplier): 496 | coords[i*multiplier2+j*multiplier+k,:,:,:,0] = aux_x+i 497 | coords[i*multiplier2+j*multiplier+k,:,:,:,1] = aux_y+j 498 | coords[i*multiplier2+j*multiplier+k,:,:,:,2] = aux_z+k 499 | coords = (coords+0.5)/dim*2.0-1.0 500 | coords = np.reshape(coords,[multiplier3,self.batch_size,3]) 501 | 502 | offset_x = int(self.crop_edge/2) 503 | offset_y = int(self.crop_edge/2) 504 | 505 | for t in range(16): 506 | img_add = add_image+str(t)+".png" 507 | print(img_add) 508 | imgo_ = cv2.imread(img_add, cv2.IMREAD_GRAYSCALE) 509 | 510 | img = cv2.resize(imgo_, (self.view_size,self.view_size)) 511 | batch_view = np.reshape(img,(1,self.view_size,self.view_size,1)) 512 | batch_view = batch_view[:, offset_y:offset_y+self.crop_size, offset_x:offset_x+self.crop_size, :] 513 | batch_view = batch_view/255.0 514 | 515 | model_z = self.sess.run(self.sE, 516 | feed_dict={ 517 | self.view_test: batch_view, 518 | }) 519 | 520 | model_float = np.zeros([dim+2,dim+2,dim+2],np.float32) 521 | for i in range(multiplier): 522 | for j in range(multiplier): 523 | for k in range(multiplier): 524 | minib = i*multiplier2+j*multiplier+k 525 | model_out = self.sess.run(self.zG, 526 | feed_dict={ 527 | self.z_vector_test: model_z, 528 | self.point_coord: coords[minib], 529 | }) 530 | model_float[aux_x+i+1,aux_y+j+1,aux_z+k+1] = np.reshape(model_out, [dima,dima,dima]) 531 | 532 | vertices, triangles = mcubes.marching_cubes(model_float, thres) 533 | mcubes.export_mesh(vertices, triangles, add_out+str(t)+".dae", str(t)) 534 | 535 | print("[sample]") 536 | 537 | @property 538 | def model_dir(self): 539 | return "{}_{}".format( 540 | self.dataset_name, self.crop_size) 541 | 542 | def save(self, checkpoint_dir, step): 543 | model_name = "IMSVR.model" 544 | checkpoint_dir = os.path.join(checkpoint_dir, self.model_dir) 545 | 546 | if not os.path.exists(checkpoint_dir): 547 | os.makedirs(checkpoint_dir) 548 | 549 | self.saver.save(self.sess, 550 | os.path.join(checkpoint_dir, model_name), 551 | global_step=step) 552 | 553 | def load(self, checkpoint_dir): 554 | import re 555 | print(" [*] Reading checkpoints...") 556 | checkpoint_dir = os.path.join(checkpoint_dir, self.model_dir) 557 | 558 | ckpt = tf.train.get_checkpoint_state(checkpoint_dir) 559 | if ckpt and ckpt.model_checkpoint_path: 560 | ckpt_name = os.path.basename(ckpt.model_checkpoint_path) 561 | self.saver.restore(self.sess, os.path.join(checkpoint_dir, ckpt_name)) 562 | counter = int(next(re.finditer("(\d+)(?!.*\d)",ckpt_name)).group(0)) 563 | print(" [*] Success to read {}".format(ckpt_name)) 564 | return True, counter 565 | else: 566 | print(" [*] Failed to find a checkpoint") 567 | return False, 0 568 | 569 | def load_pretrained(self, checkpoint_dir): 570 | import re 571 | print(" [*] Reading checkpoints...") 572 | 573 | ckpt = tf.train.get_checkpoint_state(checkpoint_dir) 574 | if ckpt and ckpt.model_checkpoint_path: 575 | ckpt_name = os.path.basename(ckpt.model_checkpoint_path) 576 | self.saver.restore(self.sess, os.path.join(checkpoint_dir, ckpt_name)) 577 | counter = int(next(re.finditer("(\d+)(?!.*\d)",ckpt_name)).group(0)) 578 | print(" [*] Success to read {}".format(ckpt_name)) 579 | return True, counter 580 | else: 581 | print(" [*] Failed to find a checkpoint") 582 | return False, 0 583 | 584 | -------------------------------------------------------------------------------- /IMSVR/ops.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import tensorflow as tf 3 | 4 | def init_weights(shape, name): 5 | return tf.get_variable(name, shape=shape, initializer=tf.contrib.layers.xavier_initializer()) 6 | 7 | def init_biases(shape): 8 | return tf.Variable(tf.zeros(shape)) 9 | 10 | def lrelu(x, leak=0.02): 11 | return tf.maximum(x, leak*x) 12 | 13 | def batch_norm(input, phase_train): 14 | return tf.contrib.layers.batch_norm(input, decay=0.999, updates_collections=None, epsilon=1e-5, scale=True, is_training=phase_train) 15 | # better using instance normalization since the batch size is 1 16 | #return tf.contrib.layers.instance_norm(input) 17 | 18 | def linear(input_, output_size, scope): 19 | shape = input_.get_shape().as_list() 20 | with tf.variable_scope(scope): 21 | matrix = tf.get_variable("Matrix", [shape[1], output_size], tf.float32, tf.random_normal_initializer(stddev=0.02)) 22 | bias = tf.get_variable("bias", [output_size], initializer=tf.zeros_initializer()) 23 | print("linear","in",shape,"out",(shape[0],output_size)) 24 | return tf.matmul(input_, matrix) + bias 25 | 26 | def conv2d(input_, shape, strides, scope, padding="SAME"): 27 | with tf.variable_scope(scope): 28 | matrix = tf.get_variable('Matrix', shape, initializer=tf.truncated_normal_initializer(stddev=0.02)) 29 | bias = tf.get_variable('bias', [shape[-1]], initializer=tf.zeros_initializer()) 30 | conv = tf.nn.conv2d(input_, matrix, strides=strides, padding=padding) 31 | conv = tf.nn.bias_add(conv, bias) 32 | print("conv2d","in",input_.shape,"out",conv.shape) 33 | return conv 34 | 35 | def conv3d(input_, shape, strides, scope, padding="SAME"): 36 | with tf.variable_scope(scope): 37 | matrix = tf.get_variable("Matrix", shape, initializer=tf.contrib.layers.xavier_initializer()) 38 | bias = tf.get_variable("bias", [shape[-1]], initializer=tf.zeros_initializer()) 39 | conv = tf.nn.conv3d(input_, matrix, strides=strides, padding=padding) 40 | conv = tf.nn.bias_add(conv, bias) 41 | print("conv3d","in",input_.shape,"out",conv.shape) 42 | return conv 43 | 44 | def conv2d_nobias(input_, shape, strides, scope, padding="SAME"): 45 | with tf.variable_scope(scope): 46 | matrix = tf.get_variable('Matrix', shape, initializer=tf.truncated_normal_initializer(stddev=0.02)) 47 | conv = tf.nn.conv2d(input_, matrix, strides=strides, padding=padding) 48 | print("conv2d","in",input_.shape,"out",conv.shape) 49 | return conv -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Learning Implicit Fields for Generative Shape Modeling 2 | 3 | Copyright (c) 2018, GrUVi lab of Simon Fraser University 4 | 5 | MIT License 6 | 7 | Copyright (c) 2018 Zhiqin Chen 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # implicit-decoder 2 | The tensorflow code for paper "Learning Implicit Fields for Generative Shape Modeling", [Zhiqin Chen](https://www.sfu.ca/~zhiqinc/), [Hao (Richard) Zhang](https://www.cs.sfu.ca/~haoz/). 3 | 4 | ### [Project page](https://www.sfu.ca/~zhiqinc/imgan/Readme.html) | [Paper](https://arxiv.org/abs/1812.02822) 5 | 6 | ### [Improved TensorFlow1 implementation](https://github.com/czq142857/IM-NET) 7 | 8 | ### [Improved PyTorch implementation](https://github.com/czq142857/IM-NET-pytorch) 9 | 10 | 11 | 12 | 13 | ## Update 14 | We have an improved implementation [here](https://github.com/czq142857/IM-NET), where we trained one model on the 13 ShapeNet categories. 15 | 16 | We have a PyTorch implementation [here](https://github.com/czq142857/IM-NET-pytorch). 17 | 18 | 19 | ## Introduction 20 | We advocate the use of implicit fields for learning generative models of shapes and introduce an implicit field decoder, called IM-NET, for shape generation, aimed at improving the visual quality of the generated shapes. An implicit field assigns a value to each point in 3D space, so that a shape can be extracted as an iso-surface. IM-NET is trained to perform this assignment by means of a binary classifier. Specifically, it takes a point coordinate, along with a feature vector encoding a shape, and outputs a value which indicates whether the point is outside the shape or not. By replacing conventional decoders by our implicit decoder for representation learning (via IM-AE) and shape generation (via IM-GAN), we demonstrate superior results for tasks such as generative shape modeling, interpolation, and single-view 3D reconstruction, particularly in terms of visual quality. 21 | 22 | 23 | ## Citation 24 | If you find our work useful in your research, please consider citing: 25 | 26 | @article{chen2018implicit_decoder, 27 | title={Learning Implicit Fields for Generative Shape Modeling}, 28 | author={Chen, Zhiqin and Zhang, Hao}, 29 | journal={Proceedings of IEEE Conference on Computer Vision and Pattern Recognition (CVPR)}, 30 | year={2019} 31 | } 32 | 33 | 34 | ## Dependencies 35 | Requirements: 36 | - Python 3.5 with numpy, scipy and h5py 37 | - [Tensorflow 1](https://www.tensorflow.org/get_started/os_setup) 38 | - [PyMCubes](https://github.com/pmneila/PyMCubes) (for matching cubes) 39 | - [pycollada](https://github.com/pycollada/pycollada) (for writing .dae files) 40 | - [OpenCV-Python](https://opencv-python-tutroals.readthedocs.io/en/latest/) (for reading and writing images) 41 | 42 | Our code has been tested with Python 3.5, TensorFlow 1.8.0, CUDA 9.1 and cuDNN 7.0 on Ubuntu 16.04 and Windows 10. 43 | 44 | 45 | ## Datasets and Pre-trained weights 46 | The original voxel models and rendered views are from [HSP](https://github.com/chaene/hsp). 47 | Since our network takes point-value pairs, the voxel models require further sampling. The sampling method can be found in our [project page](https://www.sfu.ca/~zhiqinc/imgan/Readme.html). 48 | 49 | We provide the ready-to-use datasets in hdf5 format, together with our pre-trained network weights. The weights for IM-GAN is the ones we used in our demo video. The weights for IM-SVR is the ones we used in the experiments in our paper. 50 | 51 | - [IMAE&IMGAN](https://drive.google.com/open?id=1ERuwUnRMF-5LEfdts5vv6tMpEZPX_pV1) 52 | - [IMSVR](https://drive.google.com/open?id=1n-eGpGt6NEV39zqY2Vykl4yeZTzPtn9l) 53 | 54 | Backup links: 55 | - [IMAE&IMGAN](https://pan.baidu.com/s/12pqJNebP3s9IGUNteoZLRw) 56 | - [IMSVR](https://pan.baidu.com/s/1Uosl_luOHX242nFjofEOwQ) 57 | 58 | 59 | ## Usage 60 | 61 | For data preparation, please see directory [point_sampling](https://github.com/czq142857/implicit-decoder/tree/master/point_sampling). 62 | 63 | To train an autoencoder, go to IMGAN and use the following commands for progressive training. You may want to copy the commands in a .bat or .sh file. 64 | ``` 65 | python main.py --ae --train --epoch 50 --real_size 16 --batch_size_input 4096 66 | python main.py --ae --train --epoch 100 --real_size 32 --batch_size_input 8192 67 | python main.py --ae --train --epoch 200 --real_size 64 --batch_size_input 32768 68 | ``` 69 | The above commands will train the AE model 50 epochs in 163 resolution (each shape has 4096 sampled points), then 50 epochs in 323 resolution, and finally 100 epochs in 643 resolution. 70 | 71 | 72 | To train a latent-gan, after training the autoencoder, use the following command to extract the latent codes: 73 | ``` 74 | python main.py --ae 75 | ``` 76 | Then train the latent-gan and get some samples: 77 | ``` 78 | python main.py --train --epoch 10000 79 | python main.py 80 | ``` 81 | You can change some lines in main.py to adjust the number of samples and the sampling resolution. 82 | 83 | To train the network for single-view reconstruction, after training the autoencoder, copy the weights and latent codes to the corresponding folders in IMSVR. Go to IMSVR and use the following commands to train IM-SVR and get some samples: 84 | ``` 85 | python main.py --train --epoch 1000 86 | python main.py 87 | ``` 88 | 89 | ## License 90 | This project is licensed under the terms of the MIT license (see LICENSE for details). 91 | 92 | 93 | -------------------------------------------------------------------------------- /img/car.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/img/car.gif -------------------------------------------------------------------------------- /img/chair.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/img/chair.gif -------------------------------------------------------------------------------- /img/font.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/img/font.gif -------------------------------------------------------------------------------- /img/plane.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/img/plane.gif -------------------------------------------------------------------------------- /img/rifle.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/img/rifle.gif -------------------------------------------------------------------------------- /img/table.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/img/table.gif -------------------------------------------------------------------------------- /img/teaser.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/img/teaser.png -------------------------------------------------------------------------------- /point_sampling/README.md: -------------------------------------------------------------------------------- 1 | # point sampling code for implicit-decoder 2 | 3 | See [project page](https://www.sfu.ca/~zhiqinc/imgan/Readme.html) for detailed sampling method. 4 | 5 | ## Usage 6 | 7 | In our paper we used the voxel data from HSP(https://github.com/chaene/hsp). 8 | 9 | You can also use your own voxelized data. We recommand you to normalize each shape so that the diagonal of its bounding box equals to unit length. If you use binvox you are likely to place the shape in a unit cube so that the longest edge in its bounding box is unit length. This could cause some trouble since in the code we rarely sample points near the cube border. 10 | 11 | If you have downloaded the voxelized data from HSP(https://github.com/chaene/hsp), please change the directories in the code and use the following command: 12 | ``` 13 | python vox2pointvaluepair_from_hsp.py 14 | ``` 15 | 16 | If you have prepared your own voxel data (64^3 .binvox), please change the directories in the code and use the following command: 17 | ``` 18 | python vox2pointvaluepair_from_binvox.py 19 | ``` 20 | 21 | You can visualize some shapes in the output hdf5 file by the following command, to see if the code works correctly: 22 | ``` 23 | python test_vox.py 24 | ``` 25 | 26 | Some samples are in folder "samplechair". -------------------------------------------------------------------------------- /point_sampling/binvox_rw.py: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2012 Daniel Maturana 2 | # This file is part of binvox-rw-py. 3 | # 4 | # binvox-rw-py is free software: you can redistribute it and/or modify 5 | # it under the terms of the GNU General Public License as published by 6 | # the Free Software Foundation, either version 3 of the License, or 7 | # (at your option) any later version. 8 | # 9 | # binvox-rw-py is distributed in the hope that it will be useful, 10 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | # GNU General Public License for more details. 13 | # 14 | # You should have received a copy of the GNU General Public License 15 | # along with binvox-rw-py. If not, see . 16 | # 17 | 18 | """ 19 | Binvox to Numpy and back. 20 | 21 | 22 | >>> import numpy as np 23 | >>> import binvox_rw 24 | >>> with open('chair.binvox', 'rb') as f: 25 | ... m1 = binvox_rw.read_as_3d_array(f) 26 | ... 27 | >>> m1.dims 28 | [32, 32, 32] 29 | >>> m1.scale 30 | 41.133000000000003 31 | >>> m1.translate 32 | [0.0, 0.0, 0.0] 33 | >>> with open('chair_out.binvox', 'wb') as f: 34 | ... m1.write(f) 35 | ... 36 | >>> with open('chair_out.binvox', 'rb') as f: 37 | ... m2 = binvox_rw.read_as_3d_array(f) 38 | ... 39 | >>> m1.dims==m2.dims 40 | True 41 | >>> m1.scale==m2.scale 42 | True 43 | >>> m1.translate==m2.translate 44 | True 45 | >>> np.all(m1.data==m2.data) 46 | True 47 | 48 | >>> with open('chair.binvox', 'rb') as f: 49 | ... md = binvox_rw.read_as_3d_array(f) 50 | ... 51 | >>> with open('chair.binvox', 'rb') as f: 52 | ... ms = binvox_rw.read_as_coord_array(f) 53 | ... 54 | >>> data_ds = binvox_rw.dense_to_sparse(md.data) 55 | >>> data_sd = binvox_rw.sparse_to_dense(ms.data, 32) 56 | >>> np.all(data_sd==md.data) 57 | True 58 | >>> # the ordering of elements returned by numpy.nonzero changes with axis 59 | >>> # ordering, so to compare for equality we first lexically sort the voxels. 60 | >>> np.all(ms.data[:, np.lexsort(ms.data)] == data_ds[:, np.lexsort(data_ds)]) 61 | True 62 | """ 63 | 64 | import numpy as np 65 | 66 | class Voxels(object): 67 | """ Holds a binvox model. 68 | data is either a three-dimensional numpy boolean array (dense representation) 69 | or a two-dimensional numpy float array (coordinate representation). 70 | 71 | dims, translate and scale are the model metadata. 72 | 73 | dims are the voxel dimensions, e.g. [32, 32, 32] for a 32x32x32 model. 74 | 75 | scale and translate relate the voxels to the original model coordinates. 76 | 77 | To translate voxel coordinates i, j, k to original coordinates x, y, z: 78 | 79 | x_n = (i+.5)/dims[0] 80 | y_n = (j+.5)/dims[1] 81 | z_n = (k+.5)/dims[2] 82 | x = scale*x_n + translate[0] 83 | y = scale*y_n + translate[1] 84 | z = scale*z_n + translate[2] 85 | 86 | """ 87 | 88 | def __init__(self, data, dims, translate, scale, axis_order): 89 | self.data = data 90 | self.dims = dims 91 | self.translate = translate 92 | self.scale = scale 93 | assert (axis_order in ('xzy', 'xyz')) 94 | self.axis_order = axis_order 95 | 96 | def clone(self): 97 | data = self.data.copy() 98 | dims = self.dims[:] 99 | translate = self.translate[:] 100 | return Voxels(data, dims, translate, self.scale, self.axis_order) 101 | 102 | def write(self, fp): 103 | write(self, fp) 104 | 105 | def read_header(fp): 106 | """ Read binvox header. Mostly meant for internal use. 107 | """ 108 | line = fp.readline().strip() 109 | if not line.startswith(b'#binvox'): 110 | raise IOError('Not a binvox file') 111 | dims = list(map(int, fp.readline().strip().split(b' ')[1:])) 112 | translate = list(map(float, fp.readline().strip().split(b' ')[1:])) 113 | scale = list(map(float, fp.readline().strip().split(b' ')[1:]))[0] 114 | line = fp.readline() 115 | return dims, translate, scale 116 | 117 | def read_as_3d_array(fp, fix_coords=True): 118 | """ Read binary binvox format as array. 119 | 120 | Returns the model with accompanying metadata. 121 | 122 | Voxels are stored in a three-dimensional numpy array, which is simple and 123 | direct, but may use a lot of memory for large models. (Storage requirements 124 | are 8*(d^3) bytes, where d is the dimensions of the binvox model. Numpy 125 | boolean arrays use a byte per element). 126 | 127 | Doesn't do any checks on input except for the '#binvox' line. 128 | """ 129 | dims, translate, scale = read_header(fp) 130 | raw_data = np.frombuffer(fp.read(), dtype=np.uint8) 131 | # if just using reshape() on the raw data: 132 | # indexing the array as array[i,j,k], the indices map into the 133 | # coords as: 134 | # i -> x 135 | # j -> z 136 | # k -> y 137 | # if fix_coords is true, then data is rearranged so that 138 | # mapping is 139 | # i -> x 140 | # j -> y 141 | # k -> z 142 | values, counts = raw_data[::2], raw_data[1::2] 143 | data = np.repeat(values, counts).astype(np.bool) 144 | data = data.reshape(dims) 145 | if fix_coords: 146 | # xzy to xyz TODO the right thing 147 | data = np.transpose(data, (0, 2, 1)) 148 | axis_order = 'xyz' 149 | else: 150 | axis_order = 'xzy' 151 | return Voxels(data, dims, translate, scale, axis_order) 152 | 153 | def read_as_coord_array(fp, fix_coords=True): 154 | """ Read binary binvox format as coordinates. 155 | 156 | Returns binvox model with voxels in a "coordinate" representation, i.e. an 157 | 3 x N array where N is the number of nonzero voxels. Each column 158 | corresponds to a nonzero voxel and the 3 rows are the (x, z, y) coordinates 159 | of the voxel. (The odd ordering is due to the way binvox format lays out 160 | data). Note that coordinates refer to the binvox voxels, without any 161 | scaling or translation. 162 | 163 | Use this to save memory if your model is very sparse (mostly empty). 164 | 165 | Doesn't do any checks on input except for the '#binvox' line. 166 | """ 167 | dims, translate, scale = read_header(fp) 168 | raw_data = np.frombuffer(fp.read(), dtype=np.uint8) 169 | 170 | values, counts = raw_data[::2], raw_data[1::2] 171 | 172 | sz = np.prod(dims) 173 | index, end_index = 0, 0 174 | end_indices = np.cumsum(counts) 175 | indices = np.concatenate(([0], end_indices[:-1])).astype(end_indices.dtype) 176 | 177 | values = values.astype(np.bool) 178 | indices = indices[values] 179 | end_indices = end_indices[values] 180 | 181 | nz_voxels = [] 182 | for index, end_index in zip(indices, end_indices): 183 | nz_voxels.extend(range(index, end_index)) 184 | nz_voxels = np.array(nz_voxels) 185 | # TODO are these dims correct? 186 | # according to docs, 187 | # index = x * wxh + z * width + y; // wxh = width * height = d * d 188 | 189 | x = nz_voxels / (dims[0]*dims[1]) 190 | zwpy = nz_voxels % (dims[0]*dims[1]) # z*w + y 191 | z = zwpy / dims[0] 192 | y = zwpy % dims[0] 193 | if fix_coords: 194 | data = np.vstack((x, y, z)) 195 | axis_order = 'xyz' 196 | else: 197 | data = np.vstack((x, z, y)) 198 | axis_order = 'xzy' 199 | 200 | #return Voxels(data, dims, translate, scale, axis_order) 201 | return Voxels(np.ascontiguousarray(data), dims, translate, scale, axis_order) 202 | 203 | def dense_to_sparse(voxel_data, dtype=np.int): 204 | """ From dense representation to sparse (coordinate) representation. 205 | No coordinate reordering. 206 | """ 207 | if voxel_data.ndim!=3: 208 | raise ValueError('voxel_data is wrong shape; should be 3D array.') 209 | return np.asarray(np.nonzero(voxel_data), dtype) 210 | 211 | def sparse_to_dense(voxel_data, dims, dtype=np.bool): 212 | if voxel_data.ndim!=2 or voxel_data.shape[0]!=3: 213 | raise ValueError('voxel_data is wrong shape; should be 3xN array.') 214 | if np.isscalar(dims): 215 | dims = [dims]*3 216 | dims = np.atleast_2d(dims).T 217 | # truncate to integers 218 | xyz = voxel_data.astype(np.int) 219 | # discard voxels that fall outside dims 220 | valid_ix = ~np.any((xyz < 0) | (xyz >= dims), 0) 221 | xyz = xyz[:,valid_ix] 222 | out = np.zeros(dims.flatten(), dtype=dtype) 223 | out[tuple(xyz)] = True 224 | return out 225 | 226 | #def get_linear_index(x, y, z, dims): 227 | #""" Assuming xzy order. (y increasing fastest. 228 | #TODO ensure this is right when dims are not all same 229 | #""" 230 | #return x*(dims[1]*dims[2]) + z*dims[1] + y 231 | 232 | def write(voxel_model, fp): 233 | """ Write binary binvox format. 234 | 235 | Note that when saving a model in sparse (coordinate) format, it is first 236 | converted to dense format. 237 | 238 | Doesn't check if the model is 'sane'. 239 | 240 | """ 241 | if voxel_model.data.ndim==2: 242 | # TODO avoid conversion to dense 243 | dense_voxel_data = sparse_to_dense(voxel_model.data, voxel_model.dims) 244 | else: 245 | dense_voxel_data = voxel_model.data 246 | 247 | fp.write('#binvox 1\n') 248 | fp.write('dim '+' '.join(map(str, voxel_model.dims))+'\n') 249 | fp.write('translate '+' '.join(map(str, voxel_model.translate))+'\n') 250 | fp.write('scale '+str(voxel_model.scale)+'\n') 251 | fp.write('data\n') 252 | if not voxel_model.axis_order in ('xzy', 'xyz'): 253 | raise ValueError('Unsupported voxel model axis order') 254 | 255 | if voxel_model.axis_order=='xzy': 256 | voxels_flat = dense_voxel_data.flatten() 257 | elif voxel_model.axis_order=='xyz': 258 | voxels_flat = np.transpose(dense_voxel_data, (0, 2, 1)).flatten() 259 | 260 | # keep a sort of state machine for writing run length encoding 261 | state = voxels_flat[0] 262 | ctr = 0 263 | for c in voxels_flat: 264 | if c==state: 265 | ctr += 1 266 | # if ctr hits max, dump 267 | if ctr==255: 268 | fp.write(chr(state)) 269 | fp.write(chr(ctr)) 270 | ctr = 0 271 | else: 272 | # if switch state, dump 273 | fp.write(chr(state)) 274 | fp.write(chr(ctr)) 275 | state = c 276 | ctr = 1 277 | # flush out remainders 278 | if ctr > 0: 279 | fp.write(chr(state)) 280 | fp.write(chr(ctr)) 281 | 282 | if __name__ == '__main__': 283 | import doctest 284 | doctest.testmod() 285 | -------------------------------------------------------------------------------- /point_sampling/data/samplechair/1.binvox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/point_sampling/data/samplechair/1.binvox -------------------------------------------------------------------------------- /point_sampling/data/samplechair/2.binvox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/point_sampling/data/samplechair/2.binvox -------------------------------------------------------------------------------- /point_sampling/data/samplechair/3.binvox: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/point_sampling/data/samplechair/3.binvox -------------------------------------------------------------------------------- /point_sampling/samplechair/0_16_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/point_sampling/samplechair/0_16_1.png -------------------------------------------------------------------------------- /point_sampling/samplechair/0_16_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/point_sampling/samplechair/0_16_2.png -------------------------------------------------------------------------------- /point_sampling/samplechair/0_16_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/point_sampling/samplechair/0_16_3.png -------------------------------------------------------------------------------- /point_sampling/samplechair/0_32_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/point_sampling/samplechair/0_32_1.png -------------------------------------------------------------------------------- /point_sampling/samplechair/0_32_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/point_sampling/samplechair/0_32_2.png -------------------------------------------------------------------------------- /point_sampling/samplechair/0_32_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/point_sampling/samplechair/0_32_3.png -------------------------------------------------------------------------------- /point_sampling/samplechair/0_64_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/point_sampling/samplechair/0_64_1.png -------------------------------------------------------------------------------- /point_sampling/samplechair/0_64_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/point_sampling/samplechair/0_64_2.png -------------------------------------------------------------------------------- /point_sampling/samplechair/0_64_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/point_sampling/samplechair/0_64_3.png -------------------------------------------------------------------------------- /point_sampling/samplechair/0_vox_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/point_sampling/samplechair/0_vox_1.png -------------------------------------------------------------------------------- /point_sampling/samplechair/0_vox_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/point_sampling/samplechair/0_vox_2.png -------------------------------------------------------------------------------- /point_sampling/samplechair/0_vox_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/point_sampling/samplechair/0_vox_3.png -------------------------------------------------------------------------------- /point_sampling/samplechair/samplechair_vox.hdf5: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/czq142857/implicit-decoder/62d562dd702356cbdcd1d63ef204e42f9a907751/point_sampling/samplechair/samplechair_vox.hdf5 -------------------------------------------------------------------------------- /point_sampling/samplechair/samplechair_vox.txt: -------------------------------------------------------------------------------- 1 | 1 2 | 2 3 | 3 4 | -------------------------------------------------------------------------------- /point_sampling/samplechair/statistics.txt: -------------------------------------------------------------------------------- 1 | total: 3 2 | exceed_32: 1 3 | exceed_32_ratio: 0.3333333333333333 4 | exceed_64: 0 5 | exceed_64_ratio: 0.0 6 | -------------------------------------------------------------------------------- /point_sampling/test_vox.py: -------------------------------------------------------------------------------- 1 | import os 2 | import time 3 | import math 4 | from glob import glob 5 | import tensorflow as tf 6 | import numpy as np 7 | import h5py 8 | import cv2 9 | import mcubes 10 | 11 | data_dict = h5py.File('samplechair/samplechair_vox.hdf5', 'r') 12 | data_points16 = data_dict['points_16'][:] 13 | data_values16 = data_dict['values_16'][:] 14 | data_points32 = data_dict['points_32'][:] 15 | data_values32 = data_dict['values_32'][:] 16 | data_points64 = data_dict['points_64'][:] 17 | data_values64 = data_dict['values_64'][:] 18 | data_voxels = data_dict['voxels'][:] 19 | 20 | 21 | dxb = 0 22 | 23 | batch_voxels = data_voxels[dxb:dxb+1] 24 | batch_voxels = np.reshape(batch_voxels,[64,64,64]) 25 | img1 = np.clip(np.amax(batch_voxels, axis=0)*256, 0,255).astype(np.uint8) 26 | img2 = np.clip(np.amax(batch_voxels, axis=1)*256, 0,255).astype(np.uint8) 27 | img3 = np.clip(np.amax(batch_voxels, axis=2)*256, 0,255).astype(np.uint8) 28 | cv2.imwrite(str(dxb)+"_vox_1.png",img1) 29 | cv2.imwrite(str(dxb)+"_vox_2.png",img2) 30 | cv2.imwrite(str(dxb)+"_vox_3.png",img3) 31 | vertices, triangles = mcubes.marching_cubes(batch_voxels, 0.5) 32 | mcubes.export_mesh(vertices, triangles, str(dxb)+"_vox.dae", str(dxb)) 33 | 34 | 35 | batch_points_int = data_points16[dxb,:] 36 | batch_values = data_values16[dxb,:] 37 | real_model = np.zeros([16,16,16],np.uint8) 38 | real_model[batch_points_int[:,0],batch_points_int[:,1],batch_points_int[:,2]] = np.reshape(batch_values, [-1]) 39 | img1 = np.clip(np.amax(real_model, axis=0)*256, 0,255).astype(np.uint8) 40 | img2 = np.clip(np.amax(real_model, axis=1)*256, 0,255).astype(np.uint8) 41 | img3 = np.clip(np.amax(real_model, axis=2)*256, 0,255).astype(np.uint8) 42 | cv2.imwrite(str(dxb)+"_16_1.png",img1) 43 | cv2.imwrite(str(dxb)+"_16_2.png",img2) 44 | cv2.imwrite(str(dxb)+"_16_3.png",img3) 45 | vertices, triangles = mcubes.marching_cubes(batch_voxels, 0.5) 46 | mcubes.export_mesh(vertices, triangles, str(dxb)+"_16.dae", str(dxb)) 47 | 48 | 49 | batch_points_int = data_points32[dxb,:] 50 | batch_values = data_values32[dxb,:] 51 | real_model = np.zeros([32,32,32],np.uint8) 52 | real_model[batch_points_int[:,0],batch_points_int[:,1],batch_points_int[:,2]] = np.reshape(batch_values, [-1]) 53 | img1 = np.clip(np.amax(real_model, axis=0)*256, 0,255).astype(np.uint8) 54 | img2 = np.clip(np.amax(real_model, axis=1)*256, 0,255).astype(np.uint8) 55 | img3 = np.clip(np.amax(real_model, axis=2)*256, 0,255).astype(np.uint8) 56 | cv2.imwrite(str(dxb)+"_32_1.png",img1) 57 | cv2.imwrite(str(dxb)+"_32_2.png",img2) 58 | cv2.imwrite(str(dxb)+"_32_3.png",img3) 59 | vertices, triangles = mcubes.marching_cubes(batch_voxels, 0.5) 60 | mcubes.export_mesh(vertices, triangles, str(dxb)+"_32.dae", str(dxb)) 61 | 62 | 63 | batch_points_int = data_points64[dxb,:] 64 | batch_values = data_values64[dxb,:] 65 | real_model = np.zeros([64,64,64],np.uint8) 66 | real_model[batch_points_int[:,0],batch_points_int[:,1],batch_points_int[:,2]] = np.reshape(batch_values, [-1]) 67 | img1 = np.clip(np.amax(real_model, axis=0)*256, 0,255).astype(np.uint8) 68 | img2 = np.clip(np.amax(real_model, axis=1)*256, 0,255).astype(np.uint8) 69 | img3 = np.clip(np.amax(real_model, axis=2)*256, 0,255).astype(np.uint8) 70 | cv2.imwrite(str(dxb)+"_64_1.png",img1) 71 | cv2.imwrite(str(dxb)+"_64_2.png",img2) 72 | cv2.imwrite(str(dxb)+"_64_3.png",img3) 73 | vertices, triangles = mcubes.marching_cubes(batch_voxels, 0.5) 74 | mcubes.export_mesh(vertices, triangles, str(dxb)+"_64.dae", str(dxb)) 75 | -------------------------------------------------------------------------------- /point_sampling/vox2pointvaluepair_from_binvox.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | import os 4 | import h5py 5 | import binvox_rw 6 | import random 7 | 8 | class_name_list = [ 9 | "samplechair", 10 | ] 11 | 12 | def list_image(root, recursive, exts): 13 | image_list = [] 14 | cat = {} 15 | for path, subdirs, files in os.walk(root): 16 | for fname in files: 17 | fpath = os.path.join(path, fname) 18 | suffix = os.path.splitext(fname)[1].lower() 19 | if os.path.isfile(fpath) and (suffix in exts): 20 | if path not in cat: 21 | cat[path] = len(cat) 22 | image_list.append((os.path.relpath(fpath, root), cat[path])) 23 | return image_list 24 | 25 | #hierarchical flood fill for 3D image: 32->64 26 | def hierarchicalfloodFill(img64,dim): 27 | assert dim==64 28 | img64 = np.copy(img64) 29 | 30 | #compress model 64 -> 32 31 | dim_voxel = 32 32 | img32 = np.zeros([dim_voxel,dim_voxel,dim_voxel],np.uint8) 33 | multiplier = int(64/dim_voxel) 34 | for i in range(dim_voxel): 35 | for j in range(dim_voxel): 36 | for k in range(dim_voxel): 37 | img32[i,j,k] = np.max(img64[i*multiplier:(i+1)*multiplier,j*multiplier:(j+1)*multiplier,k*multiplier:(k+1)*multiplier]) 38 | 39 | img32 = floodFill(img32, [(0,0,0),(31,0,0),(0,31,0),(31,31,0),(0,0,31),(31,0,31),(0,31,31),(31,31,31)], 32) 40 | for i in range(1,dim_voxel-1): 41 | for j in range(1,dim_voxel-1): 42 | for k in range(1,dim_voxel-1): 43 | occupied_flag = True 44 | for i0 in range(-1,2): 45 | for j0 in range(-1,2): 46 | for k0 in range(-1,2): 47 | if i0==0 and j0==0 and k0==0: continue 48 | if img32[i+i0,j+j0,k+k0]==0: occupied_flag = False 49 | if occupied_flag: 50 | img64[i*multiplier:(i+1)*multiplier,j*multiplier:(j+1)*multiplier,k*multiplier:(k+1)*multiplier] = np.ones([2,2,2],np.uint8) 51 | 52 | out64 = floodFill(img64, [(0,0,0),(63,0,0),(0,63,0),(63,63,0),(0,0,63),(63,0,63),(0,63,63),(63,63,63)], 64) 53 | 54 | print('filled', np.sum(np.abs(out64-img64))) 55 | return out64 56 | 57 | #flood fill for 3D image 58 | #input123: voxel model, initial points, size 59 | #output1: voxel model, 0 for outside, 1 for inside 60 | def floodFill(imgin, target_point_list,d): 61 | assert imgin.shape == (d,d,d) 62 | img = imgin+1 63 | queue = [] 64 | for target_point in target_point_list: 65 | if img[target_point] == 1: 66 | img[target_point] = 0 67 | queue.append(target_point) 68 | while len(queue)>0: 69 | point = queue.pop(0) 70 | for i,j,k in [(1,0,0),(-1,0,0),(0,1,0),(0,-1,0),(0,0,1),(0,0,-1)]: 71 | pi = point[0]+i 72 | pj = point[1]+j 73 | pk = point[2]+k 74 | if (pi<0 or pi>=d): continue 75 | if (pj<0 or pj>=d): continue 76 | if (pk<0 or pk>=d): continue 77 | if (img[pi,pj,pk] == 1): 78 | img[pi,pj,pk] = 0 79 | queue.append((pi,pj,pk)) 80 | img = (img>0).astype(np.uint8) 81 | return img 82 | 83 | 84 | for kkk in range(len(class_name_list)): 85 | if not os.path.exists(class_name_list[kkk]): 86 | os.makedirs(class_name_list[kkk]) 87 | 88 | #class number 89 | class_name = class_name_list[kkk] 90 | print(class_name) 91 | 92 | #dir of voxel models 93 | voxel_input = "F:\\point_sampling\\data\\"+class_name+"\\" 94 | image_list = list_image(voxel_input, False, ['.binvox']) 95 | name_list = [] 96 | for i in range(len(image_list)): 97 | imagine=image_list[i][0] 98 | name_list.append(imagine[0:-7]) 99 | name_list = sorted(name_list) 100 | name_num = len(name_list) 101 | 102 | #record statistics 103 | fstatistics = open(class_name+'\\statistics.txt','w',newline='') 104 | exceed_32 = 0 105 | exceed_64 = 0 106 | 107 | dim = 64 108 | 109 | vox_size_1 = 16 110 | vox_size_2 = 32 111 | vox_size_3 = 64 112 | 113 | batch_size_1 = 16*16*16 114 | batch_size_2 = 16*16*16*2 115 | batch_size_3 = 32*32*32 116 | 117 | class_len_all_real = name_num 118 | 119 | hdf5_path = class_name+'\\'+class_name+'_vox.hdf5' 120 | fout = open(class_name+'\\'+class_name+'_vox.txt','w',newline='') 121 | 122 | hdf5_file = h5py.File(hdf5_path, 'w') 123 | hdf5_file.create_dataset("voxels", [class_len_all_real,dim,dim,dim,1], np.uint8, compression=9) 124 | hdf5_file.create_dataset("points_16", [class_len_all_real,batch_size_1,3], np.uint8, compression=9) 125 | hdf5_file.create_dataset("values_16", [class_len_all_real,batch_size_1,1], np.uint8, compression=9) 126 | hdf5_file.create_dataset("points_32", [class_len_all_real,batch_size_2,3], np.uint8, compression=9) 127 | hdf5_file.create_dataset("values_32", [class_len_all_real,batch_size_2,1], np.uint8, compression=9) 128 | hdf5_file.create_dataset("points_64", [class_len_all_real,batch_size_3,3], np.uint8, compression=9) 129 | hdf5_file.create_dataset("values_64", [class_len_all_real,batch_size_3,1], np.uint8, compression=9) 130 | 131 | 132 | counter = 0 133 | for idx in range(name_num): 134 | print(idx) 135 | #get voxel models 136 | try: 137 | voxel_model_file = open(voxel_input+name_list[idx]+".binvox", 'rb') 138 | voxel_model_64_crude = binvox_rw.read_as_3d_array(voxel_model_file).data.astype(np.uint8) 139 | #add flip&transpose to convert coord from shapenet_v1 to shapenet_v2 140 | #Note stool is special!!! 141 | #voxel_model_64_crude = np.flip(np.transpose(voxel_model_64_crude, (1,2,0)),2) 142 | voxel_model_64 = hierarchicalfloodFill(voxel_model_64_crude, 64) 143 | except: 144 | print("error in loading") 145 | print(voxel_input+name_list[idx]+"\\model.binvox") 146 | exit(0) 147 | 148 | 149 | 150 | #compress model 64 -> 64 151 | dim_voxel = 64 152 | hdf5_file["voxels"][counter,:,:,:,:] = np.reshape(voxel_model_64, (dim_voxel,dim_voxel,dim_voxel,1)) 153 | 154 | #sample points near surface 155 | batch_size = batch_size_3 156 | 157 | sample_points = np.zeros([batch_size,3],np.uint8) 158 | sample_values = np.zeros([batch_size,1],np.uint8) 159 | batch_size_counter = 0 160 | voxel_model_64_flag = np.zeros([dim_voxel,dim_voxel,dim_voxel],np.uint8) 161 | for i in range(3,dim_voxel-3): 162 | if (batch_size_counter>=batch_size): break 163 | for j in range(3,dim_voxel-3): 164 | if (batch_size_counter>=batch_size): break 165 | for k in range(3,dim_voxel-3): 166 | if (batch_size_counter>=batch_size): break 167 | if (np.max(voxel_model_64[i-3:i+4,j-3:j+4,k-3:k+4])!=np.min(voxel_model_64[i-3:i+4,j-3:j+4,k-3:k+4])): 168 | sample_points[batch_size_counter,0] = i 169 | sample_points[batch_size_counter,1] = j 170 | sample_points[batch_size_counter,2] = k 171 | sample_values[batch_size_counter,0] = voxel_model_64[i,j,k] 172 | voxel_model_64_flag[i,j,k] = 1 173 | batch_size_counter +=1 174 | if (batch_size_counter>=batch_size): 175 | print("64-- batch_size exceeded!") 176 | exceed_64 += 1 177 | batch_size_counter = 0 178 | voxel_model_64_flag = np.zeros([dim_voxel,dim_voxel,dim_voxel],np.uint8) 179 | for i in range(0,dim_voxel,2): 180 | for j in range(0,dim_voxel,2): 181 | for k in range(0,dim_voxel,2): 182 | filled_flag = False 183 | for (i0,j0,k0) in [(i,j,k),(i+1,j,k),(i,j+1,k),(i+1,j+1,k),(i,j,k+1),(i+1,j,k+1),(i,j+1,k+1),(i+1,j+1,k+1)]: 184 | if voxel_model_64[i0,j0,k0]>0: 185 | filled_flag = True 186 | sample_points[batch_size_counter,0] = i0 187 | sample_points[batch_size_counter,1] = j0 188 | sample_points[batch_size_counter,2] = k0 189 | sample_values[batch_size_counter,0] = voxel_model_64[i0,j0,k0] 190 | voxel_model_64_flag[i0,j0,k0] = 1 191 | break 192 | if not filled_flag: 193 | sample_points[batch_size_counter,0] = i 194 | sample_points[batch_size_counter,1] = j 195 | sample_points[batch_size_counter,2] = k 196 | sample_values[batch_size_counter,0] = voxel_model_64[i,j,k] 197 | voxel_model_64_flag[i,j,k] = 1 198 | batch_size_counter +=1 199 | #fill other slots with random points 200 | while (batch_size_counter 32 235 | dim_voxel = 32 236 | voxel_model_32 = np.zeros([dim_voxel,dim_voxel,dim_voxel],np.uint8) 237 | multiplier = int(64/dim_voxel) 238 | for i in range(dim_voxel): 239 | for j in range(dim_voxel): 240 | for k in range(dim_voxel): 241 | voxel_model_32[i,j,k] = np.max(voxel_model_64[i*multiplier:(i+1)*multiplier,j*multiplier:(j+1)*multiplier,k*multiplier:(k+1)*multiplier]) 242 | 243 | #sample points near surface 244 | batch_size = batch_size_2 245 | 246 | sample_points = np.zeros([batch_size,3],np.uint8) 247 | sample_values = np.zeros([batch_size,1],np.uint8) 248 | batch_size_counter = 0 249 | voxel_model_32_flag = np.zeros([dim_voxel,dim_voxel,dim_voxel],np.uint8) 250 | for i in range(3,dim_voxel-3): 251 | if (batch_size_counter>=batch_size): break 252 | for j in range(3,dim_voxel-3): 253 | if (batch_size_counter>=batch_size): break 254 | for k in range(3,dim_voxel-3): 255 | if (batch_size_counter>=batch_size): break 256 | if (np.max(voxel_model_32[i-3:i+4,j-3:j+4,k-3:k+4])!=np.min(voxel_model_32[i-3:i+4,j-3:j+4,k-3:k+4])): 257 | sample_points[batch_size_counter,0] = i 258 | sample_points[batch_size_counter,1] = j 259 | sample_points[batch_size_counter,2] = k 260 | sample_values[batch_size_counter,0] = voxel_model_32[i,j,k] 261 | voxel_model_32_flag[i,j,k] = 1 262 | batch_size_counter +=1 263 | if (batch_size_counter>=batch_size): 264 | print("32-- batch_size exceeded!") 265 | exceed_32 += 1 266 | batch_size_counter = 0 267 | voxel_model_32_flag = np.zeros([dim_voxel,dim_voxel,dim_voxel],np.uint8) 268 | for i in range(0,dim_voxel,2): 269 | for j in range(0,dim_voxel,2): 270 | for k in range(0,dim_voxel,2): 271 | filled_flag = False 272 | for (i0,j0,k0) in [(i,j,k),(i+1,j,k),(i,j+1,k),(i+1,j+1,k),(i,j,k+1),(i+1,j,k+1),(i,j+1,k+1),(i+1,j+1,k+1)]: 273 | if voxel_model_32[i0,j0,k0]>0: 274 | filled_flag = True 275 | sample_points[batch_size_counter,0] = i0 276 | sample_points[batch_size_counter,1] = j0 277 | sample_points[batch_size_counter,2] = k0 278 | sample_values[batch_size_counter,0] = voxel_model_32[i0,j0,k0] 279 | voxel_model_32_flag[i0,j0,k0] = 1 280 | break 281 | if not filled_flag: 282 | sample_points[batch_size_counter,0] = i 283 | sample_points[batch_size_counter,1] = j 284 | sample_points[batch_size_counter,2] = k 285 | sample_values[batch_size_counter,0] = voxel_model_32[i,j,k] 286 | voxel_model_32_flag[i,j,k] = 1 287 | batch_size_counter +=1 288 | #fill other slots with random points 289 | while (batch_size_counter 16 320 | dim_voxel = 16 321 | voxel_model_16 = np.zeros([dim_voxel,dim_voxel,dim_voxel],np.uint8) 322 | multiplier = int(64/dim_voxel) 323 | for i in range(dim_voxel): 324 | for j in range(dim_voxel): 325 | for k in range(dim_voxel): 326 | voxel_model_16[i,j,k] = np.max(voxel_model_64[i*multiplier:(i+1)*multiplier,j*multiplier:(j+1)*multiplier,k*multiplier:(k+1)*multiplier]) 327 | 328 | #sample points near surface 329 | batch_size = batch_size_1 330 | 331 | sample_points = np.zeros([batch_size,3],np.uint8) 332 | sample_values = np.zeros([batch_size,1],np.uint8) 333 | batch_size_counter = 0 334 | for i in range(dim_voxel): 335 | for j in range(dim_voxel): 336 | for k in range(dim_voxel): 337 | sample_points[batch_size_counter,0] = i 338 | sample_points[batch_size_counter,1] = j 339 | sample_points[batch_size_counter,2] = k 340 | sample_values[batch_size_counter,0] = voxel_model_16[i,j,k] 341 | batch_size_counter +=1 342 | if (batch_size_counter!=batch_size): 343 | print("batch_size_counter!=batch_size") 344 | 345 | hdf5_file["points_16"][counter,:,:] = sample_points 346 | hdf5_file["values_16"][counter,:,:] = sample_values 347 | 348 | fout.write(name_list[idx]+"\n") 349 | counter += 1 350 | 351 | assert counter==class_len_all_real 352 | 353 | fstatistics.write("total: "+str(class_len_all_real)+"\n") 354 | fstatistics.write("exceed_32: "+str(exceed_32)+"\n") 355 | fstatistics.write("exceed_32_ratio: "+str(float(exceed_32)/class_len_all_real)+"\n") 356 | fstatistics.write("exceed_64: "+str(exceed_64)+"\n") 357 | fstatistics.write("exceed_64_ratio: "+str(float(exceed_64)/class_len_all_real)+"\n") 358 | 359 | fout.close() 360 | fstatistics.close() 361 | hdf5_file.close() 362 | print("finished") 363 | 364 | 365 | -------------------------------------------------------------------------------- /point_sampling/vox2pointvaluepair_from_hsp.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import cv2 3 | import os 4 | import h5py 5 | from scipy.io import loadmat 6 | import random 7 | import json 8 | 9 | class_name_list = [ 10 | "02828884_bench", 11 | "04090263_rifle", 12 | "04256520_couch", 13 | "04530566_vessel", 14 | "02958343_car", 15 | ] 16 | 17 | def list_image(root, recursive, exts): 18 | image_list = [] 19 | cat = {} 20 | for path, subdirs, files in os.walk(root): 21 | for fname in files: 22 | fpath = os.path.join(path, fname) 23 | suffix = os.path.splitext(fname)[1].lower() 24 | if os.path.isfile(fpath) and (suffix in exts): 25 | if path not in cat: 26 | cat[path] = len(cat) 27 | image_list.append((os.path.relpath(fpath, root), cat[path])) 28 | return image_list 29 | 30 | 31 | for kkk in range(len(class_name_list)): 32 | if not os.path.exists(class_name_list[kkk]): 33 | os.makedirs(class_name_list[kkk]) 34 | 35 | #class number 36 | class_name = class_name_list[kkk][:8] 37 | print(class_name_list[kkk]) 38 | 39 | #dir of voxel models 40 | voxel_input = "F:\\hsp\\shapenet\\modelBlockedVoxels256\\"+class_name+"\\" 41 | 42 | #name of output file 43 | hdf5_path = class_name_list[kkk]+'\\'+class_name+'_vox.hdf5' 44 | 45 | #obj_list 46 | fout = open(class_name_list[kkk]+'\\obj_list.txt','w',newline='') 47 | 48 | #record statistics 49 | fstatistics = open(class_name_list[kkk]+'\\statistics.txt','w',newline='') 50 | exceed_32 = 0 51 | exceed_64 = 0 52 | 53 | 54 | dim = 64 55 | 56 | vox_size_1 = 16 57 | vox_size_2 = 32 58 | vox_size_3 = 64 59 | 60 | batch_size_1 = 16*16*16 61 | batch_size_2 = 16*16*16*2 62 | batch_size_3 = 32*32*32 63 | 64 | 65 | image_list = list_image(voxel_input, True, ['.mat']) 66 | name_list = [] 67 | for i in range(len(image_list)): 68 | imagine=image_list[i][0] 69 | name_list.append(imagine[0:-4]) 70 | name_list = sorted(name_list) 71 | name_num = len(name_list) 72 | #name_list contains all obj names 73 | 74 | hdf5_file = h5py.File(hdf5_path, 'w') 75 | hdf5_file.create_dataset("voxels", [name_num,dim,dim,dim,1], np.uint8, compression=9) 76 | hdf5_file.create_dataset("points_16", [name_num,batch_size_1,3], np.uint8, compression=9) 77 | hdf5_file.create_dataset("values_16", [name_num,batch_size_1,1], np.uint8, compression=9) 78 | hdf5_file.create_dataset("points_32", [name_num,batch_size_2,3], np.uint8, compression=9) 79 | hdf5_file.create_dataset("values_32", [name_num,batch_size_2,1], np.uint8, compression=9) 80 | hdf5_file.create_dataset("points_64", [name_num,batch_size_3,3], np.uint8, compression=9) 81 | hdf5_file.create_dataset("values_64", [name_num,batch_size_3,1], np.uint8, compression=9) 82 | 83 | 84 | for idx in range(name_num): 85 | print(idx) 86 | 87 | #get voxel models 88 | name_list_idx = name_list[idx] 89 | proper_name = "shape_data/"+class_name+"/"+name_list_idx 90 | try: 91 | voxel_model_mat = loadmat(voxel_input+name_list_idx+".mat") 92 | except: 93 | print("error in loading") 94 | name_list_idx = name_list[idx-1] 95 | try: 96 | voxel_model_mat = loadmat(voxel_input+name_list_idx+".mat") 97 | except: 98 | print("error in loading") 99 | name_list_idx = name_list[idx-2] 100 | try: 101 | voxel_model_mat = loadmat(voxel_input+name_list_idx+".mat") 102 | except: 103 | print("error in loading") 104 | exit(0) 105 | 106 | 107 | 108 | voxel_model_b = voxel_model_mat['b'][:].astype(np.int32) 109 | voxel_model_bi = voxel_model_mat['bi'][:].astype(np.int32)-1 110 | voxel_model_256 = np.zeros([256,256,256],np.uint8) 111 | for i in range(16): 112 | for j in range(16): 113 | for k in range(16): 114 | voxel_model_256[i*16:i*16+16,j*16:j*16+16,k*16:k*16+16] = voxel_model_b[voxel_model_bi[i,j,k]] 115 | #add flip&transpose to convert coord from shapenet_v1 to shapenet_v2 116 | voxel_model_256 = np.flip(np.transpose(voxel_model_256, (2,1,0)),2) 117 | 118 | 119 | 120 | 121 | 122 | #compress model 256 -> 64 123 | dim_voxel = 64 124 | voxel_model_64 = np.zeros([dim_voxel,dim_voxel,dim_voxel],np.uint8) 125 | multiplier = int(256/dim_voxel) 126 | for i in range(dim_voxel): 127 | for j in range(dim_voxel): 128 | for k in range(dim_voxel): 129 | voxel_model_64[i,j,k] = np.max(voxel_model_256[i*multiplier:(i+1)*multiplier,j*multiplier:(j+1)*multiplier,k*multiplier:(k+1)*multiplier]) 130 | hdf5_file["voxels"][idx,:,:,:,:] = np.reshape(voxel_model_64, (dim_voxel,dim_voxel,dim_voxel,1)) 131 | 132 | #sample points near surface 133 | batch_size = batch_size_3 134 | 135 | sample_points = np.zeros([batch_size,3],np.uint8) 136 | sample_values = np.zeros([batch_size,1],np.uint8) 137 | batch_size_counter = 0 138 | voxel_model_64_flag = np.zeros([dim_voxel,dim_voxel,dim_voxel],np.uint8) 139 | for i in range(3,dim_voxel-3): 140 | if (batch_size_counter>=batch_size): break 141 | for j in range(3,dim_voxel-3): 142 | if (batch_size_counter>=batch_size): break 143 | for k in range(3,dim_voxel-3): 144 | if (batch_size_counter>=batch_size): break 145 | if (np.max(voxel_model_64[i-3:i+4,j-3:j+4,k-3:k+4])!=np.min(voxel_model_64[i-3:i+4,j-3:j+4,k-3:k+4])): 146 | sample_points[batch_size_counter,0] = i 147 | sample_points[batch_size_counter,1] = j 148 | sample_points[batch_size_counter,2] = k 149 | sample_values[batch_size_counter,0] = voxel_model_64[i,j,k] 150 | voxel_model_64_flag[i,j,k] = 1 151 | batch_size_counter +=1 152 | if (batch_size_counter>=batch_size): 153 | print("64-- batch_size exceeded!") 154 | exceed_64 += 1 155 | batch_size_counter = 0 156 | voxel_model_64_flag = np.zeros([dim_voxel,dim_voxel,dim_voxel],np.uint8) 157 | for i in range(0,dim_voxel,2): 158 | for j in range(0,dim_voxel,2): 159 | for k in range(0,dim_voxel,2): 160 | filled_flag = False 161 | for (i0,j0,k0) in [(i,j,k),(i+1,j,k),(i,j+1,k),(i+1,j+1,k),(i,j,k+1),(i+1,j,k+1),(i,j+1,k+1),(i+1,j+1,k+1)]: 162 | if voxel_model_64[i0,j0,k0]>0: 163 | filled_flag = True 164 | sample_points[batch_size_counter,0] = i0 165 | sample_points[batch_size_counter,1] = j0 166 | sample_points[batch_size_counter,2] = k0 167 | sample_values[batch_size_counter,0] = voxel_model_64[i0,j0,k0] 168 | voxel_model_64_flag[i0,j0,k0] = 1 169 | break 170 | if not filled_flag: 171 | sample_points[batch_size_counter,0] = i 172 | sample_points[batch_size_counter,1] = j 173 | sample_points[batch_size_counter,2] = k 174 | sample_values[batch_size_counter,0] = voxel_model_64[i,j,k] 175 | voxel_model_64_flag[i,j,k] = 1 176 | batch_size_counter +=1 177 | #fill other slots with random points 178 | while (batch_size_counter 32 213 | dim_voxel = 32 214 | voxel_model_32 = np.zeros([dim_voxel,dim_voxel,dim_voxel],np.uint8) 215 | multiplier = int(256/dim_voxel) 216 | for i in range(dim_voxel): 217 | for j in range(dim_voxel): 218 | for k in range(dim_voxel): 219 | voxel_model_32[i,j,k] = np.max(voxel_model_256[i*multiplier:(i+1)*multiplier,j*multiplier:(j+1)*multiplier,k*multiplier:(k+1)*multiplier]) 220 | 221 | #sample points near surface 222 | batch_size = batch_size_2 223 | 224 | sample_points = np.zeros([batch_size,3],np.uint8) 225 | sample_values = np.zeros([batch_size,1],np.uint8) 226 | batch_size_counter = 0 227 | voxel_model_32_flag = np.zeros([dim_voxel,dim_voxel,dim_voxel],np.uint8) 228 | for i in range(3,dim_voxel-3): 229 | if (batch_size_counter>=batch_size): break 230 | for j in range(3,dim_voxel-3): 231 | if (batch_size_counter>=batch_size): break 232 | for k in range(3,dim_voxel-3): 233 | if (batch_size_counter>=batch_size): break 234 | if (np.max(voxel_model_32[i-3:i+4,j-3:j+4,k-3:k+4])!=np.min(voxel_model_32[i-3:i+4,j-3:j+4,k-3:k+4])): 235 | sample_points[batch_size_counter,0] = i 236 | sample_points[batch_size_counter,1] = j 237 | sample_points[batch_size_counter,2] = k 238 | sample_values[batch_size_counter,0] = voxel_model_32[i,j,k] 239 | voxel_model_32_flag[i,j,k] = 1 240 | batch_size_counter +=1 241 | if (batch_size_counter>=batch_size): 242 | print("32-- batch_size exceeded!") 243 | exceed_32 += 1 244 | batch_size_counter = 0 245 | voxel_model_32_flag = np.zeros([dim_voxel,dim_voxel,dim_voxel],np.uint8) 246 | for i in range(0,dim_voxel,2): 247 | for j in range(0,dim_voxel,2): 248 | for k in range(0,dim_voxel,2): 249 | filled_flag = False 250 | for (i0,j0,k0) in [(i,j,k),(i+1,j,k),(i,j+1,k),(i+1,j+1,k),(i,j,k+1),(i+1,j,k+1),(i,j+1,k+1),(i+1,j+1,k+1)]: 251 | if voxel_model_32[i0,j0,k0]>0: 252 | filled_flag = True 253 | sample_points[batch_size_counter,0] = i0 254 | sample_points[batch_size_counter,1] = j0 255 | sample_points[batch_size_counter,2] = k0 256 | sample_values[batch_size_counter,0] = voxel_model_32[i0,j0,k0] 257 | voxel_model_32_flag[i0,j0,k0] = 1 258 | break 259 | if not filled_flag: 260 | sample_points[batch_size_counter,0] = i 261 | sample_points[batch_size_counter,1] = j 262 | sample_points[batch_size_counter,2] = k 263 | sample_values[batch_size_counter,0] = voxel_model_32[i,j,k] 264 | voxel_model_32_flag[i,j,k] = 1 265 | batch_size_counter +=1 266 | #fill other slots with random points 267 | while (batch_size_counter 16 302 | dim_voxel = 16 303 | voxel_model_16 = np.zeros([dim_voxel,dim_voxel,dim_voxel],np.uint8) 304 | multiplier = int(256/dim_voxel) 305 | for i in range(dim_voxel): 306 | for j in range(dim_voxel): 307 | for k in range(dim_voxel): 308 | voxel_model_16[i,j,k] = np.max(voxel_model_256[i*multiplier:(i+1)*multiplier,j*multiplier:(j+1)*multiplier,k*multiplier:(k+1)*multiplier]) 309 | 310 | #sample points near surface 311 | batch_size = batch_size_1 312 | 313 | sample_points = np.zeros([batch_size,3],np.uint8) 314 | sample_values = np.zeros([batch_size,1],np.uint8) 315 | batch_size_counter = 0 316 | for i in range(dim_voxel): 317 | for j in range(dim_voxel): 318 | for k in range(dim_voxel): 319 | sample_points[batch_size_counter,0] = i 320 | sample_points[batch_size_counter,1] = j 321 | sample_points[batch_size_counter,2] = k 322 | sample_values[batch_size_counter,0] = voxel_model_16[i,j,k] 323 | batch_size_counter +=1 324 | if (batch_size_counter!=batch_size): 325 | print("batch_size_counter!=batch_size") 326 | 327 | hdf5_file["points_16"][idx,:,:] = sample_points 328 | hdf5_file["values_16"][idx,:,:] = sample_values 329 | 330 | fout.write(name_list_idx+"\n") 331 | 332 | fstatistics.write("non-repeat total: "+str(name_num)+"\n") 333 | fstatistics.write("exceed_32: "+str(exceed_32)+"\n") 334 | fstatistics.write("exceed_32_ratio: "+str(float(exceed_32)/name_num)+"\n") 335 | fstatistics.write("exceed_64: "+str(exceed_64)+"\n") 336 | fstatistics.write("exceed_64_ratio: "+str(float(exceed_64)/name_num)+"\n") 337 | 338 | fout.close() 339 | fstatistics.close() 340 | hdf5_file.close() 341 | print("finished") 342 | 343 | 344 | --------------------------------------------------------------------------------