├── .gitignore ├── images ├── pipelined.jpg └── trainingd.jpg ├── sessions ├── CVAE │ └── checkpoint └── KMeans │ └── checkpoint ├── CVAEutils.py ├── CVAEplot.py ├── fastMeshDenoising_Config_Test.py ├── fastMeshDenoising_Config_Train.py ├── fastMeshDenoising_presentBoxplot.py ├── CVAE.py ├── README.MD ├── fastMeshDenoising_presentHPResults.py ├── fastMeshDenoising_CVAE_Train.py ├── fastMeshDenoising_CVAE_Train_HyperParameterAnalysis.py ├── fastMeshDenoising_CVAE_Test_On_The_Fly.py ├── fastMeshDenoising_AE_Train.py ├── fastMeshDenoising_AE_Test.py ├── fastMeshDenoising_Data_Utils_Test.py ├── fastMeshDenoising_Data_Utils_Train.py └── commonReadModelV3.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__/ 2 | .idea/ 3 | _other/ 4 | _old/ 5 | meshes/ 6 | results/ 7 | sessions/ 8 | -------------------------------------------------------------------------------- /images/pipelined.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snousias/fast-mesh-denoising/HEAD/images/pipelined.jpg -------------------------------------------------------------------------------- /images/trainingd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/snousias/fast-mesh-denoising/HEAD/images/trainingd.jpg -------------------------------------------------------------------------------- /sessions/CVAE/checkpoint: -------------------------------------------------------------------------------- 1 | model_checkpoint_path: "model_20_n1.ckpt" 2 | all_model_checkpoint_paths: "model_20_n1.ckpt" 3 | -------------------------------------------------------------------------------- /sessions/KMeans/checkpoint: -------------------------------------------------------------------------------- 1 | model_checkpoint_path: "modelKMeans_20_n1.ckpt" 2 | all_model_checkpoint_paths: "modelKMeans_20_n1.ckpt" 3 | -------------------------------------------------------------------------------- /CVAEutils.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | 3 | initializer = tf.contrib.layers.variance_scaling_initializer(factor = 1.0) 4 | 5 | 6 | def conv(inputs,filters,name): 7 | net = tf.layers.conv2d(inputs = inputs, 8 | filters = filters, 9 | kernel_size = [3,3], 10 | strides = (1,1), 11 | padding ="SAME", 12 | kernel_initializer = initializer, 13 | name = name, 14 | reuse = tf.AUTO_REUSE) 15 | return net 16 | 17 | def maxpool(input,name): 18 | net = tf.nn.max_pool(value = input, ksize = [1,2,2,1], strides = [1,2,2,1], padding = "SAME", name = name) 19 | return net 20 | 21 | def bn(inputs,is_training,name): 22 | net = tf.contrib.layers.batch_norm(inputs, decay = 0.9, is_training = is_training, reuse = tf.AUTO_REUSE, scope = name) 23 | return net 24 | 25 | def leaky(input): 26 | return tf.nn.leaky_relu(input) 27 | 28 | def drop_out(input, keep_prob): 29 | return tf.nn.dropout(input, rate=1-keep_prob) 30 | def dense(inputs, units, name): 31 | net = tf.layers.dense(inputs = inputs, 32 | units = units, 33 | reuse = tf.compat.v1.AUTO_REUSE, 34 | name = name, 35 | kernel_initializer = initializer) 36 | return net -------------------------------------------------------------------------------- /CVAEplot.py: -------------------------------------------------------------------------------- 1 | import matplotlib.pyplot as plt 2 | import tensorflow as tf 3 | import numpy as np 4 | import os 5 | basefolder='E:/_Groundwork/_Python/CVAE' 6 | 7 | def plot_2d_scatter(x,y,test_labels): 8 | plt.figure(figsize = (8,6)) 9 | plt.scatter(x,y, c = np.argmax(test_labels,1), marker ='.', edgecolor = 'none', cmap = discrete_cmap('jet')) 10 | plt.colorbar() 11 | plt.grid() 12 | if not tf.gfile.Exists(basefolder+'./Scatter'): 13 | tf.gfile.MakeDirs(basefolder+'./Scatter') 14 | plt.savefig(basefolder+'./Scatter/2D_latent_space.png') 15 | plt.close() 16 | 17 | def discrete_cmap(base_cmap =None): 18 | base = plt.cm.get_cmap(base_cmap) 19 | color_list = base(np.linspace(0,1,10)) 20 | cmap_name = base.name + str(10) 21 | return base.from_list(cmap_name,color_list,10) 22 | 23 | def plot_manifold_canvas(images, n, type, name): 24 | assert images.shape[0] == n**2, "n**2 should be number of images" 25 | height = images.shape[1] 26 | width = images.shape[2] # width = height 27 | x = np.linspace(-2, 2, n) 28 | y = np.linspace(-2, 2, n) 29 | 30 | if type is "MNIST": 31 | canvas = np.empty((n * height, n * height)) 32 | for i, yi in enumerate(x): 33 | for j, xi in enumerate(y): 34 | canvas[height*i: height*i + height, width*j: width*j + width] = np.reshape(images[n*i + j], [height, width]) 35 | plt.figure(figsize=(8, 8)) 36 | plt.imshow(canvas, cmap="gray") 37 | else: 38 | canvas = np.empty((n * height, n * height, 3)) 39 | for i, yi in enumerate(x): 40 | for j, xi in enumerate(y): 41 | canvas[height*i: height*i + height, width*j: width*j + width,:] = images[n*i + j] 42 | plt.figure(figsize=(8, 8)) 43 | plt.imshow(canvas) 44 | 45 | if not tf.gfile.Exists(basefolder+'./plot'): 46 | tf.gfile.MakeDirs(basefolder+'./plot') 47 | if not tf.gfile.Exists(basefolder+'./plot/PMLR'): 48 | tf.gfile.MakeDirs(basefolder+'./plot/PMLR') 49 | if not tf.gfile.Exists(basefolder+'./plot/PARR'): 50 | tf.gfile.MakeDirs(basefolder+'./plot/PARR') 51 | 52 | name = name + ".png" 53 | path = os.path.join(basefolder+'./plot', name) 54 | plt.savefig(path) 55 | print("saving location: %s" % (path)) 56 | plt.close() -------------------------------------------------------------------------------- /fastMeshDenoising_Config_Test.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import random 4 | import gzip 5 | import tarfile 6 | import pickle 7 | import os 8 | from six.moves import urllib 9 | from CVAEplot import * 10 | from commonReadModelV3 import * 11 | from commonReadModelV3 import Geometry 12 | import scipy.io 13 | from tensorflow.contrib.factorization import KMeans 14 | import sklearn as sk 15 | from scipy.spatial.distance import pdist, squareform 16 | import pickle 17 | #=========Generic_configurations=========# 18 | useGuided = False 19 | doRotate = True 20 | noiseLevel = 0.1 21 | nClusters = 200 22 | numberOfPermutations = 10 23 | numOfElements = 20 24 | selectedModel = 0 25 | noiseLevelAsString = '_n1' 26 | trainSet=range(0, 3) 27 | #=========Actions========================# 28 | doReadOBJ = True 29 | doTrain = False 30 | doTest = True 31 | modelsOnly = False 32 | #========================================# 33 | 34 | patchSizeGuided = numOfElements 35 | keyTest = '_' + str(numOfElements)+noiseLevelAsString 36 | #Add noise level 37 | keyTrain = '_8x'+str(numberOfPermutations)+'_' + str(numOfElements) + '_simple_normals_normalized'+noiseLevelAsString 38 | #keyTrain = '_scanned'+str(numberOfPermutations)+'_' + str(numOfElements) + '_simple_normals_normalized'+noiseLevelAsString 39 | #keyTrain = '_scanned'+str(numberOfPermutations)+'_' + str(numOfElements) + '_simple_normals_normalized'+noiseLevelAsString 40 | 41 | # distType='cosine' 42 | distType = 'squared_euclidean' 43 | rootdir= './' 44 | root = rootdir+'meshes/GroundTruth/' 45 | rootNoisy = rootdir+'meshes/Noisy/' 46 | 47 | 48 | trainModels = ['block', 49 | 'casting', 50 | 'coverrear_Lp', 51 | 'ccylinder', 52 | 'eight', 53 | 'joint', 54 | 'part-Lp', 55 | 'cad', 56 | 'fandisk', 57 | 'chinese-lion', 58 | 'sculpt', 59 | 'rockerarm', 60 | 'smooth-feature', 61 | 'trim-star', 62 | 'gear', 63 | 'boy01-scanned', 64 | 'boy02-scanned', 65 | 'pyramid-scanned', 66 | 'girl-scanned', 67 | 'cone-scanned', 68 | 'sharp-sphere', 69 | 'leg', 70 | 'screwdriver', 71 | 'carter100K', 72 | 'pulley', 73 | 'pulley-defects' 74 | ] 75 | 76 | 77 | -------------------------------------------------------------------------------- /fastMeshDenoising_Config_Train.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import random 4 | import gzip 5 | import tarfile 6 | import pickle 7 | import os 8 | from six.moves import urllib 9 | from CVAEplot import * 10 | from commonReadModelV3 import * 11 | from commonReadModelV3 import Geometry 12 | import scipy.io 13 | from tensorflow.contrib.factorization import KMeans 14 | import sklearn as sk 15 | from scipy.spatial.distance import pdist, squareform 16 | import pickle 17 | #=========Generic_configurations=========# 18 | useGuided = False 19 | doRotate = True 20 | noiseLevel = 0.1 21 | nClusters = 200 22 | numberOfPermutations = 1 23 | numOfElements = 20 24 | selectedModel = 0 25 | noiseLevelAsString = '_n1' 26 | trainSet=range(0, 8) 27 | #=========Actions========================# 28 | doReadOBJ = True 29 | doTrain = True 30 | doTest = True 31 | modelsOnly = False 32 | #========================================# 33 | 34 | patchSizeGuided = numOfElements 35 | keyTest = '_' + str(numOfElements)+noiseLevelAsString 36 | #Add noise level 37 | keyTrain = '_8x'+str(numberOfPermutations)+'_' + str(numOfElements) + '_simple_normals_normalized'+noiseLevelAsString 38 | #keyTrain = '_scanned'+str(numberOfPermutations)+'_' + str(numOfElements) + '_simple_normals_normalized'+noiseLevelAsString 39 | #keyTrain = '_scanned'+str(numberOfPermutations)+'_' + str(numOfElements) + '_simple_normals_normalized'+noiseLevelAsString 40 | 41 | # distType='cosine' 42 | distType = 'squared_euclidean' 43 | rootdir= './' 44 | root = rootdir+'meshes/GroundTruth/' 45 | rootNoisy = rootdir+'meshes/Noisy/' 46 | 47 | 48 | 49 | trainModels = ['block', 50 | 'casting', 51 | 'coverrear_Lp', 52 | 'ccylinder', 53 | 'eight', 54 | 'joint', 55 | 'part-Lp', 56 | 'cad', 57 | 'fandisk', 58 | 'chinese-lion', 59 | 'sculpt', 60 | 'rockerarm', 61 | 'smooth-feature', 62 | 'trim-star', 63 | 'gear', 64 | 'boy01-scanned', 65 | 'boy02-scanned', 66 | 'pyramid-scanned', 67 | 'girl-scanned', 68 | 'cone-scanned', 69 | 'sharp-sphere', 70 | 'leg', 71 | 'screwdriver', 72 | 'carter100K', 73 | 'pulley', 74 | 'pulley-defects' 75 | ] 76 | 77 | 78 | -------------------------------------------------------------------------------- /fastMeshDenoising_presentBoxplot.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | 5 | 6 | Dat=[[7.19553017616272, 3.9495084285736084, 3.8936190605163574, 3.7926688194274902, 4.072003364562988, 3.7544503211975098, 3.768246650695801, 3.7534778118133545, 3.8266615867614746, 3.771867036819458], 7 | [4.880508899688721, 2.5726959705352783, 3.184799909591675, 2.4157297611236572, 2.1843161582946777, 2.188011407852173, 2.2942960262298584, 2.213667631149292, 2.2000699043273926, 2.1775081157684326], 8 | [4.788172245025635, 1.7677671909332275, 1.7049124240875244, 1.654463768005371, 1.6348824501037598, 1.6705472469329834, 1.9592533111572266, 2.081798791885376, 1.6715571880340576, 1.65816330909729], 9 | [5.0453410148620605, 1.5628998279571533, 1.4489569664001465, 1.4137828350067139, 1.7502896785736084, 1.752265453338623, 1.4654185771942139, 1.5477168560028076, 1.4022257328033447, 1.407116413116455], 10 | [5.287771463394165, 1.4964451789855957, 1.414945125579834, 1.4046900272369385, 1.664771318435669, 1.4268991947174072, 1.4423234462738037, 1.4119653701782227, 1.3808207511901855, 1.3945443630218506], 11 | [0.4513382911682129, 0.16810297966003418, 0.17412447929382324, 0.16711807250976562, 0.16711831092834473, 0.1681196689605713, 0.17013764381408691, 0.1701209545135498, 0.16912007331848145, 0.1681365966796875]] 12 | 13 | 14 | Rotation= [8.11, 6.57, 5.83, 5.48, 5.83, 3.92] 15 | 16 | fig7, ax7 = plt.subplots(figsize=(6.4, 3)) 17 | 18 | ax7.set_title('Distribution of execution times for different settings') 19 | bp1=ax7.boxplot(Dat,notch=False, widths=0.35, 20 | patch_artist=True, boxprops=dict(facecolor='lightgreen')) 21 | 22 | randomDists = ['1 Core', ' 2 Cores', '4 Cores', '6 Cores', 23 | '8 Cores','GPU'] 24 | xtickNames = plt.setp(ax7, xticklabels=randomDists) 25 | plt.setp(xtickNames, rotation=0, fontsize=12,fontname="Times New Roman") 26 | ax7.set_xlabel('Execution setting',fontname="Times New Roman", fontsize=14) 27 | ax7.set_ylabel('Execution times (Seconds) ',fontname="Times New Roman", fontsize=14) 28 | #l1,=ax7.plot(range(1,(len(Rotation)+1)),Rotation, 'v-',linewidth=2,markersize=10) 29 | #ax7.legend((Rotation, Dat), ('label1', 'label2'),loc="upper left") 30 | ax7.legend([bp1["boxes"][0]], ['Normal filtering , Conditional Variational Autoencoder'], loc='upper right') 31 | #ax7.legend([bp1["boxes"][0],l1], ['Normal filtering (CVAE)','Normal rotation (Numpy)'], loc='upper right') 32 | plt.ylim(top=4.5) 33 | 34 | plt.show() -------------------------------------------------------------------------------- /CVAE.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | from CVAEutils import * 3 | import numpy as np 4 | 5 | 6 | class CVAE: 7 | def __init__(self, shape,n_cls,n_hidden,n_z, drop_rate): 8 | self.shape = shape 9 | self.n_cls = n_cls 10 | self.n_hidden = n_hidden 11 | self.n_z = n_z 12 | self.drop_rate = drop_rate 13 | self.n_out = self.shape[1]*self.shape[2] 14 | 15 | def conditional_gaussian_encoder(self, X, Y, keep_prob): 16 | 17 | with tf.compat.v1.variable_scope("gaussian_encoder", reuse = tf.compat.v1.AUTO_REUSE): 18 | X_input = tf.concat((X,Y), axis =1) 19 | net = drop_out(leaky(dense(X_input, self.n_hidden[0], name = "Dense_1")), keep_prob) 20 | net = drop_out(leaky(dense(net, self.n_hidden[1], name="Dense_2")), keep_prob) 21 | net = dense(net, self.n_z*2, name ="Dense_3") 22 | mean = net[:,:self.n_z] 23 | std = tf.nn.softplus(net[:,self.n_z:]) + 1e-6 24 | 25 | return mean, std 26 | 27 | def conditional_bernoulli_decoder(self,Z, Y, keep_prob): 28 | 29 | with tf.compat.v1.variable_scope("bernoulli_decoder", reuse = tf.compat.v1.AUTO_REUSE): 30 | z_input = tf.concat((Z,Y), axis = 1) 31 | net = drop_out(leaky(dense(z_input, self.n_hidden[2], name = "Dense_1")), keep_prob) 32 | net = drop_out(leaky(dense(net, self.n_hidden[3], name="Dense_2")), keep_prob) 33 | net = tf.nn.sigmoid(dense(net, self.n_out, name = "Dense_3")) 34 | 35 | return net 36 | 37 | 38 | def Conditional_Variational_AutoEncoder(self, X, X_noised, Y, keep_prob): 39 | 40 | X_flatten = tf.reshape(X, [-1, self.n_out]) 41 | X_flatten_noised = tf.reshape(X_noised, [-1, self.n_out]) 42 | 43 | mean, std = self.conditional_gaussian_encoder(X_flatten_noised, Y, keep_prob) 44 | z = mean + std*tf.random.normal(tf.shape(mean, out_type = tf.int32), 0, 1, dtype = tf.float32) 45 | 46 | X_out = self.conditional_bernoulli_decoder(z, Y, keep_prob) 47 | X_out = tf.clip_by_value(X_out, 1e-8, 1 - 1e-8) 48 | 49 | likelihood = tf.reduce_mean(X_flatten*tf.math.log(X_out) + (1 - X_flatten)*tf.math.log(1 - X_out)) 50 | KL_Div = tf.reduce_mean(0.15 * (1 - tf.math.log(tf.square(std) + 1e-8) + tf.square(mean) + tf.square(std))) 51 | 52 | Recon_error = -1*likelihood 53 | Regul_error = KL_Div 54 | 55 | self.ELBO = tf.abs(Recon_error + Regul_error) 56 | 57 | return z, X_out, self.ELBO 58 | 59 | def optim_op(self, loss ,learning_rate, global_step): 60 | self.optimizer = tf.compat.v1.train.AdamOptimizer(learning_rate = learning_rate).minimize(loss, global_step = global_step) 61 | return self.optimizer -------------------------------------------------------------------------------- /README.MD: -------------------------------------------------------------------------------- 1 | # Fast mesh denoising with data driven normal filtering using deep variational autoencoders 2 | 3 | This is an implementation for the paper entitled "Fast mesh denoising with data driven normal filtering using deep variational autoencoders" published in IEEE Transactions on Industrial Informatics 10.1109/TII.2020.3000491 4 | 5 | https://ieeexplore.ieee.org/document/9110709 6 | 7 | ## Description 8 | Recent advances in 3D scanning technology have enabled the deployment of 3D models in various industrial applications like digital twins, remote inspection and reverse engineering. Despite their evolving performance, 3D scanners, still introduce noise and artifacts in the acquired dense models. In this work, we propose a fast and robust denoising method for dense 3D scanned industrial models. The proposed approach employs conditional variational autoencoders to effectively filter face normals. Training and inference are performed in a sliding patch setup reducing the size of the required training data and execution times. We conducted extensive evaluation studies using 3D scanned and CAD models. The results verify plausible denoising outcomes, demonstrating similar or higher reconstruction accuracy, compared to other state-of-the-art approaches. Specifically, for 3D models with more than 1e4 faces, the presented pipeline is twice as fast as methods with equivalent reconstruction error. 9 | 10 | 11 | ## Requirements 12 | 13 | 1. Tensorflow 14 | 2. Numpy 15 | 3. Pickle 16 | 4. Matplotlib 17 | 5. SKLearn 18 | 6. Scipy 19 | 7. Gzip 20 | 8. Random 21 | 22 | 23 | ## Overview 24 | 25 | Pipeline of the proposed approach and training scheme of the CVAE 26 | ![Pipeline](./images/pipelined.jpg) 27 | 28 | ![Training](./images/trainingd.jpg) 29 | 30 | ## Running the code 31 | 32 | 33 | ### Train with groundtruth data 34 | 35 | python fastMeshDenoising_CVAE_Train.py 36 | 37 | ### Inference 38 | 39 | python fastMeshDenoising_CVAE_Test_On_The_Fly.py 40 | 41 | 42 | The generated model can be found in 43 | 44 | ./results/Comparison/Denoised/CVAE/ 45 | 46 | ## Notes 47 | 48 | ### Repository with full code and data 49 | 50 | https://gitlab.com/vvr/snousias/fast-mesh-denoising 51 | 52 | ### Structure 53 | ./data/ 54 | ./images/ 55 | ./meshes/ 56 | ./results/ 57 | ./sessions/ 58 | commonReadModelV3.py 59 | CVAE.py 60 | CVAEplot.py 61 | CVAEutils.py 62 | fastMeshDenoising*.py 63 | 64 | ### Select a model from a list of models 65 | Models in .obj format are found in./meshes/ 66 | 67 | trainModels = [ 68 | 'block', 69 | 'casting', 70 | 'coverrear_Lp', 71 | 'ccylinder', 72 | 'eight', 73 | 'joint', 74 | 'part-Lp', 75 | 'cad', 76 | 'fandisk', 77 | 'chinese-lion', 78 | 'sculpt', 79 | 'rockerarm', 80 | 'smooth-feature', 81 | 'trim-star', 82 | 'gear', 83 | 'boy01-scanned', 84 | 'boy02-scanned', 85 | 'pyramid-scanned', 86 | 'girl-scanned', 87 | 'cone-scanned', 88 | 'sharp-sphere', 89 | 'leg', 90 | 'screwdriver', 91 | 'carter100K', 92 | 'pulley', 93 | 'pulley-defects' 94 | ] 95 | 96 | ### Training set 97 | Training set comprises of the first eight models in fastMeshDenoising_Config_Train.py 98 | 99 | trainSet=range(0, 8) 100 | 101 | ###Testing model 102 | Testing model is defined by flag "selectedModel" in fastMeshDenoising_CVAE_Test_On_The_Fly.py 103 | 104 | selectedModel = 10 105 | 106 | 107 | 108 | # Citation info 109 | 110 | 111 | ### Citation 112 | 113 | S. Nousias, G. Arvanitis, A. Lalos, and K. Moustakas, “Fast mesh denoising with data driven normal filtering using deep variational autoencoders,” IEEE Trans. Ind. Informatics, pp. 1–1, 2020. 114 | 115 | ### Bibtex 116 | 117 | @article{Nousias2020, 118 | author = {Nousias, Stavros and Arvanitis, Gerasimos and Lalos, Aris and Moustakas, Konstantinos}, 119 | doi = {10.1109/TII.2020.3000491}, 120 | issn = {1551-3203}, 121 | journal = {IEEE Transactions on Industrial Informatics}, 122 | pages = {1--1}, 123 | title = {{Fast mesh denoising with data driven normal filtering using deep variational autoencoders}}, 124 | url = {https://ieeexplore.ieee.org/document/9110709/}, 125 | year = {2020} 126 | } 127 | -------------------------------------------------------------------------------- /fastMeshDenoising_presentHPResults.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import json 4 | import seaborn as sns 5 | import pandas as pd 6 | import fastMeshDenoising_Config_Train as conf 7 | import matplotlib.pyplot as plt 8 | import matplotlib.colors as cl 9 | jsonFile1='F:/_Groundwork/FastMeshDenoisingProduction/results/hopresults.json' #_1 10 | jsonFile2='F:/_Groundwork/FastMeshDenoisingProduction/results/hopresults_1.json' 11 | jsonFile3='F:/_Groundwork/FastMeshDenoisingProduction/results/hopresults_2.json' 12 | with open(jsonFile1, 'r') as f: 13 | jsonData1 = json.load(f) 14 | with open(jsonFile2, 'r') as f: 15 | jsonData2 = json.load(f) 16 | with open(jsonFile3, 'r') as f: 17 | jsonData3 = json.load(f) 18 | jsonData=jsonData1 19 | jsonData.extend(jsonData2) 20 | jsonData.extend(jsonData3) 21 | losses=[] 22 | for row in jsonData: 23 | losses.append((row["loss"])) 24 | jsonData[jsonData.index(row)]['minLoss']=np.amin(np.asarray(row["loss"])) 25 | _losses=np.asarray(losses) 26 | minVal=1000000 27 | minValRow=0 28 | for i in losses: 29 | for j in i: 30 | if j < minVal: 31 | minVal=j 32 | minValRow=losses.index(i) 33 | 34 | # Get the indices of minimum element in numpy array 35 | print(jsonData[minValRow]) 36 | 37 | 38 | 39 | from matplotlib.colors import hsv_to_rgb 40 | from sklearn import preprocessing 41 | min_max_scaler = preprocessing.MinMaxScaler() 42 | 43 | M=pd.DataFrame.from_dict(jsonData) 44 | 45 | 46 | M2 = M[['BS', 'CL', 'D1','D2', 'E1', 'E2','KP','LR','minLoss']].copy() 47 | 48 | M2.columns = ['Batch size','Cluster size','Decoding Layer 1', 49 | 'Decoding Layer 2','Encoding Layer 1','Encoding Layer 2','Keep Ratio','Learning Rate','minLoss'] 50 | 51 | 52 | M2=M2.sort_values(by=['minLoss'],ascending=False) 53 | minVal=np.min(M2['minLoss']) 54 | maxVal=np.max(M2['minLoss']) 55 | 56 | 57 | 58 | 59 | # Set data 60 | # number of variable 61 | categories = M2.columns.drop('minLoss') 62 | maxcat=np.zeros(np.shape(categories)) 63 | N = len(categories) 64 | 65 | for index,cat in enumerate(categories): 66 | maxcat[index]=M2[cat].max() 67 | if (M2[cat].max() - M2[cat] .min())==0: 68 | M2[cat]=np.repeat(0.5,len(M2[cat])) 69 | else: 70 | M2[cat]=(M2[cat]) / (M2[cat].max()) 71 | print('ok') 72 | 73 | 74 | 75 | fig = plt.figure(figsize=(10, 6)) 76 | ax = fig.add_subplot(111, polar=True) 77 | ax.grid(True) 78 | ax.set_axisbelow(True) 79 | ax.yaxis.grid(color='gray', linestyle='dashed') 80 | plt.rc('axes', axisbelow=True) 81 | [line.set_zorder(30) for line in ax.lines] 82 | tVals=[] 83 | 84 | for index, row in M2.iterrows(): 85 | stats=M2.loc[index,categories].values 86 | angles=np.linspace(0, 2*np.pi, len(categories), endpoint=False) 87 | # close the plot 88 | stats=np.concatenate((stats,[stats[0]])) 89 | angles=np.concatenate((angles,[angles[0]])) 90 | val=((256/360)*((M2.at[index, 'minLoss']-minVal)/(maxVal-minVal))) 91 | 92 | 93 | vc=128/360 94 | newval=(-(val-vc))+vc 95 | lognewval=np.log(100*val+0.5) 96 | 97 | logval = np.log(100*val+0.5) 98 | tVals.append(logval) 99 | logval=np.clip(logval,0,1) 100 | HSV=np.asarray([logval,1,1]) 101 | RGB=hsv_to_rgb(HSV) 102 | print(HSV) 103 | print(RGB) 104 | ax.plot(angles, stats, '-', linewidth=2,color=RGB,zorder=(2.5+newval)) 105 | if index==(M2.shape[0]-1): 106 | ax.fill(angles, stats, alpha=0.55,color=RGB,zorder=(2.5+newval)) 107 | 108 | 109 | #ax.set_thetagrids(angles * 180/np.pi, categories) 110 | # legend = ax.legend(categories, loc=(0.9, .95), 111 | # labelspacing=0.1, fontsize='small') 112 | # fig.text(0.5, 0.965, '5-Factor Solution Profiles Across Four Scenarios', 113 | # horizontalalignment='center', color='black', weight='normal', 114 | # size='large') 115 | 116 | 117 | # ticks = np.linspace(0, 2*np.pi, 20, endpoint=False) 118 | # plt.xticks(angles, categories, size=16) 119 | # for label,rot in zip(ax.get_xticklabels(),ticks): 120 | # label.set_rotation(rot*180./np.pi) 121 | # label.set_horizontalalignment("right") 122 | # label.set_rotation_mode("anchor") 123 | 124 | catlabels=[] 125 | 126 | for index,cat in enumerate(categories): 127 | #str(categories[index])+"\n"+ 128 | catlabels.append(str(maxcat[index])) 129 | 130 | 131 | plt.xticks(angles, categories, size=16) 132 | for label,i in zip(ax.get_xticklabels(),range(0,len(angles))): 133 | angle_rad=angles[i] 134 | if angle_rad <= np.pi/2: 135 | ha= 'left' 136 | va= "bottom" 137 | angle_text=angle_rad*(-180/np.pi)+90 138 | elif np.pi/2 < angle_rad <= np.pi: 139 | ha= 'right' 140 | va= "top" 141 | angle_text=angle_rad*(-180/np.pi)+90 142 | elif np.pi < angle_rad <= (3*np.pi/2): 143 | ha= 'right' 144 | va= "top" 145 | angle_text=angle_rad*(-180/np.pi)-90 146 | else: 147 | ha= 'left' 148 | va= "bottom" 149 | angle_text=angle_rad*(-180/np.pi)-90 150 | label.set_rotation(angle_text) 151 | label.set_verticalalignment(va) 152 | label.set_horizontalalignment(ha) 153 | 154 | 155 | 156 | plt.show() 157 | 158 | 159 | 160 | # import matplotlib.pyplot as plt 161 | # from matplotlib.colors import LogNorm 162 | # import numpy as np 163 | # from matplotlib.mlab import bivariate_normal 164 | # N = 1000 165 | # X, Y = np.mgrid[0.6:0.9:complex(0, N), 0.6:0.9:complex(0, N)] 166 | # Z1 = minVal+0.0001 *bivariate_normal(X, Y, 0.05,0.05, ((maxVal+minVal)/2),((maxVal+minVal)/2)) 167 | # plt.subplot(2, 1, 1) 168 | # plt.pcolor(X, Y, Z1, norm=LogNorm(vmin=Z1.min(), vmax=Z1.max()), cmap='rainbow_r') 169 | # from matplotlib.ticker import LogFormatter 170 | # formatter = LogFormatter(10, labelOnlyBase=False) 171 | # cb = plt.colorbar(ticks=[0.783,0.784,0.785,0.786,0.787,0.789], format=formatter) 172 | # plt.subplot(2, 1, 2) 173 | # plt.pcolor(X, Y, Z1, cmap='rainbow_r') 174 | # plt.colorbar() 175 | # plt.show() 176 | 177 | 178 | -------------------------------------------------------------------------------- /fastMeshDenoising_CVAE_Train.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import fastMeshDenoising_Data_Utils_Train as dat 4 | from fastMeshDenoising_Data_Utils_Train import * 5 | from CVAEutils import * 6 | from CVAEplot import * 7 | from CVAE import * 8 | 9 | import time 10 | import os 11 | #os.environ["CUDA_VISIBLE_DEVICES"]="-1" 12 | #os.environ["OMP_NUM_THREADS"] = "1" 13 | 14 | if __name__ == "__main__": 15 | flag = tf.app.flags 16 | FLAGS = flag.FLAGS 17 | flag.DEFINE_float("learning_rate", 0.00003, "learning rate for training") 18 | flag.DEFINE_integer("n_epoch", 30, "number of Epoch") 19 | flag.DEFINE_integer("n_z", 2, "Dimension of latent variables") 20 | flag.DEFINE_float("keep_prob", 0.99, "Dropout rate") 21 | flag.DEFINE_float("decay_rate", 0.998, "learning rate decay rate") 22 | flag.DEFINE_integer("batch_size", 256, "Batch size for training") 23 | flag.DEFINE_bool("add_noise", False, "[True/False]") 24 | flag.DEFINE_bool("PMLR", False, "Boolean for plot manifold learning result") 25 | flag.DEFINE_bool("PARR", False, "Boolean for plot analogical reasoning result") 26 | data_pipeline = data_pipeline("Custom") 27 | train_xs, train_ys, valid_xs, valid_ys, test_xs, test_ys = data_pipeline.load_preprocess_data() 28 | _, height, width = np.shape(train_xs) 29 | n_cls = np.shape(train_ys)[1] 30 | X = tf.placeholder(dtype=tf.float32, shape=[None, height, width], name="Input") 31 | X_noised = tf.placeholder(dtype=tf.float32, shape=[None, height, width], name="Input_noised") 32 | Y = tf.placeholder(dtype=tf.float32, shape=[None, n_cls], name="labels") 33 | keep_prob = tf.placeholder(dtype=tf.float32, name="drop_rate") 34 | CVAE = CVAE([_, height, width], n_cls, [1024, 2048, 4096, 4096], FLAGS.n_z, keep_prob) 35 | z, output, loss = CVAE.Conditional_Variational_AutoEncoder(X, X_noised, Y, keep_prob) 36 | latent = tf.placeholder(dtype=tf.float32, shape=[None, FLAGS.n_z], name="latent_input") 37 | global_step = tf.Variable(0, trainable=False) 38 | if FLAGS.PMLR is True: # code for plot manifold learning Results 39 | assert FLAGS.n_z == 2, "n_z should be 2!" 40 | images_manifold = CVAE.conditional_bernoulli_decoder(latent, Y, keep_prob) 41 | if FLAGS.PARR is True: # code for plot analogical reasoning result 42 | images_PARR = CVAE.conditional_bernoulli_decoder(latent, Y, keep_prob) 43 | total_batch = data_pipeline.get_total_batch(train_xs, FLAGS.batch_size) 44 | learning_rate_decayed = FLAGS.learning_rate * FLAGS.decay_rate ** (global_step / total_batch) 45 | optim_op = CVAE.optim_op(loss, learning_rate_decayed, global_step) 46 | 47 | # session_conf = tf.ConfigProto( 48 | # intra_op_parallelism_threads=1, 49 | # inter_op_parallelism_threads=1, 50 | # device_count={'GPU': 0,"CPU": 1}, 51 | # allow_soft_placement=False 52 | # ) 53 | sess = tf.Session() 54 | sess.run(tf.global_variables_initializer()) 55 | batch_v_xs, batch_vn_xs, batch_v_ys = data_pipeline.next_batch(valid_xs, valid_ys, 100, make_noise=FLAGS.add_noise) 56 | print("_" * 80) 57 | start_time = time.time() 58 | print("training started") 59 | for i in range(FLAGS.n_epoch): 60 | loss_val = 0 61 | for j in range(total_batch): 62 | batch_xs, batch_noised_xs, batch_ys = data_pipeline.next_batch(train_xs, train_ys, FLAGS.batch_size, 63 | make_noise=False) 64 | feed_dict = {X: batch_xs, X_noised: batch_noised_xs, Y: batch_ys, keep_prob: FLAGS.keep_prob} 65 | l, lr, op, g = sess.run([loss, learning_rate_decayed, optim_op, global_step], feed_dict=feed_dict) 66 | loss_val += l / total_batch 67 | if not math.isnan(loss_val) and (i % 2 == 0 or i == (FLAGS.n_epoch - 1)): 68 | images = sess.run(output, feed_dict={X: test_images_original, 69 | X_noised: test_images_noisy, 70 | Y: test_labels_updated, 71 | keep_prob: 1.0}) 72 | result = images[:, 0:3] 73 | # Convert definition space 74 | result = 2.0 * result - 1.0 * np.ones(np.shape(result)) 75 | result = np.asarray(result) 76 | mModelToProcessDenoised = copy.deepcopy(mModelToProcess) 77 | if doRotate: 78 | for r in range(0, np.size(result, axis=0)): 79 | result[r, :] = rotate(result[r, :], mModelToProcessDenoised.faces[r].rotationAxis, 80 | -mModelToProcessDenoised.faces[r].theta) 81 | updateVerticesWithNormals(mModelToProcessDenoised, result, 20) 82 | exportObj(mModelToProcessDenoised, dat.rootdir+'meshes/denoised_'+str(dat.numOfElements)+'_'+ str(dat.nClusters) +'_' + '.obj') 83 | #exportObj(mModelToProcessDenoised, dat.rootdir + 'Results-0/Comparison/Denoised/CVAE/'+str(dat.modelNameNoisy)+'_'+str(dat.numOfElements)+ '.obj') 84 | 85 | 86 | #+ str(i) 87 | #with open(dat.rootdir+'Results/result_' + str(i) + 'C.csv', 88 | with open(dat.rootdir+'meshes/result_' +str(dat.numOfElements)+'_'+ str(dat.nClusters) + '.csv', 89 | 'w') as writeFile: 90 | for j in range(0, np.size(result, axis=0)): 91 | line = str(result[j, 0]) + "," + str(result[j, 1]) + "," + str(result[j, 2]) 92 | writeFile.write(line) 93 | writeFile.write('\n') 94 | hour = int((time.time() - start_time) / 3600) 95 | min = int(((time.time() - start_time) - 3600 * hour) / 60) 96 | sec = int((time.time() - start_time) - 3600 * hour - 60 * min) 97 | print("Epoch: %.3d loss: %.5f lr: %f Time: %d hour %d min %d sec\n" % (i, loss_val, lr, hour, min, sec)) 98 | saver = tf.train.Saver() 99 | save_path = saver.save(sess, 100 | dat.rootdir+'sessions/CVAE/model_' + str(numOfElements)+noiseLevelAsString+ '.ckpt') 101 | 102 | #Exports 103 | # exportObj(mModelToProcess, 104 | # dat.rootdir+'meshes/Denoised/CVAE/' + dat._modelName + '_noisy' + noiseLevelAsString + '.obj') 105 | # 106 | # exportObj(mModelToProcessDenoised, 107 | # dat.rootdir+'meshes/Denoised/CVAE/' + dat._modelName + noiseLevelAsString + '_' + str( 108 | # dat.numOfElements) + '.obj') 109 | # 110 | # with open( 111 | # dat.rootdir+'meshes/Denoised/CVAE/' + dat._modelName + '_normals' + noiseLevelAsString + '_' + str( 112 | # dat.numOfElements) + '.csv', 'w') as writeFile: 113 | # for j in range(0, np.size(result, axis=0)): 114 | # line = str(result[j, 0]) + "," + str(result[j, 1]) + "," + str(result[j, 2]) 115 | # writeFile.write(line) 116 | # writeFile.write('\n') 117 | 118 | sess.close() 119 | -------------------------------------------------------------------------------- /fastMeshDenoising_CVAE_Train_HyperParameterAnalysis.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import fastMeshDenoising_Data_Utils_Train as dat 4 | from fastMeshDenoising_Data_Utils_Train import * 5 | from CVAEutils import * 6 | from CVAEplot import * 7 | from CVAE import * 8 | 9 | import time 10 | import os 11 | #os.environ["CUDA_VISIBLE_DEVICES"]="-1" 12 | #os.environ["OMP_NUM_THREADS"] = "1" 13 | 14 | if __name__ == "__main__": 15 | flag = tf.app.flags 16 | FLAGS = flag.FLAGS 17 | flag.DEFINE_float("learning_rate", 0.00002, "learning rate for training") 18 | flag.DEFINE_integer("n_epoch", 40, "number of Epoch") 19 | flag.DEFINE_integer("n_z", 2, "Dimension of latent variables") 20 | flag.DEFINE_float("keep_prob", 0.95, "Dropout rate") 21 | flag.DEFINE_float("decay_rate", 0.998, "learning rate decay rate") 22 | flag.DEFINE_integer("batch_size", 256, "Batch size for training") 23 | flag.DEFINE_bool("add_noise", False, "[True/False]") 24 | flag.DEFINE_bool("PMLR", False, "Boolean for plot manifold learning result") 25 | flag.DEFINE_bool("PARR", False, "Boolean for plot analogical reasoning result") 26 | 27 | 28 | 29 | 30 | 31 | # FLAGS.batch_size=128 32 | # FLAGS.keep_prob=0.8 33 | # FLAGS.learning_rate=0.00004 34 | # FLAGS.decay_rate=0.998 35 | # E1=256 36 | # E2=256 37 | # D1=256 38 | # D2=256 39 | 40 | with open('F:/_Groundwork/FastMeshDenoisingProduction/results/hopresults.json', 'w+') as writeFile: 41 | writeFile.write('[') 42 | settingID=1 43 | for FLAGS.batch_size in [512]: 44 | for FLAGS.keep_prob in [0.99]: 45 | for FLAGS.learning_rate in [0.00003]: 46 | for FLAGS.decay_rate in [0.998]: 47 | for E1 in [1024,2048]: 48 | for E2 in [1024,2048,4096]: 49 | for D1 in [1024,2048,4096]: 50 | for D2 in [1024,2048,4096]: 51 | tf.reset_default_graph() 52 | if settingID>1: 53 | writeFile.write(',') 54 | writeFile.write('{') 55 | writeFile.write( 56 | '\"NUMEL\":' + str(dat.numOfElements) + ','+ '\n'+ 57 | '\"CL\":' + str(dat.nClusters) + ','+ '\n'+ 58 | '\"BS\":' + str(FLAGS.batch_size) + ','+'\n'+ 59 | '\"KP\":' + str(FLAGS.keep_prob) + ','+'\n'+ 60 | '\"LR\":' + str(FLAGS.learning_rate) + ','+'\n'+ 61 | '\"DR\":' + str(FLAGS.decay_rate) + ','+'\n'+ 62 | '\"E1\":' + str(E1) + ','+'\n'+ 63 | '\"E2\":' + str(E2) + ','+'\n'+ 64 | '\"D1\":' + str(D1) + ','+'\n'+ 65 | '\"D2\":' + str(D2) + ','+'\n'+ 66 | '\"loss\":[' 67 | ) 68 | 69 | _data_pipeline = data_pipeline("Custom") 70 | train_xs, train_ys, valid_xs, valid_ys, test_xs, test_ys = _data_pipeline.load_preprocess_data() 71 | _, height, width = np.shape(train_xs) 72 | n_cls = np.shape(train_ys)[1] 73 | X = tf.placeholder(dtype=tf.float32, shape=[None, height, width], name="Input") 74 | X_noised = tf.placeholder(dtype=tf.float32, shape=[None, height, width], name="Input_noised") 75 | Y = tf.placeholder(dtype=tf.float32, shape=[None, n_cls], name="labels") 76 | keep_prob = tf.placeholder(dtype=tf.float32, name="drop_rate") 77 | 78 | _CVAE=None 79 | _CVAE = CVAE([_, height, width], n_cls, [E1, E2, D1, D2], FLAGS.n_z, keep_prob) 80 | z, output, loss = _CVAE.Conditional_Variational_AutoEncoder(X, X_noised, Y, keep_prob) 81 | latent = tf.placeholder(dtype=tf.float32, shape=[None, FLAGS.n_z], name="latent_input") 82 | global_step = tf.Variable(0, trainable=False) 83 | if FLAGS.PMLR is True: # code for plot manifold learning Results 84 | assert FLAGS.n_z == 2, "n_z should be 2!" 85 | images_manifold = _CVAE.conditional_bernoulli_decoder(latent, Y, keep_prob) 86 | if FLAGS.PARR is True: # code for plot analogical reasoning result 87 | images_PARR = _CVAE.conditional_bernoulli_decoder(latent, Y, keep_prob) 88 | total_batch = _data_pipeline.get_total_batch(train_xs, FLAGS.batch_size) 89 | learning_rate_decayed = FLAGS.learning_rate * FLAGS.decay_rate ** (global_step / total_batch) 90 | _optim_op = _CVAE.optim_op(loss, learning_rate_decayed, global_step) 91 | #_optim_op=tf.compat.v1.train.AdamOptimizer(learning_rate = learning_rate_decayed).minimize(loss, global_step = global_step) 92 | 93 | # session_conf = tf.ConfigProto( 94 | # intra_op_parallelism_threads=1, 95 | # inter_op_parallelism_threads=1, 96 | # device_count={'GPU': 0,"CPU": 1}, 97 | # allow_soft_placement=False 98 | # ) 99 | sess = tf.Session() 100 | sess.run(tf.compat.v1.global_variables_initializer()) 101 | batch_v_xs, batch_vn_xs, batch_v_ys = _data_pipeline.next_batch(valid_xs, valid_ys, 100, make_noise=FLAGS.add_noise) 102 | print("_" * 80) 103 | start_time = time.time() 104 | print("training started") 105 | for i in range(FLAGS.n_epoch): 106 | loss_val = 0 107 | for j in range(total_batch): 108 | batch_xs, batch_noised_xs, batch_ys = _data_pipeline.next_batch(train_xs, train_ys, FLAGS.batch_size, 109 | make_noise=False) 110 | feed_dict = {X: batch_xs, X_noised: batch_noised_xs, Y: batch_ys, keep_prob: FLAGS.keep_prob} 111 | l, lr, op, g = sess.run([loss, learning_rate_decayed, _optim_op, global_step], feed_dict=feed_dict) 112 | loss_val += l / total_batch 113 | if not math.isnan(loss_val) and (i % 2 == 0 or i == (FLAGS.n_epoch - 1)): 114 | images = sess.run(output, feed_dict={X: test_images_original, 115 | X_noised: test_images_noisy, 116 | Y: test_labels_updated, 117 | keep_prob: 1.0}) 118 | result = images[:, 0:3] 119 | # Convert definition space 120 | result = 2.0 * result - 1.0 * np.ones(np.shape(result)) 121 | result = np.asarray(result) 122 | 123 | 124 | # mModelToProcessDenoised = copy.deepcopy(mModelToProcess) 125 | # if doRotate: 126 | # for r in range(0, np.size(result, axis=0)): 127 | # result[r, :] = rotate(result[r, :], mModelToProcessDenoised.faces[r].rotationAxis, 128 | # -mModelToProcessDenoised.faces[r].theta) 129 | # updateVerticesWithNormals(mModelToProcessDenoised, result, 20) 130 | # exportObj(mModelToProcessDenoised, dat.rootdir+'meshes/denoised'+ 131 | # '_NUMEL' + str(dat.numOfElements) + 132 | # '_CL' + str(dat.nClusters) + 133 | # '_BS' + str(FLAGS.batch_size) + 134 | # '_KP' + str(FLAGS.keep_prob) + 135 | # '_LR'+str(FLAGS.learning_rate)+ 136 | # '_DR'+ str(FLAGS.decay_rate) + 137 | # '_D1' + str(D1) + 138 | # '_D2' + str(D2) + 139 | # '_E1' + str(E1) + 140 | # '_E2' + str(E2) + 141 | # '_' + '.obj') 142 | 143 | 144 | 145 | writeFile.write(str(loss_val)) 146 | if i!=(FLAGS.n_epoch-1): 147 | writeFile.write(',') 148 | hour = int((time.time() - start_time) / 3600) 149 | min = int(((time.time() - start_time) - 3600 * hour) / 60) 150 | sec = int((time.time() - start_time) - 3600 * hour - 60 * min) 151 | print("Epoch: %.3d loss: %.5f lr: %f Time: %d hour %d min %d sec\n" % (i, loss_val, lr, hour, min, sec)) 152 | sess.close() 153 | writeFile.write(']') 154 | writeFile.write('}') 155 | settingID=settingID+1 156 | 157 | writeFile.write(']') 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /fastMeshDenoising_CVAE_Test_On_The_Fly.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import random 4 | import gzip 5 | import tarfile 6 | import pickle 7 | import os 8 | from six.moves import urllib 9 | from CVAEplot import * 10 | from commonReadModelV3 import * 11 | 12 | import scipy.io 13 | from tensorflow.contrib.factorization import KMeans 14 | import sklearn as sk 15 | from scipy.spatial.distance import pdist, squareform 16 | import pickle 17 | import tensorflow as tf 18 | import numpy as np 19 | from CVAEutils import * 20 | from CVAEplot import * 21 | from CVAE import * 22 | import time 23 | import os 24 | os.environ["CUDA_VISIBLE_DEVICES"]="-1" 25 | from commonReadModelV3 import Geometry,Vertex,Face,Edge 26 | from commonReadModelV3 import Vertex 27 | from commonReadModelV3 import Face 28 | from commonReadModelV3 import Geometry 29 | 30 | 31 | # ===================== Configutation ============================ # 32 | useGuided = False 33 | doRotate = True 34 | noiseLevel = 0.1 35 | nClusters = 200 36 | numberOfPermutations = 10 37 | numOfElements = 20 38 | selectedModel = 10 39 | noiseLevelAsString = '_n1' 40 | trainSet=range(0, 8) 41 | bilateralIterations=1 42 | bilateralSigma=0.25 43 | bilateralNeighb=20 44 | vertexUpdateIterations=20 45 | 46 | doReadOBJ = False 47 | doTrain = False 48 | doTest = False 49 | modelsOnly = True 50 | # ===================== Initializations ============================ # 51 | 52 | patchSizeGuided = numOfElements 53 | keyTest = '_' + str(numOfElements)+noiseLevelAsString 54 | #Add noise level 55 | keyTrain = '_8x'+str(numberOfPermutations)+'_' + str(numOfElements) + '_simple_normals_normalized'+noiseLevelAsString 56 | #keyTrain = '_scanned'+str(numberOfPermutations)+'_' + str(numOfElements) + '_simple_normals_normalized'+noiseLevelAsString 57 | #keyTrain = '_scanned'+str(numberOfPermutations)+'_' + str(numOfElements) + '_simple_normals_normalized'+noiseLevelAsString 58 | # distType='cosine' 59 | distType = 'squared_euclidean' 60 | rootdir= './' 61 | root = rootdir+'meshes/GroundTruth/' 62 | rootNoisy = rootdir+'meshes/Noisy/' 63 | trainModels = ['block', 64 | 'casting', 65 | 'coverrear_Lp', 66 | 'ccylinder', 67 | 'eight', 68 | 'joint', 69 | 'part-Lp', 70 | 'cad', 71 | 'fandisk', 72 | 'chinese-lion', 73 | 'sculpt', 74 | 'rockerarm', 75 | 'smooth-feature', 76 | 'trim-star', 77 | 'gear', 78 | 'boy01-scanned', 79 | 'boy02-scanned', 80 | 'pyramid-scanned', 81 | 'girl-scanned', 82 | 'cone-scanned', 83 | 'sharp-sphere', 84 | 'leg', 85 | 'screwdriver', 86 | 'carter100K', 87 | 'pulley', 88 | 'pulley-defects' 89 | ] 90 | # ===================== Initializations ============================ # 91 | train_images_original = [] 92 | train_images_noisy = [] 93 | test_images_original = [] 94 | test_images_noisy = [] 95 | NormalsNoisyTest = np.empty(shape=[0, numOfElements]) 96 | t = time.time() 97 | # ===================== Read model ============================ # 98 | _modelName = trainModels[selectedModel] 99 | keyTest += '_' + _modelName 100 | modelName = _modelName 101 | print('Reading model ' + modelName) 102 | mModelTest = [] 103 | mModelSrc = root + modelName + '.obj' 104 | mModelSrcNoisy = rootNoisy + modelName + noiseLevelAsString + '.obj' 105 | mModelToProcess = loadObj(mModelSrcNoisy) 106 | updateGeometryAttibutes(mModelToProcess, useGuided=useGuided, numOfFacesForGuided=patchSizeGuided) 107 | # ===================== Patches,test_images_noisy ============================ # 108 | print('Read model complete', time.time() - t) 109 | patches = [] 110 | for i in range(0, len(mModelToProcess.faces)): 111 | if i % 200 == 0: 112 | print('Extract patch information : ' + str( 113 | np.round((100 * i / len(mModelToProcess.faces)), decimals=2)) + ' ' + '%') 114 | p,r = neighboursByFace(mModelToProcess, i, numOfElements) 115 | patches.append(p) 116 | NormalsNoisy = np.empty(shape=[len(mModelToProcess.faces), 3,numOfElements]) 117 | for idx,p in enumerate(patches): 118 | patchFacesNoisy = [mModelToProcess.faces[i] for i in p] 119 | normalsPatchFacesNoisy = np.asarray([pF.faceNormal for pF in patchFacesNoisy]) 120 | if idx % 200 == 0: 121 | print('Rotate patch information : ' + str( 122 | np.round((100 * idx / len(mModelToProcess.faces)), decimals=2)) + ' ' + '%') 123 | # vec = np.mean(np.asarray([fnm.faceNormal for fnm in patchFacesNoisy]), axis=0) 124 | vec = np.mean(np.asarray([fnm.area * fnm.faceNormal for fnm in patchFacesNoisy]), axis=0) 125 | vec = vec / np.linalg.norm(vec) 126 | target = np.asarray([0.0, 1.0, 0.0]) 127 | axis, theta = computeRotation(vec, target) 128 | mModelToProcess.faces[idx] = mModelToProcess.faces[idx]._replace(rotationAxis=axis, theta=theta) 129 | normalsPatchFacesNoisy = rotatePatch(normalsPatchFacesNoisy, axis, theta) 130 | normalsPatchFacesNoisy = normalsPatchFacesNoisy[np.newaxis, :, :] 131 | NormalsNoisy[idx,:,:]=normalsPatchFacesNoisy 132 | test_images_noisy = (NormalsNoisy + 1.0 * np.ones(np.shape(NormalsNoisy))) / 2.0 133 | test_images_noisy = np.round(test_images_noisy, decimals=6) 134 | print('Process complete') 135 | print('Time:' + str(time.time() - t)) 136 | # ===================== KMeans,test_labels_updated ============================ # 137 | Xk = tf.placeholder(tf.float32, shape=[None, len(test_images_noisy[0].ravel())]) 138 | kmeans = KMeans(inputs=Xk, num_clusters=nClusters, distance_metric=distType, use_mini_batch=True) 139 | training_graph = kmeans.training_graph() 140 | (all_scores, cluster_idx, scores, cluster_centers_initialized, init_op, train_op) = training_graph 141 | avg_distance = tf.reduce_mean(scores) 142 | sesskmeans = tf.Session() 143 | tf.train.Saver().restore(sesskmeans, 144 | rootdir + 'sessions/KMeans/modelKMeans_' + str(numOfElements) + noiseLevelAsString + '.ckpt') 145 | kMInputTest = np.reshape(test_images_noisy,(np.shape(test_images_noisy)[0],np.shape(test_images_noisy)[1]*np.shape(test_images_noisy)[2]),order='F').tolist() 146 | _, d, idx = sesskmeans.run([train_op, avg_distance, cluster_idx], 147 | feed_dict={Xk: kMInputTest}) 148 | sesskmeans.close() 149 | mSizeTest = int((np.size(test_images_noisy, axis=0))) 150 | test_labels_updated = np.zeros((mSizeTest, nClusters)) 151 | for i in range(0, mSizeTest): 152 | test_labels_updated[i, idx[0][i]] = 1.0 153 | 154 | 155 | # ===================== Bilateral iterations ============================ # 156 | class data_pipeline: 157 | def __init__(self, type): 158 | self.type = type 159 | self.debug = 0 160 | self.batch = 0 161 | 162 | def load_preprocess_data(self): 163 | self.train_images_original = train_images_original 164 | self.train_images_noisy = train_images_noisy 165 | self.test_images_original = test_images_original 166 | self.test_images_noisy = test_images_noisy 167 | self.train_images = train_images_original 168 | self.train_labels = [] 169 | self.valid_images = test_images_original 170 | self.valid_labels = test_labels_updated 171 | self.test_images = test_images_original 172 | self.test_labels = test_labels_updated 173 | print("-" * 80) 174 | print("-" * 80) 175 | print("training size: ", np.shape(self.train_images), ", ", np.shape(self.train_labels)) 176 | print("valid size: ", np.shape(self.valid_images), ", ", np.shape(self.valid_labels)) 177 | print("test size: ", np.shape(self.test_images), ", ", np.shape(self.test_labels)) 178 | return self.train_images, self.train_labels, self.valid_images, self.valid_labels, self.test_images, self.test_labels 179 | 180 | def next_batch(self, train_images_original,train_images_noisy, train_labels_updated, batch_size, make_noise=None): 181 | self.length = len(train_images_original) // batch_size 182 | batch_xs = train_images_original[self.batch * batch_size: self.batch * batch_size + batch_size, :, :] 183 | batch_noised_xs = train_images_noisy[self.batch * batch_size: self.batch * batch_size + batch_size, :, :] 184 | batch_ys = train_labels_updated[self.batch * batch_size: self.batch * batch_size + batch_size, :] 185 | self.batch += 1 186 | if self.batch == (self.length): 187 | self.batch = 0 188 | return batch_xs, batch_noised_xs, batch_ys 189 | 190 | def get_total_batch(self, images, batch_size): 191 | self.batch_size = batch_size 192 | return len(images) // self.batch_size 193 | 194 | # ===================== Intialize CVAE ============================ # 195 | if __name__ =="__main__": 196 | flag = tf.app.flags 197 | FLAGS = flag.FLAGS 198 | flag.DEFINE_float("learning_rate", 0.00002, "learning rate for training") 199 | flag.DEFINE_integer("n_epoch", 12, "number of Epoch") 200 | flag.DEFINE_integer("n_z", 2, "Dimension of latent variables") 201 | flag.DEFINE_float("keep_prob", 0.95,"Dropout rate") 202 | flag.DEFINE_float("decay_rate", 0.998,"learning rate decay rate") 203 | flag.DEFINE_integer("batch_size", 256, "Batch size for training") 204 | _, height,width = np.shape(test_images_noisy) 205 | n_cls = nClusters 206 | X = tf.placeholder(dtype = tf.float32, shape = [None, height, width], name ="Input") 207 | X_noised = tf.placeholder(dtype = tf.float32, shape = [None, height, width], name ="Input_noised") 208 | Y = tf.placeholder(dtype = tf.float32, shape = [None, n_cls], name = "labels") 209 | keep_prob = tf.placeholder(dtype = tf.float32, name = "drop_rate") 210 | CVAE = CVAE([_,height, width], n_cls, [1024, 2048, 4096, 4096], FLAGS.n_z, keep_prob) 211 | z, output, loss = CVAE.Conditional_Variational_AutoEncoder(X, X_noised, Y, keep_prob) 212 | global_step = tf.Variable(0, trainable=False) 213 | latent = tf.placeholder(dtype=tf.float32, shape=[None, FLAGS.n_z], name="latent_input") 214 | 215 | # ===================== Load session ============================ # 216 | sess = tf.Session() 217 | sess.run(tf.initialize_all_variables()) 218 | tf.train.Saver().restore(sess, rootdir+'sessions/CVAE/model_' + str(numOfElements)+noiseLevelAsString+ '.ckpt') 219 | # ===================== Run inference ============================ # 220 | print("_" * 80) 221 | print("Processing") 222 | rotAx=[ mModelToProcess.faces[r].rotationAxis for r in range(0, np.size(test_images_noisy, axis=0))] 223 | thetas=[-mModelToProcess.faces[r].theta for r in range(0, np.size(test_images_noisy, axis=0))] 224 | rotAx=np.asarray(rotAx) 225 | thetas=np.asarray(thetas) 226 | nIterTest=1 227 | tottime=0 228 | for g in range(0,nIterTest): 229 | t = time.time() 230 | images = sess.run(output, feed_dict={X_noised: test_images_noisy, 231 | Y: test_labels_updated, 232 | keep_prob: 1.0}) 233 | print("Step 1 complete "+str(time.time() - t)) 234 | result = np.asarray(2.0 * images[:, 0:3] - 1.0 * np.ones(np.shape(images[:, 0:3]))) 235 | print("Transform complete " + str(time.time() - t)) 236 | tottime = tottime + (time.time() - t) 237 | tottime = tottime / nIterTest 238 | result=np.asarray([rotate(result[r, :], rotAx[r,:],thetas[r]) for r in range(0, np.size(result, axis=0))]) 239 | print("Rotation complete "+str(time.time() - t)) 240 | sess.close() 241 | print("Full time : "+str(tottime)) 242 | 243 | # ===================== Run bilateral============================ # 244 | resultfiltered=BilateralNormalFiltering(mModelToProcess, result, sigma2=bilateralSigma,neighbours=bilateralNeighb,nIter=bilateralIterations) 245 | updateVerticesWithNormals(mModelToProcess, resultfiltered, vertexUpdateIterations) 246 | print("Step 2 complete "+str(time.time() - t)) 247 | exportObj(mModelToProcess, 248 | rootdir+'results/Comparison/Denoised/CVAE/' + _modelName + noiseLevelAsString + '_' + str(numOfElements) + '.obj') 249 | print("Export complete") 250 | print("Export normals complete "+str(time.time() - t)) 251 | -------------------------------------------------------------------------------- /fastMeshDenoising_AE_Train.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | from tensorflow.contrib.learn.python.learn.datasets import base 5 | from tensorflow.python.framework import dtypes 6 | from tensorflow.python.framework import random_seed 7 | from tensorflow.python.platform import gfile 8 | from tensorflow.python.util.deprecation import deprecated 9 | import scipy.io 10 | from six.moves import xrange 11 | import json 12 | import time 13 | import random 14 | from tensorflow.contrib.factorization import KMeans 15 | import sklearn as sk 16 | import fastMeshDenoising_Data_Utils_Train as dat 17 | from fastMeshDenoising_Data_Utils_Train import * 18 | from scipy.spatial.distance import pdist, squareform 19 | 20 | # https://github.com/aymericdamien/TensorFlow-Examples/blob/master/notebooks/3_NeuralNetworks/autoencoder.ipynb 21 | # 22 | 23 | params = { 24 | 'keyword': '', 25 | 'learning_rate': 0.000004, 26 | 'training_epochs': 12, 27 | 'batch_size': 128, 28 | 'usePolar': False, 29 | 'useWeights': False, 30 | 'useHeatmap': False, 31 | 'useFeature': True, 32 | 'useFlat': True, 33 | 'trainSeparateModels': False, 34 | 'n_hidden_layers': [512,256,128,64], 35 | } 36 | learning_rate = params['learning_rate'] 37 | training_epochs = params['training_epochs'] 38 | batch_size = params['batch_size'] 39 | n_hidden_layers = params['n_hidden_layers'] 40 | 41 | 42 | class DataSet(object): 43 | """Container class for a dataset (deprecated). 44 | 45 | THIS CLASS IS DEPRECATED. See 46 | [contrib/learn/README.md](https://www.tensorflow.org/code/tensorflow/contrib/learn/README.md) 47 | for general migration instructions. 48 | """ 49 | 50 | def __init__(self, 51 | images, 52 | labels, 53 | fake_data=False, 54 | one_hot=False, 55 | dtype=dtypes.float32, 56 | reshape=True, 57 | seed=None): 58 | """Construct a DataSet. 59 | one_hot arg is used only if fake_data is true. `dtype` can be either 60 | `uint8` to leave the input as `[0, 255]`, or `float32` to rescale into 61 | `[0, 1]`. Seed arg provides for convenient deterministic testing. 62 | """ 63 | seed1, seed2 = random_seed.get_seed(seed) 64 | # If op level seed is not set, use whatever graph level seed is returned 65 | np.random.seed(seed1 if seed is None else seed2) 66 | dtype = dtypes.as_dtype(dtype).base_dtype 67 | if dtype not in (dtypes.uint8, dtypes.float32): 68 | raise TypeError( 69 | 'Invalid image dtype %r, expected uint8 or float32' % dtype) 70 | if fake_data: 71 | self._num_examples = 10000 72 | self.one_hot = one_hot 73 | else: 74 | assert images.shape[0] == labels.shape[0], ( 75 | 'images.shape: %s labels.shape: %s' % (images.shape, labels.shape)) 76 | self._num_examples = images.shape[0] 77 | 78 | # Convert shape from [num examples, rows, columns, depth] 79 | # to [num examples, rows*columns] (assuming depth == 1) 80 | if reshape: 81 | # assert images.shape[3] == 1 82 | images = images.reshape(images.shape[0], images.shape[1] * images.shape[2]) # order='F' 83 | if dtype == dtypes.float32: 84 | # Convert from [0, 255] -> [0.0, 1.0]. 85 | images = images.astype(np.float32) 86 | # images = np.multiply(images, 1.0 / 255.0) 87 | self._images = images 88 | self._labels = labels 89 | self._epochs_completed = 0 90 | self._index_in_epoch = 0 91 | 92 | @property 93 | def images(self): 94 | return self._images 95 | 96 | @property 97 | def labels(self): 98 | return self._labels 99 | 100 | @property 101 | def num_examples(self): 102 | return self._num_examples 103 | 104 | @property 105 | def epochs_completed(self): 106 | return self._epochs_completed 107 | 108 | def next_batch(self, batch_size, fake_data=False, shuffle=True): 109 | """Return the next `batch_size` examples from this data set.""" 110 | if fake_data: 111 | fake_image = [1] * 784 112 | if self.one_hot: 113 | fake_label = [1] + [0] * 9 114 | else: 115 | fake_label = 0 116 | return [fake_image for _ in xrange(batch_size)], [ 117 | fake_label for _ in xrange(batch_size) 118 | ] 119 | start = self._index_in_epoch 120 | # Shuffle for the first epoch 121 | if self._epochs_completed == 0 and start == 0 and shuffle: 122 | perm0 = np.arange(self._num_examples) 123 | np.random.shuffle(perm0) 124 | self._images = self.images[perm0] 125 | self._labels = self.labels[perm0] 126 | # Go to the next epoch 127 | if start + batch_size > self._num_examples: 128 | # Finished epoch 129 | self._epochs_completed += 1 130 | # Get the rest examples in this epoch 131 | rest_num_examples = self._num_examples - start 132 | images_rest_part = self._images[start:self._num_examples] 133 | labels_rest_part = self._labels[start:self._num_examples] 134 | # Shuffle the data 135 | if shuffle: 136 | perm = np.arange(self._num_examples) 137 | np.random.shuffle(perm) 138 | self._images = self.images[perm] 139 | self._labels = self.labels[perm] 140 | # Start next epoch 141 | start = 0 142 | self._index_in_epoch = batch_size - rest_num_examples 143 | end = self._index_in_epoch 144 | images_new_part = self._images[start:end] 145 | labels_new_part = self._labels[start:end] 146 | return np.concatenate((images_rest_part, images_new_part), axis=0), np.concatenate( 147 | (labels_rest_part, labels_new_part), axis=0) 148 | else: 149 | self._index_in_epoch += batch_size 150 | end = self._index_in_epoch 151 | return self._images[start:end], self._labels[start:end] 152 | 153 | def fetch(self): 154 | return self._images, self._labels 155 | 156 | 157 | def asCartesian(rthetaphi): 158 | # takes list rthetaphi (single coord) 159 | r = rthetaphi[0] 160 | theta = rthetaphi[1] * np.pi / 180 # to radian 161 | phi = rthetaphi[2] * np.pi / 180 162 | x = r * np.sin(theta) * np.cos(phi) 163 | y = r * np.sin(theta) * np.sin(phi) 164 | z = r * np.cos(theta) 165 | return [x, y, z] 166 | 167 | 168 | def asSpherical(xyz): 169 | # takes list xyz (single coord) 170 | x = xyz[0] 171 | y = xyz[1] 172 | z = xyz[2] 173 | r = np.sqrt(x * x + y * y + z * z) 174 | theta = np.arccos(z / r) * 180 / np.pi # to degrees 175 | phi = np.arctan2(y, x) * 180 / np.pi 176 | if phi < 0: 177 | phi = phi + 360 178 | if theta < 0: 179 | theta = theta + 360 180 | return [r, theta, phi] 181 | 182 | 183 | def mat2Sph(M): 184 | for i in range(0, np.size(M, axis=1)): 185 | xyz = M[:, i] 186 | r, theta, phi = asSpherical(xyz) 187 | M[0, i] = r 188 | M[1, i] = theta 189 | M[2, i] = phi 190 | return M 191 | 192 | 193 | def mat2Cartesian(M): 194 | for i in range(0, np.size(M, axis=1)): 195 | rthetaphi = M[:, i] 196 | x, y, z = asSpherical(rthetaphi) 197 | M[0, i] = x 198 | M[1, i] = y 199 | M[2, i] = z 200 | return M 201 | 202 | 203 | def imputeSph(M, thetaImp, phiImp): 204 | for i in range(0, np.size(M, axis=1)): 205 | M[1, i] = M[1, i] + thetaImp 206 | M[2, i] = M[2, i] + phiImp 207 | if M[1, i] >= 360: 208 | M[1, i] = M[1, i] - int(M[1, i] / 360) * 360 209 | if M[2, i] >= 360: 210 | M[2, i] = M[2, i] - int(M[2, i] / 360) * 360 211 | return M 212 | 213 | 214 | def encoder(X, n_hidden_layers, weights, bias): 215 | layers = []; 216 | for idx, val in enumerate(n_hidden_layers): 217 | if idx == 0: 218 | layers.append( 219 | tf.nn.sigmoid(tf.matmul(X, weights['encoder_w' + str(idx + 1)]) + bias['encoder_b' + str(idx + 1)]) 220 | ) 221 | if idx > 0: 222 | layers.append( 223 | tf.nn.sigmoid(tf.matmul(layers[idx - 1], weights['encoder_w' + str(idx + 1)]) + bias['encoder_b' + str(idx + 1)]) 224 | ) 225 | return layers[len(n_hidden_layers) - 1] 226 | 227 | 228 | def decoder(x, n_hidden_layers, weights, bias): 229 | layers = []; 230 | for idx, val in enumerate(n_hidden_layers): 231 | if idx == 0: 232 | layers.append( 233 | tf.nn.sigmoid(tf.matmul(x, weights['decoder_w' + str(idx + 1)]) + bias['decoder_b' + str(idx + 1)]) 234 | ) 235 | if idx > 0: 236 | layers.append( 237 | tf.nn.sigmoid(tf.matmul(layers[idx - 1], weights['decoder_w' + str(idx + 1)]) + bias['decoder_b' + str(idx + 1)]) 238 | ) 239 | return layers[len(n_hidden_layers) - 1] 240 | 241 | 242 | # Parameters 243 | def xavier_init(size): 244 | in_dim = size[0] 245 | xavier_stddev = 1. / tf.sqrt(in_dim / 2.) 246 | return tf.random_normal(shape=size, stddev=xavier_stddev) 247 | 248 | 249 | def setW(): 250 | weights = {} 251 | for idx, val in enumerate(n_hidden_layers): 252 | if idx == 0: 253 | weights.update( 254 | # {'encoder_w' + str(idx + 1): tf.Variable(tf.random_uniform([n_input, val]))} 255 | # {'encoder_w' + str(idx + 1): tf.Variable(tf.truncated_normal([n_input, val], mean=0.0, stddev=0.5))} 256 | {'encoder_w' + str(idx + 1): tf.Variable(xavier_init([n_input, val]))} 257 | ) 258 | if idx > 0: 259 | weights.update( 260 | # {'encoder_w' + str(idx + 1): tf.Variable(tf.random_uniform([n_hidden_layers[idx - 1], n_hidden_layers[idx]]))} 261 | # {'encoder_w' + str(idx + 1): tf.Variable(tf.truncated_normal([n_hidden_layers[idx - 1], n_hidden_layers[idx]], mean=0.0, stddev=0.5))} 262 | {'encoder_w' + str(idx + 1): tf.Variable(xavier_init([n_hidden_layers[idx - 1], n_hidden_layers[idx]]))} 263 | ) 264 | 265 | for idx, val in enumerate(n_hidden_layers): 266 | tot = len(n_hidden_layers) - 1 267 | j = tot - idx 268 | if idx < tot: 269 | weights.update( 270 | # {'decoder_w' + str(idx + 1): tf.Variable(tf.random_uniform([n_hidden_layers[j], n_hidden_layers[j - 1]]))} 271 | # {'decoder_w' + str(idx + 1): tf.Variable(tf.truncated_normal([n_hidden_layers[j], n_hidden_layers[j - 1]], mean=0.0, stddev=0.5))} 272 | {'decoder_w' + str(idx + 1): tf.Variable(xavier_init([n_hidden_layers[j], n_hidden_layers[j - 1]]))} 273 | ) 274 | if idx == tot: 275 | weights.update( 276 | # {'decoder_w' + str(idx + 1): tf.Variable(tf.random_uniform([n_hidden_layers[j], n_input]))} 277 | # {'decoder_w' + str(idx + 1): tf.Variable( 278 | # tf.truncated_normal([n_hidden_layers[j], n_input], mean=0.0, stddev=0.5))} 279 | {'decoder_w' + str(idx + 1): tf.Variable(xavier_init([n_hidden_layers[j], n_input]))} 280 | ) 281 | return weights 282 | 283 | 284 | def setB(): 285 | bias = {} 286 | for idx, val in enumerate(n_hidden_layers): 287 | bias.update( 288 | {'encoder_b' + str(idx + 1): tf.Variable(tf.zeros([1, val]))} 289 | # {'encoder_b' + str(idx + 1): tf.Variable(tf.truncated_normal([1, val], mean=0.0, stddev=0.5))} 290 | # {'encoder_b' + str(idx + 1): tf.Variable(xavier_init(1, val))} 291 | ) 292 | for idx, val in enumerate(n_hidden_layers): 293 | tot = len(n_hidden_layers) - 1 294 | j = tot - idx 295 | if idx < tot: 296 | bias.update( 297 | {'decoder_b' + str(idx + 1): tf.Variable(tf.zeros([1, n_hidden_layers[j - 1]]))} 298 | # {'decoder_b' + str(idx + 1): tf.Variable( 299 | # tf.truncated_normal([1, n_hidden_layers[j - 1]], mean=0.0, stddev=0.5))} 300 | # {'decoder_b' + str(idx + 1): tf.Variable(xavier_init(1, n_hidden_layers[j - 1]))} 301 | ) 302 | if idx == tot: 303 | bias.update( 304 | {'decoder_b' + str(idx + 1): tf.Variable(tf.zeros([1, n_input]))} 305 | # {'decoder_b' + str(idx + 1): tf.Variable(tf.truncated_normal([1, n_input], mean=0.0, stddev=0.5))} 306 | # {'decoder_b' + str(idx + 1): tf.Variable(xavier_init(1, n_input))} 307 | ) 308 | return bias 309 | 310 | 311 | n_input = np.size(train_images_original, axis=1) * np.size(train_images_original, axis=2) 312 | 313 | options = dict(dtype=dtypes.float32, reshape=True, seed=None) 314 | weights = setW() 315 | bias = setB() 316 | 317 | X = tf.placeholder(tf.float32, shape=(None, n_input)) 318 | X_noise = tf.placeholder(tf.float32, shape=(None, n_input)) 319 | encoder_op = encoder(X_noise, n_hidden_layers, weights, bias) 320 | decoder_op = decoder(encoder_op, n_hidden_layers, weights, bias) 321 | entropy = tf.losses.mean_squared_error(labels=X, predictions=decoder_op) 322 | loss = tf.reduce_mean(entropy) 323 | optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize((tf.abs(loss))) 324 | # optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate).minimize((tf.abs(loss))) 325 | 326 | 327 | ############################################################################# 328 | ############################################################################# 329 | ############################################################################# 330 | val = DataSet(test_images_original, test_labels_updated, **options) 331 | val_noisy = DataSet(test_images_noisy, test_labels_updated, **options) 332 | train = DataSet(train_images_original, train_labels_updated, **options) 333 | train_noisy = DataSet(train_images_noisy, train_labels_updated, **options) 334 | ############################################################################# 335 | ############################################################################# 336 | ############################################################################# 337 | 338 | 339 | ts = int(time.time()) 340 | reportPath = dat.rootdir+'CVAE/sessions/AE/' 341 | pred = decoder_op 342 | if True: 343 | sess = tf.Session() 344 | sess.run(tf.global_variables_initializer()) 345 | num_batches = int(train.num_examples / batch_size) 346 | for epoch in range(training_epochs): 347 | total_loss = 0 348 | for batch in range(num_batches): 349 | x, _ = train.next_batch(batch_size) 350 | x_noise, _ = train_noisy.next_batch(batch_size) 351 | _, l = sess.run([optimizer, loss], feed_dict={X_noise: x_noise, X: x}) 352 | total_loss += l 353 | print("Epoch {0}: {1}".format(epoch, total_loss)) 354 | x_pred = sess.run(pred, feed_dict={X_noise: val_noisy.images}) 355 | print("Epoch {0}: {1}".format(epoch, sk.metrics.mean_squared_error(x_pred, val.images))) 356 | if epoch>5 & epoch % 2 == 0: 357 | result = x_pred[:, 0:3] 358 | # Convert definition space 359 | result = 2.0 * result - 1.0 * np.ones(np.shape(result)) 360 | result = np.asarray(result) 361 | mModelToProcessDenoised = copy.deepcopy(mModelToProcess) 362 | if doRotate: 363 | for r in range(0, np.size(result, axis=0)): 364 | result[r, :] = rotate(result[r, :], mModelToProcessDenoised.faces[r].rotationAxis, 365 | -mModelToProcessDenoised.faces[r].theta) 366 | updateVerticesWithNormals(mModelToProcessDenoised, result, 20) 367 | exportObj(mModelToProcessDenoised, dat.rootdir+'Results-0/denoised_' + str(epoch) + '.obj') 368 | with open(dat.rootdir+'Results-0/result_' + str(epoch) + 'A.csv', 369 | 'w') as writeFile: 370 | for j in range(0, np.size(result, axis=0)): 371 | line = str(result[j, 0]) + "," + str(result[j, 1]) + "," + str(result[j, 2]) 372 | writeFile.write(line) 373 | writeFile.write('\n') 374 | exportObj(mModelToProcessDenoised, 375 | dat.rootdir+'Results-0/Comparisons/Denoised/AE/' + dat._modelName +dat.noiseLevelAsString+'_' + str( 376 | dat.numOfElements) + '.obj') 377 | exportObj(mModelToProcess, 378 | dat.rootdir+'Results-0/Comparisons/Denoised/AE/' + dat._modelName + '_noisy'+dat.noiseLevelAsString +'.obj') 379 | with open(dat.rootdir+'Results-0/Comparisons/Denoised/AE/' + dat._modelName + '_normals'+dat.noiseLevelAsString+'_' + str( 380 | dat.numOfElements) + '.csv','w') as writeFile: 381 | for j in range(0, np.size(result, axis=0)): 382 | line = str(result[j, 0]) + "," + str(result[j, 1]) + "," + str(result[j, 2]) 383 | writeFile.write(line) 384 | writeFile.write('\n') 385 | 386 | 387 | 388 | 389 | 390 | saver = tf.train.Saver() 391 | save_path = saver.save(sess, reportPath +"model_"+str(numOfElements)+dat.noiseLevelAsString+".ckpt") 392 | print("Model saved in path: %s" % save_path) 393 | with open(reportPath + "readme.txt", 'w') as file: 394 | file.write(json.dumps(params)) # use `json.loads` to do the reverse 395 | 396 | -------------------------------------------------------------------------------- /fastMeshDenoising_AE_Test.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import matplotlib.pyplot as plt 4 | from tensorflow.contrib.learn.python.learn.datasets import base 5 | from tensorflow.python.framework import dtypes 6 | from tensorflow.python.framework import random_seed 7 | from tensorflow.python.platform import gfile 8 | from tensorflow.python.util.deprecation import deprecated 9 | import scipy.io 10 | from six.moves import xrange 11 | import json 12 | import time 13 | import random 14 | from tensorflow.contrib.factorization import KMeans 15 | import sklearn as sk 16 | from commonReadModelV3 import * 17 | from commonReadModelV3 import Geometry 18 | import fastMeshDenoising_Data_Utils_Test as dat 19 | from fastMeshDenoising_Data_Utils_Test import * 20 | from scipy.spatial.distance import pdist, squareform 21 | 22 | # https://github.com/aymericdamien/TensorFlow-Examples/blob/master/notebooks/3_NeuralNetworks/autoencoder.ipynb 23 | # 24 | 25 | params = { 26 | 'keyword': '', 27 | 'learning_rate': 0.000004, 28 | 'training_epochs': 12, 29 | 'batch_size': 128, 30 | 'usePolar': False, 31 | 'useWeights': False, 32 | 'useHeatmap': False, 33 | 'useFeature': True, 34 | 'useFlat': True, 35 | 'trainSeparateModels': False, 36 | 'neighbours': 8, 37 | 'n_hidden_layers': [512,256,128,64], 38 | } 39 | learning_rate = params['learning_rate'] 40 | training_epochs = params['training_epochs'] 41 | batch_size = params['batch_size'] 42 | n_hidden_layers = params['n_hidden_layers'] 43 | 44 | 45 | reportPath = dat.rootdir+'CVAE/sessions/AE/' 46 | 47 | 48 | class DataSet(object): 49 | """Container class for a dataset (deprecated). 50 | 51 | THIS CLASS IS DEPRECATED. See 52 | [contrib/learn/README.md](https://www.tensorflow.org/code/tensorflow/contrib/learn/README.md) 53 | for general migration instructions. 54 | """ 55 | 56 | def __init__(self, 57 | images, 58 | labels, 59 | fake_data=False, 60 | one_hot=False, 61 | dtype=dtypes.float32, 62 | reshape=True, 63 | seed=None): 64 | """Construct a DataSet. 65 | one_hot arg is used only if fake_data is true. `dtype` can be either 66 | `uint8` to leave the input as `[0, 255]`, or `float32` to rescale into 67 | `[0, 1]`. Seed arg provides for convenient deterministic testing. 68 | """ 69 | seed1, seed2 = random_seed.get_seed(seed) 70 | # If op level seed is not set, use whatever graph level seed is returned 71 | np.random.seed(seed1 if seed is None else seed2) 72 | dtype = dtypes.as_dtype(dtype).base_dtype 73 | if dtype not in (dtypes.uint8, dtypes.float32): 74 | raise TypeError( 75 | 'Invalid image dtype %r, expected uint8 or float32' % dtype) 76 | if fake_data: 77 | self._num_examples = 10000 78 | self.one_hot = one_hot 79 | else: 80 | assert images.shape[0] == labels.shape[0], ( 81 | 'images.shape: %s labels.shape: %s' % (images.shape, labels.shape)) 82 | self._num_examples = images.shape[0] 83 | 84 | # Convert shape from [num examples, rows, columns, depth] 85 | # to [num examples, rows*columns] (assuming depth == 1) 86 | if reshape: 87 | # assert images.shape[3] == 1 88 | images = images.reshape(images.shape[0], images.shape[1] * images.shape[2]) # order='F' 89 | if dtype == dtypes.float32: 90 | # Convert from [0, 255] -> [0.0, 1.0]. 91 | images = images.astype(np.float32) 92 | # images = np.multiply(images, 1.0 / 255.0) 93 | self._images = images 94 | self._labels = labels 95 | self._epochs_completed = 0 96 | self._index_in_epoch = 0 97 | 98 | @property 99 | def images(self): 100 | return self._images 101 | 102 | @property 103 | def labels(self): 104 | return self._labels 105 | 106 | @property 107 | def num_examples(self): 108 | return self._num_examples 109 | 110 | @property 111 | def epochs_completed(self): 112 | return self._epochs_completed 113 | 114 | def next_batch(self, batch_size, fake_data=False, shuffle=True): 115 | """Return the next `batch_size` examples from this data set.""" 116 | if fake_data: 117 | fake_image = [1] * 784 118 | if self.one_hot: 119 | fake_label = [1] + [0] * 9 120 | else: 121 | fake_label = 0 122 | return [fake_image for _ in xrange(batch_size)], [ 123 | fake_label for _ in xrange(batch_size) 124 | ] 125 | start = self._index_in_epoch 126 | # Shuffle for the first epoch 127 | if self._epochs_completed == 0 and start == 0 and shuffle: 128 | perm0 = np.arange(self._num_examples) 129 | np.random.shuffle(perm0) 130 | self._images = self.images[perm0] 131 | self._labels = self.labels[perm0] 132 | # Go to the next epoch 133 | if start + batch_size > self._num_examples: 134 | # Finished epoch 135 | self._epochs_completed += 1 136 | # Get the rest examples in this epoch 137 | rest_num_examples = self._num_examples - start 138 | images_rest_part = self._images[start:self._num_examples] 139 | labels_rest_part = self._labels[start:self._num_examples] 140 | # Shuffle the data 141 | if shuffle: 142 | perm = np.arange(self._num_examples) 143 | np.random.shuffle(perm) 144 | self._images = self.images[perm] 145 | self._labels = self.labels[perm] 146 | # Start next epoch 147 | start = 0 148 | self._index_in_epoch = batch_size - rest_num_examples 149 | end = self._index_in_epoch 150 | images_new_part = self._images[start:end] 151 | labels_new_part = self._labels[start:end] 152 | return np.concatenate((images_rest_part, images_new_part), axis=0), np.concatenate( 153 | (labels_rest_part, labels_new_part), axis=0) 154 | else: 155 | self._index_in_epoch += batch_size 156 | end = self._index_in_epoch 157 | return self._images[start:end], self._labels[start:end] 158 | 159 | def fetch(self): 160 | return self._images, self._labels 161 | 162 | 163 | def asCartesian(rthetaphi): 164 | # takes list rthetaphi (single coord) 165 | r = rthetaphi[0] 166 | theta = rthetaphi[1] * np.pi / 180 # to radian 167 | phi = rthetaphi[2] * np.pi / 180 168 | x = r * np.sin(theta) * np.cos(phi) 169 | y = r * np.sin(theta) * np.sin(phi) 170 | z = r * np.cos(theta) 171 | return [x, y, z] 172 | 173 | 174 | def asSpherical(xyz): 175 | # takes list xyz (single coord) 176 | x = xyz[0] 177 | y = xyz[1] 178 | z = xyz[2] 179 | r = np.sqrt(x * x + y * y + z * z) 180 | theta = np.arccos(z / r) * 180 / np.pi # to degrees 181 | phi = np.arctan2(y, x) * 180 / np.pi 182 | if phi < 0: 183 | phi = phi + 360 184 | if theta < 0: 185 | theta = theta + 360 186 | return [r, theta, phi] 187 | 188 | 189 | def mat2Sph(M): 190 | for i in range(0, np.size(M, axis=1)): 191 | xyz = M[:, i] 192 | r, theta, phi = asSpherical(xyz) 193 | M[0, i] = r 194 | M[1, i] = theta 195 | M[2, i] = phi 196 | return M 197 | 198 | 199 | def mat2Cartesian(M): 200 | for i in range(0, np.size(M, axis=1)): 201 | rthetaphi = M[:, i] 202 | x, y, z = asSpherical(rthetaphi) 203 | M[0, i] = x 204 | M[1, i] = y 205 | M[2, i] = z 206 | return M 207 | 208 | 209 | def imputeSph(M, thetaImp, phiImp): 210 | for i in range(0, np.size(M, axis=1)): 211 | M[1, i] = M[1, i] + thetaImp 212 | M[2, i] = M[2, i] + phiImp 213 | if M[1, i] >= 360: 214 | M[1, i] = M[1, i] - int(M[1, i] / 360) * 360 215 | if M[2, i] >= 360: 216 | M[2, i] = M[2, i] - int(M[2, i] / 360) * 360 217 | return M 218 | 219 | 220 | def encoder(X, n_hidden_layers, weights, bias): 221 | layers = []; 222 | for idx, val in enumerate(n_hidden_layers): 223 | if idx == 0: 224 | layers.append( 225 | tf.nn.sigmoid(tf.matmul(X, weights['encoder_w' + str(idx + 1)]) + bias['encoder_b' + str(idx + 1)]) 226 | ) 227 | if idx > 0: 228 | layers.append( 229 | tf.nn.sigmoid(tf.matmul(layers[idx - 1], weights['encoder_w' + str(idx + 1)]) + bias['encoder_b' + str(idx + 1)]) 230 | ) 231 | return layers[len(n_hidden_layers) - 1] 232 | 233 | 234 | def decoder(x, n_hidden_layers, weights, bias): 235 | layers = []; 236 | for idx, val in enumerate(n_hidden_layers): 237 | if idx == 0: 238 | layers.append( 239 | tf.nn.sigmoid(tf.matmul(x, weights['decoder_w' + str(idx + 1)]) + bias['decoder_b' + str(idx + 1)]) 240 | ) 241 | if idx > 0: 242 | layers.append( 243 | tf.nn.sigmoid(tf.matmul(layers[idx - 1], weights['decoder_w' + str(idx + 1)]) + bias['decoder_b' + str(idx + 1)]) 244 | ) 245 | return layers[len(n_hidden_layers) - 1] 246 | 247 | 248 | # Parameters 249 | def xavier_init(size): 250 | in_dim = size[0] 251 | xavier_stddev = 1. / tf.sqrt(in_dim / 2.) 252 | return tf.random_normal(shape=size, stddev=xavier_stddev) 253 | 254 | 255 | def setW(): 256 | weights = {} 257 | for idx, val in enumerate(n_hidden_layers): 258 | if idx == 0: 259 | weights.update( 260 | # {'encoder_w' + str(idx + 1): tf.Variable(tf.random_uniform([n_input, val]))} 261 | # {'encoder_w' + str(idx + 1): tf.Variable(tf.truncated_normal([n_input, val], mean=0.0, stddev=0.5))} 262 | {'encoder_w' + str(idx + 1): tf.Variable(xavier_init([n_input, val]))} 263 | ) 264 | if idx > 0: 265 | weights.update( 266 | # {'encoder_w' + str(idx + 1): tf.Variable(tf.random_uniform([n_hidden_layers[idx - 1], n_hidden_layers[idx]]))} 267 | # {'encoder_w' + str(idx + 1): tf.Variable(tf.truncated_normal([n_hidden_layers[idx - 1], n_hidden_layers[idx]], mean=0.0, stddev=0.5))} 268 | {'encoder_w' + str(idx + 1): tf.Variable(xavier_init([n_hidden_layers[idx - 1], n_hidden_layers[idx]]))} 269 | ) 270 | 271 | for idx, val in enumerate(n_hidden_layers): 272 | tot = len(n_hidden_layers) - 1 273 | j = tot - idx 274 | if idx < tot: 275 | weights.update( 276 | # {'decoder_w' + str(idx + 1): tf.Variable(tf.random_uniform([n_hidden_layers[j], n_hidden_layers[j - 1]]))} 277 | # {'decoder_w' + str(idx + 1): tf.Variable(tf.truncated_normal([n_hidden_layers[j], n_hidden_layers[j - 1]], mean=0.0, stddev=0.5))} 278 | {'decoder_w' + str(idx + 1): tf.Variable(xavier_init([n_hidden_layers[j], n_hidden_layers[j - 1]]))} 279 | ) 280 | if idx == tot: 281 | weights.update( 282 | # {'decoder_w' + str(idx + 1): tf.Variable(tf.random_uniform([n_hidden_layers[j], n_input]))} 283 | # {'decoder_w' + str(idx + 1): tf.Variable( 284 | # tf.truncated_normal([n_hidden_layers[j], n_input], mean=0.0, stddev=0.5))} 285 | {'decoder_w' + str(idx + 1): tf.Variable(xavier_init([n_hidden_layers[j], n_input]))} 286 | ) 287 | return weights 288 | 289 | 290 | def setB(): 291 | bias = {} 292 | for idx, val in enumerate(n_hidden_layers): 293 | bias.update( 294 | {'encoder_b' + str(idx + 1): tf.Variable(tf.zeros([1, val]))} 295 | # {'encoder_b' + str(idx + 1): tf.Variable(tf.truncated_normal([1, val], mean=0.0, stddev=0.5))} 296 | # {'encoder_b' + str(idx + 1): tf.Variable(xavier_init(1, val))} 297 | ) 298 | for idx, val in enumerate(n_hidden_layers): 299 | tot = len(n_hidden_layers) - 1 300 | j = tot - idx 301 | if idx < tot: 302 | bias.update( 303 | {'decoder_b' + str(idx + 1): tf.Variable(tf.zeros([1, n_hidden_layers[j - 1]]))} 304 | # {'decoder_b' + str(idx + 1): tf.Variable( 305 | # tf.truncated_normal([1, n_hidden_layers[j - 1]], mean=0.0, stddev=0.5))} 306 | # {'decoder_b' + str(idx + 1): tf.Variable(xavier_init(1, n_hidden_layers[j - 1]))} 307 | ) 308 | if idx == tot: 309 | bias.update( 310 | {'decoder_b' + str(idx + 1): tf.Variable(tf.zeros([1, n_input]))} 311 | # {'decoder_b' + str(idx + 1): tf.Variable(tf.truncated_normal([1, n_input], mean=0.0, stddev=0.5))} 312 | # {'decoder_b' + str(idx + 1): tf.Variable(xavier_init(1, n_input))} 313 | ) 314 | return bias 315 | 316 | 317 | n_input = np.size(train_images_original, axis=1) * np.size(train_images_original, axis=2) 318 | 319 | options = dict(dtype=dtypes.float32, reshape=True, seed=None) 320 | weights = setW() 321 | bias = setB() 322 | 323 | X = tf.placeholder(tf.float32, shape=(None, n_input)) 324 | X_noise = tf.placeholder(tf.float32, shape=(None, n_input)) 325 | encoder_op = encoder(X_noise, n_hidden_layers, weights, bias) 326 | decoder_op = decoder(encoder_op, n_hidden_layers, weights, bias) 327 | entropy = tf.losses.mean_squared_error(labels=X, predictions=decoder_op) 328 | loss = tf.reduce_mean(entropy) 329 | optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize((tf.abs(loss))) 330 | # optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate).minimize((tf.abs(loss))) 331 | 332 | 333 | ############################################################################# 334 | ############################################################################# 335 | ############################################################################# 336 | val = DataSet(test_images_original, test_labels_updated, **options) 337 | val_noisy = DataSet(test_images_noisy, test_labels_updated, **options) 338 | 339 | ############################################################################# 340 | ############################################################################# 341 | ############################################################################# 342 | 343 | 344 | 345 | 346 | pred = decoder_op 347 | if True: 348 | 349 | 350 | rotAx=[ mModelToProcess.faces[r].rotationAxis for r in range(0, np.size(test_images_original, axis=0))] 351 | thetas=[-mModelToProcess.faces[r].theta for r in range(0, np.size(test_images_original, axis=0))] 352 | rotAx=np.asarray(rotAx) 353 | thetas=np.asarray(thetas) 354 | 355 | 356 | sess = tf.Session() 357 | sess.run(tf.global_variables_initializer()) 358 | saver2 = tf.train.Saver() 359 | saver2.restore(sess, reportPath + "model_"+str(numOfElements)+".ckpt") 360 | 361 | nIterTest = 10 362 | tottime = 0 363 | for g in range(0, nIterTest): 364 | t = time.time() 365 | x_pred = sess.run(pred, feed_dict={X_noise: val_noisy.images}) 366 | print("Step 1 complete " + str(time.time() - t)) 367 | result = np.asarray(2.0 * x_pred[:, 0:3] - 1.0 * np.ones(np.shape(x_pred[:, 0:3]))) 368 | print("Transform complete " + str(time.time() - t)) 369 | tottime = tottime + (time.time() - t) 370 | tottime = tottime / nIterTest 371 | 372 | if doRotate: 373 | # result = list(map(lambda r: rotate(result[r, :], mModelToProcess.faces[r].rotationAxis,-mModelToProcess.faces[r].theta), 374 | # range(0, np.size(result, axis=0)))) 375 | result = np.asarray([rotate(result[r, :], rotAx[r, :], thetas[r]) for r in range(0, np.size(result, axis=0))]) 376 | print("Rotation complete "+str(time.time() - t)) 377 | sess.close() 378 | print("Full time : "+ dat._modelName + " "+str(dat.numOfElements)+" "+str(tottime)) 379 | 380 | 381 | 382 | updateVerticesWithNormals(mModelToProcess, result, 20) 383 | print("Step 2 complete " + str(time.time() - t)) 384 | exportObj(mModelToProcess, dat.rootdir+'Results/denoised_0.obj') 385 | print("Export complete") 386 | 387 | 388 | 389 | 390 | 391 | 392 | with open(dat.rootdir+'Results/Comparisons/Denoised/AE/' + dat._modelName + '_axis' + dat.noiseLevelAsString + '_' + str( 393 | dat.numOfElements) + '.csv','w') as writeFile: 394 | for j in range(0, np.size(result, axis=0)): 395 | line = str(rotAx[j,0]) + "," + str(rotAx[j,1]) + "," + str(rotAx[j,2]) 396 | writeFile.write(line) 397 | writeFile.write('\n') 398 | 399 | 400 | with open(dat.rootdir+'Results/Comparisons/Denoised/AE/' + dat._modelName + '_thetas' + dat.noiseLevelAsString + '_' + str( 401 | dat.numOfElements) + '.csv','w') as writeFile: 402 | for j in range(0, np.size(result, axis=0)): 403 | line = str(thetas[j]) 404 | writeFile.write(line) 405 | writeFile.write('\n') 406 | 407 | with open( 408 | dat.rootdir+'Results/Comparisons/Denoised/AE/' + dat._modelName + '_normals' + dat.noiseLevelAsString + '_' + str( 409 | dat.numOfElements) + '.csv', 'w') as writeFile: 410 | for j in range(0, np.size(result, axis=0)): 411 | line = str(result[j, 0]) + "," + str(result[j, 1]) + "," + str(result[j, 2]) 412 | writeFile.write(line) 413 | writeFile.write('\n') 414 | 415 | print("Export normals complete "+str(time.time() - t)) -------------------------------------------------------------------------------- /fastMeshDenoising_Data_Utils_Test.py: -------------------------------------------------------------------------------- 1 | from fastMeshDenoising_Config_Test import * 2 | import fastMeshDenoising_Config_Test as conf 3 | 4 | 5 | # 6 | # 7 | # 8 | # 9 | # noiseLevel = 0.1 10 | # nClusters = 200 11 | # numberOfPermutations = 10 12 | # #Add number or permulations 13 | # numOfElements = 20 14 | # _selectedModel = 22 15 | # patchSizeGuided = numOfElements 16 | # noiseLevelAsString='_n1' 17 | # keyTest = '_' + str(numOfElements)+noiseLevelAsString 18 | # #Add noise level 19 | # keyTrain = '_8x'+str(numberOfPermutations)+'_' + str(numOfElements) + '_simple_normals_normalized'+noiseLevelAsString 20 | # #keyTrain = '_scanned'+str(numberOfPermutations)+'_' + str(numOfElements) + '_simple_normals_normalized'+noiseLevelAsString 21 | # 22 | # 23 | # # distType='cosine' 24 | # distType = 'squared_euclidean' 25 | # rootdir= 'E:/_Groundwork/FastMeshDenoising/' 26 | # root = rootdir+'Results-0/Comparisons/Original/' 27 | # rootNoisy = rootdir+'Results-0/Comparisons/Noisy/' 28 | # trainModels = [ 'block', 29 | # 'casting', 30 | # 'coverrear_Lp', 31 | # 'ccylinder', 32 | # 'eight', 33 | # 'joint', 34 | # 'part_Lp', 35 | # 'cad', 36 | # 'fandisk', 37 | # 'chinese-lion', 38 | # 'sculpt', 39 | # 'rockerarm', 40 | # 'smooth-feature', 41 | # 'trim-star', 42 | # 'gear', 43 | # 'conveyore', 44 | # 'boy01-scanned', 45 | # 'boy02-scanned', 46 | # 'pyramid-scanned', 47 | # 'girl-scanned', 48 | # 'cone-scanned', 49 | # 'pulley', 50 | # 'pulley_defects' 51 | # ] 52 | 53 | 54 | 55 | _modelName = trainModels[conf.selectedModel]; 56 | keyTest += '_' + _modelName 57 | ######### Initializations ################ 58 | train_images_original = [] 59 | train_images_noisy = [] 60 | test_images_original = [] 61 | test_images_noisy = [] 62 | ######### Initializations ################ 63 | t = time.time() 64 | 65 | ''' 66 | if doTrain: 67 | for mIndex in range(0, 8): 68 | modelName = trainModels[mIndex] 69 | mModelSrc = root + modelName + '.obj' 70 | print(modelName) 71 | if doTrain: 72 | print('Initialize, read model', time.time() - t) 73 | mModel = loadObj(mModelSrc) 74 | updateGeometryAttibutes(mModel, useGuided=useGuided, numOfFacesForGuided=patchSizeGuided) 75 | print('Read model complete', time.time() - t) 76 | patches = [] 77 | for i in range(0, len(mModel.faces)): 78 | if i % 20 == 0: 79 | print('Extract patch information : ' + str( 80 | np.round((100 * i / len(mModel.faces)), decimals=2)) + ' ' + '%') 81 | w, u, pv, p = neighboursByFace(mModel, i, numOfElements) 82 | patches.append(p) 83 | print('Initial model complete', time.time() - t) 84 | if doTrain: 85 | NormalsOriginalTrain = np.empty(shape=[0, numOfElements]) 86 | NormalsNoisyTrain = np.empty(shape=[0, numOfElements]) 87 | for repeat in range(0, numberOfPermutations): 88 | print('Progress:' + str(100 * (repeat + 1) / numberOfPermutations) + '%') 89 | mModelToProcess = copy.deepcopy(mModel) 90 | addNoise(mModelToProcess, noiseLevel) 91 | updateGeometryAttibutes(mModelToProcess, useGuided=useGuided, numOfFacesForGuided=patchSizeGuided) 92 | NormalsNoisy = np.empty(shape=[0, numOfElements]) 93 | NormalsOriginal = np.empty(shape=[0, numOfElements]) 94 | for p in patches: 95 | patchFacesNoisy = [mModelToProcess.faces[i] for i in p] 96 | patchFacesOriginal = [mModel.faces[i] for i in p] 97 | normalsPatchFacesNoisy = [] 98 | normalsPatchFacesOriginal = [] 99 | if doRotate: 100 | if useGuided: 101 | vec = patchFacesNoisy[0].guidedNormal 102 | else: 103 | # vec = np.mean(np.asarray([fnm.faceNormal for fnm in patchFacesNoisy]), axis=0) 104 | vec = np.mean(np.asarray([fnm.area * fnm.faceNormal for fnm in patchFacesNoisy]), axis=0) 105 | vec = vec / np.linalg.norm(vec) 106 | target = np.asarray([0.0, 1.0, 0.0]) 107 | axis, theta = computeRotation(vec, target) 108 | for pF in patchFacesNoisy: 109 | if useGuided: 110 | normalsPatchFacesNoisy.append(rotate(pF.guidedNormal, axis, theta)) 111 | else: 112 | normalsPatchFacesNoisy.append(rotate(pF.faceNormal, axis, theta)) 113 | for pF in patchFacesOriginal: 114 | if useGuided: 115 | normalsPatchFacesOriginal.append(rotate(pF.guidedNormal, axis, theta)) 116 | else: 117 | normalsPatchFacesOriginal.append(rotate(pF.faceNormal, axis, theta)) 118 | else: 119 | for pF in patchFacesNoisy: 120 | if useGuided: 121 | normalsPatchFacesNoisy.append(pF.guidedNormal) 122 | else: 123 | normalsPatchFacesNoisy.append(pF.faceNormal) 124 | for pF in patchFacesOriginal: 125 | if useGuided: 126 | normalsPatchFacesOriginal.append(pF.guidedNormal) 127 | else: 128 | normalsPatchFacesOriginal.append(pF.faceNormal) 129 | 130 | normalsPatchFacesNoisy = np.asarray(normalsPatchFacesNoisy) 131 | normalsPatchFacesNoisy = np.transpose(normalsPatchFacesNoisy) 132 | 133 | normalsPatchFacesOriginal = np.asarray(normalsPatchFacesOriginal) 134 | normalsPatchFacesOriginal = np.transpose(normalsPatchFacesOriginal) 135 | 136 | NormalsNoisy = np.concatenate((NormalsNoisy, normalsPatchFacesNoisy[:, 0:numOfElements]), axis=0) 137 | NormalsOriginal = np.concatenate((NormalsOriginal, normalsPatchFacesOriginal[:, 0:numOfElements]), 138 | axis=0) 139 | print('Complete', time.time() - t) 140 | NormalsOriginalTrain = np.concatenate((NormalsOriginalTrain, NormalsOriginal[:, 0:numOfElements]), 141 | axis=0) 142 | NormalsNoisyTrain = np.concatenate((NormalsNoisyTrain, NormalsNoisy[:, 0:numOfElements]), axis=0) 143 | print('Process complete') 144 | 145 | fOrig = NormalsOriginalTrain 146 | fNoisy = NormalsNoisyTrain 147 | mSize = int((np.size(fOrig, axis=0) / 3)) 148 | mSize = int((np.size(fNoisy, axis=0) / 3)) 149 | for i in range(0, mSize): 150 | tStart = i * 3 151 | tEnd = i * 3 + 3 152 | toAppendΟ = fOrig[tStart:tEnd, 0:numOfElements] 153 | toAppendΟ = np.transpose(toAppendΟ) 154 | toAppendΟ = (toAppendΟ + 1.0 * np.ones(np.shape(toAppendΟ))) / 2.0 155 | toAppendN = fNoisy[tStart:tEnd, 0:numOfElements] 156 | toAppendN = np.transpose(toAppendN) 157 | toAppendN = (toAppendN + 1.0 * np.ones(np.shape(toAppendN))) / 2.0 158 | if True: 159 | train_images_original.append(toAppendΟ) 160 | train_images_noisy.append(toAppendN) 161 | ######################################################################################################################## 162 | ######################################################################################################################## 163 | ######################################################################################################################## 164 | train_images_original = np.asarray(train_images_original) 165 | train_images_noisy = np.asarray(train_images_noisy) 166 | train_images_original = np.round(train_images_original, decimals=6) 167 | train_images_noisy = np.round(train_images_noisy, decimals=6) 168 | ######################################################################################################################## 169 | ######################################################################################################################## 170 | ######################################################################################################################## 171 | ''' 172 | 173 | if doTest: 174 | modelName = _modelName 175 | print('Reading model '+ modelName) 176 | mModelTest=[] 177 | if doReadOBJ: 178 | mModelSrc = root + modelName + '.obj' 179 | mModelSrcNoisy = rootNoisy + modelName + noiseLevelAsString + '.obj' 180 | mModelTest = loadObj(mModelSrc) 181 | mModelToProcess = loadObj(mModelSrcNoisy) 182 | # outputFile = root + modelName + '.data' 183 | # fw = open(outputFile, 'wb') 184 | # pickle.dump(mModelTest, fw) 185 | # pickle.dump(mModelToProcess, fw) 186 | # fw.close() 187 | # else: 188 | # inputFile = root + modelName + '.data' 189 | # f = open(inputFile, 'rb') 190 | # mModelTest = pickle.load(f) 191 | # mModelToProcess = pickle.load(f) 192 | # f.close() 193 | 194 | 195 | if True: 196 | NormalsOriginalTest = np.empty(shape=[0, numOfElements]) 197 | NormalsNoisyTest = np.empty(shape=[0, numOfElements]) 198 | # mModelToProcess = copy.deepcopy(mModel) 199 | # addNoise(mModelToProcess, noiseLevel) 200 | updateGeometryAttibutes(mModelTest, useGuided=useGuided, numOfFacesForGuided=patchSizeGuided) 201 | updateGeometryAttibutes(mModelToProcess, useGuided=useGuided, numOfFacesForGuided=patchSizeGuided) 202 | print('Read model complete', time.time() - t) 203 | patches = [] 204 | for i in range(0, len(mModelTest.faces)): 205 | if i % 200 == 0: 206 | print('Extract patch information : ' + str( 207 | np.round((100 * i / len(mModelTest.faces)), decimals=2)) + ' ' + '%') 208 | p,_ = neighboursByFace(mModelTest, i, numOfElements) 209 | patches.append(p) 210 | 211 | NormalsNoisy = np.empty(shape=[0, numOfElements]) 212 | NormalsOriginal = np.empty(shape=[0, numOfElements]) 213 | for p in patches: 214 | patchFacesNoisy = [mModelToProcess.faces[i] for i in p] 215 | patchFacesOriginal = [mModelTest.faces[i] for i in p] 216 | normalsPatchFacesNoisy = [] 217 | normalsPatchFacesOriginal = [] 218 | if doRotate: 219 | if useGuided: 220 | vec = patchFacesNoisy[0].guidedNormal 221 | else: 222 | # vec = np.mean(np.asarray([fnm.faceNormal for fnm in patchFacesNoisy]), axis=0) 223 | vec = np.mean(np.asarray([fnm.area * fnm.faceNormal for fnm in patchFacesNoisy]), axis=0) 224 | vec = vec / np.linalg.norm(vec) 225 | target = np.asarray([0.0, 1.0, 0.0]) 226 | axis, theta = computeRotation(vec, target) 227 | idx = patchFacesNoisy[0].index 228 | mModelToProcess.faces[idx] = mModelToProcess.faces[idx]._replace(rotationAxis=axis, theta=theta) 229 | for pF in patchFacesNoisy: 230 | if useGuided: 231 | normalsPatchFacesNoisy.append(rotate(pF.guidedNormal, axis, theta)) 232 | else: 233 | normalsPatchFacesNoisy.append(rotate(pF.faceNormal, axis, theta)) 234 | 235 | idx = patchFacesOriginal[0].index 236 | mModelTest.faces[idx] = mModelTest.faces[idx]._replace(rotationAxis=axis, theta=theta) 237 | for pF in patchFacesOriginal: 238 | if useGuided: 239 | normalsPatchFacesOriginal.append(rotate(pF.guidedNormal, axis, theta)) 240 | else: 241 | normalsPatchFacesOriginal.append(rotate(pF.faceNormal, axis, theta)) 242 | else: 243 | for pF in patchFacesNoisy: 244 | if useGuided: 245 | normalsPatchFacesNoisy.append(pF.guidedNormal) 246 | else: 247 | normalsPatchFacesNoisy.append(pF.faceNormal) 248 | for pF in patchFacesOriginal: 249 | if useGuided: 250 | normalsPatchFacesOriginal.append(pF.guidedNormal) 251 | else: 252 | normalsPatchFacesOriginal.append(pF.faceNormal) 253 | 254 | normalsPatchFacesNoisy = np.asarray(normalsPatchFacesNoisy) 255 | normalsPatchFacesNoisy = np.transpose(normalsPatchFacesNoisy) 256 | 257 | normalsPatchFacesOriginal = np.asarray(normalsPatchFacesOriginal) 258 | normalsPatchFacesOriginal = np.transpose(normalsPatchFacesOriginal) 259 | 260 | #if np.size(normalsPatchFacesNoisy, axis=1) >= numOfElements: 261 | NormalsNoisy = np.concatenate((NormalsNoisy, normalsPatchFacesNoisy[:, 0:numOfElements]), axis=0) 262 | NormalsOriginal = np.concatenate((NormalsOriginal, normalsPatchFacesOriginal[:, 0:numOfElements]), axis=0) 263 | 264 | 265 | exportObj(mModelToProcess, rootdir+'mModelTest.obj') 266 | print('Time:' + str(time.time() - t)) 267 | NormalsNoisyTest = np.concatenate((NormalsNoisyTest, NormalsNoisy[:, 0:numOfElements]), axis=0) 268 | NormalsOriginalTest = np.concatenate((NormalsOriginalTest, NormalsOriginal[:, 0:numOfElements]), axis=0) 269 | print('Process complete') 270 | 271 | fNoisyTest = NormalsNoisyTest 272 | fOrigTest = NormalsOriginalTest 273 | 274 | mSizeTest = int((np.size(fNoisyTest, axis=0) / 3)) 275 | for i in range(0, mSizeTest): 276 | tStartTest = i * 3 277 | tEndTest = i * 3 + 3 278 | toAppendΟTest = fOrigTest[tStartTest:tEndTest, 0:numOfElements] 279 | toAppendΟTest = np.transpose(toAppendΟTest) 280 | toAppendΟTest = (toAppendΟTest + 1.0 * np.ones(np.shape(toAppendΟTest))) / 2.0 281 | toAppendNTest = fNoisyTest[tStartTest:tEndTest, 0:numOfElements] 282 | toAppendNTest = np.transpose(toAppendNTest) 283 | toAppendNTest = (toAppendNTest + 1.0 * np.ones(np.shape(toAppendNTest))) / 2.0 284 | if True: 285 | test_images_original.append(toAppendΟTest) 286 | test_images_noisy.append(toAppendNTest) 287 | 288 | test_images_original = np.asarray(test_images_original) 289 | test_images_noisy = np.asarray(test_images_noisy) 290 | 291 | test_images_original = np.round(test_images_original, decimals=6) 292 | test_images_noisy = np.round(test_images_noisy, decimals=6) 293 | 294 | ############################################################################# 295 | ############################################################################# 296 | ############################################################################# 297 | 298 | 299 | Geometry = collections.namedtuple("G", "vertices, normals, faces, edges, adjacency") 300 | Vertex = collections.namedtuple("V", 301 | "index,position,normal,neighbouringFaceIndices,neighbouringVerticesIndices,rotationAxis,theta") 302 | Face = collections.namedtuple("F", 303 | "index,centroid,vertices,verticesIndices,faceNormal,area,edgeIndices,neighbouringFaceIndices,guidedNormal,rotationAxis,theta") 304 | Edge = collections.namedtuple("E", "index,vertices,verticesIndices,length,facesIndices") 305 | 306 | # if doTrain: 307 | # outputFile = rootdir+'data/storeTrain' + keyTrain + '.data' 308 | # fw = open(outputFile, 'wb') 309 | # pickle.dump(train_images_original, fw) 310 | # pickle.dump(train_images_noisy, fw) 311 | # fw.close() 312 | # else: 313 | 314 | 315 | if True: 316 | inputFile = rootdir+'data/storeTrain' + keyTrain + '.data' 317 | f = open(inputFile, 'rb') 318 | train_images_original = pickle.load(f) 319 | train_images_noisy = pickle.load(f) 320 | 321 | print('Trainset') 322 | print(np.size(train_images_original,axis=0)) 323 | print(np.size(train_images_noisy, axis=0)) 324 | f.close() 325 | 326 | if doTest: 327 | outputFile = rootdir+'data/storeTest' + keyTest + '.data' 328 | fw = open(outputFile, 'wb') 329 | pickle.dump(test_images_original, fw) 330 | pickle.dump(test_images_noisy, fw) 331 | pickle.dump(mModelTest, fw) 332 | pickle.dump(mModelToProcess, fw) 333 | exportObj(mModelToProcess, rootdir+'mModelTest.obj') 334 | fw.close() 335 | else: 336 | inputFile = rootdir+'data/storeTest' + keyTest + '.data' 337 | f = open(inputFile, 'rb') 338 | test_images_original = pickle.load(f) 339 | test_images_noisy = pickle.load(f) 340 | mModelTest = pickle.load(f) 341 | mModelToProcess = pickle.load(f) 342 | exportObj(mModelToProcess, rootdir+'mModelTest.obj') 343 | f.close() 344 | 345 | if modelsOnly: 346 | exit(0) 347 | 348 | 349 | 350 | 351 | if True: 352 | mSize = int((np.size(train_images_original, axis=0))) 353 | mSizeTest = int((np.size(test_images_original, axis=0))) 354 | kMInputTrain = [] 355 | d = [] 356 | for i in range(0, mSize): 357 | d = train_images_noisy[i].ravel() 358 | kMInputTrain.append(d) 359 | Xk = tf.placeholder(tf.float32, shape=[None, len(train_images_noisy[0].ravel())]) 360 | # K-Means Parameters 361 | kmeans = KMeans(inputs=Xk, num_clusters=nClusters, distance_metric=distType, 362 | use_mini_batch=True) 363 | training_graph = kmeans.training_graph() 364 | if len(training_graph) > 6: # Tensorflow 1.4+ 365 | (all_scores, cluster_idx, scores, cluster_centers_initialized, 366 | cluster_centers_var, init_op, train_op) = training_graph 367 | else: 368 | (all_scores, cluster_idx, scores, cluster_centers_initialized, 369 | init_op, train_op) = training_graph 370 | cluster_idx = cluster_idx[0] # fix for cluster_idx being a tuple 371 | avg_distance = tf.reduce_mean(scores) 372 | # Initialize the variables (i.e. assign their default value) 373 | init_vars2 = tf.global_variables_initializer() 374 | # Start TensorFlow session 375 | sesskmeans = tf.Session() 376 | # Run the initializer 377 | sesskmeans.run(init_vars2, feed_dict={Xk: kMInputTrain}) 378 | sesskmeans.run(init_op, feed_dict={Xk: kMInputTrain}) 379 | 380 | 381 | tf.train.Saver().restore(sesskmeans, rootdir+'sessions/KMeans/modelKMeans_'+str(numOfElements)+noiseLevelAsString+'.ckpt') 382 | kMInputTest = []; 383 | for i in range(0, mSizeTest): 384 | d = test_images_noisy[i].ravel() 385 | kMInputTest.append(d) 386 | for i in range(1, 5 + 1): 387 | _, d, idx = sesskmeans.run([train_op, avg_distance, cluster_idx], 388 | feed_dict={Xk: kMInputTest}) 389 | sesskmeans.close() 390 | test_labels_updated = np.zeros((mSizeTest, nClusters)) 391 | for i in range(0, mSizeTest): 392 | test_labels_updated[i, idx[i]] = 1.0 393 | test_labels_updated = np.asarray(test_labels_updated) 394 | 395 | 396 | ############################################################################# 397 | ############################################################################# 398 | ############################################################################# 399 | ############################################################################# 400 | 401 | 402 | class data_pipeline: 403 | def __init__(self, type): 404 | self.type = type 405 | self.debug = 0 406 | self.batch = 0 407 | 408 | def load_preprocess_data(self): 409 | self.train_images_original = train_images_original 410 | self.train_images_noisy = train_images_noisy 411 | self.test_images_original = test_images_original 412 | self.test_images_noisy = test_images_noisy 413 | self.train_images = train_images_original 414 | self.train_labels = [] 415 | self.valid_images = test_images_original 416 | self.valid_labels = test_labels_updated 417 | self.test_images = test_images_original 418 | self.test_labels = test_labels_updated 419 | print("-" * 80) 420 | print("-" * 80) 421 | print("training size: ", np.shape(self.train_images), ", ", np.shape(self.train_labels)) 422 | print("valid size: ", np.shape(self.valid_images), ", ", np.shape(self.valid_labels)) 423 | print("test size: ", np.shape(self.test_images), ", ", np.shape(self.test_labels)) 424 | return self.train_images, self.train_labels, self.valid_images, self.valid_labels, self.test_images, self.test_labels 425 | 426 | def next_batch(self, train_images_original,train_images_noisy, train_labels_updated, batch_size, make_noise=None): 427 | self.length = len(train_images_original) // batch_size 428 | batch_xs = train_images_original[self.batch * batch_size: self.batch * batch_size + batch_size, :, :] 429 | batch_noised_xs = train_images_noisy[self.batch * batch_size: self.batch * batch_size + batch_size, :, :] 430 | batch_ys = train_labels_updated[self.batch * batch_size: self.batch * batch_size + batch_size, :] 431 | self.batch += 1 432 | if self.batch == (self.length): 433 | self.batch = 0 434 | return batch_xs, batch_noised_xs, batch_ys 435 | 436 | def get_total_batch(self, images, batch_size): 437 | self.batch_size = batch_size 438 | return len(images) // self.batch_size 439 | -------------------------------------------------------------------------------- /fastMeshDenoising_Data_Utils_Train.py: -------------------------------------------------------------------------------- 1 | from fastMeshDenoising_Config_Train import * 2 | 3 | _modelName = trainModels[selectedModel]; 4 | keyTest += '_' + _modelName 5 | ######### Initializations ################ 6 | train_images_original = [] 7 | train_images_noisy = [] 8 | test_images_original = [] 9 | test_images_noisy = [] 10 | ######### Initializations ################ 11 | t = time.time() 12 | if doTrain: 13 | for mIndex in trainSet: 14 | modelName = trainModels[mIndex] 15 | mModelSrc = root + modelName + '.obj' 16 | mModelSrcNoisy = rootNoisy + modelName + noiseLevelAsString + '.obj' 17 | print(modelName) 18 | if doTrain: 19 | print('Initialize, read model', time.time() - t) 20 | 21 | mModel=[] 22 | if doReadOBJ: 23 | mModel = loadObj(mModelSrc) 24 | updateGeometryAttibutes(mModel, useGuided=useGuided, numOfFacesForGuided=patchSizeGuided) 25 | # outputFile = root + modelName + '.data' 26 | # fw = open(outputFile, 'wb') 27 | # pickle.dump(mModel, fw) 28 | # fw.close() 29 | # else: 30 | # inputFile = root + modelName + '.data' 31 | # f = open(inputFile, 'rb') 32 | # mModel = pickle.load(f) 33 | 34 | print('Read model complete', time.time() - t) 35 | patches = [] 36 | for i in range(0, len(mModel.faces)): 37 | if i % 20 == 0: 38 | print('Extract patch information : ' + str( 39 | np.round((100 * i / len(mModel.faces)), decimals=2)) + ' ' + '%') 40 | p,_ = neighboursByFace(mModel, i, numOfElements) 41 | patches.append(p) 42 | print('Initial model complete', time.time() - t) 43 | if doTrain: 44 | NormalsOriginalTrain = np.empty(shape=[0, numOfElements]) 45 | NormalsNoisyTrain = np.empty(shape=[0, numOfElements]) 46 | for repeat in range(0, numberOfPermutations): 47 | print('Progress:' + str(100 * (repeat + 1) / numberOfPermutations) + '%') 48 | 49 | mModelToProcess = copy.deepcopy(mModel) 50 | addNoise(mModelToProcess, noiseLevel) 51 | #mModelToProcess = loadObj(mModelSrcNoisy) 52 | 53 | 54 | updateGeometryAttibutes(mModelToProcess, useGuided=useGuided, numOfFacesForGuided=patchSizeGuided) 55 | NormalsNoisy = np.empty(shape=[0, numOfElements]) 56 | NormalsOriginal = np.empty(shape=[0, numOfElements]) 57 | for p in patches: 58 | patchFacesNoisy = [mModelToProcess.faces[i] for i in p] 59 | patchFacesOriginal = [mModel.faces[i] for i in p] 60 | normalsPatchFacesNoisy = [] 61 | normalsPatchFacesOriginal = [] 62 | if doRotate: 63 | if useGuided: 64 | vec = patchFacesNoisy[0].guidedNormal 65 | else: 66 | # vec = np.mean(np.asarray([fnm.faceNormal for fnm in patchFacesNoisy]), axis=0) 67 | vec = np.mean(np.asarray([fnm.area * fnm.faceNormal for fnm in patchFacesNoisy]), axis=0) 68 | vec = vec / np.linalg.norm(vec) 69 | target = np.asarray([0.0, 1.0, 0.0]) 70 | axis, theta = computeRotation(vec, target) 71 | for pF in patchFacesNoisy: 72 | if useGuided: 73 | normalsPatchFacesNoisy.append(rotate(pF.guidedNormal, axis, theta)) 74 | else: 75 | normalsPatchFacesNoisy.append(rotate(pF.faceNormal, axis, theta)) 76 | for pF in patchFacesOriginal: 77 | if useGuided: 78 | normalsPatchFacesOriginal.append(rotate(pF.guidedNormal, axis, theta)) 79 | else: 80 | normalsPatchFacesOriginal.append(rotate(pF.faceNormal, axis, theta)) 81 | else: 82 | for pF in patchFacesNoisy: 83 | if useGuided: 84 | normalsPatchFacesNoisy.append(pF.guidedNormal) 85 | else: 86 | normalsPatchFacesNoisy.append(pF.faceNormal) 87 | for pF in patchFacesOriginal: 88 | if useGuided: 89 | normalsPatchFacesOriginal.append(pF.guidedNormal) 90 | else: 91 | normalsPatchFacesOriginal.append(pF.faceNormal) 92 | 93 | normalsPatchFacesNoisy = np.asarray(normalsPatchFacesNoisy) 94 | normalsPatchFacesNoisy = np.transpose(normalsPatchFacesNoisy) 95 | 96 | normalsPatchFacesOriginal = np.asarray(normalsPatchFacesOriginal) 97 | normalsPatchFacesOriginal = np.transpose(normalsPatchFacesOriginal) 98 | 99 | NormalsNoisy = np.concatenate((NormalsNoisy, normalsPatchFacesNoisy[:, 0:numOfElements]), axis=0) 100 | NormalsOriginal = np.concatenate((NormalsOriginal, normalsPatchFacesOriginal[:, 0:numOfElements]), 101 | axis=0) 102 | print('Complete', time.time() - t) 103 | NormalsOriginalTrain = np.concatenate((NormalsOriginalTrain, NormalsOriginal[:, 0:numOfElements]), 104 | axis=0) 105 | NormalsNoisyTrain = np.concatenate((NormalsNoisyTrain, NormalsNoisy[:, 0:numOfElements]), axis=0) 106 | print('Process complete') 107 | 108 | fOrig = NormalsOriginalTrain 109 | fNoisy = NormalsNoisyTrain 110 | mSize = int((np.size(fOrig, axis=0) / 3)) 111 | mSize = int((np.size(fNoisy, axis=0) / 3)) 112 | for i in range(0, mSize): 113 | tStart = i * 3 114 | tEnd = i * 3 + 3 115 | toAppendΟ = fOrig[tStart:tEnd, 0:numOfElements] 116 | toAppendΟ = np.transpose(toAppendΟ) 117 | toAppendΟ = (toAppendΟ + 1.0 * np.ones(np.shape(toAppendΟ))) / 2.0 118 | toAppendN = fNoisy[tStart:tEnd, 0:numOfElements] 119 | toAppendN = np.transpose(toAppendN) 120 | toAppendN = (toAppendN + 1.0 * np.ones(np.shape(toAppendN))) / 2.0 121 | if True: 122 | train_images_original.append(toAppendΟ) 123 | train_images_noisy.append(toAppendN) 124 | ######################################################################################################################## 125 | ######################################################################################################################## 126 | ######################################################################################################################## 127 | train_images_original = np.asarray(train_images_original) 128 | train_images_noisy = np.asarray(train_images_noisy) 129 | train_images_original = np.round(train_images_original, decimals=6) 130 | train_images_noisy = np.round(train_images_noisy, decimals=6) 131 | ######################################################################################################################## 132 | ######################################################################################################################## 133 | ######################################################################################################################## 134 | 135 | 136 | 137 | if doTest: 138 | print('Testing phase') 139 | modelName = _modelName 140 | modelNameNoisy=modelName + noiseLevelAsString 141 | mModelSrc = root + modelName + '.obj' 142 | mModelSrcNoisy = rootNoisy + modelNameNoisy + '.obj' 143 | print('Loading model' + ' ' + mModelSrcNoisy) 144 | 145 | 146 | 147 | if True: 148 | mModelToProcess = [] 149 | if doReadOBJ: 150 | mModelToProcess = loadObj(mModelSrcNoisy) 151 | updateGeometryAttibutes(mModelToProcess, useGuided=useGuided, numOfFacesForGuided=patchSizeGuided) 152 | # outputFile = rootNoisy + modelNameNoisy + '.data' 153 | # fw = open(outputFile, 'wb') 154 | # pickle.dump(mModelToProcess, fw) 155 | # fw.close() 156 | # else: 157 | # inputFile = rootNoisy + modelNameNoisy + '.data' 158 | # f = open(inputFile, 'rb') 159 | # mModelToProcess = pickle.load(f) 160 | 161 | NormalsOriginalTest = np.empty(shape=[0, numOfElements]) 162 | NormalsNoisyTest = np.empty(shape=[0, numOfElements]) 163 | 164 | 165 | mModelTest=copy.deepcopy(mModelToProcess) 166 | 167 | 168 | # mModelTest = loadObj(mModelSrc) 169 | # updateGeometryAttibutes(mModelTest, useGuided=useGuided, numOfFacesForGuided=patchSizeGuided) 170 | # mModelToProcess = copy.deepcopy(mModelTest) 171 | # addNoise(mModelToProcess, noiseLevel) 172 | # mModelToProcess = loadObj(mModelSrcNoisy) 173 | # updateGeometryAttibutes(mModelToProcess, useGuided=useGuided, numOfFacesForGuided=patchSizeGuided) 174 | 175 | 176 | 177 | 178 | 179 | 180 | print('Read model complete', time.time() - t) 181 | patches = [] 182 | for i in range(0, len(mModelTest.faces)): 183 | if i % 200 == 0: 184 | print('Extract patch information : ' + str( 185 | np.round((100 * i / len(mModelTest.faces)), decimals=2)) + ' ' + '%') 186 | p,_ = neighboursByFace(mModelTest, i, numOfElements) 187 | patches.append(p) 188 | 189 | NormalsNoisy = np.empty(shape=[0, numOfElements]) 190 | NormalsOriginal = np.empty(shape=[0, numOfElements]) 191 | for p in patches: 192 | patchFacesNoisy = [mModelToProcess.faces[i] for i in p] 193 | patchFacesOriginal = [mModelTest.faces[i] for i in p] 194 | normalsPatchFacesNoisy = [] 195 | normalsPatchFacesOriginal = [] 196 | if doRotate: 197 | if useGuided: 198 | vec = patchFacesNoisy[0].guidedNormal 199 | else: 200 | # vec = np.mean(np.asarray([fnm.faceNormal for fnm in patchFacesNoisy]), axis=0) 201 | vec = np.mean(np.asarray([fnm.area * fnm.faceNormal for fnm in patchFacesNoisy]), axis=0) 202 | vec = vec / np.linalg.norm(vec) 203 | target = np.asarray([0.0, 1.0, 0.0]) 204 | axis, theta = computeRotation(vec, target) 205 | idx = patchFacesNoisy[0].index 206 | mModelToProcess.faces[idx] = mModelToProcess.faces[idx]._replace(rotationAxis=axis, theta=theta) 207 | for pF in patchFacesNoisy: 208 | if useGuided: 209 | normalsPatchFacesNoisy.append(rotate(pF.guidedNormal, axis, theta)) 210 | else: 211 | normalsPatchFacesNoisy.append(rotate(pF.faceNormal, axis, theta)) 212 | 213 | idx = patchFacesOriginal[0].index 214 | mModelTest.faces[idx] = mModelTest.faces[idx]._replace(rotationAxis=axis, theta=theta) 215 | for pF in patchFacesOriginal: 216 | if useGuided: 217 | normalsPatchFacesOriginal.append(rotate(pF.guidedNormal, axis, theta)) 218 | else: 219 | normalsPatchFacesOriginal.append(rotate(pF.faceNormal, axis, theta)) 220 | else: 221 | for pF in patchFacesNoisy: 222 | if useGuided: 223 | normalsPatchFacesNoisy.append(pF.guidedNormal) 224 | else: 225 | normalsPatchFacesNoisy.append(pF.faceNormal) 226 | for pF in patchFacesOriginal: 227 | if useGuided: 228 | normalsPatchFacesOriginal.append(pF.guidedNormal) 229 | else: 230 | normalsPatchFacesOriginal.append(pF.faceNormal) 231 | 232 | normalsPatchFacesNoisy = np.asarray(normalsPatchFacesNoisy) 233 | normalsPatchFacesNoisy = np.transpose(normalsPatchFacesNoisy) 234 | 235 | normalsPatchFacesOriginal = np.asarray(normalsPatchFacesOriginal) 236 | normalsPatchFacesOriginal = np.transpose(normalsPatchFacesOriginal) 237 | 238 | NormalsNoisy = np.concatenate((NormalsNoisy, normalsPatchFacesNoisy[:, 0:numOfElements]), axis=0) 239 | NormalsOriginal = np.concatenate((NormalsOriginal, normalsPatchFacesOriginal[:, 0:numOfElements]), axis=0) 240 | exportObj(mModelToProcess, rootdir+'meshes/mModelTest.obj') 241 | print('Time:' + str(time.time() - t)) 242 | NormalsNoisyTest = np.concatenate((NormalsNoisyTest, NormalsNoisy[:, 0:numOfElements]), axis=0) 243 | NormalsOriginalTest = np.concatenate((NormalsOriginalTest, NormalsOriginal[:, 0:numOfElements]), axis=0) 244 | print('Process complete') 245 | 246 | fNoisyTest = NormalsNoisyTest 247 | fOrigTest = NormalsOriginalTest 248 | 249 | mSizeTest = int((np.size(fNoisyTest, axis=0) / 3)) 250 | for i in range(0, mSizeTest): 251 | tStartTest = i * 3 252 | tEndTest = i * 3 + 3 253 | toAppendΟTest = fOrigTest[tStartTest:tEndTest, 0:numOfElements] 254 | toAppendΟTest = np.transpose(toAppendΟTest) 255 | toAppendΟTest = (toAppendΟTest + 1.0 * np.ones(np.shape(toAppendΟTest))) / 2.0 256 | toAppendNTest = fNoisyTest[tStartTest:tEndTest, 0:numOfElements] 257 | toAppendNTest = np.transpose(toAppendNTest) 258 | toAppendNTest = (toAppendNTest + 1.0 * np.ones(np.shape(toAppendNTest))) / 2.0 259 | if True: 260 | test_images_original.append(toAppendΟTest) 261 | test_images_noisy.append(toAppendNTest) 262 | 263 | test_images_original = np.asarray(test_images_original) 264 | test_images_noisy = np.asarray(test_images_noisy) 265 | 266 | test_images_original = np.round(test_images_original, decimals=6) 267 | test_images_noisy = np.round(test_images_noisy, decimals=6) 268 | 269 | ############################################################################# 270 | ############################################################################# 271 | ############################################################################# 272 | 273 | 274 | Geometry = collections.namedtuple("G", "vertices, normals, faces, edges, adjacency") 275 | Vertex = collections.namedtuple("V", 276 | "index,position,normal,neighbouringFaceIndices,neighbouringVerticesIndices,rotationAxis,theta") 277 | Face = collections.namedtuple("F", 278 | "index,centroid,vertices,verticesIndices,faceNormal,area,edgeIndices,neighbouringFaceIndices,guidedNormal,rotationAxis,theta") 279 | Edge = collections.namedtuple("E", "index,vertices,verticesIndices,length,facesIndices") 280 | 281 | # if doTrain: 282 | # outputFile = rootdir+'data/storeTrain' + keyTrain + '.data' 283 | # fw = open(outputFile, 'wb') 284 | # pickle.dump(train_images_original, fw) 285 | # pickle.dump(train_images_noisy, fw) 286 | # fw.close() 287 | # else: 288 | # inputFile = rootdir+'data/storeTrain' + keyTrain + '.data' 289 | # f = open(inputFile, 'rb') 290 | # train_images_original = pickle.load(f) 291 | # train_images_noisy = pickle.load(f) 292 | # 293 | # print('Trainset') 294 | # print(np.size(train_images_original,axis=0)) 295 | # print(np.size(train_images_noisy, axis=0)) 296 | # f.close() 297 | 298 | # if doTest: 299 | # outputFile = rootdir+'data/storeTest' + keyTest + '.data' 300 | # fw = open(outputFile, 'wb') 301 | # pickle.dump(test_images_original, fw) 302 | # pickle.dump(test_images_noisy, fw) 303 | # pickle.dump(mModelTest, fw) 304 | # pickle.dump(mModelToProcess, fw) 305 | # exportObj(mModelToProcess, rootdir+'meshes/mModelTest.obj') 306 | # fw.close() 307 | # else: 308 | # inputFile = rootdir+'data/storeTest' + keyTest + '.data' 309 | # f = open(inputFile, 'rb') 310 | # test_images_original = pickle.load(f) 311 | # test_images_noisy = pickle.load(f) 312 | # mModelTest = pickle.load(f) 313 | # mModelToProcess = pickle.load(f) 314 | # exportObj(mModelToProcess, rootdir+'meshes/mModelTest.obj') 315 | # f.close() 316 | 317 | 318 | 319 | if True: 320 | mSize = int((np.size(train_images_original, axis=0))) 321 | mSizeTest = int((np.size(test_images_original, axis=0))) 322 | kMInputTrain = [] 323 | d = [] 324 | for i in range(0, mSize): 325 | d = train_images_noisy[i].ravel() 326 | kMInputTrain.append(d) 327 | 328 | # from sklearn.cluster import KMeans 329 | # for k in range(60, 100): 330 | # # Create a kmeans model on our data, using k clusters. random_state helps ensure that the algorithm returns the same results each time. 331 | # kmeans_model = KMeans(n_clusters=k, random_state=1).fit(kMInput) 332 | # # These are our fitted labels for clusters -- the first cluster has label 0, and the second has label 1. 333 | # labels = kmeans_model.labels_ 334 | # # Sum of distances of samples to their closest cluster center 335 | # interia = kmeans_model.inertia_ 336 | # print( "k:", k, " cost:", interia) 337 | 338 | Xk = tf.compat.v1.placeholder(tf.float32, shape=[None, len(train_images_noisy[0].ravel())]) 339 | # K-Means Parameters 340 | kmeans = KMeans(inputs=Xk, num_clusters=nClusters, distance_metric=distType, 341 | use_mini_batch=True) 342 | # Build KMeans graph 343 | training_graph = kmeans.training_graph() 344 | if len(training_graph) > 6: # Tensorflow 1.4+ 345 | (all_scores, cluster_idx, scores, cluster_centers_initialized, 346 | cluster_centers_var, init_op, train_op) = training_graph 347 | else: 348 | (all_scores, cluster_idx, scores, cluster_centers_initialized, 349 | init_op, train_op) = training_graph 350 | cluster_idx = cluster_idx[0] # fix for cluster_idx being a tuple 351 | avg_distance = tf.reduce_mean(scores) 352 | # Initialize the variables (i.e. assign their default value) 353 | init_vars2 = tf.compat.v1.global_variables_initializer() 354 | # Start TensorFlow session 355 | sesskmeans = tf.compat.v1.Session() 356 | # Run the initializer 357 | sesskmeans.run(init_vars2, feed_dict={Xk: kMInputTrain}) 358 | sesskmeans.run(init_op, feed_dict={Xk: kMInputTrain}) 359 | # Training 360 | for i in range(1, 100 + 1): 361 | _, d, idx = sesskmeans.run([train_op, avg_distance, cluster_idx], 362 | feed_dict={Xk: kMInputTrain}) 363 | if i % 10 == 0 or i == 1: 364 | print("Step %i, Avg Distance: %f" % (i, d)) 365 | train_labels_updated = np.zeros((mSize, nClusters)) 366 | for i in range(0, mSize): 367 | train_labels_updated[i, idx[i]] = 1.0 368 | train_labels_updated = np.asarray(train_labels_updated) 369 | 370 | saver = tf.train.Saver() 371 | save_path = saver.save(sesskmeans, rootdir+'sessions/KMeans/modelKMeans_'+str(numOfElements)+noiseLevelAsString+'.ckpt') 372 | sesskmeans.close() 373 | ############################################################################# 374 | ############################################################################# 375 | ############################################################################# 376 | ############################################################################# 377 | 378 | sessionKMeansRestored = tf.Session() 379 | tf.train.Saver().restore(sessionKMeansRestored, rootdir+'sessions/KMeans/modelKMeans_'+str(numOfElements)+noiseLevelAsString+'.ckpt') 380 | kMInputTest = []; 381 | for i in range(0, mSizeTest): 382 | d = test_images_noisy[i].ravel() 383 | #d = test_images_original[i].ravel() 384 | kMInputTest.append(d) 385 | for i in range(1, 100 + 1): 386 | _, d, idx = sessionKMeansRestored.run([train_op, avg_distance, cluster_idx], 387 | feed_dict={Xk: kMInputTest}) 388 | if i % 10 == 0 or i == 1: 389 | print("Step %i, Avg Distance: %f" % (i, d)) 390 | sessionKMeansRestored.close() 391 | test_labels_updated = np.zeros((mSizeTest, nClusters)) 392 | for i in range(0, mSizeTest): 393 | test_labels_updated[i, idx[i]] = 1.0 394 | test_labels_updated = np.asarray(test_labels_updated) 395 | with open(rootdir+'sessions/KMeans/mModelClustering.csv', 'w') as writeFile: 396 | for idx_ in idx: 397 | line = str(idx_) 398 | writeFile.write(line) 399 | writeFile.write('\n') 400 | 401 | ############################################################################# 402 | ############################################################################# 403 | ############################################################################# 404 | ############################################################################# 405 | 406 | 407 | 408 | class data_pipeline: 409 | def __init__(self, type): 410 | self.type = type 411 | self.debug = 0 412 | self.batch = 0 413 | 414 | def load_preprocess_data(self): 415 | self.train_images_original = train_images_original 416 | self.train_images_noisy = train_images_noisy 417 | self.test_images_original = test_images_original 418 | self.test_images_noisy = test_images_noisy 419 | self.train_images = train_images_original 420 | self.train_labels = train_labels_updated 421 | self.valid_images = test_images_original 422 | self.valid_labels = test_labels_updated 423 | self.test_images = test_images_original 424 | self.test_labels = test_labels_updated 425 | print("-" * 80) 426 | print("-" * 80) 427 | print("training size: ", np.shape(self.train_images), ", ", np.shape(self.train_labels)) 428 | print("valid size: ", np.shape(self.valid_images), ", ", np.shape(self.valid_labels)) 429 | print("test size: ", np.shape(self.test_images), ", ", np.shape(self.test_labels)) 430 | return self.train_images, self.train_labels, self.valid_images, self.valid_labels, self.test_images, self.test_labels 431 | 432 | def next_batch(self, images, labels, batch_size, make_noise=None): 433 | self.length = len(train_images_original) // batch_size 434 | batch_xs = train_images_original[self.batch * batch_size: self.batch * batch_size + batch_size, :, :] 435 | batch_noised_xs = train_images_noisy[self.batch * batch_size: self.batch * batch_size + batch_size, :, :] 436 | batch_ys = train_labels_updated[self.batch * batch_size: self.batch * batch_size + batch_size, :] 437 | self.batch += 1 438 | if self.batch == (self.length): 439 | self.batch = 0 440 | return batch_xs, batch_noised_xs, batch_ys 441 | 442 | def get_total_batch(self, images, batch_size): 443 | self.batch_size = batch_size 444 | return len(images) // self.batch_size 445 | -------------------------------------------------------------------------------- /commonReadModelV3.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import collections 3 | import numpy as np 4 | from sklearn.neighbors import KDTree 5 | from scipy.sparse import dok_matrix 6 | import time 7 | import copy 8 | import math 9 | from joblib import Parallel, delayed 10 | from numpy import linalg as LA 11 | 12 | Geometry = collections.namedtuple("Geometry", "vertices, normals, faces, edges, adjacency") 13 | Vertex = collections.namedtuple("Vertex", 14 | "index,position,delta,normal,neighbouringFaceIndices,neighbouringVerticesIndices,rotationAxis,theta,color,edgeIndices") 15 | Face = collections.namedtuple("Face", 16 | "index,centroid,delta,vertices,verticesIndices,verticesIndicesSorted,faceNormal,area,edgeIndices,neighbouringFaceIndices,guidedNormal,rotationAxis,theta,color") 17 | Edge = collections.namedtuple("Edge", "index,vertices,verticesIndices,length,facesIndices,edgeNormal") 18 | 19 | def list2dict(lst): 20 | res_dct = {lst[i]: i for i in range(0, len(lst))} 21 | return res_dct 22 | 23 | 24 | def loadObj(filename): 25 | vertices = [] 26 | normals = [] 27 | faces = [] 28 | edges = [] 29 | adjacency = [] 30 | with open(filename, newline='') as f: 31 | flines = f.readlines() 32 | # Read vertices 33 | indexCounter = 0; 34 | print('Reading Vertices') 35 | for row in flines: 36 | if row[0] == 'v' and row[1] == ' ': 37 | line = row.rstrip() 38 | line = line[2:len(line)] 39 | coords = line.split() 40 | coords = list(map(float, coords)) 41 | v = Vertex( 42 | index=indexCounter, 43 | position=np.asarray([coords[0], coords[1], coords[2]]), 44 | delta=[], 45 | normal=np.asarray([0.0, 0.0, 0.0]), 46 | neighbouringFaceIndices=[], 47 | neighbouringVerticesIndices=[], 48 | theta=0.0, 49 | edgeIndices=[], 50 | rotationAxis=np.asarray([0.0, 0.0, 0.0]), 51 | #color=np.asarray([coords[3], coords[4], coords[5]]) 52 | color = np.asarray([0.0, 0.0, 0.0]) 53 | ) 54 | indexCounter += 1; 55 | vertices.append(v) 56 | # Read Faces 57 | indexCounter = 0; 58 | print('Reading Faces') 59 | for row in flines: 60 | if row[0] == 'f': 61 | line = row.rstrip() 62 | line = line[2:len(line)] 63 | lineparts = line.strip().split() 64 | faceline = []; 65 | for fi in lineparts: 66 | fi = fi.split('/') 67 | faceline.append(int(fi[0]) - 1) 68 | f = Face( 69 | index=indexCounter, 70 | verticesIndices=[int(faceline[0]), int(faceline[1]), int(faceline[2])], 71 | verticesIndicesSorted=[int(faceline[0]), int(faceline[1]), int(faceline[2])].sort(), 72 | vertices=[], 73 | centroid=np.asarray([0.0, 0.0, 0.0]), 74 | delta=[], 75 | faceNormal=np.asarray([0.0, 0.0, 0.0]), 76 | edgeIndices=[], 77 | area=0.0, 78 | neighbouringFaceIndices=[], 79 | guidedNormal=np.asarray([0.0, 0.0, 0.0]), 80 | theta=0.0, 81 | rotationAxis=np.asarray([0.0, 1.0, 0.0]), 82 | color=np.asarray([0.0, 0.0, 0.0]) 83 | ) 84 | indexCounter += 1; 85 | faces.append(f) 86 | 87 | # Which vertices are neighbouring to each vertex 88 | print('Which vertices are neighbouring to each vertex') 89 | for idx_f, f in enumerate(faces): 90 | v0 = f.verticesIndices[0] 91 | v1 = f.verticesIndices[1] 92 | v2 = f.verticesIndices[2] 93 | if v1 not in vertices[v0].neighbouringVerticesIndices: 94 | vertices[v0].neighbouringVerticesIndices.append(v1) 95 | if v2 not in vertices[v0].neighbouringVerticesIndices: 96 | vertices[v0].neighbouringVerticesIndices.append(v2) 97 | if v0 not in vertices[v1].neighbouringVerticesIndices: 98 | vertices[v1].neighbouringVerticesIndices.append(v0) 99 | if v2 not in vertices[v1].neighbouringVerticesIndices: 100 | vertices[v1].neighbouringVerticesIndices.append(v2) 101 | if v0 not in vertices[v2].neighbouringVerticesIndices: 102 | vertices[v2].neighbouringVerticesIndices.append(v0) 103 | if v1 not in vertices[v2].neighbouringVerticesIndices: 104 | vertices[v2].neighbouringVerticesIndices.append(v1) 105 | 106 | # Which faces are neighbouring to each vertex 107 | print('Which faces are neighbouring to each vertex') 108 | for idx_f, f in enumerate(faces): 109 | for idx_v, v in enumerate(f.verticesIndices): 110 | vertices[v].neighbouringFaceIndices.append(f.index) 111 | 112 | print('Which faces are neighbouring to each face') 113 | for idx_v, v in enumerate(vertices): 114 | for idx_f in v.neighbouringFaceIndices: 115 | for jdx_f in v.neighbouringFaceIndices: 116 | common = set(faces[idx_f].verticesIndices) & set(faces[jdx_f].verticesIndices) 117 | if len(common) == 2: 118 | faces[idx_f].neighbouringFaceIndices.append(jdx_f) 119 | 120 | for idx_f, fi in enumerate(faces): 121 | neighbouringFaceIndices=faces[idx_f].neighbouringFaceIndices 122 | faces[idx_f]=faces[idx_f]._replace(neighbouringFaceIndices=list(set(neighbouringFaceIndices))) 123 | 124 | ind_e=0 125 | _edges=[] 126 | for idx_v,vi in enumerate(vertices): 127 | neighbouringVerts=vertices[idx_v].neighbouringVerticesIndices 128 | for nv in neighbouringVerts: 129 | _edges.append([idx_v,nv]) 130 | _edges = np.asarray(_edges) 131 | _edges.sort(axis=1) 132 | _edges = np.unique(_edges, axis=0) 133 | _edges=_edges.tolist() 134 | for idx_e,ei in enumerate(_edges): 135 | 136 | vertices[ei[0]].edgeIndices.append(idx_e) 137 | vertices[ei[1]].edgeIndices.append(idx_e) 138 | 139 | f1=vertices[ei[0]].neighbouringFaceIndices 140 | f2=vertices[ei[1]].neighbouringFaceIndices 141 | 142 | 143 | fs = list(set(f1).intersection(f2)) 144 | E = Edge( 145 | index=ind_e, 146 | vertices=[], 147 | verticesIndices=[ei[0], ei[1]], 148 | length=0.0, 149 | facesIndices=fs, 150 | edgeNormal=np.asarray([1.0, 0.0, 0.0]) 151 | ) 152 | edges.append(E) 153 | for fsi in fs: 154 | faces[fsi].edgeIndices.append(idx_e) 155 | 156 | 157 | 158 | 159 | 160 | return Geometry( 161 | vertices=vertices, 162 | normals=normals, 163 | faces=faces, 164 | edges=edges, 165 | adjacency=[] 166 | ) 167 | 168 | 169 | 170 | def loadObjPC(filename,nn=6): 171 | vertices = [] 172 | normals = [] 173 | faces = [] 174 | edges = [] 175 | adjacency = [] 176 | with open(filename, newline='') as f: 177 | flines = f.readlines() 178 | # Read vertices 179 | indexCounter = 0; 180 | print('Reading Vertices') 181 | for row in flines: 182 | if row[0] == 'v' and row[1] == ' ': 183 | line = row.rstrip() 184 | line = line[2:len(line)] 185 | coords = line.split() 186 | coords = list(map(float, coords)) 187 | v = Vertex( 188 | index=indexCounter, 189 | position=np.asarray([coords[0], coords[1], coords[2]]), 190 | delta=[], 191 | normal=np.asarray([0.0, 0.0, 0.0]), 192 | neighbouringFaceIndices=[], 193 | neighbouringVerticesIndices=[], 194 | theta=0.0, 195 | edgeIndices=[], 196 | rotationAxis=np.asarray([0.0, 0.0, 0.0]), 197 | #color=np.asarray([coords[3], coords[4], coords[5]]) 198 | color = np.asarray([0.5, 0.5, 0.5]) 199 | ) 200 | indexCounter += 1; 201 | vertices.append(v) 202 | V = np.asarray([v.position for v in vertices]) 203 | tree = KDTree(V) 204 | nearest_dist, nearest_ind = tree.query(V, k=nn + 1) 205 | for idx_v, v in enumerate(vertices): 206 | vertices[idx_v]=vertices[idx_v]._replace(neighbouringVerticesIndices=nearest_ind[idx_v,1:]) 207 | # Which faces are neighbouring to each vertex 208 | # print('Which faces are neighbouring to each vertex') 209 | # for idx_f, f in enumerate(faces): 210 | # for idx_v, v in enumerate(f.verticesIndices): 211 | # vertices[v].neighbouringFaceIndices.append(f.index) 212 | 213 | 214 | return Geometry( 215 | vertices=vertices, 216 | normals=normals, 217 | faces=faces, 218 | edges=edges, 219 | adjacency=[] 220 | ) 221 | 222 | 223 | def addNoise(Geom, noiseLevel): 224 | avg_len = 0.0 225 | for idx_e, e in enumerate(Geom.edges): 226 | avg_len += e.length 227 | avg_len = avg_len / len(Geom.edges) 228 | stddev = avg_len * noiseLevel 229 | g = np.random.normal(0, stddev, len(Geom.vertices)) 230 | #stddevList=[avg_len * np.random.uniform(low=0.01, high=0.3) for i in range(0,len(Geom.vertices))] 231 | #muList = [0.0 for i in range(0, len(Geom.vertices))] 232 | #g = np.random.normal(muList, stddevList, len(Geom.vertices)) 233 | for idx_v, v in enumerate(Geom.vertices): 234 | Geom.vertices[idx_v].position[0] = Geom.vertices[idx_v].position[0] + Geom.vertices[idx_v].normal[0] * g[idx_v] 235 | Geom.vertices[idx_v].position[1] = Geom.vertices[idx_v].position[1] + Geom.vertices[idx_v].normal[1] * g[idx_v] 236 | Geom.vertices[idx_v].position[2] = Geom.vertices[idx_v].position[2] + Geom.vertices[idx_v].normal[2] * g[idx_v] 237 | 238 | 239 | 240 | def exportObj(Geom, filename,color=False): 241 | F = [] 242 | for f in Geom.faces: 243 | F.append(np.asarray(f.verticesIndices) + np.ones(np.shape(f.verticesIndices))) 244 | F = np.asarray(F) 245 | 246 | with open(filename, 'w') as writeFile: 247 | for v in Geom.vertices: 248 | line = "v " + str(v.position[0]) + " " + str(v.position[1]) + " " + str(v.position[2]) 249 | if color: 250 | line=line+" "+str(v.color[0]) + " " + str(v.color[1]) + " " + str(v.color[2]) 251 | writeFile.write(line) 252 | writeFile.write('\n') 253 | 254 | 255 | for j in range(0, np.size(F, axis=0)): 256 | line = "f " + str(int(F[j, 0])) + " " + str(int(F[j, 1])) + " " + str(int(F[j, 2])) 257 | writeFile.write(line) 258 | writeFile.write('\n') 259 | print('Obj model ' + filename + ' exported') 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | def exportObjPC(Geom, filename): 268 | V = [] 269 | F = [] 270 | N = [] 271 | for v in Geom.vertices: 272 | V.append(v.position) 273 | for v in Geom.vertices: 274 | N.append(np.asarray(v.normal)) 275 | for f in Geom.faces: 276 | F.append(np.asarray(f.verticesIndices) + np.ones(np.shape(f.verticesIndices))) 277 | V = np.asarray(V) 278 | N = np.asarray(N) 279 | 280 | with open(filename, 'w') as writeFile: 281 | for j in range(0, np.size(N, axis=0)): 282 | line = "vn " + str(N[j, 0]) + " " + str(N[j, 1]) + " " + str(N[j, 2]) 283 | writeFile.write(line) 284 | writeFile.write('\n') 285 | line = "v " + str(V[j, 0]) + " " + str(V[j, 1]) + " " + str(V[j, 2]) 286 | writeFile.write(line) 287 | writeFile.write('\n') 288 | 289 | 290 | print('Obj model ' + filename + ' exported') 291 | 292 | 293 | def exportPLYPC(Geom, filename): 294 | V = [] 295 | F = [] 296 | N = [] 297 | for v in Geom.vertices: 298 | V.append(v.position) 299 | for v in Geom.vertices: 300 | N.append(np.asarray(v.normal)) 301 | V = np.asarray(V) 302 | N = np.asarray(N) 303 | 304 | with open(filename, 'w') as writeFile: 305 | writeFile.write("ply") 306 | writeFile.write('\n') 307 | writeFile.write("format ascii 1.0") 308 | writeFile.write('\n') 309 | writeFile.write("comment VCGLIB generated") 310 | writeFile.write('\n') 311 | writeFile.write("element vertex "+ str(N.shape[0])) 312 | writeFile.write('\n') 313 | writeFile.write("property float x") 314 | writeFile.write('\n') 315 | writeFile.write("property float y") 316 | writeFile.write('\n') 317 | writeFile.write("property float z") 318 | writeFile.write('\n') 319 | writeFile.write("property float nx") 320 | writeFile.write('\n') 321 | writeFile.write("property float ny") 322 | writeFile.write('\n') 323 | writeFile.write("property float nz") 324 | writeFile.write('\n') 325 | writeFile.write("element face 0") 326 | writeFile.write('\n') 327 | writeFile.write("property list uchar int vertex_indices") 328 | writeFile.write('\n') 329 | writeFile.write("end_header") 330 | writeFile.write('\n') 331 | for j in range(0, np.size(N, axis=0)): 332 | line = str(round(V[j, 0])) + " " + str(V[j, 1]) + " " + str(V[j, 2]) + " " + str(N[j, 0]) + " " + str(N[j, 1]) + " " + str(N[j, 2]) 333 | writeFile.write(line) 334 | writeFile.write('\n') 335 | print('PLY model ' + filename + ' exported') 336 | 337 | 338 | 339 | def f7(seq): 340 | seen = set() 341 | seen_add = seen.add 342 | return [x for x in seq if not (x in seen or seen_add(x))] 343 | 344 | 345 | 346 | def cropList(listToProcess,maxElements): 347 | if len(listToProcess)<(maxElements): 348 | for i in range(0,maxElements-len(listToProcess)): 349 | listToProcess.append(listToProcess[0]) 350 | if len(listToProcess) > (maxElements): 351 | listToProcess=listToProcess[:(maxElements)] 352 | return listToProcess 353 | 354 | def neighboursByVertex(Geom, vertexIndex, numOfNeighbours,useRings=True): 355 | patchVertices = [] 356 | rings=[] 357 | patchVertices.append(vertexIndex) 358 | rings=[[vertexIndex]] 359 | for i in patchVertices: 360 | rings.append(np.asarray(Geom.vertices[i].neighbouringVerticesIndices)) 361 | for j in Geom.vertices[i].neighbouringVerticesIndices: 362 | if len(patchVertices) < numOfNeighbours: 363 | if j not in patchVertices: 364 | patchVertices.append(j) 365 | # for j in Geom.vertices[i].neighbouringVerticesIndices: 366 | # if len(patchVertices) < numOfNeighbours: 367 | # patchVertices.append(j) 368 | # patchVertices = f7(patchVertices) 369 | patchVertices = cropList(patchVertices, numOfNeighbours) 370 | rings=np.asarray(rings) 371 | rings=np.concatenate(rings).ravel().tolist() 372 | rings=cropList(rings,numOfNeighbours) 373 | return patchVertices,rings 374 | 375 | 376 | def neighboursByFace(Geom, faceIndex, numOfNeighbours,useRings=True): 377 | #patchFaces = [] 378 | #patchFaces.append(faceIndex) 379 | rings = [faceIndex] 380 | 381 | # patchFaces = [faceIndex] 382 | # for i in patchFaces: 383 | # for j in Geom.faces[i].neighbouringFaceIndices: 384 | # if len(patchFaces) < numOfNeighbours: 385 | # if j not in patchFaces: 386 | # patchFaces.append(j) 387 | 388 | 389 | patchFaces = [faceIndex] 390 | crosschecklist=set() 391 | for i in patchFaces: 392 | for j in Geom.faces[i].neighbouringFaceIndices: 393 | if len(patchFaces) < numOfNeighbours: 394 | if j not in crosschecklist: 395 | patchFaces.append(j) 396 | crosschecklist.add(j) 397 | 398 | 399 | # for i in patchFaces: 400 | # if len(patchFaces) < numOfNeighbours: 401 | # patchFaces.extend(Geom.faces[i].neighbouringFaceIndices) 402 | # patchFaces=sorted(set(patchFaces), key=patchFaces.index) 403 | # ik = 0 404 | # while ik < numOfNeighbours: 405 | # ikk=patchFaces[ik] 406 | # patchFaces.extend(Geom.faces[ikk].neighbouringFaceIndices) 407 | # patchFaces = sorted(set(patchFaces), key=patchFaces.index) 408 | # ik += 1 409 | # for i in patchFaces: 410 | # for j in Geom.faces[i].neighbouringFaceIndices: 411 | # if len(patchFaces) < numOfNeighbours: 412 | # if j not in patchFaces: 413 | # patchFaces.append(j) 414 | # for i in rings: 415 | # if len(rings) < 4*numOfNeighbours: 416 | # rings.extend(Geom.faces[i].neighbouringFaceIndices) 417 | # np.savetxt('test1.csv',patchFaces,delimiter=',') 418 | # patchFaces=sorted(set(rings), key=rings.index) 419 | # np.savetxt('test2.csv',patchFaces,delimiter=',') 420 | # rings=cropList(rings,numOfNeighbours) 421 | 422 | patchFaces=cropList(patchFaces,numOfNeighbours) 423 | return patchFaces,rings 424 | 425 | 426 | 427 | 428 | 429 | def updateGeometryConnectivity(Geom): 430 | print('Updating geometry connectivity') 431 | 432 | 433 | def updateGeometryAttibutes(Geom, useGuided=False, numOfFacesForGuided=10,computeDeltas=False,computeAdjacency=False,computeVertexNormals=True): 434 | print('Updating geometry attributes') 435 | ## Positioning & orientation 436 | print('Get vertex objects for each face') 437 | for idx_f, f in enumerate(Geom.faces): 438 | v = [Geom.vertices[fvi] for fvi in Geom.faces[idx_f].verticesIndices] 439 | Geom.faces[idx_f] = Geom.faces[idx_f]._replace(vertices=v) 440 | print('Compute centroids') 441 | for idx_f, f in enumerate(Geom.faces): 442 | vPos = [Geom.vertices[i].position for i in Geom.faces[idx_f].verticesIndices] 443 | vPos = np.asarray(vPos) 444 | centroid = np.mean(vPos, axis=0) 445 | Geom.faces[idx_f] = Geom.faces[idx_f]._replace(centroid=centroid) 446 | print('Process centroids and normals per face') 447 | for idx_f, f in enumerate(Geom.faces): 448 | bc = Geom.faces[idx_f].vertices[1].position - Geom.faces[idx_f].vertices[2].position 449 | ba = Geom.faces[idx_f].vertices[0].position - Geom.faces[idx_f].vertices[2].position 450 | normal = np.cross(bc, ba) 451 | faceArea = 0.5 * np.linalg.norm(normal) 452 | Geom.faces[idx_f] = Geom.faces[idx_f]._replace(area=faceArea) 453 | if np.linalg.norm(normal)!=0: 454 | normalizedNormal = normal / np.linalg.norm(normal) 455 | else: 456 | normalizedNormal = np.asarray([0.0,1.0,0.0]) 457 | print("Problem") 458 | Geom.faces[idx_f].faceNormal[0] = normalizedNormal[0] 459 | Geom.faces[idx_f].faceNormal[1] = normalizedNormal[1] 460 | Geom.faces[idx_f].faceNormal[2] = normalizedNormal[2] 461 | if np.linalg.norm(normalizedNormal)==0: 462 | print('Warning') 463 | 464 | if computeVertexNormals: 465 | print('Process normals per vertex') 466 | for idx_v, v in enumerate(Geom.vertices): 467 | normal = np.asarray([0.0, 0.0, 0.0]) 468 | for idx_f, f in enumerate(Geom.vertices[idx_v].neighbouringFaceIndices): 469 | normal += Geom.faces[f].faceNormal 470 | normal = normal / len(Geom.vertices[idx_v].neighbouringFaceIndices) 471 | normal = normal / np.linalg.norm(normal) 472 | Geom.vertices[idx_v].normal[0] = normal[0] 473 | Geom.vertices[idx_v].normal[1] = normal[1] 474 | Geom.vertices[idx_v].normal[2] = normal[2] 475 | 476 | if useGuided: 477 | print('Process guided') 478 | numOfFaces_ = numOfFacesForGuided 479 | patches = [] 480 | for i in range(0, len(Geom.faces)): 481 | # print('Start searching patces for face '+str(i)+' '+ str(time.time() - t)) 482 | p = neighboursByFace(Geom, i, numOfFaces_) 483 | patches.append(p) 484 | # print('Searching patces for face complete '+str(i)+ ' '+str(time.time() - t)) 485 | for idx_f, f in enumerate(Geom.faces): 486 | if idx_f != f.index: 487 | print('Maybe prob', f.index) 488 | selectedPatches = [] 489 | for p in patches: 490 | if f.index in p: 491 | selectedPatches.append(p) 492 | patchFactors = [] 493 | for p in selectedPatches: 494 | patchFaces = [Geom.faces[i] for i in p] 495 | patchNormals = [pF.faceNormal for pF in patchFaces] 496 | normalsDiffWithinPatch = [np.linalg.norm(patchNormals[0] - p, 2) for p in patchNormals] 497 | maxDiff = max(normalsDiffWithinPatch) 498 | patchNormals = np.asarray(patchNormals) 499 | M = np.matmul(np.transpose(patchNormals), patchNormals) 500 | w, v = np.linalg.eig(M) 501 | eignorm = np.linalg.norm(np.diag(v)) 502 | patchFactor = eignorm * maxDiff 503 | patchFactors.append(patchFactor) 504 | minIndex = np.argmin(np.asarray(patchFactors)) 505 | p = selectedPatches[minIndex] 506 | patchFaces = [Geom.faces[i] for i in p] 507 | weightedNormalFactors = [pF.area * pF.faceNormal for pF in patchFaces] 508 | weightedNormalFactors = np.asarray(weightedNormalFactors) 509 | weightedNormal = np.mean(weightedNormalFactors, axis=0) 510 | weightedNormal = weightedNormal / np.linalg.norm(weightedNormal) 511 | Geom.faces[f.index] = Geom.faces[f.index]._replace(guidedNormal=weightedNormal) 512 | 513 | if computeDeltas: 514 | print("Compute deltas") 515 | for idx_v, v in enumerate(Geom.vertices): 516 | neibs=Geom.vertices[idx_v].neighbouringVerticesIndices 517 | vPos=np.asarray([Geom.vertices[i].position for i in neibs]) 518 | sSum=np.sum(vPos,axis=0)/len(neibs) 519 | computedDelta=Geom.vertices[idx_v].position-sSum 520 | Geom.vertices[idx_v]=Geom.vertices[idx_v]._replace(delta=computedDelta) 521 | 522 | 523 | # if computeAdjacency: 524 | # print("Compute adjacency matrix") 525 | # S = dok_matrix((len(Geom.vertices), len(Geom.vertices)), dtype=np.int) 526 | # for idx_f, f in enumerate(Geom.faces): 527 | # vInds = Geom.faces[idx_f].verticesIndices 528 | # S[vInds[0] ,vInds[1]] = 1 529 | # S[vInds[1] ,vInds[0]] = 1 530 | # S[vInds[1] ,vInds[2]] = 1 531 | # S[vInds[2] ,vInds[1]] = 1 532 | # S[vInds[0] ,vInds[2]] = 1 533 | # S[vInds[2] ,vInds[0]] = 1 534 | 535 | 536 | 537 | 538 | def computeAdjacencyMatrix(Geom): 539 | S = dok_matrix((len(Geom.vertices), len(Geom.vertices)), dtype=np.int) 540 | for idx_f, f in enumerate(Geom.faces): 541 | vInds = Geom.faces[idx_f].verticesIndices 542 | S[vInds[0], vInds[1]] = 1 543 | S[vInds[1], vInds[0]] = 1 544 | S[vInds[1], vInds[2]] = 1 545 | S[vInds[2], vInds[1]] = 1 546 | S[vInds[0], vInds[2]] = 1 547 | S[vInds[2], vInds[0]] = 1 548 | return S 549 | 550 | 551 | def create_identity_dok_matrix(n,m): 552 | S = dok_matrix((n, m), dtype=np.int) 553 | minDimension=min(n,m) 554 | for i in range(minDimension): 555 | S[i,i]=1 556 | return S 557 | 558 | 559 | 560 | 561 | 562 | 563 | def asCartesian(rthetaphi): 564 | # takes list rthetaphi (single coord) 565 | r = rthetaphi[0] 566 | theta = rthetaphi[1] * np.pi / 180 # to radian 567 | phi = rthetaphi[2] * np.pi / 180 568 | x = r * np.sin(theta) * np.cos(phi) 569 | y = r * np.sin(theta) * np.sin(phi) 570 | z = r * np.cos(theta) 571 | return [x, y, z] 572 | 573 | 574 | def asSpherical(xyz): 575 | # takes list xyz (single coord) 576 | x = xyz[0] 577 | y = xyz[1] 578 | z = xyz[2] 579 | r = np.sqrt(x * x + y * y + z * z) 580 | theta = np.arccos(z / r) * 180 / np.pi # to degrees 581 | phi = np.arctan2(y, x) * 180 / np.pi 582 | if phi < 0: 583 | phi = phi + 360 584 | if theta < 0: 585 | theta = theta + 360 586 | return [r, theta, phi] 587 | 588 | 589 | def mat2Sph(M): 590 | for i in range(0, np.size(M, axis=1)): 591 | xyz = M[:, i] 592 | r, theta, phi = asSpherical(xyz) 593 | M[0, i] = r 594 | M[1, i] = theta 595 | M[2, i] = phi 596 | return M 597 | 598 | 599 | def mat2Cartesian(M): 600 | for i in range(0, np.size(M, axis=1)): 601 | rthetaphi = M[:, i] 602 | x, y, z = asSpherical(rthetaphi) 603 | M[0, i] = x 604 | M[1, i] = y 605 | M[2, i] = z 606 | return M 607 | 608 | 609 | def rotate(a, axis, theta): 610 | if theta != 0: 611 | costheta = math.cos(theta) 612 | sintheta = math.sin(theta) 613 | a = a * costheta + np.cross(axis, a) * sintheta + axis * np.dot(axis, a) * (1 - costheta) 614 | return a 615 | 616 | def rotatePatch(patch,axis,theta): 617 | if theta != 0: 618 | # for fIndex in range(np.shape(patch)[0]): 619 | # patch[fIndex,]=rotate(patch[fIndex,], axis, theta) 620 | # patch = np.transpose(patch) 621 | I = np.eye(3) 622 | K = np.array([[0, -axis[2], axis[1]], [axis[2], 0, -axis[0]], [-axis[1], axis[0], 0]]) 623 | R = I + np.sin(theta) * K + (1 - np.cos(theta)) * np.matmul(K, K) 624 | for fIndex in range(np.shape(patch)[0]): 625 | patch[fIndex,] = np.matmul(R, np.transpose( 626 | patch[fIndex,])) 627 | patch = np.transpose(patch) 628 | return patch 629 | 630 | def computeRotation(vec, target): 631 | vec = vec / np.linalg.norm(vec) 632 | target = target / np.linalg.norm(target) 633 | theta = math.acos(np.dot(vec, target) / (np.linalg.norm(vec) * np.linalg.norm(target))) 634 | axis = np.cross(vec, target) 635 | if np.linalg.norm(axis) != 0: 636 | axis = axis / np.linalg.norm(axis) 637 | return axis, theta 638 | 639 | def computePointCloudNormals(Geom,nNeigb): 640 | print('Starting normals computation') 641 | V=np.asarray([v.position for v in Geom.vertices]) 642 | N=np.zeros(np.shape(V)) 643 | 644 | tree = KDTree(V) 645 | nearest_dist, nearest_ind = tree.query(V, k=nNeigb+1) 646 | nearest_ind=nearest_ind[:,1:] 647 | for i in range(V.shape[0]): 648 | if i % 2000 == 0: 649 | print('Normals computation : ' + str(np.round((100 * i / V.shape[0]), decimals=2)) + ' ' + '%') 650 | #Geom.vertices[i]=Geom.vertices[i]._replace(neighbouringVerticesIndices=nearest_ind) 651 | nearest_vertices=V[np.array(nearest_ind[i]),:] 652 | nearest_vertices=np.transpose(nearest_vertices) 653 | #d=nearest_vertices-np.matlib.repmat(V[i,:], len(nearest_ind[i]), 1) 654 | #meanD=np.matlib.repmat(np.mean(d,axis=0), d.shape[0], 1) 655 | #dm=d-meanD 656 | #Cov=np.matmul(np.transpose(dm),dm)/nNeigb 657 | Cov=np.cov(nearest_vertices) 658 | wi, vi = LA.eig(Cov) 659 | d=wi 660 | #d = np.diag(wi) 661 | index_min = np.argmin(d) 662 | val_min=d[index_min] 663 | N[i,:]=np.transpose(vi[:,index_min]) 664 | Geom.vertices[i].normal[0]= N[i,0] 665 | Geom.vertices[i].normal[1] = N[i,1] 666 | Geom.vertices[i].normal[2] = N[i,2] 667 | adjList=[0] 668 | for i in adjList: 669 | for nn in nearest_ind[i, :].tolist(): 670 | if nn not in adjList: 671 | N[nn] = np.sign(np.dot(N[i, :], N[nn, :])) * N[nn, :] 672 | adjList.append(nn) 673 | for i in range(N.shape[0]): 674 | Geom.vertices[i].normal[0]= N[i,0] 675 | Geom.vertices[i].normal[1] = N[i,1] 676 | Geom.vertices[i].normal[2] = N[i,2] 677 | print('ok') 678 | # for nIter in range(60): 679 | # Temp = np.zeros(np.shape(N)) 680 | # for i in range(N.shape[0]): 681 | # for nn in range(len(nearest_ind[i,:])): 682 | # #Temp[i,:] = Temp[i,:] + np.sign(np.dot(N[i,:],N[nn,:]))*N[nn,:] 683 | # #Temp[i, :] = np.sign(np.dot(N[i, :], N[nn, :])) * N[i, :] 684 | # #Temp[i, :] = Temp[i, :] + np.sign(np.dot(N[i,:],N[nearest_ind[i,nn],:]))*N[nearest_ind[i,nn], :] 685 | # Temp[i, :] = np.sign(np.dot(N[i, :], N[nearest_ind[i, nn], :])) * N[i, :] 686 | # for i in range(N.shape[0]): 687 | # Temp[i, :] = Temp[i, :]/np.linalg.norm(Temp[i, :]) 688 | # N[i, :] = Temp[i, :] 689 | return V,nearest_ind 690 | 691 | 692 | 693 | def computeThetas(mModel,rModel): 694 | thetas=np.zeros((len(mModel.faces),1)) 695 | for f_index,f in enumerate(mModel.faces): 696 | nr=rModel.faces[f_index].faceNormal 697 | nm=mModel.faces[f_index].faceNormal 698 | thetas[f_index]=180*(np.arccos(np.dot(nr,nm)/(np.linalg.norm(nr)*np.linalg.norm(nm)))/np.pi) 699 | return np.mean(thetas) 700 | 701 | def computeThetasV2(mModel,rModel): 702 | thetas=np.zeros((len(mModel.faces),1)) 703 | for f_index,f in enumerate(mModel.faces): 704 | nr=rModel.faces[f_index].faceNormal 705 | nm=mModel.faces[f_index].faceNormal 706 | thetas[f_index]=180*(np.arccos(np.dot(nr,nm)/(np.linalg.norm(nr)*np.linalg.norm(nm)))/np.pi) 707 | return thetas 708 | 709 | 710 | def computeNMSE(G,R,axis=0): 711 | NMSE=0 712 | if axis==0: 713 | NMSE = np.linalg.norm(G-R)/np.linalg.norm(G) 714 | #NMSE = np.linalg.norm(G - R) / np.linalg.norm(G - np.tile(np.mean(G, axis=0), (np.shape(G)[0], 1))) 715 | return NMSE 716 | 717 | 718 | 719 | def hsv2rgb(h, s, v): 720 | h = float(h) 721 | s = float(s) 722 | v = float(v) 723 | h60 = h / 60.0 724 | h60f = math.floor(h60) 725 | hi = int(h60f) % 6 726 | f = h60 - h60f 727 | p = v * (1 - s) 728 | q = v * (1 - f * s) 729 | t = v * (1 - (1 - f) * s) 730 | r, g, b = 0, 0, 0 731 | if hi == 0: 732 | r, g, b = v, t, p 733 | elif hi == 1: 734 | r, g, b = q, v, p 735 | elif hi == 2: 736 | r, g, b = p, v, t 737 | elif hi == 3: 738 | r, g, b = p, q, v 739 | elif hi == 4: 740 | r, g, b = t, p, v 741 | elif hi == 5: 742 | r, g, b = v, p, q 743 | r, g, b = int(r * 255), int(g * 255), int(b * 255) 744 | return r, g, b 745 | 746 | 747 | def rgb2hsv(r, g, b): 748 | r, g, b = r / 255.0, g / 255.0, b / 255.0 749 | mx = max(r, g, b) 750 | mn = min(r, g, b) 751 | df = mx - mn 752 | if mx == mn: 753 | h = 0 754 | elif mx == r: 755 | h = (60 * ((g - b) / df) + 360) % 360 756 | elif mx == g: 757 | h = (60 * ((b - r) / df) + 120) % 360 758 | elif mx == b: 759 | h = (60 * ((r - g) / df) + 240) % 360 760 | if mx == 0: 761 | s = 0 762 | else: 763 | s = df / mx 764 | v = mx 765 | return h, s, v 766 | 767 | 768 | 769 | 770 | 771 | 772 | def make_uniform_quantizer(max_val,min_val,nbits): 773 | print("Start") 774 | lvl_count = 2**nbits 775 | step = (max_val - min_val) / (lvl_count - 1) 776 | def q(val): 777 | return np.round((np.clip(val, a_min = min_val, a_max = max_val)-min_val)/step) 778 | def dq(val): 779 | return np.clip(min_val+(step*np.round(val)),a_min=min_val,a_max=max_val) 780 | return q,dq 781 | 782 | 783 | 784 | def quantizeArray(A,nbits=12,axis=1): 785 | mMax=np.max(A) 786 | mMin=np.min(A) 787 | q, dq = make_uniform_quantizer(mMax, mMin, nbits) 788 | for i in range(np.shape(A)[axis]): 789 | if axis==1: 790 | A[:,i]=dq(q(A[:,i])) 791 | if axis==0: 792 | A[i,:]=dq(q(A[i,:])) 793 | return A 794 | 795 | def computeGL(mModel,i): 796 | N = mModel.vertices[i].neighbouringVerticesIndices 797 | sumd = 0 798 | sumn = np.zeros(np.shape(mModel.vertices[i].position)) 799 | for j in N: 800 | sumd = sumd + (1 / np.linalg.norm(mModel.vertices[i].position - mModel.vertices[j].position)) 801 | sumn = sumn + ( 802 | mModel.vertices[j].position / np.linalg.norm(mModel.vertices[i].position - mModel.vertices[j].position)) 803 | GL=mModel.vertices[i].position-sumn/sumd 804 | return GL 805 | 806 | 807 | 808 | 809 | 810 | def updateVerticesWithNormals(Geom, N, nIter): 811 | for i in range(0, nIter): 812 | for idx_v, v in enumerate(Geom.vertices): 813 | updatedNormal = np.asarray([0.0, 0.0, 0.0]) 814 | for vf in Geom.vertices[idx_v].neighbouringFaceIndices: 815 | # Geom.faces[vf] 816 | n = N[vf, :] 817 | # print(n) 818 | updateFactor = np.dot(n, (Geom.vertices[Geom.faces[vf].verticesIndices[0]].position - Geom.vertices[ 819 | idx_v].position)) * n + \ 820 | np.dot(n, (Geom.vertices[Geom.faces[vf].verticesIndices[1]].position - Geom.vertices[ 821 | idx_v].position)) * n + \ 822 | np.dot(n, (Geom.vertices[Geom.faces[vf].verticesIndices[2]].position - Geom.vertices[ 823 | idx_v].position)) * n 824 | # print(updateFactor) 825 | updatedNormal = updateFactor + updatedNormal 826 | updatedNormal = updatedNormal / (3 * len(v.neighbouringFaceIndices)) 827 | Geom.vertices[idx_v] = Geom.vertices[idx_v]._replace(position=Geom.vertices[idx_v].position + updatedNormal) 828 | 829 | 830 | def BilateralNormalFiltering(Geom, faceNormals,sigma2,neighbours, nIter): 831 | 832 | sigma1 = np.zeros(len(Geom.faces)) 833 | if np.shape(faceNormals)[0] == len(Geom.faces): 834 | 835 | for idx_f, f in enumerate(Geom.faces): 836 | for fi in f.neighbouringFaceIndices: 837 | sigma1[idx_f] = sigma1[idx_f] + np.linalg.norm(f.centroid - Geom.faces[fi].centroid) 838 | sigma1[idx_f] = sigma1[idx_f] / len(f.neighbouringFaceIndices) 839 | 840 | for iteration in range(nIter): 841 | for idx_f, f in enumerate(Geom.faces): 842 | casumnb = np.zeros(3) 843 | canormalizer = 0 844 | currentFaceNormal=faceNormals[idx_f, :] 845 | p,r = neighboursByFace(Geom,idx_f,neighbours) 846 | p.pop(0) 847 | for fi in p: 848 | cat = np.linalg.norm(f.centroid - Geom.faces[fi].centroid) 849 | # cah = np.linalg.norm(f.faceNormal - Geom.faces[fi].faceNormal) 850 | cah = np.linalg.norm(faceNormals[idx_f, :] - faceNormals[fi, :]) 851 | cawc = np.exp(-(cat ** 2) / (2 * (sigma1[idx_f] ** 2))) 852 | caws = np.exp(-(cah ** 2) / (2 * (sigma2 ** 2))) 853 | caweight = cawc * caws * f.area 854 | casumnb = casumnb + caweight * faceNormals[fi, :] 855 | canormalizer = canormalizer + caweight 856 | faceNormals[idx_f, :] = casumnb / canormalizer 857 | 858 | #faceNormalsUpdated[idx_f, :] =fupdated 859 | #faceNormals=faceNormalsUpdated 860 | #print(np.linalg.norm(faceNormalsUpdated-faceNormals)) 861 | 862 | 863 | 864 | return faceNormals --------------------------------------------------------------------------------