├── README.md ├── code ├── matlab │ ├── ACAPOpt.mexw64 │ ├── AddPartFace2TotalFace.m │ ├── AddPriori.m │ ├── AdjustOutputEncode.m │ ├── CGAL-vc140-mt-4.11.dll │ ├── FeatureMap.m │ ├── GetBoundingBox4PointCloud.m │ ├── GetBoundingBox4PointCloudWithFaces.m │ ├── GetOptimizedObj.m │ ├── GetTransformedCube.m │ ├── Optimize.m │ ├── Pipeline.m │ ├── PrepareDataForVae.m │ ├── ReconstructFromCode4ReconInterRandom.m │ ├── ReconstructFromCodeMixIntegerReadingObjinAdvance.m │ ├── SaveObj.m │ ├── SaveObjT.mexw64 │ ├── SupportAnalysis.m │ ├── SupportAnalysisScript.m │ ├── axisangle2matrix.m │ ├── boundbox.m │ ├── cell2file.m │ ├── changebbxvert.m │ ├── cotlp.m │ ├── cotlpvf.m │ ├── create_regular_grid.m │ ├── cube.m │ ├── file2cellArray.m │ ├── generate_data.m │ ├── get_direction.m │ ├── get_vaefeatureforallpart.m │ ├── getlabel.m │ ├── isout.m │ ├── libgmp-10.dll │ ├── libmpfr-4.dll │ ├── mccExcludedFiles.log │ ├── meshlp.mexw64 │ ├── meshlpvf.mexw64 │ ├── mpfr-vc80-mt.dll │ ├── nonregistration │ │ ├── NonRigidAlignment3Dnew.m │ │ ├── TimedProgressBar.m │ │ ├── mkdirOptional.m │ │ ├── nonrigidregis.m │ │ ├── register_script.m │ │ └── search_nn_bidirector.m │ ├── normalizerow.m │ ├── optimize.exe │ ├── patchslim.m │ ├── point_mesh_squared_distance.mexw64 │ ├── readOBJ.m │ ├── readme.txt │ ├── readobjfromfile.mexw64 │ ├── regist.m │ ├── remove_duplicate_vertices.m │ ├── removeoutliner.m │ ├── requiredMCRProducts.txt │ ├── sort_nat.m │ └── writeOBJ.m └── python │ ├── chair_reproduce │ ├── config.py │ ├── icp.py │ ├── model_stacknewvae.py │ ├── render.py │ ├── test.py │ ├── test_stacknewvae.py │ ├── train_stacknewvae.py │ ├── train_symfeature.py │ └── utils.py │ └── plane_reproduce │ ├── config.py │ ├── icp.py │ ├── model_stacknewvae.py │ ├── render.py │ ├── test.py │ ├── test_stacknewvae.py │ ├── train_stacknewvae.py │ ├── train_symfeature.py │ └── utils.py ├── data_checkpoint_link.txt ├── install.sh ├── introduction.txt ├── liability form.pdf ├── mvdata.sh └── teaser.jpg /README.md: -------------------------------------------------------------------------------- 1 | # Deep Generative Network for Structured Deformable Mesh 2 | 3 | ![](./teaser.jpg) 4 | 5 | ## Goal 6 | 7 | Propose a deep generative network to explore shape collections, which can be used for interpolation, generation, and editing. 8 | 9 | ## Abstract 10 | 11 | We introduce SDM-NET, a deep generative neural network which produces structured deformable meshes. Specifically, the network is trained to generate a spatial arrangement of closed, deformable mesh parts, which respects the global part structure of a shape collection, e.g., chairs, airplanes, etc. Our key observation is that while the overall structure of a 3D shape can be complex, the shape can usually be decomposed into a set of parts, each homeomorphic to a box, and the finer-scale geometry of the part can be recovered by deforming the box. The architecture of SDM-NET is that of a two-level variational autoencoder (VAE). At the part level, a PartVAE learns a deformable model of part geometries. At the structural level, we train a Structured Parts VAE (SP-VAE), which jointly learns the part structure of a shape collection and the part geometries, ensuring the coherence between global shape structure and surface details. Through extensive experiments and comparisons with the state-of-the-art deep generative models of shapes, we demonstrate the superiority of SDM-NET in generating meshes with visual quality, flexible topology, and meaningful structures, benefiting shape interpolation and other subsequent modeling tasks. 12 | 13 | ## Description 14 | 15 | Given a collection of shapes of the same category with part-level labels, our method represents them using a structured set of deformable boxes, each corresponding to a part. We shape collections by allowing individual boxes to be flexibly deformable and propose a two-level VAE architecture called SDM-NET, including PartVAE for encoding the geometry of deformable boxes, and SP-VAE for joint encoding of part geometry and global structure such as symmetry and support. Moreover, to ensure that decoded shapes are physically plausible and stable, we introduce an optimization based on multiple constraints including support stability, which can be compactly formulated and efficiently optimized. Our SDM-NET model allows easy generation of plausible meshes with flexible structures and fine details. 16 | 17 | ## Prerequisites 18 | 19 | 1. System 20 | 21 | - **Ubuntu 16.04 or later** 22 | - **NVIDIA GPU + CUDA 9.0 cuDNN 7.6.1** 23 | 24 | 2. Software 25 | 26 | - Python 3.6 27 | 28 | ```shell 29 | sh install.sh 30 | ``` 31 | 32 | - MATLAB 33 | 34 | 35 | ## Data and Checkpoint 36 | 37 | All the [data](https://drive.google.com/file/d/1myWnHmuk2XD7lyHJL7KAgok89DT7SETF/view?usp=sharing) and [checkpoint](https://drive.google.com/file/d/1ItmG9tQ7vEE31anDU_z2yER2Wdon9_Ez/view?usp=sharing) used to reproduce the result is stored in google drive. Links are also available in `data_checkpoint_link.txt`. Save the two zip files in current directory. 38 | 39 | After downloading the data and checkpoint, the directory tree looks like this: 40 | 41 | ```txt 42 | ── SDMNET_stamp 43 |    ├── checkpoint 44 |    ├── code 45 |    ├── data 46 |    ├── data_checkpoint_link.txt 47 |    ├── install.sh 48 | ├── liability form.pdf 49 |    ├── introduction.txt 50 |    ├── mvdata.sh 51 |    ├── README.md 52 | └── teaser.jpg 53 | ``` 54 | 55 | Then execute: 56 | ```sh 57 | unzip data.zip 58 | cp ./data/chair* ./code/python/chair_reproduce 59 | cp ./data/plane* ./code/python/plane_reproduce 60 | 61 | unzip checkpoint.zip 62 | mv ./checkpoint/05060123_6863bin_1-joint_1-l0_100.0-l2_10.0-l3_1.0-l4_0.001-model_chair-trcet_1.0 ./code/python/chair_reproduce 63 | mv ./checkpoint/05050238_2556bin_0-joint_0-l0_100.0-l2_10.0-l3_1.0-l4_0.001-model_plane-trcet_1.0 ./code/python/plane_reproduce 64 | ``` 65 | 66 | ## Reproduce 67 | 68 | 1. Interpolation between shapes 69 | 70 | ```shell 71 | cd ./code/python/plane_reproduce 72 | CUDA_VISIBLE_DEVICES='' python ./test_stacknewvae.py --output_dir ./05050238_2556bin_0-joint_0-l0_100.0-l2_10.0-l3_1.0-l4_0.001-model_plane-trcet_1.0 --interids '1f5537f4747ec847622c69c3abc6f80' 'f16381a160f20bc4a3b534252984039' 'efbb9337b9bd3cab56ed1d365b05390d' 73 | 74 | cd ../chair_reproduce 75 | CUDA_VISIBLE_DEVICES='' python ./test_stacknewvae.py --output_dir ./05060123_6863bin_1-joint_1-l0_100.0-l2_10.0-l3_1.0-l4_0.001-model_chair-trcet_1.0 --interids '4e664dae1bafe49f19fb4103277a6b93' '1c17cc67b8c747c3febad4f49b26ec52' '2bbf00f0c583fd8a4b3c42e318f3affc' 76 | ``` 77 | 78 | After running the command, interpolated meshes are saved to a sub directory `interpolationxxxx` in the checkpoint directory specified by `--output_dir` argument, `./05050238_2556bin_0-joint_0-l0_100.0-l2_10.0-l3_1.0-l4_0.001-model_plane-trcet_1.0/interpolation80000`for example. 79 | 80 | 2. Postprocess 81 | 82 | Open `./code/matlab` in MATLAB. Execute following commands. 83 | 84 | ```matlab 85 | GetOptimizedObj('../python/chair_reproduce/05060123_6863bin_1-joint_1-l0_100.0-l2_10.0-l3_1.0-l4_0.001-model_chair-trcet_1.0/interpolation100000', 'chair', 2, 0, 0) 86 | ``` 87 | 88 | The output meshes are in `../python/chair_reproduce/05060123_6863bin_1-joint_1-l0_100.0-l2_10.0-l3_1.0-l4_0.001-model_chair-trcet_1.0/interpolation100000`. 89 | 90 | Open those meshes in meshlab and you will see the reproduced results for **Fig.1** in the original paper. (**NOTE**: Some parts' faces might have wrong normals, use **double face** mode for beter visualization) 91 | 92 | ## Citation 93 | If you found this code useful please cite our work as: 94 | 95 |     @article{gaosdmnet2019, 96 |         author = {Gao, Lin and Yang, Jie and Wu, Tong and Yuan, Yu-Jie and Fu, Hongbo and Lai, Yu-Kun and Zhang, Hao(Richard)}, 97 |         title = {{SDM-NET}: Deep Generative Network for Structured Deformable Mesh}, 98 |         journal = {ACM Transactions on Graphics (Proceedings of ACM SIGGRAPH Asia 2019)}, 99 |         year = {2019}, 100 |         volume = 38, 101 |         pages = {243:1--243:15}, 102 |         number = 6 103 |     } 104 | -------------------------------------------------------------------------------- /code/matlab/ACAPOpt.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gaolinorange/SDMNET_stamp/5208f1210b77e3251dde3bdafc120a48dc69e833/code/matlab/ACAPOpt.mexw64 -------------------------------------------------------------------------------- /code/matlab/AddPartFace2TotalFace.m: -------------------------------------------------------------------------------- 1 | function new_total_f = AddPartFace2TotalFace(total_f, part_f) 2 | max_point = max(total_f(:)); 3 | if isempty(max_point) 4 | new_total_f = [total_f; part_f]; 5 | else 6 | part_f = part_f + max_point; 7 | new_total_f = [total_f; part_f]; 8 | end 9 | end -------------------------------------------------------------------------------- /code/matlab/AddPriori.m: -------------------------------------------------------------------------------- 1 | function [code] = AddPriori(code, type, part_names) 2 | part_num = size(part_names, 2); 3 | if strcmp(type, 'chair') == 1 4 | code(8, 1+3) = 1; 5 | code(3, 1+8+part_num) = 1; 6 | for i = 4:7 7 | code(i, 1+8) = 1; 8 | code(8, 1+i+part_num) = 1; 9 | end 10 | symmetry = [ 11 | 1, 1, 0, 0, 0; 12 | 1, 1, 0, 0, 0; 13 | 0, 0, 0, 0, 0; 14 | 1, 1, 0, 0, 0; 15 | 1, 1, 0, 0, 0; 16 | 1, 1, 0, 0, 0; 17 | 1, 1, 0, 0, 0; 18 | 0, 0, 0, 0, 0; 19 | 1, 1, 0, 0, 0; 20 | 1, 1, 0, 0, 0; 21 | ]; 22 | code(:, 2*part_num+5:2*part_num+9) = symmetry; 23 | elseif strcmp(type, 'knife') == 1 24 | code(2, 1+1) = 1; 25 | code(1, 1+2+part_num) = 1; 26 | symmetry = [ 27 | 0, 0, 0, 0, 0; 28 | 0, 0, 0, 0, 0; 29 | ]; 30 | code(:, 2*part_num+5:2*part_num+9) = symmetry; 31 | elseif strcmp(type, 'guitar') == 1 32 | supporting = [ 33 | 0, 0, 0; 34 | 1, 0, 0; 35 | 0, 1, 0 36 | ]; 37 | code(:, 2:1+part_num) = supporting; 38 | code(:, 2+part_num:1+2*part_num) = supporting'; 39 | symmetry = [ 40 | 0, 0, 0, 0, 0; 41 | 0, 0, 0, 0, 0; 42 | 0, 0, 0, 0, 0; 43 | ]; 44 | code(:, 2*part_num+5:2*part_num+9) = symmetry; 45 | elseif strcmp(type, 'skateboard') == 1 46 | supporting = [ 47 | 0, 0, 0, 0, 0, 0, 0; 48 | 1, 0, 0, 1, 1, 1, 1; 49 | 1, 0, 0, 1, 1, 1, 1; 50 | 1, 0, 0, 0, 0, 0, 0; 51 | 1, 0, 0, 0, 0, 0, 0; 52 | 1, 0, 0, 0, 0, 0, 0; 53 | 1, 0, 0, 0, 0, 0, 0; 54 | ]; 55 | code(:, 2:1+part_num) = supporting; 56 | code(:, 2+part_num:1+2*part_num) = supporting'; 57 | symmetry = [ 58 | 0, 0, 0, 0, 0; 59 | 0, 0, 0, 0, 0; 60 | 0, 0, 0, 0, 0; 61 | 1, 1, 0, 0, 0; 62 | 1, 1, 0, 0, 0; 63 | 1, 1, 0, 0, 0; 64 | 1, 1, 0, 0, 0; 65 | ]; 66 | code(:, 2*part_num+5:2*part_num+9) = symmetry; 67 | elseif strcmp(type, 'cup') == 1 68 | supporting = [ 69 | 0, 0; 70 | 1, 0; 71 | ]; 72 | code(:, 2:1+part_num) = supporting; 73 | code(:, 2+part_num:1+2*part_num) = supporting'; 74 | symmetry = [ 75 | 0, 0, 0, 0, 0; 76 | 0, 0, 0, 0, 0; 77 | ]; 78 | code(:, 2*part_num+5:2*part_num+9) = symmetry; 79 | elseif strcmp(type, 'car') == 1 80 | supporting = [ 81 | 0, 0, 0, 0, 0, 1, 1; 82 | 1, 0, 0, 0, 0, 0, 0; 83 | 1, 0, 0, 0, 0, 0, 0; 84 | 1, 0, 0, 0, 0, 0, 0; 85 | 1, 0, 0, 0, 0, 0, 0; 86 | 0, 0, 0, 0, 0, 0, 0; 87 | 0, 0, 0, 0, 0, 0, 0; 88 | ]; 89 | code(:, 2:1+part_num) = supporting; 90 | code(:, 2+part_num:1+2*part_num) = supporting'; 91 | symmetry = [ 92 | 0, 0, 0, 0, 0; 93 | 1, 1, 0, 0, 0; 94 | 1, 1, 0, 0, 0; 95 | 1, 1, 0, 0, 0; 96 | 1, 1, 0, 0, 0; 97 | 1, 1, 0, 0, 0; 98 | 1, 1, 0, 0, 0; 99 | ]; 100 | code(:, 2*part_num+5:2*part_num+9) = symmetry; 101 | elseif strcmp(type, 'plane') == 1 102 | supporting = [ 103 | 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0; 104 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0; 105 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1; 106 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 107 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 108 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 109 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 110 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 111 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 112 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 113 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 114 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 115 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 116 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0; 117 | ]; 118 | code(:, 2:1+part_num) = supporting; 119 | code(:, 2+part_num:1+2*part_num) = supporting'; 120 | symmetry = [ 121 | 0, 0, 0, 0, 0; 122 | 1, 1, 0, 0, 0; 123 | 1, 1, 0, 0, 0; 124 | 1, 1, 0, 0, 0; 125 | 1, 1, 0, 0, 0; 126 | 0, 0, 0, 0, 0; 127 | 0, 0, 0, 0, 0; 128 | 0, 0, 0, 0, 0; 129 | 1, 1, 0, 0, 0; 130 | 1, 1, 0, 0, 0; 131 | 1, 1, 0, 0, 0; 132 | 1, 1, 0, 0, 0; 133 | 1, 1, 0, 0, 0; 134 | 1, 1, 0, 0, 0; 135 | ]; 136 | code(:, 2*part_num+5:2*part_num+9) = symmetry; 137 | elseif strcmp(type, 'table') == 1 138 | supporting = [ 139 | 0, 0, 0, 0, 0, 0, 0, 0; 140 | 1, 0, 0, 0, 0, 0, 0, 0; 141 | 1, 0, 0, 0, 0, 0, 0, 0; 142 | 1, 0, 0, 0, 0, 0, 0, 0; 143 | 1, 0, 0, 0, 0, 0, 0, 0; 144 | 1, 0, 0, 0, 0, 0, 0, 0; 145 | 1, 0, 0, 0, 0, 0, 0, 0; 146 | 1, 0, 0, 0, 0, 0, 0, 0; 147 | 1, 0, 0, 0, 0, 0, 0, 0; 148 | ]; 149 | code(:, 2:1+part_num) = supporting; 150 | code(:, 2+part_num:1+2*part_num) = supporting'; 151 | symmetry = [ 152 | 0, 0, 0, 0, 0; 153 | 1, 1, 0, 0, 0; 154 | 1, 1, 0, 0, 0; 155 | 1, 1, 0, 0, 0; 156 | 1, 1, 0, 0, 0; 157 | 1, 1, 0, 0, 0; 158 | 1, 1, 0, 0, 0; 159 | 1, 1, 0, 0, 0; 160 | 1, 1, 0, 0, 0; 161 | ]; 162 | code(:, 2*part_num+5:2*part_num+9) = symmetry; 163 | end 164 | end -------------------------------------------------------------------------------- /code/matlab/AdjustOutputEncode.m: -------------------------------------------------------------------------------- 1 | function [new_encode] = AdjustOutputEncode(encode) 2 | new_encode = zeros(size(encode)); 3 | n = size(encode, 1); 4 | for i = 1:n 5 | for j = 1:2*n+1 6 | if encode(i, j) < 0.5 7 | new_encode(i, j) = 0; 8 | else 9 | new_encode(i, j) = 1; 10 | end 11 | end 12 | for j = 2*n+2:2*n+4 13 | new_encode(i, j) = encode(i, j); 14 | end 15 | for j = 2*n+5:2*n+9 16 | if encode(i, j) < 0.5 17 | new_encode(i, j) = 0; 18 | else 19 | new_encode(i, j) = 1; 20 | end 21 | end 22 | end 23 | end -------------------------------------------------------------------------------- /code/matlab/CGAL-vc140-mt-4.11.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gaolinorange/SDMNET_stamp/5208f1210b77e3251dde3bdafc120a48dc69e833/code/matlab/CGAL-vc140-mt-4.11.dll -------------------------------------------------------------------------------- /code/matlab/FeatureMap.m: -------------------------------------------------------------------------------- 1 | function [ fmlogdr, fms ] = FeatureMap( LOGDR, S ) 2 | 3 | %LOGDR = LOGDR'; 4 | [mlogdr, nlogdr] = size(LOGDR); 5 | [ms, ns] = size(S); 6 | edgenum = nlogdr/9; 7 | snum = ns/9; 8 | %create 9 | fmlogdr = zeros(mlogdr, edgenum*3); 10 | fms = zeros(ms, snum*6); 11 | 12 | for i = 1 : mlogdr 13 | for j = 0 : edgenum-1 14 | fmlogdr(i, j*3+1) = LOGDR(i, j*9+2); 15 | fmlogdr(i, j*3+2) = LOGDR(i, j*9+3); 16 | fmlogdr(i, j*3+3) = LOGDR(i, j*9+6); 17 | end 18 | end 19 | 20 | 21 | for i = 1 : ms 22 | for j = 0 : snum-1 23 | fms(i, j*6+1) = S(i, j*9+1); 24 | fms(i, j*6+2) = S(i, j*9+2); 25 | fms(i, j*6+3) = S(i, j*9+3); 26 | fms(i, j*6+4) = S(i, j*9+5); 27 | fms(i, j*6+5) = S(i, j*9+6); 28 | fms(i, j*6+6) = S(i, j*9+9); 29 | end 30 | end 31 | 32 | end 33 | 34 | -------------------------------------------------------------------------------- /code/matlab/GetBoundingBox4PointCloud.m: -------------------------------------------------------------------------------- 1 | function [local_bbox,local_bbox_face] = GetBoundingBox4PointCloud(pc) 2 | if size(pc, 1) == 0 3 | local_bbox = []; 4 | return; 5 | end 6 | % get bounding box 7 | max_point = max(pc, [], 1); 8 | maxx = max_point(1)+0.001; 9 | maxy = max_point(2)+0.001; 10 | maxz = max_point(3)+0.001; 11 | 12 | min_point = min(pc, [], 1); 13 | minx = min_point(1)-0.001; 14 | miny = min_point(2)-0.001; 15 | minz = min_point(3)-0.001; 16 | 17 | x_diff = maxx - minx; 18 | y_diff = maxy - miny; 19 | z_diff = maxz - minz; 20 | local_bbox(1, :) = [minx, miny, minz]; 21 | local_bbox(2, :) = [minx+x_diff, miny, minz]; 22 | local_bbox(3, :) = [minx+x_diff, miny, minz+z_diff]; 23 | local_bbox(4, :) = [minx, miny, minz+z_diff]; 24 | local_bbox(5, :) = [minx, miny+y_diff, minz]; 25 | local_bbox(6, :) = [minx+x_diff, miny+y_diff, minz]; 26 | local_bbox(7, :) = [minx+x_diff, miny+y_diff, minz+z_diff]; 27 | local_bbox(8, :) = [minx, miny+y_diff, minz+z_diff]; 28 | local_bbox_face=[1 6 2;5 6 1;7 3 2 ;7 2 6 ;4 3 7; 8 4 7;1 4 8;1 8 5;5 7 6;5 8 7 ;1 3 4; 1 2 3]; 29 | end -------------------------------------------------------------------------------- /code/matlab/GetBoundingBox4PointCloudWithFaces.m: -------------------------------------------------------------------------------- 1 | function [v, f] = GetBoundingBox4PointCloudWithFaces(pc) 2 | if size(pc, 1) == 0 3 | v = []; 4 | f = []; 5 | return; 6 | end 7 | % get bounding box 8 | max_point = max(pc, [], 1); 9 | maxx = max_point(1); 10 | maxy = max_point(2); 11 | maxz = max_point(3); 12 | 13 | min_point = min(pc, [], 1); 14 | minx = min_point(1); 15 | miny = min_point(2); 16 | minz = min_point(3); 17 | 18 | x_diff = maxx - minx; 19 | y_diff = maxy - miny; 20 | z_diff = maxz - minz; 21 | v(1, :) = [minx, miny, minz]; 22 | v(2, :) = [minx+x_diff, miny, minz]; 23 | v(3, :) = [minx+x_diff, miny, minz+z_diff]; 24 | v(4, :) = [minx, miny, minz+z_diff]; 25 | v(5, :) = [minx, miny+y_diff, minz]; 26 | v(6, :) = [minx+x_diff, miny+y_diff, minz]; 27 | v(7, :) = [minx+x_diff, miny+y_diff, minz+z_diff]; 28 | v(8, :) = [minx, miny+y_diff, minz+z_diff]; 29 | 30 | f = [1,2,3,4;5,6,7,8;1,2,6,5;3,4,8,7;1,4,8,5;2,3,7,6]; 31 | end -------------------------------------------------------------------------------- /code/matlab/GetOptimizedObj.m: -------------------------------------------------------------------------------- 1 | % recon_inter_random_dir: contain all parts dir 2 | % type: plane, knife and so on 3 | % recon_inter_random: 1 represent recon, 2 represent inter, 3 represent random 4 | % use_struct: struc_part or part 5 | function GetOptimizedObj(recon_inter_random_dir, type, recon_inter_random, use_struct, use_origin) 6 | part_names = getlabel(type); 7 | 8 | mat_prefix = ''; 9 | if 1 == recon_inter_random 10 | mat_prefix = 'recover'; 11 | elseif 2 == recon_inter_random 12 | mat_prefix = 'inter'; 13 | elseif 3 == recon_inter_random 14 | mat_prefix = 'random'; 15 | else 16 | return; 17 | end 18 | 19 | n = size(part_names, 2); 20 | if 0 == use_origin && 0 == use_struct 21 | merge_dir = fullfile(recon_inter_random_dir, 'merge'); 22 | elseif 0 == use_origin && 1 == use_struct 23 | merge_dir = fullfile(recon_inter_random_dir, 'merge_struct'); 24 | elseif 1 == use_origin && 1 == use_struct 25 | merge_dir = fullfile(recon_inter_random_dir, 'merge_struct_origin'); 26 | elseif 1 == use_origin && 0 == use_struct 27 | merge_dir = fullfile(recon_inter_random_dir, 'merge_origin'); 28 | end 29 | 30 | if ~exist(merge_dir, 'dir') 31 | mkdir(merge_dir); 32 | end 33 | 34 | if 0 == use_struct 35 | part_dirs = fullfile(recon_inter_random_dir, part_names); 36 | else 37 | part_dirs = fullfile(recon_inter_random_dir, cellfun(@(x) ['struc_',x] ,part_names, 'UniformOutput',false)); 38 | end 39 | 40 | if 0 == use_origin 41 | mat = load(fullfile(recon_inter_random_dir, [mat_prefix, '_sym.mat'])); 42 | else 43 | % for debug 44 | mat = load(fullfile(recon_inter_random_dir, '..', '..', [type, '_vaefeature.mat'])); 45 | end 46 | 47 | max_num = 0; 48 | max_dir_files = {}; 49 | for i = 1:n 50 | sub_dir = fullfile(recon_inter_random_dir, part_names{i}); 51 | sub_dir_files = dir(fullfile(sub_dir, ['*_', part_names{i}, '.obj'])); 52 | sub_num = size(sub_dir_files, 1); 53 | if sub_num > max_num 54 | max_num = sub_num; 55 | max_dir_files = sub_dir_files; 56 | end 57 | end 58 | max_dir_names = {max_dir_files.name}; 59 | [max_dir_names, ~] = sort_nat(max_dir_names); 60 | 61 | if 1 == use_origin 62 | max_dir_names = mat.modelname; 63 | else 64 | 65 | end 66 | 67 | 68 | for i = 1:length(max_dir_names) 69 | if i <= 2 70 | continue; 71 | end 72 | id = max_dir_names{i}; 73 | splitparts = strsplit(id, '_'); 74 | id = splitparts{1}(1:end); 75 | disp(id); 76 | if 0 == use_origin 77 | code = reshape(mat.symmetry_feature(i, :), n, 2*n+9); 78 | else 79 | code = squeeze(mat.symmetryf(i, :, :)); 80 | end 81 | code = AdjustOutputEncode(code); 82 | 83 | part_pcs = cell(n, 1); 84 | part_faces = cell(n, 1); 85 | for j = 1:n 86 | obj_filename = fullfile(part_dirs{j}, [id, '_', part_names{j}, '.obj']); 87 | if exist(obj_filename, 'file') 88 | if ispc 89 | [part_pc, part_face] = cotlp(obj_filename); 90 | else 91 | [part_pc, part_face] = readObj(obj_filename); 92 | part_face = part_face'; 93 | end 94 | part_pcs{j} = part_pc; 95 | part_faces{j} = part_face'; 96 | end 97 | end 98 | tic; 99 | [total_pc, total_face, total_optimized_pc, total_optimized_face] = ReconstructFromCodeMixIntegerReadingObjinAdvance(code, part_pcs, part_faces, type); 100 | toc; 101 | if ispc 102 | SaveObjT(fullfile(merge_dir, ['optimized_', id, '.obj']), total_optimized_pc', total_optimized_face'); 103 | SaveObjT(fullfile(merge_dir, ['unoptimized_', id, '.obj']), total_pc', total_face'); 104 | else 105 | SaveObj(fullfile(merge_dir, ['optimized_', id, '.obj']), total_optimized_pc', total_optimized_face'); 106 | SaveObj(fullfile(merge_dir, ['unoptimized_', id, '.obj']), total_pc', total_face'); 107 | end 108 | end 109 | end -------------------------------------------------------------------------------- /code/matlab/GetTransformedCube.m: -------------------------------------------------------------------------------- 1 | function GetTransformedCube(pts_labels_dir, dir_postfix, type) 2 | % if use_postfix == 0 3 | % dir_postfix = 2000; 4 | % pts_dir = fullfile(pts_labels_dir, 'points'); 5 | % else 6 | % pts_dir = fullfile(pts_labels_dir, ['points', num2str(dir_postfix)]); 7 | % end 8 | pts_dir = pts_labels_dir; 9 | model_normalizedobj='model_normalized.obj'; 10 | pts_list = dir([pts_dir, '\*']); 11 | pts_list(1:2)=[]; 12 | 13 | divide_with_face_dir = fullfile(pts_labels_dir, ['../box', num2str(dir_postfix)]); 14 | if ~exist(divide_with_face_dir, 'dir') 15 | mkdir(divide_with_face_dir); 16 | end 17 | part_names = getlabel(type); 18 | 19 | origin_cube_dir = ['cube_', type]; 20 | cube_vs = {}; 21 | cube_fs = {}; 22 | for i = 1:size(part_names, 2) 23 | cubename=fullfile(origin_cube_dir, ['cube_', part_names{i}, '.obj']); 24 | if ~exist(cubename,'file') 25 | cubename=fullfile(origin_cube_dir, ['cube_std.obj']); 26 | end 27 | [v, f] = readobjfromfile(cubename); 28 | cube_vs = [cube_vs, v]; 29 | cube_fs = [cube_fs, f+1]; 30 | end 31 | 32 | specified_id = ''; 33 | for i=1:size(pts_list, 1) 34 | disp(i); 35 | splitparts = strsplit(pts_list(i).name, '.'); 36 | pts_numstr = splitparts{1}; 37 | disp(pts_numstr); 38 | mesh_filename = fullfile(pts_labels_dir, pts_numstr,'models',model_normalizedobj); 39 | 40 | if strcmp(specified_id,'')==0&&0 == strcmp(pts_numstr, specified_id) 41 | continue; 42 | end 43 | [vertex, ~] = readobjfromfile(mesh_filename); 44 | if size(vertex,1)>400000 45 | continue 46 | end 47 | 48 | % used to store divide point cloud 49 | sub_divide_without_face_dir = fullfile(pts_labels_dir, pts_numstr,'models'); 50 | if ~exist(sub_divide_without_face_dir, 'dir') 51 | continue; 52 | end 53 | 54 | sub_divide_with_face_dir = fullfile(divide_with_face_dir, pts_numstr); 55 | if ~exist(sub_divide_with_face_dir, 'dir') 56 | mkdir(sub_divide_with_face_dir); 57 | end 58 | 59 | copyfile(mesh_filename, fullfile(sub_divide_with_face_dir, model_normalizedobj)) 60 | for j = 1:size(part_names, 2) 61 | if exist(fullfile(divide_with_face_dir, ['transformed_cube_', part_names{j}, '.obj']), 'file') 62 | continue; 63 | end 64 | if ~exist(fullfile(sub_divide_without_face_dir, [part_names{j}, '.obj']), 'file') 65 | continue; 66 | end 67 | try 68 | [part_points,~] = readobjfromfile(fullfile(sub_divide_without_face_dir, [part_names{j}, '.obj'])); 69 | catch 70 | continue; 71 | end 72 | % part_points=removeoutliner(part_points); 73 | % if size(part_points, 1) == 0 74 | % continue; 75 | % end 76 | 77 | transformed_box = zeros(8, 3); 78 | try 79 | [~,cornerpoints,h,~,~] = boundbox(part_points(:,1),part_points(:,2),part_points(:,3),'v',1); 80 | transformed_box=changebbxvert(cornerpoints); 81 | catch 82 | max_point = max(part_points, [], 1); 83 | maxx = max_point(1); 84 | maxy = max_point(2); 85 | maxz = max_point(3); 86 | 87 | min_point = min(part_points, [], 1); 88 | minx = min_point(1); 89 | miny = min_point(2); 90 | minz = min_point(3); 91 | 92 | x_diff = maxx - minx; 93 | y_diff = maxy - miny; 94 | z_diff = maxz - minz; 95 | transformed_box(1, :) = [minx, miny, minz]; 96 | transformed_box(2, :) = [minx+x_diff, miny, minz]; 97 | transformed_box(3, :) = [minx+x_diff, miny, minz+z_diff]; 98 | transformed_box(4, :) = [minx, miny, minz+z_diff]; 99 | 100 | transformed_box(5, :) = [minx, miny+y_diff, minz]; 101 | transformed_box(6, :) = [minx+x_diff, miny+y_diff, minz]; 102 | transformed_box(7, :) = [minx+x_diff, miny+y_diff, minz+z_diff]; 103 | transformed_box(8, :) = [minx, miny+y_diff, minz+z_diff]; 104 | end 105 | 106 | transformed_box(:, 4) = 1; 107 | 108 | origin_box = zeros(8, 3); 109 | origin_box(1, :) = [-0.5, -0.5, -0.5]+[0.5, 0.5, 0.5]; 110 | origin_box(2, :) = [0.5, -0.5, -0.5]+[0.5, 0.5, 0.5]; 111 | origin_box(3, :) = [0.5, -0.5, 0.5]+[0.5, 0.5, 0.5]; 112 | origin_box(4, :) = [-0.5, -0.5, 0.5]+[0.5, 0.5, 0.5]; 113 | 114 | origin_box(5, :) = [-0.5, 0.5, -0.5]+[0.5, 0.5, 0.5]; 115 | origin_box(6, :) = [0.5, 0.5, -0.5]+[0.5, 0.5, 0.5]; 116 | origin_box(7, :) = [0.5, 0.5, 0.5]+[0.5, 0.5, 0.5]; 117 | origin_box(8, :) = [-0.5, 0.5, 0.5]+[0.5, 0.5, 0.5]; 118 | origin_box(:, 4) = 1; 119 | 120 | % transpose to 4 * N 121 | transformed_box = transformed_box'; 122 | origin_box = origin_box'; 123 | transform_matrix = transformed_box/origin_box; 124 | disp(transform_matrix); 125 | 126 | % save objs 127 | local_cubeid_v = cube_vs{j}; 128 | local_cubeid_f = cube_fs{j}; 129 | tempV = local_cubeid_v; 130 | tempV(:, 4) = 1; 131 | transformed_v = transform_matrix*tempV'; 132 | 133 | SaveObjT(fullfile(sub_divide_with_face_dir, ['transformed_cube_', part_names{j}, '.obj']), transformed_v(1:3, :), local_cubeid_f'); 134 | copyfile(fullfile(sub_divide_without_face_dir, [part_names{j}, '.obj']), fullfile(sub_divide_with_face_dir, [part_names{j}, '.obj'])) 135 | end 136 | end 137 | end -------------------------------------------------------------------------------- /code/matlab/Optimize.m: -------------------------------------------------------------------------------- 1 | % path = './test'; 2 | function Optimize(interpolation_dir, category, gap) 3 | if strcmp(category, 'plane') 4 | load('./libtomlab.dll', '-mat'); 5 | elseif strcmp(category, 'chair') 6 | load('./libopenmp.dll', '-mat'); 7 | end 8 | part_names = gelabel(category); 9 | for i = 1:size(part_names) 10 | part_dir = fullfile(interpolation_dir, part_names{i}); 11 | if ~exist(part_dir, 'dir') 12 | disp('part_dir missing'); 13 | disp(part_dir); 14 | end 15 | end 16 | category = 'test'; 17 | if ~exist(category, 'dir') 18 | mkdir(category); 19 | end 20 | for i = 1:gap:200 21 | writeOBJ(fullfile(category, [num2str(i), '.obj']), all_vfs{i, 1}, all_vfs{i, 2}); 22 | end 23 | end -------------------------------------------------------------------------------- /code/matlab/Pipeline.m: -------------------------------------------------------------------------------- 1 | % preprocess total pipeline: divide, get transformed cube, get sub mesh, resigter, get structure code, post regist 2 | 3 | % Car 4 | 5 | addpath('./nonregistration') 6 | cate='car'; 7 | postfix=50; 8 | partname={}; 9 | 10 | categarydir = './DATA/Car/Car'; 11 | box_dir =[categarydir,'\..\box',num2str(postfix)]; 12 | vaedir=[categarydir,'\..\vaenew',num2str(postfix)]; 13 | 14 | GetTransformedCube(categarydir, postfix, cate); 15 | regist(box_dir, cate) 16 | SupportAnalysisScript(box_dir, cate); 17 | generate_data(box_dir,vaedir,cate,partname,''); 18 | 19 | % next steps: 20 | % 1. train sdm-net 21 | % 2. obtain the merged obj by "GetOptimizedObj.m" 22 | % for the post-processing in our paper, we have some demos in "DEMO.m" 23 | -------------------------------------------------------------------------------- /code/matlab/PrepareDataForVae.m: -------------------------------------------------------------------------------- 1 | function PrepareDataForVae(source_dir, target_dir,cate) 2 | d = dir(source_dir); 3 | if isempty(dir(['.\cube_',cate])) 4 | error('error') 5 | end 6 | % returns logical vector 7 | isub = [d(:).isdir]; 8 | sub_folds = {d(isub).name}'; 9 | sub_folds(ismember(sub_folds,{'.','..'})) = []; 10 | model_normalizedobj='model_normalized.obj'; 11 | 12 | for i = 1:size(sub_folds, 1) 13 | disp(i); 14 | disp(sub_folds{i}); 15 | [v]=dir(fullfile(source_dir,sub_folds{i},model_normalizedobj)); 16 | if ~exist(fullfile(source_dir,sub_folds{i},model_normalizedobj),'file') 17 | % rmdir(fullfile(source_dir,sub_folds{i}),'s') 18 | continue 19 | end 20 | if v.bytes>15000000 21 | continue 22 | end 23 | register_dir = fullfile(source_dir, sub_folds{i}); 24 | part_list = getlabel(cate); 25 | % if length(part_list)<2 26 | % a=1; 27 | % end 28 | for j = 1:length(part_list) 29 | % disp(part_list(j)); 30 | partname = part_list{j}; 31 | if exist( fullfile(register_dir, [partname, '_reg.obj']), 'file') 32 | if ~exist(fullfile(target_dir, partname),'file') 33 | mkdir(fullfile(target_dir, partname)); 34 | end 35 | copyfile(fullfile(register_dir, [partname, '_reg.obj']), fullfile(target_dir, partname, [sub_folds{i}, '_', partname, '.obj'])); 36 | % copyfile(fullfile(register_dir, [partname, '_reg.obj']), fullfile(target_dir, partname, [num2str(i+1), '.obj'])); 37 | if ~exist(fullfile(target_dir, partname, ['0_',partname,'.obj']),'file') 38 | if ~exist(['.\cube_',cate,'\cube_', partname,'_new.obj'],'file') 39 | assert(exist(['.\cube_',cate,'\cube_std.obj'],'file')>0) 40 | copyfile(['.\cube_',cate,'\cube_std.obj'], fullfile(target_dir, partname, ['0_',partname,'.obj'])); 41 | else 42 | assert(exist(['.\cube_',cate,'\cube_', partname,'_new.obj'],'file')>0) 43 | copyfile(['.\cube_',cate,'\cube_', partname,'_new.obj'], fullfile(target_dir, partname, ['0_',partname,'.obj'])); 44 | end 45 | if ~exist(fullfile(target_dir, [cate,'.obj']),'file') 46 | copyfile( fullfile(target_dir, partname, ['0_',partname,'.obj']), fullfile(target_dir, [cate,'.obj'])) 47 | end 48 | end 49 | end 50 | end 51 | end 52 | end -------------------------------------------------------------------------------- /code/matlab/ReconstructFromCode4ReconInterRandom.m: -------------------------------------------------------------------------------- 1 | %% ReconstructFromCode: reconstruct from code using quadratic optimization 2 | function [total_pc, total_face, total_optimized_pc, total_optimized_face] = ReconstructFromCode4ReconInterRandom(code, part_pcs, part_faces, type, structure) 3 | if strcmp(type, 'chair') == 1 4 | part_names = {'armrest_1', 'armrest_2', 'back', 'leg1_1', 'leg1_2', 'leg2_1', 'leg2_2', 'seat'}; 5 | elseif strcmp(type, 'knife') == 1 6 | part_names = {'part1', 'part2'}; 7 | elseif strcmp(type, 'guitar') == 1 8 | part_names = {'part1', 'part2', 'part3'}; 9 | elseif strcmp(type, 'skateboard') 10 | part_names = {'surface', 'bearing1', 'bearing2', 'wheel1_1', 'wheel1_2', 'wheel2_1', 'wheel2_2'}; 11 | elseif strcmp(type, 'cup') == 1 12 | part_names = {'part1', 'part2'}; 13 | elseif strcmp(type, 'car') == 1 14 | part_names = {'body', 'left_front_wheel', 'right_front_wheel', 'left_behind_wheel', 'right_behind_wheel'}; 15 | elseif strcmp(type, 'plane') == 1 16 | part_names = {'body', 'left_wing', 'right_wing', 'left_tail', 'right_tail', 'upper_tail', 'down_tail', 'front_landing_gear', 'left_landing_gear', 'right_landing_gear', 'left_engine_1', 'right_engine_1', 'left_engine_2', 'right_engine_2'}; 17 | elseif strcmp(type, 'table') == 1 18 | part_names = {'surface', 'leg1_1', 'leg1_2', 'leg2_1', 'leg2_2', 'leg3_1', 'leg3_2', 'leg4_1', 'leg4_2'}; 19 | end 20 | 21 | % load(fullfile(dir, 'code.mat')); 22 | % is_valid = check_valid(type, num); 23 | n = size(code, 1); 24 | supporting = code(:, 2:1+n); 25 | supported = code(:, 2+n:1+2*n); 26 | center = code(:, 2+2*n:4+2*n); 27 | is_symmetry = code(:, 5+2*n); 28 | global_symmetry_plane = code(:, 6+2*n:9+2*n); 29 | 30 | % part_pcs = cell(n, 1); 31 | % part_faces = cell(n, 1); 32 | p0 = zeros(n, 3); 33 | q0 = zeros(n, 3); 34 | p = zeros(n, 3); 35 | q = zeros(n, 3); 36 | 37 | y_order = zeros(n, 2); 38 | for i = 1:n 39 | % part_pc_name = fullfile(dir, ['transformed_cube_', part_names{i}, '.obj']); 40 | % part_pc_name = fullfile(dir, [part_names{i}, '.obj']); 41 | part_pc = part_pcs{i}; 42 | part_face = part_faces{i}; 43 | % if exist(part_pc_name, 'file') 44 | if ~isempty(part_pc) 45 | % [part_pc, part_face] = cotlp(part_pc_name); 46 | part_bbox = GetBoundingBox4PointCloud(part_pc); 47 | % part_pcs{i} = part_pc; 48 | % part_faces{i} = part_face'; 49 | q0(i, :) = 1/2*(part_bbox(7, :) - part_bbox(1, :)); 50 | 51 | y_order(i, 1) = i; 52 | y_order(i, 2) = part_bbox(1, 2); 53 | else 54 | % part_pcs{i} = []; 55 | q0(i, :) = [0, 0, 0]; 56 | 57 | y_order(i, 1) = i; 58 | y_order(i, 2) = inf; 59 | end 60 | 61 | p0(i, :) = code(i, 2*n+2:2*n+4); 62 | end 63 | num_parts = 0; 64 | for i = 1:n 65 | p(i, :) = p0(i, :); 66 | q(i, :) = q0(i, :); 67 | end 68 | % 6n*1 69 | x0 = zeros(6*n, 1); 70 | % 6n*1 71 | x = zeros(6*n, 1); 72 | % change x and x0 to one-column vector 73 | % 6n*1 74 | for i = 1:n 75 | x0(3*i-2:3*i, 1) = p0(i, :); 76 | x0(3*n+3*i-2:3*n+3*i, 1) = q0(i, :); 77 | x(3*i-2:3*i, 1) = p(i, :); 78 | x(3*n+3*i-2:3*n+3*i, 1) = q(i, :); 79 | end 80 | part_v = structure{1, 1}; 81 | part_f = structure{1, 2}; 82 | % 1/2 83 | alpha = 10000000; 84 | H = eye(6*n, 6*n); 85 | H(3*n+1:6*n, :) = alpha*H(3*n+1:6*n, :); 86 | f = -H'*x0; 87 | A = []; 88 | b = []; 89 | Aeq = []; 90 | beq = []; 91 | lb = []; 92 | ub = []; 93 | 94 | % symmetry constraint 95 | i = 1; 96 | while i <= n 97 | % symmetry constraint 98 | if 1 == is_symmetry(i) 99 | j = i+1; 100 | normal = global_symmetry_plane(i, 1:3); 101 | d = abs(dot(center(i, :), normal)); 102 | 103 | % symmetry constraint 1 104 | temp_A_for_pi_sub_pj = zeros(3, 6*n); 105 | temp_A_for_pi_sub_pj(:, 3*i-2:3*i) = eye(3,3); 106 | temp_A_for_pi_sub_pj(:, 3*j-2:3*j) = -eye(3,3); 107 | temp_A = normal*temp_A_for_pi_sub_pj; 108 | temp_b = -2*d; 109 | Aeq = [Aeq; temp_A]; 110 | beq = [beq; temp_b]; 111 | 112 | % symmetry constraint 2 113 | % convert cross product to matrix multiplication 114 | % https://en.wikipedia.org/wiki/Cross_product#Conversion_to_matrix_multiplication 115 | normal_temp = zeros(3, 3); 116 | normal_temp(1,2) = normal(1,3); 117 | normal_temp(1,3) = -normal(1,2); 118 | normal_temp(2,1) = -normal(1,3); 119 | normal_temp(2,3) = normal(1,1); 120 | normal_temp(3,1) = normal(1,2); 121 | normal_temp(3,2) = -normal(1,1); 122 | temp_A = normal_temp*temp_A_for_pi_sub_pj; 123 | temp_b = [0, 0, 0]'; 124 | Aeq = [Aeq; temp_A]; 125 | beq = [beq; temp_b]; 126 | 127 | % symmetry constraint 3 128 | temp_A_for_qi_sub_qj = zeros(3, 6*n); 129 | temp_A_for_qi_sub_qj(:, 3*n+3*i-2:3*n+3*i) = eye(3,3); 130 | temp_A_for_qi_sub_qj(:, 3*n+3*j-2:3*n+3*j) = -eye(3,3); 131 | temp_A = temp_A_for_qi_sub_qj; 132 | temp_b = [0, 0, 0]'; 133 | Aeq = [Aeq; temp_A]; 134 | beq = [beq; temp_b]; 135 | 136 | i = i + 1; 137 | end 138 | i = i + 1; 139 | end 140 | % equal length constraint 141 | for i = 1:n 142 | i_supporting = code(i, 2:n+1); 143 | i_supported = code(i, n+2:2*n+1); 144 | supporting_group = []; 145 | supported_group = []; 146 | for j = 1:n 147 | if 1 == i_supporting(j) 148 | supporting_group = [supporting_group, j]; 149 | end 150 | if 1 == i_supported(j) 151 | supported_group = [supported_group, j]; 152 | end 153 | end 154 | for j = 1:size(i_supporting, 2) 155 | for k = j+1:size(i_supporting, 2) 156 | j_name = part_names{j}; 157 | k_name = part_names{k}; 158 | j_parts = strsplit(j_name, '_'); 159 | k_parts = strsplit(k_name, '_'); 160 | % same type 161 | if 1 == strcmp(j_parts{1}, k_parts{1}) 162 | temp_qj_sub_qk = zeros(1, 6*n); 163 | temp_qj_sub_qk(1, 3*n+3*j-1) = 1; 164 | temp_qj_sub_qk(1, 3*n+3*k-1) = -1; 165 | 166 | temp_A = temp_qj_sub_qk; 167 | Aeq = [Aeq; temp_A]; 168 | temp_b = 0; 169 | beq = [beq; temp_b]; 170 | end 171 | end 172 | end 173 | for j = 1:size(i_supported, 2) 174 | for k = j+1:size(i_supported, 2) 175 | j_name = part_names{j}; 176 | k_name = part_names{k}; 177 | j_parts = strsplit(j_name, '_'); 178 | k_parts = strsplit(k_name, '_'); 179 | % same type 180 | if 1 == strcmp(j_parts{1}, k_parts{1}) 181 | temp_qj_sub_qk = zeros(1, 6*n); 182 | temp_qj_sub_qk(1, 3*n+3*j-1) = 1; 183 | temp_qj_sub_qk(1, 3*n+3*k-1) = -1; 184 | 185 | temp_A = temp_qj_sub_qk; 186 | Aeq = [Aeq; temp_A]; 187 | temp_b = 0; 188 | beq = [beq; temp_b]; 189 | end 190 | end 191 | end 192 | end 193 | % Support Relationship Constraint 194 | for i = 1:n 195 | for j = 1:n 196 | if i == j 197 | continue; 198 | end 199 | % if i supports j 200 | if 1 == supporting(i, j) 201 | if q0(i, 2) > q0(j, 2) 202 | temp_A_for_pj_sub_qj = zeros(1, 6*n); 203 | temp_A_for_pj_sub_qj(1, 3*j-1) = 1; 204 | % narrow the range of variation 205 | temp_A_for_pj_sub_qj(1, 3*n+3*j-1) = -0.7; 206 | 207 | temp_A_for_pi_add_qi = zeros(1, 6*n); 208 | temp_A_for_pi_add_qi(1, 3*i-1) = 1; 209 | temp_A_for_pi_add_qi(1, 3*n+3*i-1) = 1; 210 | 211 | temp_A_for_pj_add_qj = zeros(1, 6*n); 212 | temp_A_for_pj_add_qj(1, 3*j-1) = 1; 213 | temp_A_for_pj_add_qj(1, 3*n+3*j-1) = 1; 214 | 215 | temp_A = temp_A_for_pj_sub_qj - temp_A_for_pi_add_qi; 216 | temp_b = 0; 217 | A = [A; temp_A]; 218 | b = [b; temp_b]; 219 | 220 | temp_A = temp_A_for_pi_add_qi - temp_A_for_pj_add_qj; 221 | temp_b = 0; 222 | A = [A; temp_A]; 223 | b = [b; temp_b]; 224 | else 225 | temp_A_for_pi_sub_qi = zeros(1, 6*n); 226 | temp_A_for_pi_sub_qi(1, 3*i-1) = 1; 227 | temp_A_for_pi_sub_qi(1, 3*n+3*i-1) = -1; 228 | 229 | temp_A_for_pj_sub_qj = zeros(1, 6*n); 230 | temp_A_for_pj_sub_qj(1, 3*j-1) = 1; 231 | temp_A_for_pj_sub_qj(1, 3*n+3*j-1) = -1; 232 | 233 | temp_A_for_pi_add_qi = zeros(1, 6*n); 234 | temp_A_for_pi_add_qi(1, 3*i-1) = 1; 235 | % narrow the range of variation 236 | temp_A_for_pi_add_qi(1, 3*n+3*i-1) = 0.7; 237 | 238 | temp_A = temp_A_for_pi_sub_qi - temp_A_for_pj_sub_qj; 239 | temp_b = 0; 240 | A = [A; temp_A]; 241 | b = [b; temp_b]; 242 | 243 | temp_A = temp_A_for_pj_sub_qj - temp_A_for_pi_add_qi; 244 | temp_b = 0; 245 | A = [A; temp_A]; 246 | b = [b; temp_b]; 247 | end 248 | end 249 | end 250 | end 251 | 252 | % Stable Support Constraint 253 | for i = 1:n 254 | supporting_i_items_group = []; 255 | for j = i:n 256 | if 1 == supported(i, j) 257 | supporting_i_items_group = [supporting_i_items_group, j]; 258 | % x axis 259 | temp_A_for_pi_sub_qi = zeros(1, 6*n); 260 | temp_A_for_pi_sub_qi(1, 3*i-2) = 1; 261 | temp_A_for_pi_sub_qi(1, 3*n+3*i-2) = -1; 262 | 263 | temp_A_for_pj = zeros(1, 6*n); 264 | temp_A_for_pj(1, 3*j-2) = 1; 265 | 266 | temp_A_for_pi_add_qi = zeros(1, 6*n); 267 | temp_A_for_pi_add_qi(1, 3*i-2) = 1; 268 | temp_A_for_pi_add_qi(1, 3*n+3*i-2) = 1; 269 | 270 | temp_A = temp_A_for_pj - temp_A_for_pi_add_qi; 271 | temp_b = 0; 272 | A = [A; temp_A]; 273 | b = [b; temp_b]; 274 | 275 | temp_A = temp_A_for_pi_sub_qi - temp_A_for_pj; 276 | temp_b = 0; 277 | A = [A; temp_A]; 278 | b = [b; temp_b]; 279 | 280 | % z axis 281 | temp_A_for_pi_sub_qi = zeros(1, 6*n); 282 | temp_A_for_pi_sub_qi(1, 3*i) = 1; 283 | temp_A_for_pi_sub_qi(1, 3*n+3*i) = -1; 284 | 285 | temp_A_for_pj = zeros(1, 6*n); 286 | temp_A_for_pj(1, 3*j) = 1; 287 | 288 | temp_A_for_pi_add_qi = zeros(1, 6*n); 289 | temp_A_for_pi_add_qi(1, 3*i) = 1; 290 | temp_A_for_pi_add_qi(1, 3*n+3*i) = 1; 291 | 292 | temp_A = temp_A_for_pj - temp_A_for_pi_add_qi; 293 | temp_b = 0; 294 | A = [A; temp_A]; 295 | b = [b; temp_b]; 296 | 297 | temp_A = temp_A_for_pi_sub_qi - temp_A_for_pj; 298 | temp_b = 0; 299 | A = [A; temp_A]; 300 | b = [b; temp_b]; 301 | end 302 | end 303 | x_min = inf; 304 | z_min = inf; 305 | x_max = -inf; 306 | z_max = -inf; 307 | x_min_index = 0; 308 | z_min_index = 0; 309 | x_max_index = 0; 310 | z_max_index = 0; 311 | for j = 1:size(supporting_i_items_group) 312 | j_index = supporting_i_items_group(j); 313 | j_p = p0(j_index, :); 314 | j_q = q0(j_index, :); 315 | if j_p(1)-j_q(1) < x_min 316 | x_min = j_p(1); 317 | x_min_index = j_index; 318 | end 319 | if j_p(3)-j_q(3) < z_min 320 | z_min = j_p(3); 321 | z_min_index = j_index; 322 | end 323 | if j_p(1)+j_q(1) > x_max 324 | x_max = j_p(1); 325 | x_max_index = j_index; 326 | end 327 | if j_p(3)+j_q(3) > z_max 328 | z_max = j_p(3); 329 | z_max_index = j_index; 330 | end 331 | end 332 | if x_min_index ~= 0 && x_max_index ~= 0 333 | % x axis 334 | temp_A_for_pi_sub_qi = zeros(1, 6*n); 335 | temp_A_for_pi_sub_qi(1, 3*x_min_index-2) = 1; 336 | temp_A_for_pi_sub_qi(1, 3*n+3*x_min_index-2) = -1; 337 | % temp_A_for_pi_sub_qi(1, 3*n+3*x_min_index-2) = -0.1; 338 | 339 | temp_A_for_pj = zeros(1, 6*n); 340 | temp_A_for_pj(1, 3*i-2) = 1; 341 | 342 | temp_A_for_pi_add_qi = zeros(1, 6*n); 343 | temp_A_for_pi_add_qi(1, 3*x_max_index-2) = 1; 344 | temp_A_for_pi_add_qi(1, 3*n+3*x_max_index-2) = 1; 345 | % temp_A_for_pi_add_qi(1, 3*n+3*x_max_index-2) = 0.1; 346 | 347 | temp_A = temp_A_for_pi_sub_qi - temp_A_for_pj; 348 | temp_b = 0; 349 | A = [A; temp_A]; 350 | b = [b; temp_b]; 351 | 352 | temp_A = temp_A_for_pj - temp_A_for_pi_add_qi; 353 | temp_b = 0; 354 | A = [A; temp_A]; 355 | b = [b; temp_b]; 356 | end 357 | if z_min_index ~= 0 && z_max_index ~= 0 358 | % z axis 359 | temp_A_for_pi_sub_qi = zeros(1, 6*n); 360 | temp_A_for_pi_sub_qi(1, 3*z_min_index) = 1; 361 | temp_A_for_pi_sub_qi(1, 3*n+3*x_min_index) = -1; 362 | % temp_A_for_pi_sub_qi(1, 3*n+3*z_min_index) = -0.1; 363 | 364 | temp_A_for_pj = zeros(1, 6*n); 365 | temp_A_for_pj(1, 3*i) = 1; 366 | 367 | temp_A_for_pi_add_qi = zeros(1, 6*n); 368 | temp_A_for_pi_add_qi(1, 3*z_max_index) = 1; 369 | temp_A_for_pi_add_qi(1, 3*n+3*z_max_index) = 1; 370 | % temp_A_for_pi_add_qi(1, 3*n+3*z_max_index) = 0.1; 371 | 372 | 373 | temp_A = temp_A_for_pi_sub_qi - temp_A_for_pj; 374 | temp_b = 0; 375 | A = [A; temp_A]; 376 | b = [b; temp_b]; 377 | 378 | temp_A = temp_A_for_pj - temp_A_for_pi_add_qi; 379 | temp_b = 0; 380 | A = [A; temp_A]; 381 | b = [b; temp_b]; 382 | end 383 | end 384 | 385 | [x, fval]= quadprog(H,f, A, b); 386 | % fprintf('fval: %f\n', fval); 387 | % extract optimized p and q 388 | for i = 1:n 389 | p(i, 1:3) = x(3*i-2:3*i, 1)'; 390 | q(i, 1:3) = x(3*n+3*i-2:3*n+3*i, 1)'; 391 | end 392 | % if strcmp(type, 'chair') == 1 393 | % p(1:2, 1:3) = p(1:2,1:3)*0.9; 394 | % p(4:7, 1:3) = p(4:7,1:3)*0.9; 395 | % elseif strcmp(type, 'plane') == 1 396 | % p(2, 1) = p(2, 1) + 0.035; 397 | % p(3, 1) = p(3, 1) - 0.035; 398 | % p(4:5, 2) = p(4, 2) + 0.005; 399 | % p(4:5, 3) = p(5, 3) - 0.03; 400 | % p(11:12, 3) = p(11:12, 3) + 0.05; 401 | % p(13:14, 3) = p(13:14, 3) + 0.05; 402 | % end 403 | % total_optimized_pc = []; 404 | % total_pc = []; 405 | % total_face = []; 406 | % begin_index = 1; 407 | % end_index = n; 408 | % if strcmp(type, 'chair') == 1 409 | % part_pc = part_pcs{n} - mean(part_pcs{n}, 1) + p(n, :); 410 | % total_pc = [total_pc; part_pc]; 411 | % total_optimized_pc = [total_optimized_pc; part_pc]; 412 | % total_face = [total_face; part_faces{n}]; 413 | % begin_index = 1; 414 | % end_index = n-1; 415 | % else 416 | % part_pc = part_pcs{1} - mean(part_pcs{1}, 1) + p(1, :); 417 | % total_pc = [total_pc; part_pc]; 418 | % total_optimized_pc = [total_optimized_pc; part_pc]; 419 | % total_face = [total_face; part_faces{1}]; 420 | % begin_index = 2; 421 | % end_index = n; 422 | % end 423 | % for i = begin_index:end_index 424 | % part_pc = part_pcs{i}; 425 | % if ~isempty(part_pc) 426 | % total_pc = [total_optimized_pc; part_pc]; 427 | % [idx, D] = knnsearch(total_optimized_pc, part_pc); 428 | % [min_d, min_index] = min(D); 429 | % dxyz = total_optimized_pc(idx(min_index), :) - part_pc(min_index, :); 430 | % p(i, :) = p(i, :) + dxyz; 431 | % total_optimized_pc = [total_optimized_pc; part_pc]; 432 | % total_face = [total_face; part_faces{i}]; 433 | % end 434 | % end 435 | 436 | % place every part in optimized position p using optimized size q 437 | total_optimized_pc = []; 438 | total_pc = []; 439 | total_face = []; 440 | total_optimized_pc = part_v; 441 | total_optimized_face = part_f; 442 | for i = 1:num_parts 443 | if ~isempty(part_pcs{i}) 444 | % if strcmp(type, 'plane') && (i == 6 || i == 11 || i == 12 || i == 13 || i == 14) && code(i, 1) == 0 445 | % continue; 446 | % end 447 | if strcmp(type, 'chair') && (i == 1 || i == 2) && code(i, 1) == 0 448 | continue; 449 | end 450 | optimized_pc = part_pcs{i} - mean(part_pcs{i}, 1) + p(i, :); 451 | unoptimized_pc = part_pcs{i} - mean(part_pcs{i}, 1) + p0(i, :); 452 | total_pc = [total_pc; unoptimized_pc]; 453 | total_face = AddPartFace2TotalFace(total_face, part_faces{i}); 454 | total_optimized_pc = [total_optimized_pc; optimized_pc]; 455 | end 456 | end 457 | % total_optimized_face = total_face; 458 | % if ispc 459 | % SaveObjT(fullfile(dir, 'unoptimized.obj'), total_pc', total_face'); 460 | % SaveObjT(fullfile(dir, 'optimized.obj'), total_optimized_pc', total_face'); 461 | % else 462 | % SaveObj(fullfile(dir, 'unoptimized.obj'), total_pc', total_faces'); 463 | % SaveObj(fullfile(dir, 'optimized.obj'), total_optimized_pc', total_face'); 464 | % end 465 | end -------------------------------------------------------------------------------- /code/matlab/SaveObj.m: -------------------------------------------------------------------------------- 1 | function [ ] = SaveObj( inputname, ver, face) 2 | %UNTITLED3 Summary of this function goes here 3 | % Detailed explanation goes here 4 | [m,n]=size(ver); 5 | if n==1 6 | newver=reshape(ver, 3,m/3); 7 | else 8 | newver=ver; 9 | end 10 | [m,n]=size(newver); 11 | fid=fopen(inputname,'w'); 12 | for i = 1 : n 13 | verline=['v ',num2str(newver(1,i)),' ',num2str(newver(2,i)),' ',num2str(newver(3,i))]; 14 | fprintf(fid,'%s\n',verline); 15 | end 16 | [m,n]=size(face); 17 | for i = 1:n 18 | faceline=['f ',num2str(face(1,i)),' ',num2str(face(2,i)),' ',num2str(face(3,i))]; 19 | fprintf(fid,'%s\n',faceline); 20 | end 21 | fclose(fid); 22 | end 23 | 24 | -------------------------------------------------------------------------------- /code/matlab/SaveObjT.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gaolinorange/SDMNET_stamp/5208f1210b77e3251dde3bdafc120a48dc69e833/code/matlab/SaveObjT.mexw64 -------------------------------------------------------------------------------- /code/matlab/SupportAnalysis.m: -------------------------------------------------------------------------------- 1 | function SupportAnalysis(part_objs_dir, type) 2 | part_names = getlabel(type); 3 | 4 | global_symmetry_plane = [1, 0, 0, 0]; 5 | 6 | part_num = size(part_names, 2); 7 | code = zeros(part_num, part_num*2+9); 8 | code = AddPriori(code, type, part_names); 9 | 10 | part_pcs = cell(part_num, 1); 11 | part_bboxs = cell(part_num, 1); 12 | i = 1; 13 | while i <= part_num 14 | part_name = part_names{i}; 15 | part_obj = fullfile(part_objs_dir, [part_name, '.obj']); 16 | if exist(part_obj, 'file') 17 | code(i, 1) = 1; 18 | [part_pc,~] = readobjfromfile(part_obj); 19 | 20 | if i+1 <= part_num 21 | next_part_name = part_names{i+1}; 22 | % if symmetry 23 | part_name_split = strsplit(part_name, '_'); 24 | next_part_name_split = strsplit(next_part_name, '_'); 25 | if 1 == strcmp(part_name_split{1}, next_part_name_split{1}) 26 | code(i, 2*part_num+5) = 1; 27 | code(i, 2*part_num+6:2*part_num+9) = global_symmetry_plane; 28 | code(i+1, 2*part_num+5) = 1; 29 | code(i+1, 2*part_num+6:2*part_num+9) = global_symmetry_plane; 30 | end 31 | end 32 | 33 | % fill center part 34 | [part_pc_bbox, ~] = GetBoundingBox4PointCloud(part_pc); 35 | % code(i, 2*part_num+2:2*part_num+4) = (part_pc_bbox(7, :) + part_pc_bbox(1, :))/2; 36 | code(i, 2*part_num+2:2*part_num+4) = mean(part_pc); 37 | else 38 | part_pc = []; 39 | end 40 | 41 | part_pcs{i} = part_pc; 42 | part_bbox = GetBoundingBox4PointCloud(part_pc); 43 | part_bboxs{i} = part_bbox; 44 | i=i+1; 45 | end 46 | 47 | distance = zeros(part_num, part_num); 48 | for i = 1:part_num 49 | for j = 1:part_num 50 | if i ~= j 51 | if size(part_pcs{i}, 1) == 0 || size(part_pcs{j}, 1) == 0 52 | distance(i, j) = inf; 53 | else 54 | [IDX, D] = knnsearch(part_pcs{i}, part_pcs{j}); 55 | dist = min(D, [], 1); 56 | distance(i, j) = dist; 57 | end 58 | else 59 | distance(i, j) = Inf; 60 | end 61 | end 62 | end 63 | for i = 1:part_num 64 | if size(part_pcs{i}, 1) == 0 || sum(code(i, 2:1+part_num)) ~= 0 65 | continue; 66 | end 67 | [~, j] = min(distance(i, :)); 68 | bboxa = part_bboxs{i}; 69 | bboxb = part_bboxs{j}; 70 | % if IsIntersected(bboxa, bboxb) 71 | i_mean = mean(part_pcs{i}, 1); 72 | j_mean = mean(part_pcs{j}, 1); 73 | % i support j 74 | if i_mean(2) < j_mean(2) 75 | code(i, 1+j) = 1; 76 | code(j, part_num+1+i) = 1; 77 | % j support i 78 | else 79 | code(j, i+1) = 1; 80 | code(i, part_num+1+j) = 1; 81 | end 82 | % end 83 | end 84 | save(fullfile(part_objs_dir, 'code.mat'), 'code'); 85 | end -------------------------------------------------------------------------------- /code/matlab/SupportAnalysisScript.m: -------------------------------------------------------------------------------- 1 | function SupportAnalysisScript(divide_dir, type) 2 | d = dir(divide_dir); 3 | isub = [d(:).isdir]; 4 | name_folds = {d(isub).name}'; 5 | name_folds(ismember(name_folds,{'.','..'})) = []; 6 | 7 | for i = 1:size(name_folds, 1) 8 | SupportAnalysis(fullfile(divide_dir, name_folds{i}), type); 9 | end 10 | end -------------------------------------------------------------------------------- /code/matlab/axisangle2matrix.m: -------------------------------------------------------------------------------- 1 | function R = axisangle2matrix(w,a) 2 | % AXISANGLE2MATRIX Conver axis angle rotations into corresponding rotation 3 | % matrices 4 | % 5 | % R = axisangle2matrix(w,a) 6 | % 7 | % Inputs: 8 | % w n by 3 list of axis vectors 9 | % a n by 1 list of angles 10 | % Output: 11 | % R 3 by 3 by n array of rotation matrices 12 | % 13 | 14 | % For now NaNs are not allowed 15 | assert(~any(isnan(w(:)))); 16 | assert(size(w,1) == size(a,1)); 17 | n = size(w,1); 18 | assert(size(w,2) == 3); 19 | 20 | 21 | % build the rotation matrix 22 | s = sin(a); 23 | c = cos(a); 24 | t = 1 - c; 25 | 26 | w = normalizerow(w); 27 | 28 | x = w(:,1); 29 | y = w(:,2); 30 | z = w(:,3); 31 | R = zeros([3,3,n]); 32 | R(1,1,:) = t.*x.*x + c; 33 | R(2,1,:) = t.*y.*x + s.*z; 34 | R(3,1,:) = t.*z.*x - s.*y; 35 | 36 | R(1,2,:) = t.*x.*y - s.*z; 37 | R(2,2,:) = t.*y.*y + c; 38 | R(3,2,:) = t.*z.*y + s.*x; 39 | 40 | R(1,3,:) = t.*x.*z + s.*y; 41 | R(2,3,:) = t.*y.*z - s.*x; 42 | R(3,3,:) = t.*z.*z + c; 43 | 44 | end 45 | -------------------------------------------------------------------------------- /code/matlab/boundbox.m: -------------------------------------------------------------------------------- 1 | function [rotmat,cornerpoints,h,surface,edgelength] = boundbox(x,y,z,metric,level) 2 | % minboundbox: Compute the minimal bounding box of points in 3d 3 | % usage: [rotmat,cornerpoints,volume,surface,edgelength] = minboundbox(x,y,z,metric,level) 4 | % 5 | % arguments: (input) 6 | % x,y,z - vectors of points, describing points in 3d as 7 | % (x,y,z) pairs. x, y and z must be the same lengths. 8 | % 9 | % metric - (OPTIONAL) - single letter character flag which 10 | % denotes the use of minimal volume, surface or sum of edges as the 11 | % metric to be minimized. metric may be either 'v', 's' or 'e', 12 | % capitalization is ignored. 13 | % 14 | % DEFAULT: 'v' ('volume') 15 | % 16 | % level - (OPTIONAL) - either 1, 2, 3 or 4. This denotes the level of 17 | % reliability of the resulting minimal bounding box. 18 | % '1' denotes the search for a bounding box, where one side of the 19 | % box coincides with a face of the convex hull. (fast) 20 | % '2' like '1', but also incorporates a search through each pair of edges 21 | % which form a plane which coincides with one side of the box (slow) 22 | % '3' like '1', but also incorporates a search through each edge which is 23 | % parallel to an edge of the box (reasonably fast) 24 | % '4' like '1', '2' and '3' together. (slowest) (Never needed that.) 25 | % 26 | % It depends on the application, what should be chosen here. 27 | % See the example at the end for the effects of this parameter. 28 | % 29 | % DEFAULT: '3' 30 | % 31 | % arguments: (output) 32 | % rotmat - (3x3) rotation matrix for mapping of the pointcloud into a 33 | % box which is axis-parallel (use inv(rotmat) for inverse 34 | % mapping). 35 | % 36 | % cornerpoints - (8x3) the cornerpoints of the bounding box. 37 | % 38 | % volume - (scalar) volume of the minimal box itself. 39 | % 40 | % surface - (scalar) surface of the minimal box as found. 41 | % 42 | % edgelength - (scalar) sum of the edgelengths of the minimal box as found. 43 | % 44 | % Thanks to John d'Errico for providing the solution to the 2d version of 45 | % this problem via minboundrect from the FEX. I took a huge amount of his 46 | % syntax, organisation and comments for this submission. (Hope he wont sue 47 | % me, though.) 48 | % 49 | % Thanks to Roger Stafford and John d'Errico for helpful discussions and 50 | % suggestions. 51 | % 52 | % The algorithm is still not proven to produce the smallest possible 53 | % enclosing box. But i never found any counterexamples for the 'best' 54 | % algorithm with level 4, whilst the second example below shows, there are 55 | % differences between the levels. I would be happy to have a proof that 56 | % level 3 suffices for each case. 57 | % 58 | % Example usage: 59 | % 60 | % (1) 61 | % x = rand(100,1); 62 | % y = rand(100,1); 63 | % z = rand(100,1); 64 | % [rotmat,cornerpoints,volume,surface] = minboundbox(x,y,z); 65 | % plot3(x,y,z,'b.');hold on;plotminbox(cornerpoints,'r'); 66 | % 67 | % (2) 68 | % x=[1,0,0.1,1];y=[0,1,0.1,1];z=[0,0,0.9,1]; 69 | % [nerd,cornerpoints1,nerd,nerd] = minboundbox(x,y,z,'v',1); 70 | % [nerd,cornerpoints2,nerd,nerd] = minboundbox(x,y,z,'v',2); 71 | % [nerd,cornerpoints3,nerd,nerd] = minboundbox(x,y,z,'v',3); 72 | % plot3(x,y,z,'bo','LineWidth',5);hold on; 73 | % plotminbox(cornerpoints1,'b');hold on; 74 | % plotminbox(cornerpoints2,'m');hold on; 75 | % plotminbox(cornerpoints3,'r');axis equal;grid on;hold off; 76 | % 77 | % 78 | % See also: minboundcircle, minboundtri, minboundsphere, minboundrect 79 | % 80 | % 81 | % Author: Johannes Korsawe 82 | % E-mail: johannes.korsawe@volkswagen.de 83 | % Release: 1.1 84 | % Release date: 16/02/2015 85 | 86 | % default for metric 87 | if (nargin<4) || isempty(metric) 88 | metric = 'v'; 89 | elseif ~ischar(metric) 90 | error 'metric must be a character flag if it is supplied.' 91 | else 92 | % check for 'v', 's' or 'e' 93 | metric = lower(metric(:)'); 94 | ind = strmatch(metric,{'volume','surface','edges'}); 95 | if isempty(ind) 96 | error 'metric does not match either ''volume'', ''surface'' or ''edges''.' 97 | end 98 | % just keep the first letter. 99 | metric = metric(1); 100 | end 101 | 102 | % default for level 103 | if (nargin<5 || isempty(level)), 104 | level=4; 105 | elseif ~isnumeric(level) || (level~=1 && level~=2 && level~=3 && level~=4), 106 | error 'metric does not match either ''1'', ''2'', ''3'' or ''3''.' 107 | end 108 | 109 | % preprocess data 110 | x = x(:); 111 | y = y(:); 112 | z = z(:); 113 | 114 | % not many error checks to worry about 115 | n1 = length(x);n2 = length(y);n3 = length(z); 116 | if n1 ~= n2 || n1 ~= n3 || n2 ~= n3, 117 | error 'x, y and z must be the same sizes' 118 | end 119 | 120 | % start out with the convex hull of the points to 121 | % reduce the problem dramatically. Note that any 122 | % points in the interior of the convex hull are 123 | % never needed, so we drop them. 124 | 125 | try 126 | K = convhulln([x,y,z],{'Qt'}); % 'Pp' will silence the warnings 127 | 128 | % exclude those points inside the hull as not relevant 129 | % also sorts the points into their convex hull as a 130 | % closed polygon 131 | 132 | Ki = unique(K(:)); 133 | [tf,loc] = ismember(K(:),Ki);K = reshape(loc,size(K)); 134 | x = x(Ki); 135 | y = y(Ki); 136 | z = z(Ki); 137 | n1 =length(x); 138 | 139 | catch 140 | error 'The number and/or distribution of given points does not allow the construction of a convex hull.' 141 | end 142 | 143 | % now we must find the bounding box of those points that remain 144 | 145 | % get the angle of each face of the hull polygon. 146 | % calculate local coordinate system 147 | % x,y and z values of faces' cornerpoints 148 | fx = [x(K(:,1)),x(K(:,2)),x(K(:,3))]; 149 | fy = [y(K(:,1)),y(K(:,2)),y(K(:,3))]; 150 | fz = [z(K(:,1)),z(K(:,2)),z(K(:,3))]; 151 | % faces' edges 152 | v1 = [fx(:,2)-fx(:,1),fy(:,2)-fy(:,1),fz(:,2)-fz(:,1)]; 153 | v1 = v1./(repmat(sqrt(sum(v1.^2,2)),1,3)); 154 | v2 = [fx(:,3)-fx(:,1),fy(:,3)-fy(:,1),fz(:,3)-fz(:,1)]; 155 | v2 = v2-repmat(dot(v1,v2,2),1,3).*v1; 156 | v2 = v2./(repmat(sqrt(sum(v2.^2,2)),1,3)); 157 | % faces' normals 158 | nv = cross(v1,v2,2); 159 | % faces' orientations measured in Euler angles 160 | [alpha,beta,gamma]=euler123(v1,v2,nv); 161 | 162 | nang = size(alpha,1); 163 | d = inf; % this will be the minimal value 164 | rotmat=[];minmax=[]; 165 | xyz = [x,y,z]; 166 | if level==1 || level==3, % check each face of the hull 167 | for i = 1:nang, 168 | % check current orientation 169 | % receive minimal value, rotation matrix and dimensions of the enclosing box 170 | [d, rotmat, minmax] = checkbox(alpha(i),beta(i),gamma(i),xyz,metric,d,rotmat,minmax); 171 | end 172 | end 173 | 174 | if level>1, 175 | e = edgelist(K);ne = size(e,1); % get a sorted list of edges 176 | end 177 | 178 | if level==2 || level==4, % check each set of two edges of the convex hull (which obviously includes case '1' above) 179 | for i = 1:ne, % go through edge list 180 | va = xyz(e(i,1),:)-xyz(e(i,2),:); 181 | va = va/norm(va); 182 | for j = i+1:ne, % go through remaining edge list 183 | vb = xyz(e(j,1),:)-xyz(e(j,2),:); 184 | vb = vb - dot(va,vb)*va; % orthogonaylize second edge wrt first 185 | nv = cross(va,vb); % normal to plane formed by the two edges 186 | if sum(abs(nv))>0, 187 | vb = vb/norm(vb);nv = nv/norm(nv); 188 | [alp,bet,gam]=euler123(va,vb,nv); 189 | [d, rotmat, minmax] = checkbox(alp,bet,gam,xyz,metric,d,rotmat,minmax); 190 | end 191 | end 192 | end 193 | end 194 | 195 | if level==3 || level==4, % check edge as parallel to one edge of the bounding box 196 | for i = 1:ne, % go through edge list 197 | % calculate rhs with edge as one of the axes 198 | va = xyz(e(i,1),:)-xyz(e(i,2),:); 199 | vb = [va(2),-va(1),0];if sum(abs(vb))==0,vb = [va(3),0,-va(1)];end 200 | va = va/norm(va);vb = vb/norm(vb); 201 | nv = cross(va,vb); 202 | % check all combinations of possible rhs 203 | [alp,bet,gam]=euler123(va,vb,nv); 204 | [d, rotmat, minmax] = checkbox(alp,bet,gam,xyz,metric,d,rotmat,minmax); 205 | [alp,bet,gam]=euler123(vb,nv,va); 206 | [d, rotmat, minmax] = checkbox(alp,bet,gam,xyz,metric,d,rotmat,minmax); 207 | [alp,bet,gam]=euler123(nv,va,vb); 208 | [d, rotmat, minmax] = checkbox(alp,bet,gam,xyz,metric,d,rotmat,minmax); 209 | end 210 | end 211 | 212 | % get the output values 213 | % h = [minmax(1,1),minmax(1,2),minmax(1,3); % xmin,ymin,zmin 214 | % minmax(2,1),minmax(1,2),minmax(1,3); % xmax,ymin,zmin 215 | % minmax(2,1),minmax(2,2),minmax(1,3); % xmax,ymax,zmin 216 | % minmax(1,1),minmax(2,2),minmax(1,3); % xmin,ymax,zmin 217 | % minmax(1,1),minmax(1,2),minmax(2,3); % xmin,ymin,zmax 218 | % minmax(2,1),minmax(1,2),minmax(2,3); % xmax,ymin,zmax 219 | % minmax(2,1),minmax(2,2),minmax(2,3); % xmax,ymax,zmax 220 | % minmax(1,1),minmax(2,2),minmax(2,3); % xmin,ymax,zmax 221 | % ]; 222 | h = [minmax(1,1),minmax(1,2),minmax(1,3); % xmin,ymin,zmin 1 223 | minmax(2,1),minmax(1,2),minmax(1,3); % xmax,ymin,zmin 2 224 | minmax(2,1),minmax(1,2),minmax(2,3); % xmax,ymin,zmax 3 225 | minmax(1,1),minmax(1,2),minmax(2,3); % xmin,ymin,zmax 4 226 | minmax(1,1),minmax(2,2),minmax(1,3); % xmin,ymax,zmin 5 227 | minmax(2,1),minmax(2,2),minmax(1,3); % xmax,ymax,zmin 6 228 | minmax(2,1),minmax(2,2),minmax(2,3); % xmax,ymax,zmax 7 229 | minmax(1,1),minmax(2,2),minmax(2,3); % xmin,ymax,zmax 8 230 | ]; 231 | 232 | cornerpoints = h*inv(rotmat); % minimal boxes' cornerpoints 233 | subcoor=inv(rotmat); 234 | h=subcoor; 235 | % h = minmax(2,:)-minmax(1,:); 236 | volume = h(1)*h(2)*h(3); 237 | surface = 2*(h(1)*h(2)+h(2)*h(3)+h(3)*h(1)); 238 | edgelength = 4*sum(h); 239 | 240 | % all done 241 | 242 | end % mainline end 243 | 244 | function [alpha,beta,gamma]=euler123(v1,v2,nv) 245 | % calculate Euler angles for the x, y', z'' Euler sequence 246 | % see also 247 | % http://en.wikipedia.org/wiki/Euler_angles 248 | % http://de.wikipedia.org/wiki/Eulersche_Winkel 249 | 250 | % --> beta 251 | beta = asin(sign(nv(:,1)).*min(1,abs(nv(:,1)))); 252 | % --> alpha 253 | alpha=0*beta; 254 | i1 = find(nv(:,1)==1);i2 = setdiff(1:size(nv,1),i1); 255 | if ~isempty(i1), 256 | alpha(i1) = asin(sign(v2(i1,3)).*min(1,abs(v2(i1,3)))); 257 | end 258 | if ~isempty(i2), 259 | alpha(i2) = acos(sign(nv(i2,3)./cos(beta(i2))).*min(1,abs(nv(i2,3)./cos(beta(i2))))); 260 | i3 = find(sign(nv(i2,2)) ~= sign(-sin(alpha(i2)).*cos(beta(i2)))); 261 | alpha(i2(i3)) = -alpha(i2(i3)); 262 | end 263 | % --> gamma 264 | gamma = 0*alpha; 265 | if ~isempty(i2), 266 | singamma = -v2(i2,1)./cos(beta(i2)); 267 | i21 = find(v1(i2,1)>=0);i22=setdiff(1:length(i2),i21); 268 | gamma(i2(i21)) = asin(sign(singamma(i21)).*min(1,abs(singamma(i21)))); 269 | gamma(i2(i22)) = -pi-asin(sign(singamma(i22)).*min(1,abs(singamma(i22)))); 270 | end 271 | 272 | end % function euler123 273 | 274 | function [d, rotmat, minmax] = checkbox(alpha,beta,gamma,xyz,metric,d,rotmat,minmax) 275 | 276 | % will need a 3x3 rotation matrix through (Euler X, Y', Z'')-angles alpha, beta and gamma 277 | Rmat = @(alpha,beta,gamma) [cos(beta)*cos(gamma) -cos(beta)*sin(gamma) sin(beta) 278 | sin(alpha)*sin(beta)*cos(gamma)+cos(alpha)*sin(gamma) -sin(alpha)*sin(beta)*sin(gamma)+cos(alpha)*cos(gamma) -sin(alpha)*cos(beta) 279 | -cos(alpha)*sin(beta)*cos(gamma)+sin(alpha)*sin(gamma) cos(alpha)*sin(beta)*sin(gamma)+sin(alpha)*cos(gamma) cos(alpha)*cos(beta)]; 280 | 281 | rot = Rmat(alpha,beta,gamma); 282 | xyz_i = xyz*rot; % now the actual face is in the x-y plane 283 | 284 | x_i = xyz_i(:,1);y_i = xyz_i(:,2); % .. so take only the x and y values 285 | rot2 = minrect(x_i,y_i,metric); % find the optimal rotation around z-axis 286 | rot = rot*[[rot2,[0;0]];[0,0,1]]; % combine that with the formar rotation 287 | xyz_i = xyz*rot; % now again the xyz_i values, but in optimal axisparallel shape 288 | 289 | xyzmin = min(xyz_i,[],1); 290 | xyzmax = max(xyz_i,[],1); 291 | h = xyzmax-xyzmin; 292 | 293 | if metric == 'v', % smallest volume 294 | d_i = h(1)*h(2)*h(3); 295 | elseif metric == 's', % smallest surface 296 | d_i = h(1)*h(2)+h(2)*h(3)+h(3)*h(1); 297 | else, % smallest sum of edges 298 | d_i = sum(h); 299 | end 300 | 301 | if d_i < d, 302 | d = d_i; 303 | rotmat = rot; 304 | minmax = [xyzmin;xyzmax]; 305 | end 306 | 307 | end % function checkbox 308 | 309 | function rot = minrect(x,y,metric) 310 | % see comments from minboundrect of John d'Errico 311 | % i am only interested in the additional rotation matrix around [0,0,1] 312 | 313 | % 16.2.2015: fix for change in released function convhull 314 | if verLessThan('matlab','7.10'), 315 | edges = convhull(x,y,{'Qt'}); 316 | else, 317 | edges = convhull(x,y); 318 | end 319 | x = x(edges);y = y(edges); 320 | ind = 1:length(x)-1; 321 | %Rmat = @(theta) 322 | edgeangles = atan2(y(ind+1) - y(ind),x(ind+1) - x(ind));edgeangles = unique(mod(edgeangles,pi/2)); 323 | nang = length(edgeangles); 324 | area = inf;perimeter = inf;met = inf;xy = [x,y]; 325 | for i = 1:nang 326 | % rot_i = Rmat(-edgeangles(i)); 327 | theta=-edgeangles(i);rot_i = [cos(theta) sin(theta);-sin(theta) cos(theta)]; 328 | xyr = xy*rot_i; 329 | xymin = min(xyr,[],1);xymax = max(xyr,[],1); 330 | A_i = prod(xymax - xymin);P_i = 2*sum(xymax-xymin); 331 | if metric=='v', M_i = A_i;else, M_i = P_i;end 332 | if M_i0&&bbxsign(i,2)<0&&bbxsign(i,3)<0 39 | bbxnew(2,:)=cornerpoints(i,:); 40 | continue; 41 | end 42 | if bbxsign(i,1)>0&&bbxsign(i,2)<0&&bbxsign(i,3)>0 43 | bbxnew(3,:)=cornerpoints(i,:); 44 | continue; 45 | end 46 | if bbxsign(i,1)<0&&bbxsign(i,2)<0&&bbxsign(i,3)>0 47 | bbxnew(4,:)=cornerpoints(i,:); 48 | continue; 49 | end 50 | if bbxsign(i,1)<0&&bbxsign(i,2)>0&&bbxsign(i,3)<0 51 | bbxnew(5,:)=cornerpoints(i,:); 52 | continue; 53 | end 54 | if bbxsign(i,1)>0&&bbxsign(i,2)>0&&bbxsign(i,3)<0 55 | bbxnew(6,:)=cornerpoints(i,:); 56 | continue; 57 | end 58 | if bbxsign(i,1)>0&&bbxsign(i,2)>0&&bbxsign(i,3)>0 59 | bbxnew(7,:)=cornerpoints(i,:); 60 | continue; 61 | end 62 | if bbxsign(i,1)<0&&bbxsign(i,2)>0&&bbxsign(i,3)>0 63 | bbxnew(8,:)=cornerpoints(i,:); 64 | continue; 65 | end 66 | end 67 | end 68 | 69 | 70 | function [n1,id]=makedirect(n1,id1) 71 | if (id1==1) 72 | if n1(1)<0 73 | n1=-n1; 74 | end 75 | id=1; 76 | elseif id1==2 77 | if n1(2)<0 78 | n1=-n1; 79 | end 80 | id=1; 81 | elseif id1==3 82 | if n1(3)<0 83 | n1=-n1; 84 | end 85 | id=1; 86 | else 87 | error('error') 88 | end 89 | end -------------------------------------------------------------------------------- /code/matlab/cotlp.m: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gaolinorange/SDMNET_stamp/5208f1210b77e3251dde3bdafc120a48dc69e833/code/matlab/cotlp.m -------------------------------------------------------------------------------- /code/matlab/cotlpvf.m: -------------------------------------------------------------------------------- 1 | function [ v, f, n, fn ] = cotlpvf( filename ) 2 | 3 | [v, f, n, fn] = meshlpvf(filename); 4 | v = v'; 5 | n = n'; 6 | fn = fn'; 7 | 8 | end 9 | 10 | -------------------------------------------------------------------------------- /code/matlab/create_regular_grid.m: -------------------------------------------------------------------------------- 1 | function [UV,F, res, edge_norms] = ... 2 | create_regular_grid(xRes, yRes, xWrap, yWrap, near, far) 3 | % Creates list of triangle vertex indices for a rectangular domain, 4 | % optionally wrapping around in X/Y direction. 5 | % 6 | % Usage: 7 | % [UV,F,res,edge_norms] = create_regular_grid(xRes, yRes, xWrap, yWrap) 8 | % 9 | % Input: 10 | % xRes, yRes: number of points in X/Y direction 11 | % wrapX, wrapY: wrap around in X/Y direction 12 | % near, far: near and far should be fractions of one which control the 13 | % pinching of the domain at the center and sides 14 | % 15 | % Output: 16 | % F : mesh connectivity (triangles) 17 | % UV: UV coordinates in interval [0,1]x[0,1] 18 | % res: mesh resolution 19 | % 20 | % Example: 21 | % % Create and m by n cylinder 22 | % m = 10; n = 20; 23 | % [V,F] = create_regular_grid(m,n,1,0); 24 | % V = [sin(2*pi*V(:,1)) cos(2*pi*V(:,1)) (n-1)*2*pi/(m-1)*V(:,2)]; 25 | % tsurf(F,V); axis equal; 26 | % 27 | 28 | if (nargin<2) yRes=xRes; end 29 | if (nargin<3) xWrap=0; end 30 | if (nargin<4) yWrap=0; end 31 | if (nargin<5) overlap=0; end 32 | 33 | %res = [yRes, xRes]; 34 | res_wrap = [yRes+yWrap, xRes+xWrap]; 35 | 36 | %xSpace = linspace(0,1,xRes+xWrap); if (xWrap) xSpace = xSpace(1:end-1); end 37 | %ySpace = linspace(0,1,yRes+yWrap); if (yWrap) ySpace = ySpace(1:end-1); end 38 | xSpace = linspace(0,1,xRes+xWrap); 39 | ySpace = linspace(0,1,yRes+yWrap); 40 | 41 | [X, Y] = meshgrid(xSpace, ySpace); 42 | UV_wrap = [X(:), Y(:)]; 43 | 44 | % Must perform pinch before edge_norms are taken 45 | if(exist('near') & exist('far')) 46 | if(near>0 & far>0) 47 | t = ( ... 48 | UV_wrap(:,1).*(UV_wrap(:,1)<0.5)+ ... 49 | (1-UV_wrap(:,1)).*(UV_wrap(:,1)>=0.5) ... 50 | )/0.5; 51 | t = 1-sin(t*pi/2+pi/2); 52 | UV_wrap(:,2) = ... 53 | far/2 + ... 54 | near*(UV_wrap(:,2)-0.5).*(1-t) + ... 55 | far*(UV_wrap(:,2)-0.5).*t; 56 | else 57 | %error('Pinch must be between 0 and 1'); 58 | end 59 | end 60 | 61 | 62 | idx_wrap = reshape(1:prod(res_wrap), res_wrap); 63 | 64 | v1_wrap = idx_wrap(1:end-1, 1:end-1); v1_wrap=v1_wrap(:)'; 65 | v2_wrap = idx_wrap(1:end-1, 2:end ); v2_wrap=v2_wrap(:)'; 66 | v3_wrap = idx_wrap(2:end , 1:end-1); v3_wrap=v3_wrap(:)'; 67 | v4_wrap = idx_wrap(2:end , 2:end ); v4_wrap=v4_wrap(:)'; 68 | 69 | F_wrap = [v1_wrap;v2_wrap;v3_wrap; v2_wrap;v4_wrap;v3_wrap]; 70 | F_wrap = reshape(F_wrap, [3, 2*length(v1_wrap)])'; 71 | 72 | % old way 73 | % edges = [F_wrap(:,1) F_wrap(:,2); F_wrap(:,2) F_wrap(:,3); F_wrap(:,3) F_wrap(:,1)]; 74 | % edge_norms = sqrt(sum((UV_wrap(edges(:,1),:)-UV_wrap(edges(:,2),:)).^2,2)); 75 | % edge_norms = reshape(edge_norms,size(F_wrap,1),3); 76 | 77 | % edges numbered same as opposite vertices 78 | edge_norms = [ ... 79 | sqrt(sum((UV_wrap(F_wrap(:,2),:)-UV_wrap(F_wrap(:,3),:)).^2,2)) ... 80 | sqrt(sum((UV_wrap(F_wrap(:,3),:)-UV_wrap(F_wrap(:,1),:)).^2,2)) ... 81 | sqrt(sum((UV_wrap(F_wrap(:,1),:)-UV_wrap(F_wrap(:,2),:)).^2,2)) ... 82 | ]; 83 | 84 | % correct indices 85 | res = [yRes,xRes]; 86 | idx = reshape(1:prod(res),res); 87 | if (xWrap) idx = [idx, idx(:,1)]; end 88 | if (yWrap) idx = [idx; idx(1,:)]; end 89 | idx_flat = idx(:); 90 | 91 | % this might not be neccessary, could just rebuild UV like before 92 | UV = reshape(UV_wrap,[size(idx_wrap),2]); 93 | UV = UV(1:end-yWrap,1:end-xWrap,:); 94 | UV = reshape(UV,xRes*yRes,2); 95 | 96 | F = [idx_flat(F_wrap(:,1)),idx_flat(F_wrap(:,2)),idx_flat(F_wrap(:,3))]; 97 | -------------------------------------------------------------------------------- /code/matlab/cube.m: -------------------------------------------------------------------------------- 1 | function [V,F] = cube(x,y,z) 2 | % CUBE Construct a mesh of the unit cube. Sides are ordered like sides of a 3 | % die (one of many dice). 4 | % 5 | % [V,F] = cube(x,y,z) 6 | % 7 | % Inputs: 8 | % x number of vertices along x-axis 9 | % y number of vertices along y-ayis 10 | % z number of vertices along z-azis 11 | % Outputs: 12 | % V x*y*z by 3 list of vertex positions 13 | % F #F by 3 list of triangle indices 14 | % 15 | % 16 | if nargin<2 17 | y = x; 18 | end 19 | if nargin<3 20 | z = y; 21 | end 22 | 23 | sam = [x y;z y;x z;x z;z y;x y]; 24 | axes = [0 1 0;0 1 0;1 0 0;1 0 0;0 1 0;0 1 0]; 25 | angles = [0 pi/2 pi/2 -pi/2 -pi/2 pi]; 26 | V = []; 27 | F = []; 28 | for s = 1:6 29 | [CV,CF] = create_regular_grid(sam(s,1),sam(s,2),0,0); 30 | CV(:,3) = 0; 31 | R = round(axisangle2matrix(axes(s,:),angles(s))); 32 | F = [F;size(V,1)+CF]; 33 | V = [V;(CV-0.5)*R+0.5]; 34 | end 35 | 36 | % Should be able to do this procedurally 37 | [V,~,J] = remove_duplicate_vertices(V,1e-12); 38 | F = J(F); 39 | % oops inside out 40 | F = fliplr(F); 41 | 42 | end 43 | -------------------------------------------------------------------------------- /code/matlab/file2cellArray.m: -------------------------------------------------------------------------------- 1 | function CA = file2cellArray(fname) 2 | % fname is a string that names a .txt file in the current directory. 3 | % CA is a cell array with CA{k} being the k-th line in the file. 4 | 5 | fid= fopen(fname, 'r'); 6 | ik= 0; 7 | while ~feof(fid) 8 | ik= ik+1; 9 | CA{ik}= fgetl(fid); 10 | end 11 | fclose(fid); -------------------------------------------------------------------------------- /code/matlab/generate_data.m: -------------------------------------------------------------------------------- 1 | function generate_data(source_dir,target_dir,cate,partname,goodlist) 2 | 3 | objlist=dir(source_dir); 4 | objlist(1:2)=[]; 5 | isdir1=[objlist.isdir]; 6 | objlist=objlist(isdir1); 7 | for i=1:length(objlist) 8 | if exist(fullfile(source_dir,objlist(i).name,['code.bad']),'file') 9 | 10 | source = fullfile(source_dir,objlist(i).name,['code.bad']); 11 | target = fullfile(source_dir,objlist(i).name,['code.mat']); 12 | movefile(source,target) 13 | end 14 | end 15 | 16 | % copy file 17 | if isempty(goodlist) 18 | goodlist={objlist.name}; 19 | else 20 | goodlist=file2cellArray(goodlist); 21 | end 22 | PrepareDataForVae(source_dir, target_dir, cate); 23 | % compute acap 24 | partlist=dir(target_dir); 25 | partlist(1:2)=[]; 26 | isdir1=[partlist.isdir]; 27 | partlist=partlist(isdir1); 28 | objnamecell=containers.Map(); 29 | maxobjnum=0; 30 | I=0; 31 | 32 | for i=1:length(partlist) 33 | 34 | list_bad=dir(fullfile(target_dir,partlist(i).name,'*.bad')); 35 | for k=1:length(list_bad) 36 | [~,badmatname]=fileparts(list_bad(k).name); 37 | source = fullfile(target_dir,partlist(i).name,[badmatname,'.bad']); 38 | target = fullfile(target_dir,partlist(i).name,[badmatname,'.obj']); 39 | movefile(source,target) 40 | end 41 | list=dir(fullfile(target_dir,partlist(i).name,'*.obj')); 42 | [~,id]=sort_nat({list.name}); 43 | list=list(id); 44 | objnamecell(partlist(i).name)=list; 45 | if length(list)>maxobjnum 46 | maxobjnum=length(list); 47 | I=i; 48 | end 49 | 50 | end 51 | % 52 | % symmatlist=dir([sym_dir,'*.mat']); 53 | maxobjlist=objnamecell(partlist(I).name); 54 | for i=1:length(partname) 55 | partlist(i).name=partname{i}; 56 | end 57 | 58 | for i=1:maxobjnum 59 | 60 | splitparts = strsplit(maxobjlist(i).name, '_'); 61 | index=splitparts{1}; 62 | if i==1 63 | symmetryf(i,:,:)=zeros(length(objnamecell),2*length(objnamecell)+9); 64 | modelname{i}='0'; 65 | continue; 66 | end 67 | % if ~exist(fullfile(sym_dir,[index,'.mat']),'file') 68 | % continue 69 | % end 70 | if ~exist(fullfile(source_dir,index,['code.mat']),'file') 71 | continue 72 | end 73 | symmat=load(fullfile(source_dir,index,['code.mat'])); 74 | % symf=reshape(symmat.symmetry_feature,5,[]); 75 | symf=symmat.code; 76 | matuse=zeros(length(partlist),1); 77 | for fid=1:length(objnamecell) 78 | if exist(fullfile(target_dir,partlist(fid).name,[index,'_',partlist(fid).name,'.obj']),'file') 79 | matuse(fid)=1; 80 | end 81 | end 82 | if all(symf(:,1)==matuse) && ismember(index,goodlist) 83 | symmetryf(i,:,:)=symf; 84 | modelname{i}=index; 85 | else 86 | for k=1:length(objnamecell) 87 | if exist(fullfile(target_dir,partlist(k).name,[index,'_',partlist(k).name,'.obj']),'file') 88 | movefile(fullfile(target_dir,partlist(k).name,[index,'_',partlist(k).name,'.obj']),fullfile(target_dir,partlist(k).name,[index,'_',partlist(k).name,'.bad'])) 89 | end 90 | end 91 | movefile(fullfile(source_dir,index,['code.mat']),fullfile(source_dir,index,['code.bad'])) 92 | end 93 | end 94 | 95 | %compute acap 96 | for i=1:length(partlist) 97 | ACAPOpt(fullfile(target_dir,partlist(i).name)); 98 | % get_vaefeature(fullfile(target_dir,partlist(i).name),partlist(i).name) 99 | end 100 | deleteid=sum(sum(abs(symmetryf),2),3)==0; 101 | deleteid(1)=0; 102 | symmetryf(deleteid,:,:)=[]; 103 | modelname(deleteid)=[]; 104 | 105 | get_vaefeatureforallpart(target_dir,modelname,symmetryf, cate) 106 | 107 | end -------------------------------------------------------------------------------- /code/matlab/get_direction.m: -------------------------------------------------------------------------------- 1 | function [direction] = get_direction(A, B) 2 | distances = pdist2(A, B);%calculate the distance between 2 datasets 3 | minDistance = min(distances(:));%find the minimum value of distance 4 | [rowOfA, rowOfB] = find(distances == minDistance); 5 | A_coord_closest=A(rowOfA,:); 6 | B_coord_closest=B(rowOfB,:); 7 | direction = A_coord_closest - B_coord_closest; 8 | end 9 | -------------------------------------------------------------------------------- /code/matlab/get_vaefeatureforallpart.m: -------------------------------------------------------------------------------- 1 | %stack vae script 2 | function get_vaefeatureforallpart(datafolder,modelname, symmetryf, name) 3 | partlist=dir(datafolder); 4 | partlist(1:2)=[]; 5 | isdir1=[partlist.isdir]; 6 | partlist=partlist(isdir1); 7 | warning off 8 | % objlist=dir([datafolder,'\*.obj']); 9 | % [~,i]=sort_nat({objlist.name}); 10 | % objlist = objlist(i); 11 | vertex=[]; 12 | for i=1:length(modelname) 13 | for p=1:length(partlist) 14 | if exist(fullfile(datafolder,partlist(p).name,[modelname{i},'_',partlist(p).name,'.obj']),'file') 15 | [v,~]=readobjfromfile(fullfile(datafolder,partlist(p).name,[modelname{i},'_',partlist(p).name,'.obj'])); 16 | vertex(i,p,:,:)=v; 17 | else 18 | vertex(i,p,:,:)=zeros(size(v,1),3); 19 | end 20 | end 21 | end 22 | 23 | firstobj=fullfile(datafolder,partlist(1).name,[modelname{1},'_',partlist(1).name,'.obj']); 24 | [ v, f, ~, ~, L_, VVsimp, CotWeight] = cotlp(firstobj); 25 | W = full(CotWeight); 26 | pointnum = size(W,1); 27 | D = zeros(pointnum); 28 | for i = 1:pointnum 29 | D(i,i) = sum(W(i,:)); 30 | end 31 | L = D-W; 32 | recon = inv(L'*L)*L'; 33 | 34 | neighbour=zeros(size(v,1),100); 35 | maxnum=0; 36 | for i=1:size(VVsimp,1) 37 | neighbour(i,1:size(VVsimp{i,:},2))=VVsimp{i,:}; 38 | if size(VVsimp{i,:},2)>maxnum 39 | maxnum=size(VVsimp{i,:},2); 40 | end 41 | end 42 | neighbour(:,maxnum+1:end)=[]; 43 | 44 | for i = 1:pointnum 45 | for j = 1:maxnum 46 | curneighbour = neighbour(i,j); 47 | if curneighbour == 0 48 | break 49 | end 50 | w = W(i,curneighbour)/2; 51 | vdiff(i,j,:) = w*(v(i,:)-v(curneighbour,:)); 52 | edges1Ring(i,j) = sqrt(sum((v(i,:)-v(curneighbour,:)).^2)); 53 | if neighbour(i,j)>0 54 | % cotweight(i,j)=CotWeight(i,neighbour2(i,j)); 55 | cotweight(i,j)=1/length(nonzeros(neighbour(i,:))); 56 | end 57 | end 58 | end 59 | W1 = full(L_); 60 | for i = 1:size(W1,1) 61 | for j = 1:size(W1,2) 62 | if W1(i,j) ~= 0 63 | W1(i,j)=1; 64 | end 65 | end 66 | end 67 | 68 | % LOGRNEW=dlmread([datafolder,'\LOGRNEW.txt']); 69 | % S=dlmread([datafolder,'\S.txt']); 70 | logrling=zeros(1,pointnum,3); 71 | sling=zeros(1,pointnum,6); 72 | for p=1:length(partlist) 73 | partfolder = fullfile(datafolder,partlist(p).name); 74 | objlist=dir([partfolder,'\*.obj']); 75 | [~,i]=sort_nat({objlist.name}); 76 | objlist = objlist(i); 77 | modelname_postfix=cellfun(@(x) [x,'_',partlist(p).name,'.obj'],modelname,'UniformOutput',false); 78 | [~,id]=ismember(modelname_postfix,{objlist.name}); 79 | if exist([partfolder,'\simp\FeatureMatgao.mat'],'file') 80 | fv=load([partfolder,'\simp\FeatureMatgao.mat']); 81 | LOGRNEW=fv.LOGRNEW; 82 | S=fv.S; 83 | elseif exist([partfolder,'\fv_r.mat'],'file') 84 | fv=load([partfolder,'\fv_r.mat']); 85 | LOGRNEW=fv.LOGR; 86 | S=fv.S; 87 | else 88 | LOGRNEW=dlmread([partfolder,'\LOGRNEW.txt']); 89 | S=dlmread([partfolder,'\S.txt']); 90 | end 91 | [ fmlogdr, fms ] = FeatureMap( LOGRNEW, S ); 92 | fmlogdr=permute(reshape(fmlogdr,size(fmlogdr,1),3,pointnum),[1,3,2]); 93 | fms=permute(reshape(fms,size(fms,1),6,pointnum),[1,3,2]); 94 | fmlogdr=[fmlogdr;logrling]; 95 | fms=[fms;sling]; 96 | id(id==0)=size(fms,1); 97 | FLOGRNEW(:,p,:,:)=fmlogdr(id,:,:); 98 | FS(:,p,:,:)=fms(id,:,:); 99 | end 100 | ref_V=v; 101 | ref_F=f'; 102 | 103 | % [ fmlogdr, fms ] = FeatureMap( fv.LOGRNEW, fv.S ); 104 | % feature = cat(2, fms, fmlogdr); 105 | save([datafolder,'\',name,'_vaefeature.mat'],'ref_V','ref_F','FLOGRNEW','FS','L',... 106 | 'neighbour','recon','vdiff','vertex','cotweight','W1','symmetryf','modelname','partlist','-v7.3') 107 | end 108 | 109 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /code/matlab/getlabel.m: -------------------------------------------------------------------------------- 1 | function part_names = getlabel(cate) 2 | type = cate; 3 | if strcmp(type, 'chair') == 1 4 | part_names = {'armrest1_1', 'armrest1_2', 'back', 'leg1_1', 'leg1_2', 'leg2_1', 'leg2_2', 'seat', 'armrest2_1', 'armrest2_2'}; 5 | elseif strcmp(type, 'knife') == 1 6 | part_names = {'part1', 'part2'}; 7 | elseif strcmp(type, 'guitar') == 1 8 | part_names = {'part1', 'part2', 'part3'}; 9 | elseif strcmp(type, 'monitor') == 1 10 | part_names = {'display', 'connector', 'base'}; 11 | elseif strcmp(type, 'cup') == 1 12 | part_names = {'part1', 'part2'}; 13 | elseif strcmp(type, 'car') == 1 14 | part_names = {'body', 'left_front_wheel', 'right_front_wheel', 'left_back_wheel', 'right_back_wheel', 'left_mirror', 'right_mirror'}; 15 | elseif strcmp(type, 'plane') == 1 16 | part_names = {'body', 'left_wing', 'right_wing', 'left_tail', 'right_tail', 'upper_tail', 'down_tail', 'front_gear', 'left_gear', 'right_gear', 'left_engine1', 'right_engine1', 'left_engine2', 'right_engine2'}; 17 | elseif strcmp(type, 'table') == 1 18 | part_names = {'surface', 'leg1_1', 'leg1_2', 'leg2_1', 'leg2_2', 'leg3_1', 'leg3_2', 'leg4_1', 'leg4_2'}; 19 | end 20 | end -------------------------------------------------------------------------------- /code/matlab/isout.m: -------------------------------------------------------------------------------- 1 | function all=isout(data) 2 | % c=mean(data); 3 | % data=abs(data-c); 4 | all=zeros(length(data),1); 5 | [data_sort,id]=sort(data); 6 | grad=diff(data_sort); 7 | 8 | idx = find(grad > 0.02); 9 | if ~isempty(idx) 10 | if idx finishSz 73 | obj.waitMsg= waitMsg; 74 | obj.finishTimeMsg= [ repmat( ' ', 1, waitSz - finishSz ), ... 75 | finishTimeMsg ]; 76 | else 77 | obj.finishTimeMsg= finishTimeMsg; 78 | obj.waitMsg= [ repmat( ' ', 1, finishSz - waitSz ), ... 79 | waitMsg ]; 80 | end 81 | obj.format= [ '%03d:%02d:%04.1f' ... % hh:mm:ss.s 82 | obj.percentDoneMsg '%3.0f%%']; % 4 characters wide, percentage 83 | obj.textWidth= length(obj.waitMsg) + 3 + 1 + 2 + 1 + 4 + ... 84 | length(obj.percentDoneMsg) + 1 + 2 + 1; 85 | fprintf(1, [ repmat( ' ', 1, 20 ) '\n' ] ); % buffers multitasking uncertanties of the output to the command line 86 | obj.showStatus( 0, [ repmat( ' ', 1, obj.textWidth-4 ),' 0%' ] ); 87 | end 88 | 89 | function percent= progress(obj) 90 | obj.updateFile(); 91 | [ percent, remainingTime, timeElapsed ]= obj.getProgress(); 92 | timedMsg= obj.getTimedMsg( remainingTime, percent ); 93 | obj.showStatus( percent, [ obj.waitMsg timedMsg ] ); 94 | end 95 | 96 | function [ percent, timeElapsed ]= stop(obj) 97 | [ percent, ~, timeElapsed ]= obj.getProgress(); 98 | delete( obj.fname ); 99 | percent= 100; 100 | timedMsg= obj.getTimedMsg( timeElapsed, percent ); 101 | obj.showStatus( percent, [ obj.finishTimeMsg timedMsg ] ); 102 | end 103 | 104 | end 105 | 106 | methods ( Static ) 107 | 108 | function fname= getFName() 109 | baseName= './.timedBar/timedProgressbar_Transient(deleteThis)_'; 110 | fname= [ baseName, num2str(randi(1000)) '.txt' ]; 111 | while exist( fname, 'file' ) 112 | fname= [ baseName, num2str(randi(1000)) '.txt' ]; 113 | end 114 | end 115 | 116 | end 117 | 118 | 119 | methods ( Access= protected ) 120 | 121 | function fname= setFName(obj) 122 | fname= obj.getFName(); 123 | while exist( fname, 'file' ) 124 | fname= obj.getFName(); 125 | end 126 | end 127 | 128 | function [ percent, remainingTime, timeElapsed ]= getProgress(obj) 129 | f= fopen( obj.fname, 'r' ); 130 | [ readbuffer, progressCountPlus2 ]= fscanf( f, '%ld' ); 131 | fclose( f ); 132 | 133 | ticInit= uint64( readbuffer(1) ); 134 | timeElapsed= toc( ticInit ); 135 | 136 | progressCount= progressCountPlus2 - 2; 137 | targetCount= double( readbuffer(2) ); % avoids Matlab's buggy assumption of readbuffer type as uint64 138 | 139 | percent = progressCount * 100 / targetCount; 140 | if percent > 0 141 | remainingTime= timeElapsed * ( 100 / percent - 1 ); 142 | else 143 | remainingTime= timeElapsed * 200; % initial duration estimate 144 | end 145 | end 146 | 147 | function showStatus( obj, percent, statusMsg ) 148 | x= round( percent * obj.barWidth / 100 ); 149 | marker= '>'; 150 | if x < obj.barWidth 151 | bar= [ ' [', repmat( '=', 1, x ), marker, ... 152 | repmat( ' ', 1, obj.barWidth - x - 1 ), ']' ]; 153 | else 154 | bar= [ ' [', repmat( '=', 1, x ), ... 155 | repmat( ' ', 1, obj.barWidth - x ), ']' ]; 156 | end 157 | statusLine= [ statusMsg, bar ]; 158 | 159 | % console print: 160 | % <--------status message----------->_[<------progress bar----->] 161 | % Wait for 001:28:36.7, completed 38% [========> ] 162 | 163 | if percent > 0 && percent < 100 164 | cursorRewinder= repmat( char(8), 1, 1+obj.rewindLength ); 165 | disp( [ cursorRewinder, statusLine ] ); 166 | % disp(statusLine) 167 | elseif percent == 100 168 | cursorRewinder= repmat( char(8), 1, 1+obj.rewindLength ); 169 | disp( [ cursorRewinder, statusLine ] ); 170 | else % percent == 0 171 | disp( statusLine ); 172 | end 173 | obj.rewindLength= length( statusLine ); 174 | end 175 | 176 | function timedMsg= getTimedMsg( obj, timeSec, percent ) 177 | hh= fix( timeSec / 3600 ); 178 | mm= fix( ( timeSec - hh * 3600 ) / 60 ); 179 | ss= max( ( timeSec - hh * 3600 - mm * 60 ), 0.1 ); 180 | timedMsg = sprintf( obj.format, hh, mm, ss, percent ); 181 | end 182 | 183 | function updateFile(obj) 184 | if ~exist( obj.fname, 'file' ) 185 | error( [ obj.fname ' not found. It must have been deleted.' ] ); 186 | end 187 | f = fopen(obj.fname, 'a'); 188 | fprintf(f, '1\n'); 189 | fclose(f); 190 | end 191 | 192 | end 193 | 194 | end 195 | -------------------------------------------------------------------------------- /code/matlab/nonregistration/mkdirOptional.m: -------------------------------------------------------------------------------- 1 | function [] = mkdirOptional(dirName) 2 | %MKDIROPTIONAL Summary of this function goes here 3 | % Detailed explanation goes here 4 | 5 | if(~exist(dirName,'dir')) 6 | mkdir(dirName) 7 | end 8 | 9 | end 10 | 11 | -------------------------------------------------------------------------------- /code/matlab/nonregistration/nonrigidregis.m: -------------------------------------------------------------------------------- 1 | function nonrigidregis(folder,name) 2 | 3 | % w1 plane s2 point w3 global rigid w4 local rigid 4 | 5 | if nargin>1 6 | numpart=1; 7 | else 8 | samplelist=dir([folder,'\transformed_cube_*.obj']); 9 | numpart=length(samplelist); 10 | end 11 | for i=1:numpart 12 | 13 | if nargin<1 14 | samplefile = samplelist(i).name; 15 | splitparts = strsplit(samplefile, '_'); 16 | [~,name]=fileparts(splitparts{3}); 17 | end 18 | 19 | srcfile = fullfile(folder, ['transformed_cube_',name, '.obj']); 20 | tarfile = fullfile(folder, [name,'.obj']); 21 | savefile = fullfile(folder, [name, '_reg.obj']); 22 | 23 | % srcfile=[folder,'\part',num2str(i),'.obj']; 24 | % tarfile=[folder,'\sample_part',num2str(i),'_pc.obj']; 25 | % savefile =[folder,'\part',num2str(i),'_reg.obj']; 26 | w1 = 7; 27 | w2 = 0.0; 28 | w3 = 0; 29 | w4 = 40; 30 | % w1 = 50.0; 31 | % w2 = 100; 32 | % w3 = 1500; 33 | % w4 = 90; 34 | iter = 40; 35 | % regis_union(srcfile, tarfile, savefile); 36 | if exist(srcfile,'file')&&exist(tarfile,'file') 37 | 38 | 39 | if ~exist(savefile,'file') 40 | try 41 | NonRigidAlignment3Dnew(srcfile,tarfile, iter,savefile,w1,w2,w3,w4); 42 | % denoise_mesh1(tmpfile, savefile) 43 | % end 44 | catch 45 | continue 46 | end 47 | end 48 | end 49 | 50 | end 51 | end -------------------------------------------------------------------------------- /code/matlab/nonregistration/register_script.m: -------------------------------------------------------------------------------- 1 | % register 2 | pathFolder = 'G:\wutong\sig2019\shapenetcore_segmentation\03624134_knif\divide_with_face30000' 3 | 4 | d = dir(pathFolder); 5 | isub = [d(:).isdir]; %# returns logical vector 6 | nameFolds = {d(isub).name}'; 7 | nameFolds(ismember(nameFolds,{'.','..'})) = []; 8 | parfor i = 1:size(nameFolds, 1) 9 | nonrigidregis([pathFolder, '\', nameFolds{i}],'part1') 10 | end 11 | parfor i = 1:size(nameFolds, 1) 12 | nonrigidregis([pathFolder, '\', nameFolds{i}],'part2') 13 | end 14 | 15 | 16 | -------------------------------------------------------------------------------- /code/matlab/nonregistration/search_nn_bidirector.m: -------------------------------------------------------------------------------- 1 | function [sqrDz,P,NP]=search_nn_bidirector(Z,ZF,Y,YF,NFY) 2 | % find the nnpoint bi-directory 3 | [sqrDz,Iz,Cz] = point_mesh_squared_distance(Z,Y,YF); 4 | % idz=knnsearch(Y,Cz); 5 | 6 | [sqrDy,Iy,Cy] = point_mesh_squared_distance(Y,Z,ZF); 7 | id_out=find(sqrDy>0.0001); 8 | id_out=[]; 9 | if ~isempty(id_out) 10 | on_Source = Cy(id_out,:); 11 | idy=knnsearch(Z,on_Source); 12 | y_out=Y(id_out,:); 13 | Cz(idy,:)=y_out; 14 | sqrDz(idy,:)=sqrDy(id_out,:); 15 | 16 | P=Cz; 17 | NP=NFY(Iz,:); 18 | 19 | for i=1:length(id_out) 20 | id=find(sum(YF==id_out(i),2)==1); 21 | if isempty(id) 22 | continue; 23 | end 24 | NP(idy(i),:)=mean(NFY(id,:)); 25 | end 26 | else 27 | P = Cz; 28 | NP = NFY(Iz,:); 29 | end 30 | end -------------------------------------------------------------------------------- /code/matlab/normalizerow.m: -------------------------------------------------------------------------------- 1 | function [ A ] = normalizerow( A ) %#codegen 2 | % NORMALIZEROW Normalize each row so that each row's l2 norm as a vector is 1 3 | % 4 | % [ A ] = normalizerow( A ) 5 | % 6 | % Input: 7 | % A #A by D list of row vectors of dimension D 8 | % Output: 9 | % B #B by D list of normalized row vectors 10 | % 11 | % Copyright 2011, Alec Jacobson (jacobson@inf.ethz.ch), Daniele Panozzo 12 | % 13 | 14 | if issparse(A) 15 | % speed up (20x) for large sparse matrices 16 | A = bsxfun(@times,A,1./sqrt(sum(A.^2,2))); 17 | else 18 | A = A./repmat(sqrt(sum(A.^2,2)),1,size(A,2)); 19 | end 20 | end 21 | 22 | -------------------------------------------------------------------------------- /code/matlab/optimize.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gaolinorange/SDMNET_stamp/5208f1210b77e3251dde3bdafc120a48dc69e833/code/matlab/optimize.exe -------------------------------------------------------------------------------- /code/matlab/patchslim.m: -------------------------------------------------------------------------------- 1 | function [vnew, fnew]=patchslim(v, f) 2 | % PATCHSLIM removes duplicate vertices in surface meshes. 3 | % 4 | % This function finds and removes duplicate vertices. 5 | % 6 | % USAGE: [v, f]=patchslim(v, f) 7 | % 8 | % Where v is the vertex list and f is the face list specifying vertex 9 | % connectivity. 10 | % 11 | % v contains the vertices for all triangles [3*n x 3]. 12 | % f contains the vertex lists defining each triangle face [n x 3]. 13 | % 14 | % This will reduce the size of typical v matrix by about a factor of 6. 15 | % 16 | % For more information see: 17 | % http://www.esmonde-white.com/home/diversions/matlab-program-for-loading-stl-files 18 | % 19 | % Francis Esmonde-White, May 2010 20 | if ~exist('v','var') 21 | error('The vertex list (v) must be specified.'); 22 | end 23 | if ~exist('f','var') 24 | error('The vertex connectivity of the triangle faces (f) must be specified.'); 25 | end 26 | [vnew, indexm, indexn] = unique(v, 'rows'); 27 | fnew = indexn(f); -------------------------------------------------------------------------------- /code/matlab/point_mesh_squared_distance.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gaolinorange/SDMNET_stamp/5208f1210b77e3251dde3bdafc120a48dc69e833/code/matlab/point_mesh_squared_distance.mexw64 -------------------------------------------------------------------------------- /code/matlab/readOBJ.m: -------------------------------------------------------------------------------- 1 | function [V,F,UV,TF,N,NF] = readOBJ(filename,varargin) 2 | % READOBJ reads an OBJ file with vertex/face information 3 | % 4 | % [V,F,UV,TF,N,NF] = readOBJ(filename) 5 | % [V,F,UV,TF,N,NF] = readOBJ(filename,'ParameterName',ParameterValue,...) 6 | % 7 | % Input: 8 | % filename path to .obj file 9 | % Optional: 10 | % 'Quads' whether to output face information in X by 4 matrices (faces 11 | % with degree larger than 4 are still triangulated). A trailing zero 12 | % will mean a triangle was read. 13 | % Outputs: 14 | % V #V by 3 list of vertices 15 | % F #F by 3 list of triangle indices 16 | % UV #UV by 2 list of texture coordinates 17 | % TF #F by 3 list of triangle texture coordinates 18 | % N #N by 3 list of normals 19 | % NF #F by 3 list of triangle corner normal indices into N 20 | % 21 | % Examples: 22 | % % read a quad/triangle mesh and display it 23 | % [V,F] = readOBJ('quads.obj','Quads',true); 24 | % % Turn triangles into degenerate quads 25 | % DF = (F==0).*F(:,[4 1 2 3])+(F~=0).*F; 26 | % trisurf(DF,V(:,1),V(:,2),V(:,3)); 27 | % 28 | % 29 | % See also: load_mesh, readOBJfast, readOFF 30 | 31 | % default values 32 | quads = false; 33 | % Map of parameter names to variable names 34 | params_to_variables = containers.Map( ... 35 | {'Quads'}, ... 36 | {'quads'}); 37 | v = 1; 38 | while v <= numel(varargin) 39 | param_name = varargin{v}; 40 | if isKey(params_to_variables,param_name) 41 | assert(v+1<=numel(varargin)); 42 | v = v+1; 43 | % Trick: use feval on anonymous function to use assignin to this workspace 44 | feval(@()assignin('caller',params_to_variables(param_name),varargin{v})); 45 | else 46 | error('Unsupported parameter: %s',varargin{v}); 47 | end 48 | v=v+1; 49 | end 50 | 51 | numv = 0; 52 | numf = 0; 53 | numuv = 0; 54 | numtf = 0; 55 | numn = 0; 56 | numnf = 0; 57 | 58 | % simplex size 59 | if quads 60 | ss = 4; 61 | else 62 | ss = 3; 63 | end 64 | % Amortized array allocation 65 | V = zeros(10000,3); 66 | F = zeros(10000,ss); 67 | UV = zeros(10000,3); 68 | TF = zeros(10000,ss); 69 | N = zeros(10000,3); 70 | NF = zeros(10000,ss); 71 | 72 | triangulated = false; 73 | all_ss = true; 74 | fp = fopen( filename, 'r' ); 75 | type = fscanf( fp, '%s', 1 ); 76 | count = 0; 77 | while strcmp( type, '' ) == 0 78 | line = fgets(fp); 79 | if strcmp( type, 'v' ) == 1 80 | v = sscanf( line, '%lf %lf %lf' ); 81 | numv = numv+1; 82 | if(numv>size(V,1)) 83 | V = cat(1,V,zeros(10000,3)); 84 | end 85 | V(numv,:) = [v(1:3)']; 86 | elseif strcmp( type, 'vt') 87 | v = sscanf( line, '%f %f %f' ); 88 | numuv = numuv+1; 89 | if size(UV,2)>2 && length(v) == 2 90 | UV = UV(:,1:2); 91 | end 92 | if(numuv>size(UV,1)) 93 | UV = cat(1,UV,zeros(10000,length(v))); 94 | end 95 | UV(numuv,:) = [v']; 96 | elseif strcmp( type, 'vn') 97 | n = sscanf( line, '%f %f %f' ); 98 | numn = numn+1; 99 | if(numn>size(N,1)) 100 | N = cat(1,N,zeros(10000,3)); 101 | end 102 | N(numn,:) = [n']; 103 | elseif strcmp( type, 'f' ) == 1 104 | [t, count] = sscanf(line,'%d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d %d/%d/%d'); 105 | if (count>2) 106 | tf = t(2:3:end); 107 | nf = t(3:3:end); 108 | t = t(1:3:end); 109 | else 110 | [t, count] = sscanf(line, '%d/%d %d/%d %d/%d %d/%d %d/%d'); 111 | if (count>2) 112 | tf = t(2:2:end); 113 | t = t(1:2:end); 114 | nf = -ones(numel(t),1); 115 | else 116 | [t, count] = sscanf(line, '%d//%d %d//%d %d//%d %d//%d %d//%d'); 117 | if (count>2) 118 | nf = t(2:2:end); 119 | t = t(1:2:end); 120 | tf = -ones(numel(t),1); 121 | else 122 | [t, count] = sscanf( line, '%d %d %d %d %d %d %d %d %d %d %d\n' ); 123 | if (count>2) 124 | tf = -ones(numel(t),1); 125 | nf = -ones(numel(t),1); 126 | else 127 | [t, count] = sscanf( line, '%d// %d// %d// %d// %d// %d// %d// %d// %d// %d// %d//\n' ); 128 | tf = -ones(numel(t),1); 129 | nf = -ones(numel(t),1); 130 | end 131 | end 132 | end 133 | end 134 | t = t + (t<0).* (numv+1); 135 | tf = tf + (tf<0).*(numuv+1); 136 | nf = nf + (nf<0).*(numn+1); 137 | 138 | assert(numel(t) == numel(tf)); 139 | assert(numel(t) == numel(nf)); 140 | if numel(t) > ss 141 | if ~triangulated 142 | warning('Trivially triangulating high degree facets'); 143 | end 144 | triangulated = true; 145 | end 146 | j = 2; 147 | i = 1; 148 | %Vt = V(t,:); 149 | %[~,A] = affine_fit(Vt); 150 | %VtA = Vt*A; 151 | %VtA0 = Vt*A; 152 | %[~,alpha] = curvature(VtA); 153 | %flip = -sign(sum(alpha)); 154 | %E = [1:size(VtA,1);2:size(VtA,1) 1]'; 155 | %[dV,dF] = triangle(VtA,E,[]); 156 | %if size(dF,1)>2 157 | % tsurf(dF,dV); 158 | % hold on; 159 | % plot(VtA0([1:end 1],1),VtA0([1:end 1],2),'LineWidth',3); 160 | % hold off 161 | % pause 162 | %end 163 | while true 164 | if numel(t) > ss 165 | corners = [1 2 3]; 166 | 167 | %plot(VtA0([1:end 1],1),VtA0([1:end 1],2)); 168 | %hold on; 169 | %plot(VtA([1:3],1),VtA([1:3],2),'LineWidth',3); 170 | %hold off; 171 | %expand_axis(2); 172 | %pause; 173 | 174 | %[~,alpha] = curvature(VtA,[1 2;2 3]); 175 | %alpha = flip * alpha(2); 176 | %others = VtA(setdiff(1:end,corners),:); 177 | %these = VtA(corners,:); 178 | %w = inpolygon(others(:,1),others(:,2),these(:,1),these(:,2)); 179 | %alpha 180 | %if alpha>=0 && ~any(w) 181 | % % lazy 182 | % t = t([2:end 1]); 183 | % VtA = VtA([2:end 1],:); 184 | % continue; 185 | %end 186 | else 187 | if all_ss && numel(t)size(F,1)) 195 | F = cat(1,F,zeros(10000,ss)); 196 | end 197 | F(numf,1:numel(corners)) = [t(corners)']; 198 | numtf = numtf+1; 199 | if(numtf>size(TF,1)) 200 | TF = cat(1,TF,zeros(10000,ss)); 201 | end 202 | TF(numtf,1:numel(corners)) = [tf(corners)']; 203 | numnf = numnf+1; 204 | if(numnf>size(NF,1)) 205 | NF = cat(1,NF,zeros(10000,ss)); 206 | end 207 | NF(numnf,1:numel(corners)) = [nf(corners)']; 208 | if numel(t) <= ss 209 | break; 210 | end 211 | t = t([1 3:end]); 212 | tf = tf([1 3:end]); 213 | nf = nf([1 3:end]); 214 | %VtA = VtA([1 3:end],:); 215 | if numel(t) < 3 216 | break; 217 | end 218 | end 219 | elseif strcmp( type, '#' ) == 1 220 | %fscanf( fp, '%s\n', 1 ); 221 | % ignore line 222 | end 223 | type = fscanf( fp, '%s', 1 ); 224 | end 225 | fclose( fp ); 226 | 227 | %try 228 | % F = cell2mat(F); 229 | %end 230 | V = V(1:numv,:); 231 | F = F(1:numf,:); 232 | UV = UV(1:numuv,:); 233 | TF = TF(1:numtf,:); 234 | N = N(1:numn,:); 235 | NF = NF(1:numnf,:); 236 | 237 | %% transform into array if all faces have the same number of vertices 238 | 239 | if (size(UV,1)>0) UV = UV; end 240 | 241 | end 242 | -------------------------------------------------------------------------------- /code/matlab/readme.txt: -------------------------------------------------------------------------------- 1 | optimize Executable 2 | 3 | 1. Prerequisites for Deployment 4 | 5 | Verify that version 9.6 (R2019a) of the MATLAB Runtime is installed. 6 | If not, you can run the MATLAB Runtime installer. 7 | To find its location, enter 8 | 9 | >>mcrinstaller 10 | 11 | at the MATLAB prompt. 12 | NOTE: You will need administrator rights to run the MATLAB Runtime installer. 13 | 14 | Alternatively, download and install the Windows version of the MATLAB Runtime for R2019a 15 | from the following link on the MathWorks website: 16 | 17 | http://www.mathworks.com/products/compiler/mcr/index.html 18 | 19 | For more information about the MATLAB Runtime and the MATLAB Runtime installer, see 20 | "Distribute Applications" in the MATLAB Compiler documentation 21 | in the MathWorks Documentation Center. 22 | 23 | 2. Files to Deploy and Package 24 | 25 | Files to Package for Standalone 26 | ================================ 27 | -optimize.exe 28 | -MCRInstaller.exe 29 | Note: if end users are unable to download the MATLAB Runtime using the 30 | instructions in the previous section, include it when building your 31 | component by clicking the "Runtime included in package" link in the 32 | Deployment Tool. 33 | -This readme file 34 | 35 | 36 | 37 | 3. Definitions 38 | 39 | For information on deployment terminology, go to 40 | http://www.mathworks.com/help and select MATLAB Compiler > 41 | Getting Started > About Application Deployment > 42 | Deployment Product Terms in the MathWorks Documentation 43 | Center. 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /code/matlab/readobjfromfile.mexw64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gaolinorange/SDMNET_stamp/5208f1210b77e3251dde3bdafc120a48dc69e833/code/matlab/readobjfromfile.mexw64 -------------------------------------------------------------------------------- /code/matlab/regist.m: -------------------------------------------------------------------------------- 1 | function regist(Dirpath, type) 2 | %% This process takes a long time 3 | d = dir(Dirpath); 4 | isub = [d(:).isdir]; %# returns logical vector 5 | nameFolds = {d(isub).name}'; 6 | nameFolds(ismember(nameFolds,{'.','..'})) = []; 7 | 8 | part_names=getlabel(type); 9 | 10 | 11 | for p=1:length(part_names) 12 | parfor i = 1:size(nameFolds, 1) 13 | nonrigidregis([Dirpath, '\', nameFolds{i}],part_names{p}) 14 | end 15 | end 16 | 17 | 18 | end -------------------------------------------------------------------------------- /code/matlab/remove_duplicate_vertices.m: -------------------------------------------------------------------------------- 1 | function [SV,SVI,SVJ] = remove_duplicate_vertices(V,epsilon,varargin) 2 | % REMOVE_DUPLICATE_VERTICES Remove duplicate vertices upto a uniqueness 3 | % tolerance (epsilon) 4 | % 5 | % SV = remove_duplicate_vertices(V,epsilon) 6 | % [SV,SVI,SVJ] = ... 7 | % remove_duplicate_vertices(V,epsilon,'ParameterName',ParameterValue,...) 8 | % 9 | % Inputs: 10 | % V #V by dim list of vertex positions 11 | % epsilon uniqueness tolerance (significant digit) 12 | % Optional: 13 | % 'WhiteList' Only merge vertices from the following selection (not 14 | % working correctly, yet) 15 | % Outputs: 16 | % SV #SV by dim new list of vertex positions 17 | % SVI #SV by 1 list of indices so SV = V(SVI,:) 18 | % SVJ #V by 1 list of indices so V = SV(SVJ,:) 19 | % 20 | % Example: 21 | % % Mesh in (V,F) 22 | % [SV,SVI,SVJ] = remove_duplicate_vertices(V,1e-7); 23 | % % remap faces 24 | % SF = SVJ(F); 25 | % 26 | 27 | % default values 28 | whitelist = []; 29 | % Map of parameter names to variable names 30 | params_to_variables = containers.Map( ... 31 | {'WhiteList'}, ... 32 | {'whitelist'}); 33 | v = 1; 34 | while v <= numel(varargin) 35 | param_name = varargin{v}; 36 | if isKey(params_to_variables,param_name) 37 | assert(v+1<=numel(varargin)); 38 | v = v+1; 39 | % Trick: use feval on anonymous function to use assignin to this workspace 40 | feval(@()assignin('caller',params_to_variables(param_name),varargin{v})); 41 | else 42 | error('Unsupported parameter: %s',varargin{v}); 43 | end 44 | v=v+1; 45 | end 46 | 47 | if isempty(whitelist) 48 | assert(nargin==1 || epsilon >= 0); 49 | if nargin==1 || epsilon == 0 50 | [SV,SVI,SVJ] = unique(V,'rows','stable'); 51 | else 52 | [~,SVI,SVJ] = unique(round(V/(10*epsilon)),'rows','stable'); 53 | SV = V(SVI,:); 54 | end 55 | else 56 | error('not implemented correctly') 57 | VW = V(whitelist,:); 58 | J = 1:size(V,1); 59 | JW = J(whitelist); 60 | [SVW,SVIW,SVJW] = remove_duplicate_vertices(VW,epsilon); 61 | SJ = 1:size(V,1); 62 | SJ(whitelist) = JW(SVJ); 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /code/matlab/removeoutliner.m: -------------------------------------------------------------------------------- 1 | function pcout=removeoutliner(pc) 2 | x=pc(:,1); 3 | y=pc(:,2); 4 | z=pc(:,3); 5 | tfx=isout(x); 6 | tfy=isout(y); 7 | tfz=isout(z); 8 | isouta=any([tfx,tfy,tfz],2); 9 | pcout=pc(~isouta,:); 10 | end -------------------------------------------------------------------------------- /code/matlab/requiredMCRProducts.txt: -------------------------------------------------------------------------------- 1 | 35010 -------------------------------------------------------------------------------- /code/matlab/sort_nat.m: -------------------------------------------------------------------------------- 1 | function [cs,index] = sort_nat(c,mode) 2 | %sort_nat: Natural order sort of cell array of strings. 3 | % usage: [S,INDEX] = sort_nat(C) 4 | % 5 | % where, 6 | % C is a cell array (vector) of strings to be sorted. 7 | % S is C, sorted in natural order. 8 | % INDEX is the sort order such that S = C(INDEX); 9 | % 10 | % Natural order sorting sorts strings containing digits in a way such that 11 | % the numerical value of the digits is taken into account. It is 12 | % especially useful for sorting file names containing index numbers with 13 | % different numbers of digits. Often, people will use leading zeros to get 14 | % the right sort order, but with this function you don't have to do that. 15 | % For example, if C = {'file1.txt','file2.txt','file10.txt'}, a normal sort 16 | % will give you 17 | % 18 | % {'file1.txt' 'file10.txt' 'file2.txt'} 19 | % 20 | % whereas, sort_nat will give you 21 | % 22 | % {'file1.txt' 'file2.txt' 'file10.txt'} 23 | % 24 | % See also: sort 25 | 26 | % Version: 1.4, 22 January 2011 27 | % Author: Douglas M. Schwarz 28 | % Email: dmschwarz=ieee*org, dmschwarz=urgrad*rochester*edu 29 | % Real_email = regexprep(Email,{'=','*'},{'@','.'}) 30 | 31 | 32 | % Set default value for mode if necessary. 33 | if nargin < 2 34 | mode = 'ascend'; 35 | end 36 | 37 | % Make sure mode is either 'ascend' or 'descend'. 38 | modes = strcmpi(mode,{'ascend','descend'}); 39 | is_descend = modes(2); 40 | if ~any(modes) 41 | error('sort_nat:sortDirection',... 42 | 'sorting direction must be ''ascend'' or ''descend''.') 43 | end 44 | 45 | % Replace runs of digits with '0'. 46 | c2 = regexprep(c,'\d+','0'); 47 | 48 | % Compute char version of c2 and locations of zeros. 49 | s1 = char(c2); 50 | z = s1 == '0'; 51 | 52 | % Extract the runs of digits and their start and end indices. 53 | [digruns,first,last] = regexp(c,'\d+','match','start','end'); 54 | 55 | % Create matrix of numerical values of runs of digits and a matrix of the 56 | % number of digits in each run. 57 | num_str = length(c); 58 | max_len = size(s1,2); 59 | num_val = NaN(num_str,max_len); 60 | num_dig = NaN(num_str,max_len); 61 | for i = 1:num_str 62 | num_val(i,z(i,:)) = sscanf(sprintf('%s ',digruns{i}{:}),'%f'); 63 | num_dig(i,z(i,:)) = last{i} - first{i} + 1; 64 | end 65 | 66 | % Find columns that have at least one non-NaN. Make sure activecols is a 67 | % 1-by-n vector even if n = 0. 68 | activecols = reshape(find(~all(isnan(num_val))),1,[]); 69 | n = length(activecols); 70 | 71 | % Compute which columns in the composite matrix get the numbers. 72 | numcols = activecols + (1:2:2*n); 73 | 74 | % Compute which columns in the composite matrix get the number of digits. 75 | ndigcols = numcols + 1; 76 | 77 | % Compute which columns in the composite matrix get chars. 78 | charcols = true(1,max_len + 2*n); 79 | charcols(numcols) = false; 80 | charcols(ndigcols) = false; 81 | 82 | % Create and fill composite matrix, comp. 83 | comp = zeros(num_str,max_len + 2*n); 84 | comp(:,charcols) = double(s1); 85 | comp(:,numcols) = num_val(:,activecols); 86 | comp(:,ndigcols) = num_dig(:,activecols); 87 | 88 | % Sort rows of composite matrix and use index to sort c in ascending or 89 | % descending order, depending on mode. 90 | [unused,index] = sortrows(comp); 91 | if is_descend 92 | index = index(end:-1:1); 93 | end 94 | index = reshape(index,size(c)); 95 | cs = c(index); 96 | -------------------------------------------------------------------------------- /code/matlab/writeOBJ.m: -------------------------------------------------------------------------------- 1 | function writeOBJ(filename, V,F,UV,TF,N,NF) 2 | % WRITEOBJ writes an OBJ file with vertex/face information 3 | % 4 | % writeOBJ(filename,V,F,UV,N) 5 | % 6 | % Input: 7 | % filename path to .obj file 8 | % V #V by 3 list of vertices 9 | % F #F by 3 list of triangle indices 10 | % UV #UV by 2 list of texture coordinates 11 | % TF #TF by 3 list of corner texture indices into UV 12 | % N #N by 3 list of normals 13 | % NF #NF by 3 list of corner normal indices into N 14 | % 15 | 16 | %disp(['writing: ',filename]); 17 | f = fopen( filename, 'w' ); 18 | 19 | 20 | if size(V,2) == 2 21 | warning('Appending 0s as z-coordinate'); 22 | V(:,end+1:3) = 0; 23 | else 24 | assert(size(V,2) == 3); 25 | end 26 | fprintf( f, 'v %0.17g %0.17g %0.17g\n', V'); 27 | 28 | hasN = exist('N','var') && ~isempty(N); 29 | hasUV = exist('UV','var') && ~isempty(UV); 30 | 31 | if hasUV 32 | switch size(UV,2) 33 | case 2 34 | fprintf( f, 'vt %0.17g %0.17g\n', UV'); 35 | case 3 36 | fprintf( f, 'vt %0.17g %0.17g %0.17g\n', UV'); 37 | end 38 | end 39 | 40 | if hasN 41 | %for k=1:size(N,1) 42 | % fprintf( f, 'vn %f %f %f\n', N(k,1), N(k,2), N(k,3) ); 43 | %end 44 | fprintf( f, 'vn %0.17g %0.17g %0.17g\n', N'); 45 | end 46 | 47 | if hasUV && (~exist('TF','var') || isempty(TF)) 48 | TF = F; 49 | end 50 | if hasN && (~exist('NF','var') || isempty(NF)) 51 | NF = F; 52 | end 53 | 54 | if ~hasN && ~hasUV 55 | % A lot faster if we just have faces and they're all triangles 56 | fmt = repmat(' %d',1,size(F,2)); 57 | fprintf( f,['f' fmt '\n'], F'); 58 | else 59 | for k=1:size(F,1) 60 | if ( (~hasN) && (~hasUV) ) || (any(TF(k,:)<=0,2) && any(NF(k,:)<=0,2)) 61 | fmt = repmat(' %d',1,size(F,2)); 62 | fprintf( f,['f' fmt '\n'], F(k,:)); 63 | elseif ( hasUV && (~hasN || any(NF(k,:)<=0,2))) 64 | fmt = repmat(' %d/%d',1,size(F,2)); 65 | fprintf( f, ['f' fmt '\n'], [F(k,:);TF(k,:)]); 66 | elseif ( (hasN) && (~hasUV || any(TF(k,:)<=0,2))) 67 | fmt = repmat(' %d//%d',1,size(F,2)); 68 | fprintf( f, ['f' fmt '\n'],[F(k,:);TF(k,:)]'); 69 | elseif ( (hasN) && (hasUV) ) 70 | assert(all(NF(k,:)>0)); 71 | assert(all(TF(k,:)>0)); 72 | fmt = repmat(' %d/%d/%d',1,size(F,2)); 73 | fprintf( f, ['f' fmt '\n'],[F(k,:);TF(k,:);NF(k,:)]); 74 | end 75 | end 76 | end 77 | 78 | 79 | fclose(f); 80 | -------------------------------------------------------------------------------- /code/python/chair_reproduce/config.py: -------------------------------------------------------------------------------- 1 | import os, time 2 | import sys 3 | import numpy as np 4 | import tensorflow as tf 5 | from utils import * 6 | from numpy.linalg import pinv 7 | import glob 8 | import shutil 9 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 10 | sys.path.append(BASE_DIR) 11 | sys.path.append(os.path.dirname(BASE_DIR)) 12 | 13 | 14 | class Config(): 15 | def __init__(self, args, istraining = True): 16 | self.fcvae = bool(int(args.fcvae)) # symmetry 17 | self.changenet = bool(int(args.bin)) 18 | # self.hidden_dim = [4, 8, 16, 32, 64] 19 | if istraining: 20 | self.hidden_dim = args.lz_d 21 | else: 22 | self.hidden_dim = [int(x) for x in eval(args.lz_d)] 23 | self.batch_size = int(args.batch_size) 24 | self.featurefile = args.featurefile 25 | self.jointly = bool(int(args.joint)) 26 | self.train_percent = float(args.trcet) 27 | # self.neighbourfile = args.neighbourfile 28 | # self.distancefile = args.distancefile 29 | 30 | self.lambda0 = float(args.l0) 31 | # self.lambda1 = args.l1 32 | self.lambda2 = float(args.l2) 33 | self.lambda3 = float(args.l3) 34 | self.lambda4 = float(args.l4) 35 | # self.lambda5 = args.l5 36 | self.lr = float(args.lr) 37 | 38 | self.K = int(args.K) 39 | self.graph_conv = bool(int(args.gcnn)) 40 | self.layers = int(args.layer) 41 | self.activate = args.activ 42 | 43 | self.finaldim = int(args.finaldim) 44 | self.epoch_deform = int(args.epoch_deform) 45 | self.epoch_structure = int(args.epoch_structure) 46 | self.output_dir = args.output_dir 47 | self.use_ae_or_vae = args.autoencoder 48 | if istraining: 49 | self.control_idx = args.controlid 50 | else: 51 | self.control_idx = [int(x) for x in eval(args.controlid)] 52 | 53 | self.num_vaes = int(args.numvae) 54 | self.hidden_dim = self.hidden_dim[0:self.num_vaes] 55 | print(type(self.hidden_dim)) 56 | assert(self.num_vaes == len(self.hidden_dim)) 57 | # self.latent_dim = [c//2 for c in self.hidden_dim] 58 | 59 | # if not symmetry: 60 | # self.feature, self.neighbour, self.degrees, self.logrmin, self.logrmax, self.smin, self.smax, self.modelnum, self.pointnum, self.maxdegree, \ 61 | # self.L1, self.cotw1, self.laplacian, self.reconmatrix, self.vdiff, self.all_vertex = load_datanew(self.featurefile, self.graph_conv) 62 | # self.vertex_dim = 9 63 | # else: 64 | # self.feature, self.pointnum, self.vertex_dim, self.modelnum, self.sym_featuremin, self.sym_featuremax = load_data_sym(self.featurefile) 65 | # self.neighbour = [] 66 | # self.degrees = [] 67 | # self.logrmin = [] 68 | # self.logrmax = [] 69 | # self.smin = [] 70 | # self.smax = [] 71 | # self.maxdegree = [] 72 | # self.L1, self.cotw1, self.laplacian, self.reconmatrix, self.vdiff, self.all_vertex = [], [], [], [], [], [] 73 | # self.mesh 74 | 75 | if args.model == 'chair': 76 | self.part_name = ['armrest_1', 'armrest_2', 'back', 'leg1_1', 'leg1_2', 'leg2_1', 'leg2_2', 'seat'] 77 | # part_names = {'armrest_1', 'armrest_2', 'leg1_1', 'leg1_2', 'leg2_1', 'leg2_2', 'seat'}; 78 | # part_names = {'back', 'seat'}; 79 | elif args.model == 'knife': 80 | self.part_name = ['part1', 'part2'] 81 | elif args.model == 'guitar': 82 | self.part_name = ['part1', 'part2', 'part3'] 83 | elif args.model == 'skateboard': 84 | self.part_name = ['surface', 'bearing1', 'bearing2', 'wheel1_1', 'wheel1_2', 'wheel2_1', 'wheel2_2'] 85 | elif args.model == 'cup': 86 | self.part_name = ['part1', 'part2'] 87 | elif args.model == 'car': 88 | self.part_name = ['body', 'left_front_wheel', 'right_front_wheel', 'left_behind_wheel', 'right_behind_wheel'] 89 | elif args.model == 'plane': 90 | self.part_name = ['body', 'left_wing', 'right_wing', 'left_tail', 'right_tail', 'upper_tail', 'down_tail', 'front_landing_gear', 'left_landing_gear', 'right_landing_gear', 'left_engine_1', 'right_engine_1', 'left_engine_2', 'right_engine_2'] 91 | elif args.model == 'table': 92 | self.part_name = ['surface', 'leg1_1', 'leg1_2', 'leg2_1', 'leg2_2', 'leg3_1', 'leg3_2', 'leg4_1', 'leg4_2'] 93 | else: 94 | raise Exception("抛出一个异常") 95 | 96 | self.feature, self.neighbour, self.degrees, self.logrmin, self.logrmax, self.smin, self.smax, self.modelnum, self.pointnum, self.maxdegree, \ 97 | self.L1, self.cotw1, self.laplacian, self.reconmatrix, self.vdiff, self.all_vertex, self.symmetry_feature, self.boxmin, self.boxmax, self.modelname, \ 98 | self.part_name = load_datanew(self.featurefile, self.changenet, self.graph_conv) 99 | self.vertex_dim = 9 100 | 101 | 102 | if os.path.exists(args.filename): 103 | self.mesh = readmesh(args.filename) 104 | else: 105 | print('the basemesh is not exist') 106 | exit() 107 | 108 | L = self.laplacian 109 | print(self.pointnum) 110 | 111 | for i in self.control_idx: 112 | temp = np.zeros((1, self.pointnum)) 113 | temp[0, i] = 1 114 | L = np.concatenate((L,temp)) 115 | 116 | # self.deform_reconmatrix = np.dot(pinv(np.dot(L.transpose(), L)), L.transpose()) 117 | self.deform_reconmatrix = self.reconmatrix # if don't need align the shape,please use this line, otherwise, comment this line and uncomment the former line 118 | # self.deform_reconmatrix = [] 119 | 120 | 121 | timecurrent = time.strftime('%m%d%H%M%S', time.localtime(time.time())) 122 | if not os.path.exists(self.output_dir): 123 | os.makedirs(self.output_dir) 124 | if not os.path.exists(self.output_dir+'/code'+timecurrent): 125 | os.makedirs(self.output_dir+'/code'+timecurrent) 126 | [os.system('cp '+file +' %s' % self.output_dir + '/code'+timecurrent+'/\n') for file in glob.glob(r'./code/*.py')] 127 | 128 | if os.path.exists(os.path.join(self.output_dir, 'log.txt')): 129 | self.flog = open(os.path.join(self.output_dir, 'log.txt'), 'a') 130 | printout(self.flog, 'add '+timecurrent) 131 | else: 132 | self.flog = open(os.path.join(self.output_dir, 'log.txt'), 'w') 133 | 134 | self.iddat_name = args.iddatfile 135 | self.train_id, self.valid_id = spilt_dataset(len(self.feature), self.train_percent, self.iddat_name) 136 | if not istraining: 137 | printout(self.flog, 'add test') 138 | else: 139 | argpaser2file(args, args.output_dir+'/'+timecurrent+'.ini') 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /code/python/chair_reproduce/icp.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from sklearn.neighbors import NearestNeighbors 3 | 4 | 5 | def best_fit_transform(A, B): 6 | ''' 7 | Calculates the least-squares best-fit transform that maps corresponding points A to B in m spatial dimensions 8 | Input: 9 | A: Nxm numpy array of corresponding points 10 | B: Nxm numpy array of corresponding points 11 | Returns: 12 | T: (m+1)x(m+1) homogeneous transformation matrix that maps A on to B 13 | R: mxm rotation matrix 14 | t: mx1 translation vector 15 | ''' 16 | #print(A.shape, B.shape) 17 | assert A.shape == B.shape 18 | 19 | # get number of dimensions 20 | m = A.shape[1] 21 | 22 | # translate points to their centroids 23 | centroid_A = np.mean(A, axis=0) 24 | centroid_B = np.mean(B, axis=0) 25 | AA = A - centroid_A 26 | BB = B - centroid_B 27 | 28 | # rotation matrix 29 | H = np.dot(AA.T, BB) 30 | U, S, Vt = np.linalg.svd(H) 31 | R = np.dot(Vt.T, U.T) 32 | 33 | # special reflection case 34 | if np.linalg.det(R) < 0: 35 | Vt[m-1,:] *= -1 36 | R = np.dot(Vt.T, U.T) 37 | 38 | # translation 39 | t = centroid_B.T - np.dot(R,centroid_A.T) 40 | 41 | # homogeneous transformation 42 | T = np.identity(m+1) 43 | T[:m, :m] = R 44 | T[:m, m] = t 45 | 46 | return T, R, t 47 | 48 | 49 | def nearest_neighbor(src, dst): 50 | ''' 51 | Find the nearest (Euclidean) neighbor in dst for each point in src 52 | Input: 53 | src: Nxm array of points 54 | dst: Nxm array of points 55 | Output: 56 | distances: Euclidean distances of the nearest neighbor 57 | indices: dst indices of the nearest neighbor 58 | ''' 59 | 60 | assert src.shape == dst.shape 61 | 62 | neigh = NearestNeighbors(n_neighbors=1) 63 | neigh.fit(dst) 64 | distances, indices = neigh.kneighbors(src, return_distance=True) 65 | return distances.ravel(), indices.ravel() 66 | 67 | 68 | def icp(A, B, init_pose=None, max_iterations=20, tolerance=0.001): 69 | ''' 70 | The Iterative Closest Point method: finds best-fit transform that maps points A on to points B 71 | Input: 72 | A: Nxm numpy array of source mD points 73 | B: Nxm numpy array of destination mD point 74 | init_pose: (m+1)x(m+1) homogeneous transformation 75 | max_iterations: exit algorithm after max_iterations 76 | tolerance: convergence criteria 77 | Output: 78 | T: final homogeneous transformation that maps A on to B 79 | distances: Euclidean distances (errors) of the nearest neighbor 80 | i: number of iterations to converge 81 | ''' 82 | 83 | assert A.shape == B.shape 84 | 85 | # get number of dimensions 86 | m = A.shape[1] 87 | 88 | # make points homogeneous, copy them to maintain the originals 89 | src = np.ones((m+1,A.shape[0])) 90 | dst = np.ones((m+1,B.shape[0])) 91 | src[:m,:] = np.copy(A.T) 92 | dst[:m,:] = np.copy(B.T) 93 | 94 | # apply the initial pose estimation 95 | if init_pose is not None: 96 | src = np.dot(init_pose, src) 97 | 98 | prev_error = 0 99 | 100 | for i in range(max_iterations): 101 | # find the nearest neighbors between the current source and destination points 102 | distances, indices = nearest_neighbor(src[:m,:].T, dst[:m,:].T) 103 | 104 | # compute the transformation between the current source and nearest destination points 105 | T,_,_ = best_fit_transform(src[:m,:].T, dst[:m,indices].T) 106 | 107 | # update the current source 108 | src = np.dot(T, src) 109 | 110 | # check error 111 | mean_error = np.mean(distances) 112 | if np.abs(prev_error - mean_error) < tolerance: 113 | break 114 | prev_error = mean_error 115 | 116 | # calculate final transformation 117 | T,_,_ = best_fit_transform(A, src[:m,:].T) 118 | 119 | return T, distances, i -------------------------------------------------------------------------------- /code/python/chair_reproduce/render.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import numpy as np 3 | import trimesh 4 | import os 5 | 6 | def render(path, name): 7 | obj_name = os.path.join(path, name) 8 | # print logged messages 9 | trimesh.util.attach_to_log() 10 | 11 | # load a mesh 12 | mesh = trimesh.load(obj_name) 13 | 14 | # get a scene object containing the mesh, this is equivalent to: 15 | # scene = trimesh.scene.Scene(mesh) 16 | scene = mesh.scene() 17 | 18 | # add a base transform for the camera which just 19 | # centers the mesh into the FOV of the camera 20 | scene.set_camera() 21 | 22 | # a 45 degree homogenous rotation matrix around 23 | # the Y axis at the scene centroid 24 | rotate = trimesh.transformations.rotation_matrix( 25 | angle=np.radians(180.0), 26 | direction=[0, 1, 0], 27 | point=scene.centroid) 28 | 29 | for i in range(1): 30 | trimesh.constants.log.info('Saving image %d', i) 31 | 32 | # rotate the camera view transform 33 | camera_old, _geometry = scene.graph['camera'] 34 | camera_new = np.dot(camera_old, rotate) 35 | 36 | # apply the new transform 37 | scene.graph['camera'] = camera_new 38 | 39 | # saving an image requires an opengl context, so if -nw 40 | # is passed don't save the image 41 | try: 42 | # increment the file name 43 | file_name = os.path.join(path, name.split('.')[0] + '.png') 44 | # save a render of the object as a png 45 | png = scene.save_image(resolution=[1920, 1080], visible=True) 46 | with open(file_name, 'wb') as f: 47 | f.write(png) 48 | f.close() 49 | 50 | except BaseException as E: 51 | print("unable to save image", str(E)) 52 | 53 | if __name__ == '__main__': 54 | path = sys.argv[1] 55 | filelist = [file for file in os.listdir(path) if file.endswith('.obj')] 56 | for file in filelist: 57 | render(path, file) 58 | -------------------------------------------------------------------------------- /code/python/chair_reproduce/test.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import scipy.io as sio 4 | from six.moves import xrange 5 | import time 6 | import h5py 7 | import pickle 8 | 9 | import argparse 10 | from utils import * 11 | # import model 12 | import openmesh as om 13 | # from vispy.plot import Fig 14 | # import vispy.io as io 15 | 16 | 17 | # with tf.Graph().as_default(): 18 | # a = tf.constant([[1,2],[3,4],[5,6]],name='a') 19 | # b = tf.constant([[[1,2],[3,4],[5,6]],[[1,2],[3,4],[7,8]]]) 20 | 21 | # dataset = tf.data.Dataset.from_tensor_slices((a, a)) 22 | # dataset = dataset.shuffle(buffer_size=1000).batch(2).repeat(10) 23 | # print(dataset.output_shapes) 24 | # print(np.shape(dataset)) 25 | # # b = tf.tile(a,[2,3]) 26 | # print(np.shape(a)) 27 | # print(np.shape(b)) 28 | # sess = tf.Session() 29 | # bb,cc,dd,ff = sess.run([[a,a],[b,b],[a,b],dataset]) 30 | # print(bb) 31 | # print(cc) 32 | # print(dd) 33 | # print(ff) 34 | # EPOCHS = 10 35 | # x, y = tf.placeholder(tf.float32, shape=[None,2]), tf.placeholder(tf.float32, shape=[None,1]) 36 | # dataset = tf.data.Dataset.from_tensor_slices((x, y)) 37 | # train_data = (np.random.sample((100,2)), np.random.sample((100,1))) 38 | # test_data = (np.array([[1,2]]), np.array([[0]])) 39 | # print(train_data) 40 | # print(test_data) 41 | # iter = dataset.make_initializable_iterator() 42 | # features, labels = iter.get_next() 43 | # with tf.Session() as sess: 44 | # # initialise iterator with train data 45 | # sess.run(iter.initializer, feed_dict={ x: train_data[0], y: train_data[1]}) 46 | # for _ in range(5): 47 | # print(sess.run([features, labels])) 48 | # # switch to test data 49 | # sess.run(iter.initializer, feed_dict={ x: test_data[0], y: test_data[1]}) 50 | # print(sess.run([features, labels])) 51 | 52 | # sess.run(iter.initializer, feed_dict={ x: train_data[0], y: train_data[1]}) 53 | # for _ in range(5): 54 | # print(sess.run([features, labels])) 55 | # # switch to test data 56 | # sess.run(iter.initializer, feed_dict={ x: test_data[0], y: test_data[1]}) 57 | # print(sess.run([features, labels])) 58 | # timecurrent = time.strftime('%m%d%H%M%S', time.localtime(time.time())) + '_' + str(random.randint(1000,9999)) 59 | # parser = argparse.ArgumentParser() 60 | 61 | # # you must set this parameter 62 | # parser.add_argument('--output_dir', default='./result'+timecurrent, type = str) 63 | 64 | # # --------------------------not include in file name------------------------------------- 65 | # parser.add_argument('--model', default = 'scape', type = str) # training model name 66 | # parser.add_argument('--lz_d', nargs='+', default = [128, 32], type=int) # dimension of latent space 67 | # parser.add_argument('--l0', default = 10.0, type = float) # 1.0 generation loss 68 | # # parser.add_argument('--l1', default = 0.5, type = float) # 0.5 distance loss 69 | # parser.add_argument('--l2', default = 10.0, type = float) # 0.5 weight loss 70 | # parser.add_argument('--l3', default = 1.0, type = float) # 0.005 Kl loss 71 | # parser.add_argument('--l4', default = 0.00, type = float) # 0.005 l2 loss 72 | # # parser.add_argument('--l5', default = 0.2, type = float) # 0.005 region loss 73 | # parser.add_argument('--joint', default = 0, type = int) # jointly training 74 | # parser.add_argument('--bin', default = 0, type = int) # use binary to train net 75 | # parser.add_argument('--trcet', default = 1.0, type = float) # training percent of the dataset 76 | # parser.add_argument('--layer', default = 2, type = int) # the number of mesh convolution layer 77 | # parser.add_argument('--activ', default = '', type = str) # activate function of structure net : every layer 78 | # parser.add_argument('--lr', default = 0.001, type = float) # learning rate need adjust if the loss is too large in the early training 79 | # parser.add_argument('--fcvae', default = 0, type = int) 80 | # parser.add_argument('--batch_size', default = 64, type = int) 81 | # parser.add_argument('--K', default=3, type = int) 82 | # parser.add_argument('--gcnn', default=0, type = int) 83 | # parser.add_argument('--iddatfile', default = 'id.dat', type = str) 84 | # parser.add_argument('--autoencoder', default='vae', type = str) 85 | # parser.add_argument('--numvae', default = 2, type = int) 86 | # parser.add_argument('--finaldim', default = 9, type = int) 87 | # parser.add_argument('--filename', default = 'horse.obj', type = str) 88 | # parser.add_argument('--featurefile', default = 'hips_vaefeature.mat', type = str) 89 | # parser.add_argument('--controlid', nargs='+', default = [0], type=int) 90 | # parser.add_argument('--epoch_deform', default=10000, type = int) 91 | # parser.add_argument('--epoch_structure', default=100000, type = int) 92 | 93 | 94 | # args = parser.parse_args() 95 | 96 | # print(type(args.epoch_structure)) 97 | 98 | def load(sess, checkpoint_dir): 99 | import re 100 | print(" [*] Reading checkpoints...") 101 | # checkpoint_dir = os.path.join(checkpoint_dir, self.model_dir, self.model_name) 102 | # saver = self.saver 103 | 104 | ckpt = tf.train.get_checkpoint_state(checkpoint_dir) 105 | # import the inspect_checkpoint library 106 | from tensorflow.python.tools import inspect_checkpoint as chkp 107 | 108 | if ckpt and ckpt.model_checkpoint_path: 109 | ckpt_name = os.path.basename(ckpt.model_checkpoint_path) 110 | 111 | # saver.restore(sess, os.path.join(checkpoint_dir, ckpt_name)) 112 | # print all tensors in checkpoint file 113 | chkp.print_tensors_in_checkpoint_file(os.path.join(checkpoint_dir, ckpt_name), tensor_name='', all_tensors=False,all_tensor_names=True) 114 | # chkp._count_total_params 115 | 116 | # if not ckpt_name.find('best') == -1: 117 | # counter = 0 118 | # else: 119 | # counter = int(next(re.finditer("(\d+)(?!.*\d)", ckpt_name)).group(0)) 120 | 121 | # print(" [*] Success to read {}".format(ckpt_name)) 122 | # return True, counter 123 | else: 124 | print(" [*] Failed to find a checkpoint") 125 | # return False, 0 # model = convMESH() 126 | 127 | # inifile2args(args, ininame='0425171950.ini') 128 | with tf.Session() as sess: 129 | load(sess, '') 130 | 131 | 132 | 133 | # Reinitializable iterator to switch between Datasets 134 | # EPOCHS = 10 135 | # # making fake data using numpy 136 | # train_data = (np.random.sample((3,2)), np.random.sample((3,1))) 137 | # test_data = (np.random.sample((10,2)), np.random.sample((10,1))) 138 | # print(train_data) 139 | # print('aa') 140 | # print(test_data) 141 | 142 | # # create two datasets, one for training and one for test 143 | # train_dataset = tf.data.Dataset.from_tensor_slices(train_data) 144 | # test_dataset = tf.data.Dataset.from_tensor_slices(test_data) 145 | 146 | # train_dataset = train_dataset.shuffle(buffer_size=10000).batch(3) 147 | # # train_dataset = train_dataset.shuffle(buffer_size=10000) 148 | # # train_dataset = train_dataset.batch(self.batch_size) 149 | 150 | # # create a iterator of the correct shape and type 151 | # iter_train = tf.data.Iterator.from_structure(train_dataset.output_types, train_dataset.output_shapes) 152 | # iter_test = tf.data.Iterator.from_structure(test_dataset.output_types, test_dataset.output_shapes) 153 | # features_train, labels_train = iter_train.get_next() 154 | # features_test, labels_test = iter_test.get_next() 155 | # # create the initialisation operations 156 | # train_init_op = iter_train.make_initializer(train_dataset) 157 | # test_init_op = iter_test.make_initializer(test_dataset) 158 | # with tf.Session() as sess: 159 | # sess.run(train_init_op) # switch to train dataset 160 | # sess.run(test_init_op) # switch to val dataset 161 | # for _ in range(EPOCHS): 162 | # print('train') 163 | # print(sess.run([features_train, labels_train])) 164 | # print('test') 165 | # print(sess.run([features_test, labels_test])) 166 | 167 | 168 | 169 | # parser = argparse.ArgumentParser() 170 | 171 | # parser.add_argument('--hiddendim', default = 50, type = int) 172 | # parser.add_argument('-f', '--featurefile', default = 'scapefeature.mat', type = str) 173 | # parser.add_argument('-n', '--neighbourfile', default = 'scapeneighbour.mat', type = str) 174 | # parser.add_argument('--neighbourvariable', default = 'neighbour', type = str) 175 | # # parser.add_argument('-d', '--distancefile', default = 'scapedistance.mat', type = str) 176 | # # parser.add_argument('--distancevariable', default = 'distance', type = str) 177 | # parser.add_argument('--l1', default = 0.5, type = float) 178 | # parser.add_argument('--l2', default = 0.5, type = float) 179 | # parser.add_argument('--lr', default = 0.001, type = float) 180 | # parser.add_argument('--finaldim', default = 9, type = int) 181 | # parser.add_argument('-l', '--layers', default = 1, type = int) 182 | # # parser.add_argument('-m', '--maxepoch', default=2000, type = str) 183 | # #parser.add_argument('--modelfile', default = 'convmesh-modelbest', type = str) 184 | # parser.add_argument('--output_dir', default='./result', type = str) 185 | 186 | # args = parser.parse_args() 187 | # argpaser2file(args,args.output_dir+'/example_test.ini') 188 | 189 | # hidden_dim = args.hiddendim 190 | # featurefile = args.featurefile 191 | # neighbourfile = args.neighbourfile 192 | # neighbourvariable = args.neighbourvariable 193 | # # distancefile = args.distancefile 194 | # # distancevariable = args.distancevariable 195 | # lambda1 = args.l1 196 | # lambda2 = args.l2 197 | # lr = args.lr 198 | # finaldim = args.finaldim 199 | # layers = args.layers 200 | # modelfile = args.output_dir+'/convmesh-modelbest' 201 | # # maxepoch = args.maxepoch 202 | 203 | # feature, logrmin, logrmax, smin, smax, pointnum = load_data(featurefile) 204 | 205 | # neighbour, degrees, maxdegree = load_neighbour(neighbourfile, neighbourvariable, pointnum) 206 | 207 | # # geodesic_weight = load_geodesic_weight(distancefile, distancevariable, pointnum) 208 | 209 | # model = model.convMESH(pointnum, neighbour, degrees, maxdegree, hidden_dim, finaldim, layers, lambda1, lambda2, lr) 210 | 211 | # model.individual_dimension(modelfile, feature, logrmin, logrmax, smin, smax) 212 | 213 | # mesh1 = readmesh('chairbacksub.obj') 214 | 215 | 216 | # point_array1 = mesh1.points() 217 | # # point_array2 = mesh2.points() 218 | # face = mesh1.face_vertex_indices() 219 | 220 | # fig = Fig() 221 | # ax_left = fig[0, 0] 222 | 223 | # image=ax_left.mesh(vertices=point_array1, faces=face, vertex_colors=None, face_colors=None, color=(0.5, 0.5, 1.0), fname=None, meshdata=None) 224 | # print(image) 225 | # io.write_png("wonderful.png",image) 226 | # C = np.ones((np.shape(point_array2)[0], 4)) 227 | # C[:,0:3] = point_array2 228 | # align_deforma_v = (np.dot(T, C.T).T)[:,0:3] 229 | 230 | # savemesh(mesh2, 'align.obj', align_deforma_v) 231 | 232 | # from numpy import load 233 | # from vispy.geometry import MeshData 234 | # from vispy.io.image import write_png 235 | # from vispy.plot import Fig 236 | 237 | # # download https://dl.dropboxusercontent.com/u/66601/fsaverage.npz 238 | # # surf = load('fsaverage.npz') 239 | 240 | # meshdata = MeshData(vertices=point_array1, faces=face) 241 | 242 | # fig = Fig() 243 | # plt = fig[0, 0] 244 | # SKIN_COLOR = 0.94, 0.82, 0.81, 1. 245 | 246 | # plt.mesh(meshdata=meshdata, color=SKIN_COLOR) 247 | 248 | # plt.view.camera.center = (35, -18, 15) 249 | # plt.view.camera.scale_factor = 128 250 | # plt.view.camera.elevation = 0 251 | # plt.view.camera.azimuth = 90 252 | 253 | # img = fig.render() 254 | # write_png('rendered_default.png', img) -------------------------------------------------------------------------------- /code/python/chair_reproduce/test_stacknewvae.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import scipy.io as sio 4 | from six.moves import xrange 5 | import time 6 | import h5py 7 | import pickle 8 | import argparse 9 | from utils import * 10 | import model_stacknewvae as modelvae 11 | import os 12 | from config import * 13 | import icp 14 | import random 15 | 16 | 17 | # vae 18 | timecurrent = time.strftime('%m%d%H%M%S', time.localtime(time.time())) + '_' + str(random.randint(1000,9999)) 19 | test = True 20 | parser = argparse.ArgumentParser() 21 | 22 | # you must set this parameter 23 | parser.add_argument('--output_dir', default='./result'+timecurrent, type = str) 24 | 25 | # --------------------------not include in file name------------------------------------- 26 | parser.add_argument('--model', default = 'scape', type = str) # training model name 27 | parser.add_argument('--lz_d', nargs='+', default = [128, 32], type=int) # dimension of latent space 28 | parser.add_argument('--l0', default = 10.0, type = float) # 1.0 generation loss 29 | # parser.add_argument('--l1', default = 0.5, type = float) # 0.5 distance loss 30 | parser.add_argument('--l2', default = 10.0, type = float) # 0.5 weight loss 31 | parser.add_argument('--l3', default = 1.0, type = float) # 0.005 Kl loss 32 | parser.add_argument('--l4', default = 0.00, type = float) # 0.005 l2 loss 33 | # parser.add_argument('--l5', default = 0.2, type = float) # 0.005 region loss 34 | parser.add_argument('--joint', default = 0, type = int) # jointly training 35 | parser.add_argument('--bin', default = 0, type = int) # use binary to train net 36 | parser.add_argument('--trcet', default = 1.0, type = float) # training percent of the dataset 37 | parser.add_argument('--layer', default = 2, type = int) # the number of mesh convolution layer 38 | parser.add_argument('--activ', default = '', type = str) # activate function of structure net : every layer 39 | parser.add_argument('--lr', default = 0.001, type = float) # learning rate need adjust if the loss is too large in the early training 40 | parser.add_argument('--fcvae', default = 0, type = int) 41 | parser.add_argument('--batch_size', default = 64, type = int) 42 | parser.add_argument('--K', default=3, type = int) 43 | parser.add_argument('--gcnn', default=0, type = int) 44 | parser.add_argument('--iddatfile', default = 'id.dat', type = str) 45 | parser.add_argument('--autoencoder', default='vae', type = str) 46 | parser.add_argument('--numvae', default = 2, type = int) 47 | parser.add_argument('--finaldim', default = 9, type = int) 48 | parser.add_argument('--filename', default = 'horse.obj', type = str) 49 | parser.add_argument('--featurefile', default = 'hips_vaefeature.mat', type = str) 50 | parser.add_argument('--controlid', nargs='+', default = [0], type=int) 51 | parser.add_argument('--epoch_deform', default=10000, type = int) 52 | parser.add_argument('--epoch_structure', default=100000, type = int) 53 | 54 | # inter 55 | parser.add_argument('--beginid', default='3', type = str) 56 | parser.add_argument('--endid', default='4', type = str) 57 | parser.add_argument('--interids', nargs='+', default=['3'], type = str) 58 | 59 | args = parser.parse_args() 60 | 61 | if not args.autoencoder.find('tan') == -1: 62 | args.l3 = 0.00 63 | 64 | args.featurefile = args.model + '_vaefeature.mat' 65 | args.filename = args.model + '.obj' 66 | args.iddatfile = args.model + '_vaeid.dat' 67 | 68 | ininame = getFileName(args.output_dir, '.ini') 69 | if len(ininame)>1: 70 | x = int(input('Please select a number:')) 71 | else: 72 | x = 0 73 | args = inifile2args(args, os.path.join(args.output_dir, ininame[x])) 74 | [print('{}: {}'.format(x,k)) for x,k in vars(args).items()] 75 | #args.output_dir = './1219002003K_3-fcvae_0-gcnn_0-l0_1000.0-l3_1.0-l4_0.1-layer_2-lr_0.001-lz_d_128-model_chairbacksub' 76 | 77 | # parafile = args.output_dir + '/checkpoint/convmesh-modelbest'# + str(args.maxepoch) 78 | 79 | # if not os.path.exists(parafile + '.index'): 80 | # training = True 81 | # else: 82 | # training = False 83 | 84 | # if test: 85 | # recentfolder = traversalDir_FirstDir('./') 86 | # args.output_dir = './' + recentfolder[1] 87 | # print(args.output_dir) 88 | 89 | datainfo = Config(args, False) 90 | datainfo.featurefile = args.featurefile 91 | print(args.output_dir) 92 | print(args.lz_d) 93 | model = modelvae.convMESH(datainfo) 94 | 95 | # model.recover_mesh(datainfo) 96 | # model.random_gen(datainfo) 97 | # model.interpolate1(datainfo, [args.beginid, args.endid]) 98 | if len(args.interids) != 0: 99 | model.interpolate1(datainfo, args.interids) 100 | 101 | # print(safe_b64encode(str(para))) 102 | # print(safe_b64decode(safe_b64encode(str(para)))) 103 | 104 | 105 | # hidden_dim = args.hiddendim 106 | # featurefile = args.featurefile 107 | # neighbourfile = args.neighbourfile 108 | # neighbourvariable = args.neighbourvariable 109 | # distancefile = args.distancefile 110 | # distancevariable = args.distancevariable 111 | # lambda0 = args.l0 112 | # lambda1 = args.l1 113 | # lambda2 = args.l2 114 | # lambda3 = args.l3 115 | # lr = args.lr 116 | # finaldim = args.finaldim 117 | # layers = args.layers 118 | # maxepoch = args.maxepoch 119 | 120 | # feature, logrmin, logrmax, smin, smax, pointnum = load_data(featurefile) 121 | 122 | # neighbour, degrees, maxdegree = load_neighbour(neighbourfile, neighbourvariable, pointnum) 123 | 124 | # geodesic_weight = load_geodesic_weight(distancefile, distancevariable, pointnum) 125 | 126 | # #model.train(feature, geodesic_weight, maxepoch) 127 | # if not test: 128 | # model.train_scvae() 129 | # # model_stack.train_vae_inorder(datainfo.geodesic_weight) 130 | #model.individual_dimension_vae(args.output_dir + '/convmesh-model-20000', datainfo) 131 | # recover_data1(model.base) 132 | #model.output_res_feature(args.output_dir + '/convmesh-model-20000', datainfo) 133 | # parafile = args.output_dir + '/convmesh-model-' + str(max(args.epoch_deform, args.epoch_structure)) 134 | 135 | # model.interpolate1(args.output_dir + '/convmesh-model-2000', datainfo, [2,3]) 136 | # model.recover_mesh(args.output_dir + '/convmesh-model-4000', datainfo) 137 | # model.recover_mesh(args.output_dir + '/convmesh-model-6000', datainfo) 138 | # model.recover_mesh(args.output_dir + '/convmesh-model-8000', datainfo) 139 | 140 | # model.recover_mesh(args.output_dir + '/convmesh-modelbest', datainfo) 141 | # model.individual_dimension(args.output_dir + '/convmesh-modelbest', datainfo) 142 | 143 | # model.get_res_feature(args.output_dir + '/convmesh-modelbest', datainfo) 144 | 145 | # with tf.Graph().as_default(): 146 | # a = tf.constant([[1,2],[3,4],[5,6]],name='a') 147 | # b = tf.constant([[[1,2],[3,4],[5,6]],[[1,2],[3,4],[7,8]]]) 148 | # # b = tf.tile(a,[2,3]) 149 | # print(np.shape(a)) 150 | # print(np.shape(b)) 151 | # sess = tf.Session() 152 | # print(sess.run(b-a)) 153 | 154 | # mesh1 = readmesh('scape.obj') 155 | # mesh2 = readmesh('4.obj') 156 | # v1=np.zeros((2500, 3)).astype('float32') 157 | # v2=np.zeros((2500, 3)).astype('float32') 158 | # point_array1 = mesh1.points() 159 | # point_array2 = mesh2.points() 160 | 161 | # T,R,t = icp.best_fit_transform(point_array2, point_array1) 162 | # C = np.ones((np.shape(point_array2)[0], 4)) 163 | # C[:,0:3] = point_array2 164 | # align_deforma_v = (np.dot(T, C.T).T)[:,0:3] 165 | 166 | # savemesh(mesh2, 'align.obj', align_deforma_v) 167 | 168 | 169 | 170 | -------------------------------------------------------------------------------- /code/python/chair_reproduce/train_stacknewvae.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import scipy.io as sio 4 | from six.moves import xrange 5 | import time 6 | import h5py 7 | import pickle 8 | import argparse 9 | from utils import * 10 | import model_stacknewvae as modelvae 11 | import os 12 | from config import * 13 | import icp 14 | import random 15 | 16 | 17 | # vae 18 | timecurrent = time.strftime('%m%d%H%M', time.localtime(time.time())) + '_' + str(random.randint(1000,9999)) 19 | test = False 20 | parser = argparse.ArgumentParser() 21 | 22 | parser.add_argument('--model', default = 'scape', type = str) # training model name 23 | parser.add_argument('--l0', default = 10.0, type = float) # 1.0 generation loss 24 | # parser.add_argument('--l1', default = 0.5, type = float) # 0.5 distance loss 25 | parser.add_argument('--l2', default = 10.0, type = float) # 0.5 weight loss 26 | parser.add_argument('--l3', default = 1.0, type = float) # 0.005 Kl loss 27 | parser.add_argument('--l4', default = 0.001, type = float) # 0.005 l2 loss 28 | # parser.add_argument('--l5', default = 0.2, type = float) # 0.005 region loss 29 | parser.add_argument('--joint', default = 0, type = int) # jointly training 30 | parser.add_argument('--bin', default = 0, type = int) # use binary to train net 31 | parser.add_argument('--trcet', default = 1.0, type = float) # training percent of the dataset 32 | 33 | # --------------------------not include in file name------------------------------------- 34 | parser.add_argument('--lz_d', nargs='+', default = [128, 32], type=int) # dimension of latent space 35 | parser.add_argument('--layer', default = 2, type = int) # the number of mesh convolution layer 36 | parser.add_argument('--activ', default = '', type = str) # activate function of structure net : every layer 37 | parser.add_argument('--lr', default = 0.001, type = float) # learning rate need adjust if the loss is too large in the early training 38 | parser.add_argument('--fcvae', default = 0, type = int) 39 | parser.add_argument('--batch_size', default = 64, type = int) 40 | parser.add_argument('--K', default=3, type = int) 41 | parser.add_argument('--gcnn', default=0, type = int) 42 | parser.add_argument('--iddatfile', default = 'id.dat', type = str) 43 | parser.add_argument('--autoencoder', default='vae', type = str) 44 | parser.add_argument('--numvae', default = 2, type = int) 45 | parser.add_argument('--finaldim', default = 9, type = int) 46 | parser.add_argument('--filename', default = 'horse.obj', type = str) 47 | parser.add_argument('--featurefile', default = 'hips_vaefeature.mat', type = str) 48 | parser.add_argument('--controlid', nargs='+', default = [0], type=int) 49 | parser.add_argument('--epoch_deform', default=15000, type = int) 50 | parser.add_argument('--epoch_structure', default=100000, type = int) 51 | parser.add_argument('--output_dir', default='./result'+timecurrent, type = str) 52 | 53 | args = parser.parse_args() 54 | 55 | if not args.autoencoder.find('tan') == -1: 56 | args.l3 = 0.00 57 | 58 | args.featurefile = args.model + '_vaefeature.mat' 59 | args.filename = args.model + '.obj' 60 | args.iddatfile = args.model + '_vaeid.dat' 61 | theList = ['K','gcnn','nvae','fcvae','activ','lr','layer','lz_d'] 62 | if not args.output_dir.find('./result'+timecurrent) == -1: 63 | a = './' + timecurrent + "-".join(["{}_{}".format(k,args.__dict__[k]) for k in sorted(args.__dict__.keys()) if len(k) < 6 and k not in theList]) 64 | a = a.replace(' ','') 65 | a = a.replace('[','') 66 | a = a.replace(']','') 67 | a = a.replace(',','--') 68 | args.output_dir = a.replace(',','--') 69 | 70 | #args.output_dir = './1219002003K_3-fcvae_0-gcnn_0-l0_1000.0-l3_1.0-l4_0.1-layer_2-lr_0.001-lz_d_128-model_chairbacksub' 71 | 72 | # parafile = args.output_dir + '/checkpoint/convmesh-modelbest'# + str(args.maxepoch) 73 | 74 | # if not os.path.exists(parafile + '.index'): 75 | # training = True 76 | # else: 77 | # training = False 78 | 79 | # if test: 80 | # recentfolder = traversalDir_FirstDir('./') 81 | # args.output_dir = './' + recentfolder[1] 82 | # print(args.output_dir) 83 | 84 | datainfo = Config(args) 85 | 86 | print(args.output_dir) 87 | print(args.lz_d) 88 | model = modelvae.convMESH(datainfo) 89 | 90 | 91 | # print(safe_b64encode(str(para))) 92 | # print(safe_b64decode(safe_b64encode(str(para)))) 93 | 94 | 95 | # hidden_dim = args.hiddendim 96 | # featurefile = args.featurefile 97 | # neighbourfile = args.neighbourfile 98 | # neighbourvariable = args.neighbourvariable 99 | # distancefile = args.distancefile 100 | # distancevariable = args.distancevariable 101 | # lambda0 = args.l0 102 | # lambda1 = args.l1 103 | # lambda2 = args.l2 104 | # lambda3 = args.l3 105 | # lr = args.lr 106 | # finaldim = args.finaldim 107 | # layers = args.layers 108 | # maxepoch = args.maxepoch 109 | 110 | # feature, logrmin, logrmax, smin, smax, pointnum = load_data(featurefile) 111 | 112 | # neighbour, degrees, maxdegree = load_neighbour(neighbourfile, neighbourvariable, pointnum) 113 | 114 | # geodesic_weight = load_geodesic_weight(distancefile, distancevariable, pointnum) 115 | 116 | 117 | 118 | # #model.train(feature, geodesic_weight, maxepoch) 119 | if not test: 120 | model.train_scvae() 121 | # # model_stack.train_vae_inorder(datainfo.geodesic_weight) 122 | #model.individual_dimension_vae(args.output_dir + '/convmesh-model-20000', datainfo) 123 | # recover_data1(model.base) 124 | #model.output_res_feature(args.output_dir + '/convmesh-model-20000', datainfo) 125 | # parafile = args.output_dir + '/convmesh-model-' + str(max(args.epoch_deform, args.epoch_structure)) 126 | model.recover_mesh(datainfo) 127 | model.random_gen(datainfo) 128 | model.interpolate1(datainfo, [3, 4]) 129 | # model.interpolate1(args.output_dir + '/convmesh-model-2000', datainfo, [2,3]) 130 | # model.recover_mesh(args.output_dir + '/convmesh-model-4000', datainfo) 131 | # model.recover_mesh(args.output_dir + '/convmesh-model-6000', datainfo) 132 | # model.recover_mesh(args.output_dir + '/convmesh-model-8000', datainfo) 133 | 134 | # model.recover_mesh(args.output_dir + '/convmesh-modelbest', datainfo) 135 | # model.individual_dimension(args.output_dir + '/convmesh-modelbest', datainfo) 136 | 137 | # model.get_res_feature(args.output_dir + '/convmesh-modelbest', datainfo) 138 | 139 | 140 | 141 | # with tf.Graph().as_default(): 142 | # a = tf.constant([[1,2],[3,4],[5,6]],name='a') 143 | # b = tf.constant([[[1,2],[3,4],[5,6]],[[1,2],[3,4],[7,8]]]) 144 | # # b = tf.tile(a,[2,3]) 145 | # print(np.shape(a)) 146 | # print(np.shape(b)) 147 | # sess = tf.Session() 148 | # print(sess.run(b-a)) 149 | 150 | # mesh1 = readmesh('scape.obj') 151 | # mesh2 = readmesh('4.obj') 152 | # v1=np.zeros((2500, 3)).astype('float32') 153 | # v2=np.zeros((2500, 3)).astype('float32') 154 | # point_array1 = mesh1.points() 155 | # point_array2 = mesh2.points() 156 | 157 | # T,R,t = icp.best_fit_transform(point_array2, point_array1) 158 | # C = np.ones((np.shape(point_array2)[0], 4)) 159 | # C[:,0:3] = point_array2 160 | # align_deforma_v = (np.dot(T, C.T).T)[:,0:3] 161 | 162 | # savemesh(mesh2, 'align.obj', align_deforma_v) 163 | 164 | 165 | 166 | -------------------------------------------------------------------------------- /code/python/chair_reproduce/train_symfeature.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import scipy.io as sio 4 | from six.moves import xrange 5 | import time 6 | import h5py 7 | import pickle 8 | 9 | import argparse 10 | from utils import * 11 | import model_stacknewvae as modelvae 12 | import os 13 | from config import * 14 | import icp 15 | 16 | 17 | # vae 18 | timecurrent = time.strftime('%m%d%H%M%S', time.localtime(time.time())) 19 | test = False 20 | parser = argparse.ArgumentParser() 21 | 22 | parser.add_argument('--model', default = 'chair', type = str) 23 | 24 | parser.add_argument('--lz_d', nargs='+', default = [16], type=int) 25 | parser.add_argument('--l0', default = 1000.0, type = float) # 1.0 generation loss 26 | parser.add_argument('--l3', default = 1.0, type = float) # 0.005 Kl loss 27 | parser.add_argument('--l4', default = 0.0, type = float) # 0.005 l2 loss 28 | parser.add_argument('--lr', default = 0.001, type = float) # learning rate need adjust if the loss is too large in the early training 29 | parser.add_argument('--batch_size', default = 10000, type = int) 30 | 31 | parser.add_argument('--iddatfile', default = 'id.dat', type = str) 32 | parser.add_argument('--autoencoder', default='vae', type = str) 33 | parser.add_argument('--finaldim', default = 5, type = int) 34 | parser.add_argument('--featurefile', default = 'hips_vaefeature.mat', type = str) 35 | parser.add_argument('--maxepoch', default=500000, type = int) 36 | parser.add_argument('--output_dir', default='./result'+timecurrent, type = str) 37 | 38 | # parser.add_argument('--K', default=3, type = int) 39 | # parser.add_argument('--gcnn', default=0, type = int) 40 | # parser.add_argument('--layer', default = 3, type = int) 41 | parser.add_argument('--fcvae', default = 1, type = int) 42 | parser.add_argument('--numvae', default = 1, type = int) 43 | parser.add_argument('--filename', default = 'horse.obj', type = str) 44 | parser.add_argument('--controlid', nargs='+', default = [0], type=int) 45 | 46 | args = parser.parse_args() 47 | 48 | if not args.autoencoder.find('tan') == -1: 49 | args.l3 = 0.00 50 | 51 | if not args.output_dir.find('./result'+timecurrent) == -1: 52 | a = './' + timecurrent + "-".join(["{}_{}".format(k,args.__dict__[k]) for k in sorted(args.__dict__.keys()) if len(k) < 6]) 53 | a = a.replace(' ','') 54 | a = a.replace('[','') 55 | a = a.replace(']','') 56 | a = a.replace(',','--') 57 | args.output_dir = a.replace(',','--') 58 | 59 | # args.output_dir = './1217154045l0_1000.0-l3_1.0-l4_0.0-lr_0.001-lz_d_16-model_chair' 60 | 61 | args.featurefile = args.model + '_symfeature.mat' 62 | args.iddatfile = args.model + '_symid.dat' 63 | 64 | # if test: 65 | # recentfolder = traversalDir_FirstDir('./') 66 | # args.output_dir = './' + recentfolder[1] 67 | # print(args.output_dir) 68 | 69 | datainfo = Config(args, symmetry = True) 70 | argpaser2file(args, args.output_dir+'/'+timecurrent+'.ini') 71 | 72 | print(args.output_dir) 73 | print(args.lz_d) 74 | model = modelvae.convMESH(datainfo, symmetry = True) 75 | 76 | 77 | # print(safe_b64encode(str(para))) 78 | # print(safe_b64decode(safe_b64encode(str(para)))) 79 | 80 | if not test: 81 | model.train_total_vae() 82 | 83 | parafile = args.output_dir + '/convmesh-model-' + str(args.maxepoch) 84 | model.recover_mesh(parafile, datainfo) 85 | model.random_gen(parafile, datainfo) 86 | model.interpolate1(parafile, datainfo, [469, 477]) 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /code/python/plane_reproduce/config.py: -------------------------------------------------------------------------------- 1 | import os, time 2 | import sys 3 | import numpy as np 4 | import tensorflow as tf 5 | from utils import * 6 | from numpy.linalg import pinv 7 | import glob 8 | import shutil 9 | BASE_DIR = os.path.dirname(os.path.abspath(__file__)) 10 | sys.path.append(BASE_DIR) 11 | sys.path.append(os.path.dirname(BASE_DIR)) 12 | 13 | 14 | class Config(): 15 | def __init__(self, args, istraining = True): 16 | self.fcvae = bool(int(args.fcvae)) # symmetry 17 | self.changenet = bool(int(args.bin)) 18 | # self.hidden_dim = [4, 8, 16, 32, 64] 19 | if istraining: 20 | self.hidden_dim = args.lz_d 21 | else: 22 | self.hidden_dim = [int(x) for x in eval(args.lz_d)] 23 | self.batch_size = int(args.batch_size) 24 | self.featurefile = args.featurefile 25 | self.jointly = bool(int(args.joint)) 26 | self.train_percent = float(args.trcet) 27 | # self.neighbourfile = args.neighbourfile 28 | # self.distancefile = args.distancefile 29 | 30 | self.lambda0 = float(args.l0) 31 | # self.lambda1 = args.l1 32 | self.lambda2 = float(args.l2) 33 | self.lambda3 = float(args.l3) 34 | self.lambda4 = float(args.l4) 35 | # self.lambda5 = args.l5 36 | self.lr = float(args.lr) 37 | 38 | self.K = int(args.K) 39 | self.graph_conv = bool(int(args.gcnn)) 40 | self.layers = int(args.layer) 41 | self.activate = args.activ 42 | 43 | self.finaldim = int(args.finaldim) 44 | self.epoch_deform = int(args.epoch_deform) 45 | self.epoch_structure = int(args.epoch_structure) 46 | self.output_dir = args.output_dir 47 | self.use_ae_or_vae = args.autoencoder 48 | if istraining: 49 | self.control_idx = args.controlid 50 | else: 51 | self.control_idx = [int(x) for x in eval(args.controlid)] 52 | 53 | self.num_vaes = int(args.numvae) 54 | self.hidden_dim = self.hidden_dim[0:self.num_vaes] 55 | print(type(self.hidden_dim)) 56 | assert(self.num_vaes == len(self.hidden_dim)) 57 | # self.latent_dim = [c//2 for c in self.hidden_dim] 58 | 59 | # if not symmetry: 60 | # self.feature, self.neighbour, self.degrees, self.logrmin, self.logrmax, self.smin, self.smax, self.modelnum, self.pointnum, self.maxdegree, \ 61 | # self.L1, self.cotw1, self.laplacian, self.reconmatrix, self.vdiff, self.all_vertex = load_datanew(self.featurefile, self.graph_conv) 62 | # self.vertex_dim = 9 63 | # else: 64 | # self.feature, self.pointnum, self.vertex_dim, self.modelnum, self.sym_featuremin, self.sym_featuremax = load_data_sym(self.featurefile) 65 | # self.neighbour = [] 66 | # self.degrees = [] 67 | # self.logrmin = [] 68 | # self.logrmax = [] 69 | # self.smin = [] 70 | # self.smax = [] 71 | # self.maxdegree = [] 72 | # self.L1, self.cotw1, self.laplacian, self.reconmatrix, self.vdiff, self.all_vertex = [], [], [], [], [], [] 73 | # self.mesh 74 | 75 | if args.model == 'chair': 76 | self.part_name = ['armrest_1', 'armrest_2', 'back', 'leg1_1', 'leg1_2', 'leg2_1', 'leg2_2', 'seat'] 77 | # part_names = {'armrest_1', 'armrest_2', 'leg1_1', 'leg1_2', 'leg2_1', 'leg2_2', 'seat'}; 78 | # part_names = {'back', 'seat'}; 79 | elif args.model == 'knife': 80 | self.part_name = ['part1', 'part2'] 81 | elif args.model == 'guitar': 82 | self.part_name = ['part1', 'part2', 'part3'] 83 | elif args.model == 'skateboard': 84 | self.part_name = ['surface', 'bearing1', 'bearing2', 'wheel1_1', 'wheel1_2', 'wheel2_1', 'wheel2_2'] 85 | elif args.model == 'cup': 86 | self.part_name = ['part1', 'part2'] 87 | elif args.model == 'car': 88 | self.part_name = ['body', 'left_front_wheel', 'right_front_wheel', 'left_behind_wheel', 'right_behind_wheel'] 89 | elif args.model == 'plane': 90 | self.part_name = ['body', 'left_wing', 'right_wing', 'left_tail', 'right_tail', 'upper_tail', 'down_tail', 'front_landing_gear', 'left_landing_gear', 'right_landing_gear', 'left_engine_1', 'right_engine_1', 'left_engine_2', 'right_engine_2'] 91 | elif args.model == 'table': 92 | self.part_name = ['surface', 'leg1_1', 'leg1_2', 'leg2_1', 'leg2_2', 'leg3_1', 'leg3_2', 'leg4_1', 'leg4_2'] 93 | else: 94 | raise Exception("抛出一个异常") 95 | 96 | self.feature, self.neighbour, self.degrees, self.logrmin, self.logrmax, self.smin, self.smax, self.modelnum, self.pointnum, self.maxdegree, \ 97 | self.L1, self.cotw1, self.laplacian, self.reconmatrix, self.vdiff, self.all_vertex, self.symmetry_feature, self.boxmin, self.boxmax, self.modelname, \ 98 | self.part_name = load_datanew(self.featurefile, self.changenet, self.graph_conv) 99 | self.vertex_dim = 9 100 | 101 | 102 | if os.path.exists(args.filename): 103 | self.mesh = readmesh(args.filename) 104 | else: 105 | print('the basemesh is not exist') 106 | exit() 107 | 108 | L = self.laplacian 109 | print(self.pointnum) 110 | 111 | for i in self.control_idx: 112 | temp = np.zeros((1, self.pointnum)) 113 | temp[0, i] = 1 114 | L = np.concatenate((L,temp)) 115 | 116 | # self.deform_reconmatrix = np.dot(pinv(np.dot(L.transpose(), L)), L.transpose()) 117 | self.deform_reconmatrix = self.reconmatrix # if don't need align the shape,please use this line, otherwise, comment this line and uncomment the former line 118 | # self.deform_reconmatrix = [] 119 | 120 | 121 | timecurrent = time.strftime('%m%d%H%M%S', time.localtime(time.time())) 122 | if not os.path.exists(self.output_dir): 123 | os.makedirs(self.output_dir) 124 | if not os.path.exists(self.output_dir+'/code'+timecurrent): 125 | os.makedirs(self.output_dir+'/code'+timecurrent) 126 | [os.system('cp '+file +' %s' % self.output_dir + '/code'+timecurrent+'/\n') for file in glob.glob(r'./code/*.py')] 127 | 128 | if os.path.exists(os.path.join(self.output_dir, 'log.txt')): 129 | self.flog = open(os.path.join(self.output_dir, 'log.txt'), 'a') 130 | printout(self.flog, 'add '+timecurrent) 131 | else: 132 | self.flog = open(os.path.join(self.output_dir, 'log.txt'), 'w') 133 | 134 | self.iddat_name = args.iddatfile 135 | self.train_id, self.valid_id = spilt_dataset(len(self.feature), self.train_percent, self.iddat_name) 136 | if not istraining: 137 | printout(self.flog, 'add test') 138 | else: 139 | argpaser2file(args, args.output_dir+'/'+timecurrent+'.ini') 140 | 141 | 142 | 143 | -------------------------------------------------------------------------------- /code/python/plane_reproduce/icp.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from sklearn.neighbors import NearestNeighbors 3 | 4 | 5 | def best_fit_transform(A, B): 6 | ''' 7 | Calculates the least-squares best-fit transform that maps corresponding points A to B in m spatial dimensions 8 | Input: 9 | A: Nxm numpy array of corresponding points 10 | B: Nxm numpy array of corresponding points 11 | Returns: 12 | T: (m+1)x(m+1) homogeneous transformation matrix that maps A on to B 13 | R: mxm rotation matrix 14 | t: mx1 translation vector 15 | ''' 16 | #print(A.shape, B.shape) 17 | assert A.shape == B.shape 18 | 19 | # get number of dimensions 20 | m = A.shape[1] 21 | 22 | # translate points to their centroids 23 | centroid_A = np.mean(A, axis=0) 24 | centroid_B = np.mean(B, axis=0) 25 | AA = A - centroid_A 26 | BB = B - centroid_B 27 | 28 | # rotation matrix 29 | H = np.dot(AA.T, BB) 30 | U, S, Vt = np.linalg.svd(H) 31 | R = np.dot(Vt.T, U.T) 32 | 33 | # special reflection case 34 | if np.linalg.det(R) < 0: 35 | Vt[m-1,:] *= -1 36 | R = np.dot(Vt.T, U.T) 37 | 38 | # translation 39 | t = centroid_B.T - np.dot(R,centroid_A.T) 40 | 41 | # homogeneous transformation 42 | T = np.identity(m+1) 43 | T[:m, :m] = R 44 | T[:m, m] = t 45 | 46 | return T, R, t 47 | 48 | 49 | def nearest_neighbor(src, dst): 50 | ''' 51 | Find the nearest (Euclidean) neighbor in dst for each point in src 52 | Input: 53 | src: Nxm array of points 54 | dst: Nxm array of points 55 | Output: 56 | distances: Euclidean distances of the nearest neighbor 57 | indices: dst indices of the nearest neighbor 58 | ''' 59 | 60 | assert src.shape == dst.shape 61 | 62 | neigh = NearestNeighbors(n_neighbors=1) 63 | neigh.fit(dst) 64 | distances, indices = neigh.kneighbors(src, return_distance=True) 65 | return distances.ravel(), indices.ravel() 66 | 67 | 68 | def icp(A, B, init_pose=None, max_iterations=20, tolerance=0.001): 69 | ''' 70 | The Iterative Closest Point method: finds best-fit transform that maps points A on to points B 71 | Input: 72 | A: Nxm numpy array of source mD points 73 | B: Nxm numpy array of destination mD point 74 | init_pose: (m+1)x(m+1) homogeneous transformation 75 | max_iterations: exit algorithm after max_iterations 76 | tolerance: convergence criteria 77 | Output: 78 | T: final homogeneous transformation that maps A on to B 79 | distances: Euclidean distances (errors) of the nearest neighbor 80 | i: number of iterations to converge 81 | ''' 82 | 83 | assert A.shape == B.shape 84 | 85 | # get number of dimensions 86 | m = A.shape[1] 87 | 88 | # make points homogeneous, copy them to maintain the originals 89 | src = np.ones((m+1,A.shape[0])) 90 | dst = np.ones((m+1,B.shape[0])) 91 | src[:m,:] = np.copy(A.T) 92 | dst[:m,:] = np.copy(B.T) 93 | 94 | # apply the initial pose estimation 95 | if init_pose is not None: 96 | src = np.dot(init_pose, src) 97 | 98 | prev_error = 0 99 | 100 | for i in range(max_iterations): 101 | # find the nearest neighbors between the current source and destination points 102 | distances, indices = nearest_neighbor(src[:m,:].T, dst[:m,:].T) 103 | 104 | # compute the transformation between the current source and nearest destination points 105 | T,_,_ = best_fit_transform(src[:m,:].T, dst[:m,indices].T) 106 | 107 | # update the current source 108 | src = np.dot(T, src) 109 | 110 | # check error 111 | mean_error = np.mean(distances) 112 | if np.abs(prev_error - mean_error) < tolerance: 113 | break 114 | prev_error = mean_error 115 | 116 | # calculate final transformation 117 | T,_,_ = best_fit_transform(A, src[:m,:].T) 118 | 119 | return T, distances, i -------------------------------------------------------------------------------- /code/python/plane_reproduce/render.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import numpy as np 3 | import trimesh 4 | import os 5 | 6 | def render(path, name): 7 | obj_name = os.path.join(path, name) 8 | # print logged messages 9 | trimesh.util.attach_to_log() 10 | 11 | # load a mesh 12 | mesh = trimesh.load(obj_name) 13 | 14 | # get a scene object containing the mesh, this is equivalent to: 15 | # scene = trimesh.scene.Scene(mesh) 16 | scene = mesh.scene() 17 | 18 | # add a base transform for the camera which just 19 | # centers the mesh into the FOV of the camera 20 | scene.set_camera() 21 | 22 | # a 45 degree homogenous rotation matrix around 23 | # the Y axis at the scene centroid 24 | rotate = trimesh.transformations.rotation_matrix( 25 | angle=np.radians(180.0), 26 | direction=[0, 1, 0], 27 | point=scene.centroid) 28 | 29 | for i in range(1): 30 | trimesh.constants.log.info('Saving image %d', i) 31 | 32 | # rotate the camera view transform 33 | camera_old, _geometry = scene.graph['camera'] 34 | camera_new = np.dot(camera_old, rotate) 35 | 36 | # apply the new transform 37 | scene.graph['camera'] = camera_new 38 | 39 | # saving an image requires an opengl context, so if -nw 40 | # is passed don't save the image 41 | try: 42 | # increment the file name 43 | file_name = os.path.join(path, name.split('.')[0] + '.png') 44 | # save a render of the object as a png 45 | png = scene.save_image(resolution=[1920, 1080], visible=True) 46 | with open(file_name, 'wb') as f: 47 | f.write(png) 48 | f.close() 49 | 50 | except BaseException as E: 51 | print("unable to save image", str(E)) 52 | 53 | if __name__ == '__main__': 54 | path = sys.argv[1] 55 | filelist = [file for file in os.listdir(path) if file.endswith('.obj')] 56 | for file in filelist: 57 | render(path, file) 58 | -------------------------------------------------------------------------------- /code/python/plane_reproduce/test.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import scipy.io as sio 4 | from six.moves import xrange 5 | import time 6 | import h5py 7 | import pickle 8 | 9 | import argparse 10 | from utils import * 11 | # import model 12 | import openmesh as om 13 | # from vispy.plot import Fig 14 | # import vispy.io as io 15 | 16 | 17 | # with tf.Graph().as_default(): 18 | # a = tf.constant([[1,2],[3,4],[5,6]],name='a') 19 | # b = tf.constant([[[1,2],[3,4],[5,6]],[[1,2],[3,4],[7,8]]]) 20 | 21 | # dataset = tf.data.Dataset.from_tensor_slices((a, a)) 22 | # dataset = dataset.shuffle(buffer_size=1000).batch(2).repeat(10) 23 | # print(dataset.output_shapes) 24 | # print(np.shape(dataset)) 25 | # # b = tf.tile(a,[2,3]) 26 | # print(np.shape(a)) 27 | # print(np.shape(b)) 28 | # sess = tf.Session() 29 | # bb,cc,dd,ff = sess.run([[a,a],[b,b],[a,b],dataset]) 30 | # print(bb) 31 | # print(cc) 32 | # print(dd) 33 | # print(ff) 34 | # EPOCHS = 10 35 | # x, y = tf.placeholder(tf.float32, shape=[None,2]), tf.placeholder(tf.float32, shape=[None,1]) 36 | # dataset = tf.data.Dataset.from_tensor_slices((x, y)) 37 | # train_data = (np.random.sample((100,2)), np.random.sample((100,1))) 38 | # test_data = (np.array([[1,2]]), np.array([[0]])) 39 | # print(train_data) 40 | # print(test_data) 41 | # iter = dataset.make_initializable_iterator() 42 | # features, labels = iter.get_next() 43 | # with tf.Session() as sess: 44 | # # initialise iterator with train data 45 | # sess.run(iter.initializer, feed_dict={ x: train_data[0], y: train_data[1]}) 46 | # for _ in range(5): 47 | # print(sess.run([features, labels])) 48 | # # switch to test data 49 | # sess.run(iter.initializer, feed_dict={ x: test_data[0], y: test_data[1]}) 50 | # print(sess.run([features, labels])) 51 | 52 | # sess.run(iter.initializer, feed_dict={ x: train_data[0], y: train_data[1]}) 53 | # for _ in range(5): 54 | # print(sess.run([features, labels])) 55 | # # switch to test data 56 | # sess.run(iter.initializer, feed_dict={ x: test_data[0], y: test_data[1]}) 57 | # print(sess.run([features, labels])) 58 | # timecurrent = time.strftime('%m%d%H%M%S', time.localtime(time.time())) + '_' + str(random.randint(1000,9999)) 59 | # parser = argparse.ArgumentParser() 60 | 61 | # # you must set this parameter 62 | # parser.add_argument('--output_dir', default='./result'+timecurrent, type = str) 63 | 64 | # # --------------------------not include in file name------------------------------------- 65 | # parser.add_argument('--model', default = 'scape', type = str) # training model name 66 | # parser.add_argument('--lz_d', nargs='+', default = [128, 32], type=int) # dimension of latent space 67 | # parser.add_argument('--l0', default = 10.0, type = float) # 1.0 generation loss 68 | # # parser.add_argument('--l1', default = 0.5, type = float) # 0.5 distance loss 69 | # parser.add_argument('--l2', default = 10.0, type = float) # 0.5 weight loss 70 | # parser.add_argument('--l3', default = 1.0, type = float) # 0.005 Kl loss 71 | # parser.add_argument('--l4', default = 0.00, type = float) # 0.005 l2 loss 72 | # # parser.add_argument('--l5', default = 0.2, type = float) # 0.005 region loss 73 | # parser.add_argument('--joint', default = 0, type = int) # jointly training 74 | # parser.add_argument('--bin', default = 0, type = int) # use binary to train net 75 | # parser.add_argument('--trcet', default = 1.0, type = float) # training percent of the dataset 76 | # parser.add_argument('--layer', default = 2, type = int) # the number of mesh convolution layer 77 | # parser.add_argument('--activ', default = '', type = str) # activate function of structure net : every layer 78 | # parser.add_argument('--lr', default = 0.001, type = float) # learning rate need adjust if the loss is too large in the early training 79 | # parser.add_argument('--fcvae', default = 0, type = int) 80 | # parser.add_argument('--batch_size', default = 64, type = int) 81 | # parser.add_argument('--K', default=3, type = int) 82 | # parser.add_argument('--gcnn', default=0, type = int) 83 | # parser.add_argument('--iddatfile', default = 'id.dat', type = str) 84 | # parser.add_argument('--autoencoder', default='vae', type = str) 85 | # parser.add_argument('--numvae', default = 2, type = int) 86 | # parser.add_argument('--finaldim', default = 9, type = int) 87 | # parser.add_argument('--filename', default = 'horse.obj', type = str) 88 | # parser.add_argument('--featurefile', default = 'hips_vaefeature.mat', type = str) 89 | # parser.add_argument('--controlid', nargs='+', default = [0], type=int) 90 | # parser.add_argument('--epoch_deform', default=10000, type = int) 91 | # parser.add_argument('--epoch_structure', default=100000, type = int) 92 | 93 | 94 | # args = parser.parse_args() 95 | 96 | # print(type(args.epoch_structure)) 97 | 98 | def load(sess, checkpoint_dir): 99 | import re 100 | print(" [*] Reading checkpoints...") 101 | # checkpoint_dir = os.path.join(checkpoint_dir, self.model_dir, self.model_name) 102 | # saver = self.saver 103 | 104 | ckpt = tf.train.get_checkpoint_state(checkpoint_dir) 105 | # import the inspect_checkpoint library 106 | from tensorflow.python.tools import inspect_checkpoint as chkp 107 | 108 | if ckpt and ckpt.model_checkpoint_path: 109 | ckpt_name = os.path.basename(ckpt.model_checkpoint_path) 110 | 111 | # saver.restore(sess, os.path.join(checkpoint_dir, ckpt_name)) 112 | # print all tensors in checkpoint file 113 | chkp.print_tensors_in_checkpoint_file(os.path.join(checkpoint_dir, ckpt_name), tensor_name='', all_tensors=False,all_tensor_names=True) 114 | # chkp._count_total_params 115 | 116 | # if not ckpt_name.find('best') == -1: 117 | # counter = 0 118 | # else: 119 | # counter = int(next(re.finditer("(\d+)(?!.*\d)", ckpt_name)).group(0)) 120 | 121 | # print(" [*] Success to read {}".format(ckpt_name)) 122 | # return True, counter 123 | else: 124 | print(" [*] Failed to find a checkpoint") 125 | # return False, 0 # model = convMESH() 126 | 127 | # inifile2args(args, ininame='0425171950.ini') 128 | with tf.Session() as sess: 129 | load(sess, '') 130 | 131 | 132 | 133 | # Reinitializable iterator to switch between Datasets 134 | # EPOCHS = 10 135 | # # making fake data using numpy 136 | # train_data = (np.random.sample((3,2)), np.random.sample((3,1))) 137 | # test_data = (np.random.sample((10,2)), np.random.sample((10,1))) 138 | # print(train_data) 139 | # print('aa') 140 | # print(test_data) 141 | 142 | # # create two datasets, one for training and one for test 143 | # train_dataset = tf.data.Dataset.from_tensor_slices(train_data) 144 | # test_dataset = tf.data.Dataset.from_tensor_slices(test_data) 145 | 146 | # train_dataset = train_dataset.shuffle(buffer_size=10000).batch(3) 147 | # # train_dataset = train_dataset.shuffle(buffer_size=10000) 148 | # # train_dataset = train_dataset.batch(self.batch_size) 149 | 150 | # # create a iterator of the correct shape and type 151 | # iter_train = tf.data.Iterator.from_structure(train_dataset.output_types, train_dataset.output_shapes) 152 | # iter_test = tf.data.Iterator.from_structure(test_dataset.output_types, test_dataset.output_shapes) 153 | # features_train, labels_train = iter_train.get_next() 154 | # features_test, labels_test = iter_test.get_next() 155 | # # create the initialisation operations 156 | # train_init_op = iter_train.make_initializer(train_dataset) 157 | # test_init_op = iter_test.make_initializer(test_dataset) 158 | # with tf.Session() as sess: 159 | # sess.run(train_init_op) # switch to train dataset 160 | # sess.run(test_init_op) # switch to val dataset 161 | # for _ in range(EPOCHS): 162 | # print('train') 163 | # print(sess.run([features_train, labels_train])) 164 | # print('test') 165 | # print(sess.run([features_test, labels_test])) 166 | 167 | 168 | 169 | # parser = argparse.ArgumentParser() 170 | 171 | # parser.add_argument('--hiddendim', default = 50, type = int) 172 | # parser.add_argument('-f', '--featurefile', default = 'scapefeature.mat', type = str) 173 | # parser.add_argument('-n', '--neighbourfile', default = 'scapeneighbour.mat', type = str) 174 | # parser.add_argument('--neighbourvariable', default = 'neighbour', type = str) 175 | # # parser.add_argument('-d', '--distancefile', default = 'scapedistance.mat', type = str) 176 | # # parser.add_argument('--distancevariable', default = 'distance', type = str) 177 | # parser.add_argument('--l1', default = 0.5, type = float) 178 | # parser.add_argument('--l2', default = 0.5, type = float) 179 | # parser.add_argument('--lr', default = 0.001, type = float) 180 | # parser.add_argument('--finaldim', default = 9, type = int) 181 | # parser.add_argument('-l', '--layers', default = 1, type = int) 182 | # # parser.add_argument('-m', '--maxepoch', default=2000, type = str) 183 | # #parser.add_argument('--modelfile', default = 'convmesh-modelbest', type = str) 184 | # parser.add_argument('--output_dir', default='./result', type = str) 185 | 186 | # args = parser.parse_args() 187 | # argpaser2file(args,args.output_dir+'/example_test.ini') 188 | 189 | # hidden_dim = args.hiddendim 190 | # featurefile = args.featurefile 191 | # neighbourfile = args.neighbourfile 192 | # neighbourvariable = args.neighbourvariable 193 | # # distancefile = args.distancefile 194 | # # distancevariable = args.distancevariable 195 | # lambda1 = args.l1 196 | # lambda2 = args.l2 197 | # lr = args.lr 198 | # finaldim = args.finaldim 199 | # layers = args.layers 200 | # modelfile = args.output_dir+'/convmesh-modelbest' 201 | # # maxepoch = args.maxepoch 202 | 203 | # feature, logrmin, logrmax, smin, smax, pointnum = load_data(featurefile) 204 | 205 | # neighbour, degrees, maxdegree = load_neighbour(neighbourfile, neighbourvariable, pointnum) 206 | 207 | # # geodesic_weight = load_geodesic_weight(distancefile, distancevariable, pointnum) 208 | 209 | # model = model.convMESH(pointnum, neighbour, degrees, maxdegree, hidden_dim, finaldim, layers, lambda1, lambda2, lr) 210 | 211 | # model.individual_dimension(modelfile, feature, logrmin, logrmax, smin, smax) 212 | 213 | # mesh1 = readmesh('chairbacksub.obj') 214 | 215 | 216 | # point_array1 = mesh1.points() 217 | # # point_array2 = mesh2.points() 218 | # face = mesh1.face_vertex_indices() 219 | 220 | # fig = Fig() 221 | # ax_left = fig[0, 0] 222 | 223 | # image=ax_left.mesh(vertices=point_array1, faces=face, vertex_colors=None, face_colors=None, color=(0.5, 0.5, 1.0), fname=None, meshdata=None) 224 | # print(image) 225 | # io.write_png("wonderful.png",image) 226 | # C = np.ones((np.shape(point_array2)[0], 4)) 227 | # C[:,0:3] = point_array2 228 | # align_deforma_v = (np.dot(T, C.T).T)[:,0:3] 229 | 230 | # savemesh(mesh2, 'align.obj', align_deforma_v) 231 | 232 | # from numpy import load 233 | # from vispy.geometry import MeshData 234 | # from vispy.io.image import write_png 235 | # from vispy.plot import Fig 236 | 237 | # # download https://dl.dropboxusercontent.com/u/66601/fsaverage.npz 238 | # # surf = load('fsaverage.npz') 239 | 240 | # meshdata = MeshData(vertices=point_array1, faces=face) 241 | 242 | # fig = Fig() 243 | # plt = fig[0, 0] 244 | # SKIN_COLOR = 0.94, 0.82, 0.81, 1. 245 | 246 | # plt.mesh(meshdata=meshdata, color=SKIN_COLOR) 247 | 248 | # plt.view.camera.center = (35, -18, 15) 249 | # plt.view.camera.scale_factor = 128 250 | # plt.view.camera.elevation = 0 251 | # plt.view.camera.azimuth = 90 252 | 253 | # img = fig.render() 254 | # write_png('rendered_default.png', img) -------------------------------------------------------------------------------- /code/python/plane_reproduce/test_stacknewvae.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import scipy.io as sio 4 | from six.moves import xrange 5 | import time 6 | import h5py 7 | import pickle 8 | import argparse 9 | from utils import * 10 | import model_stacknewvae as modelvae 11 | import os 12 | from config import * 13 | import icp 14 | import random 15 | 16 | 17 | # vae 18 | timecurrent = time.strftime('%m%d%H%M%S', time.localtime(time.time())) + '_' + str(random.randint(1000,9999)) 19 | test = True 20 | parser = argparse.ArgumentParser() 21 | 22 | # you must set this parameter 23 | parser.add_argument('--output_dir', default='./result'+timecurrent, type = str) 24 | 25 | # --------------------------not include in file name------------------------------------- 26 | parser.add_argument('--model', default = 'scape', type = str) # training model name 27 | parser.add_argument('--lz_d', nargs='+', default = [128, 32], type=int) # dimension of latent space 28 | parser.add_argument('--l0', default = 10.0, type = float) # 1.0 generation loss 29 | # parser.add_argument('--l1', default = 0.5, type = float) # 0.5 distance loss 30 | parser.add_argument('--l2', default = 10.0, type = float) # 0.5 weight loss 31 | parser.add_argument('--l3', default = 1.0, type = float) # 0.005 Kl loss 32 | parser.add_argument('--l4', default = 0.00, type = float) # 0.005 l2 loss 33 | # parser.add_argument('--l5', default = 0.2, type = float) # 0.005 region loss 34 | parser.add_argument('--joint', default = 0, type = int) # jointly training 35 | parser.add_argument('--bin', default = 0, type = int) # use binary to train net 36 | parser.add_argument('--trcet', default = 1.0, type = float) # training percent of the dataset 37 | parser.add_argument('--layer', default = 2, type = int) # the number of mesh convolution layer 38 | parser.add_argument('--activ', default = '', type = str) # activate function of structure net : every layer 39 | parser.add_argument('--lr', default = 0.001, type = float) # learning rate need adjust if the loss is too large in the early training 40 | parser.add_argument('--fcvae', default = 0, type = int) 41 | parser.add_argument('--batch_size', default = 64, type = int) 42 | parser.add_argument('--K', default=3, type = int) 43 | parser.add_argument('--gcnn', default=0, type = int) 44 | parser.add_argument('--iddatfile', default = 'id.dat', type = str) 45 | parser.add_argument('--autoencoder', default='vae', type = str) 46 | parser.add_argument('--numvae', default = 2, type = int) 47 | parser.add_argument('--finaldim', default = 9, type = int) 48 | parser.add_argument('--filename', default = 'horse.obj', type = str) 49 | parser.add_argument('--featurefile', default = 'hips_vaefeature.mat', type = str) 50 | parser.add_argument('--controlid', nargs='+', default = [0], type=int) 51 | parser.add_argument('--epoch_deform', default=10000, type = int) 52 | parser.add_argument('--epoch_structure', default=100000, type = int) 53 | 54 | # inter 55 | parser.add_argument('--beginid', default='3', type = str) 56 | parser.add_argument('--endid', default='4', type = str) 57 | parser.add_argument('--interids', nargs='+', default=['3'], type = str) 58 | 59 | args = parser.parse_args() 60 | 61 | if not args.autoencoder.find('tan') == -1: 62 | args.l3 = 0.00 63 | 64 | args.featurefile = args.model + '_vaefeature.mat' 65 | args.filename = args.model + '.obj' 66 | args.iddatfile = args.model + '_vaeid.dat' 67 | 68 | ininame = getFileName(args.output_dir, '.ini') 69 | if len(ininame)>1: 70 | x = int(input('Please select a number:')) 71 | else: 72 | x = 0 73 | args = inifile2args(args, os.path.join(args.output_dir, ininame[x])) 74 | [print('{}: {}'.format(x,k)) for x,k in vars(args).items()] 75 | #args.output_dir = './1219002003K_3-fcvae_0-gcnn_0-l0_1000.0-l3_1.0-l4_0.1-layer_2-lr_0.001-lz_d_128-model_chairbacksub' 76 | 77 | # parafile = args.output_dir + '/checkpoint/convmesh-modelbest'# + str(args.maxepoch) 78 | 79 | # if not os.path.exists(parafile + '.index'): 80 | # training = True 81 | # else: 82 | # training = False 83 | 84 | # if test: 85 | # recentfolder = traversalDir_FirstDir('./') 86 | # args.output_dir = './' + recentfolder[1] 87 | # print(args.output_dir) 88 | 89 | datainfo = Config(args, False) 90 | datainfo.featurefile = args.featurefile 91 | 92 | print(args.output_dir) 93 | print(args.lz_d) 94 | model = modelvae.convMESH(datainfo) 95 | 96 | # model.recover_mesh(datainfo) 97 | # model.random_gen(datainfo) 98 | # model.interpolate1(datainfo, [args.beginid, args.endid]) 99 | #print(args.interids) 100 | if len(args.interids) != 0: 101 | model.interpolate1(datainfo, args.interids) 102 | 103 | # print(safe_b64encode(str(para))) 104 | # print(safe_b64decode(safe_b64encode(str(para)))) 105 | 106 | 107 | # hidden_dim = args.hiddendim 108 | # featurefile = args.featurefile 109 | # neighbourfile = args.neighbourfile 110 | # neighbourvariable = args.neighbourvariable 111 | # distancefile = args.distancefile 112 | # distancevariable = args.distancevariable 113 | # lambda0 = args.l0 114 | # lambda1 = args.l1 115 | # lambda2 = args.l2 116 | # lambda3 = args.l3 117 | # lr = args.lr 118 | # finaldim = args.finaldim 119 | # layers = args.layers 120 | # maxepoch = args.maxepoch 121 | 122 | # feature, logrmin, logrmax, smin, smax, pointnum = load_data(featurefile) 123 | 124 | # neighbour, degrees, maxdegree = load_neighbour(neighbourfile, neighbourvariable, pointnum) 125 | 126 | # geodesic_weight = load_geodesic_weight(distancefile, distancevariable, pointnum) 127 | 128 | # #model.train(feature, geodesic_weight, maxepoch) 129 | # if not test: 130 | # model.train_scvae() 131 | # # model_stack.train_vae_inorder(datainfo.geodesic_weight) 132 | #model.individual_dimension_vae(args.output_dir + '/convmesh-model-20000', datainfo) 133 | # recover_data1(model.base) 134 | #model.output_res_feature(args.output_dir + '/convmesh-model-20000', datainfo) 135 | # parafile = args.output_dir + '/convmesh-model-' + str(max(args.epoch_deform, args.epoch_structure)) 136 | 137 | # model.interpolate1(args.output_dir + '/convmesh-model-2000', datainfo, [2,3]) 138 | # model.recover_mesh(args.output_dir + '/convmesh-model-4000', datainfo) 139 | # model.recover_mesh(args.output_dir + '/convmesh-model-6000', datainfo) 140 | # model.recover_mesh(args.output_dir + '/convmesh-model-8000', datainfo) 141 | 142 | # model.recover_mesh(args.output_dir + '/convmesh-modelbest', datainfo) 143 | # model.individual_dimension(args.output_dir + '/convmesh-modelbest', datainfo) 144 | 145 | # model.get_res_feature(args.output_dir + '/convmesh-modelbest', datainfo) 146 | 147 | # with tf.Graph().as_default(): 148 | # a = tf.constant([[1,2],[3,4],[5,6]],name='a') 149 | # b = tf.constant([[[1,2],[3,4],[5,6]],[[1,2],[3,4],[7,8]]]) 150 | # # b = tf.tile(a,[2,3]) 151 | # print(np.shape(a)) 152 | # print(np.shape(b)) 153 | # sess = tf.Session() 154 | # print(sess.run(b-a)) 155 | 156 | # mesh1 = readmesh('scape.obj') 157 | # mesh2 = readmesh('4.obj') 158 | # v1=np.zeros((2500, 3)).astype('float32') 159 | # v2=np.zeros((2500, 3)).astype('float32') 160 | # point_array1 = mesh1.points() 161 | # point_array2 = mesh2.points() 162 | 163 | # T,R,t = icp.best_fit_transform(point_array2, point_array1) 164 | # C = np.ones((np.shape(point_array2)[0], 4)) 165 | # C[:,0:3] = point_array2 166 | # align_deforma_v = (np.dot(T, C.T).T)[:,0:3] 167 | 168 | # savemesh(mesh2, 'align.obj', align_deforma_v) 169 | 170 | 171 | 172 | -------------------------------------------------------------------------------- /code/python/plane_reproduce/train_stacknewvae.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import scipy.io as sio 4 | from six.moves import xrange 5 | import time 6 | import h5py 7 | import pickle 8 | import argparse 9 | from utils import * 10 | import model_stacknewvae as modelvae 11 | import os 12 | from config import * 13 | import icp 14 | import random 15 | 16 | 17 | # vae 18 | timecurrent = time.strftime('%m%d%H%M', time.localtime(time.time())) + '_' + str(random.randint(1000,9999)) 19 | test = False 20 | parser = argparse.ArgumentParser() 21 | 22 | parser.add_argument('--model', default = 'scape', type = str) # training model name 23 | parser.add_argument('--l0', default = 10.0, type = float) # 1.0 generation loss 24 | # parser.add_argument('--l1', default = 0.5, type = float) # 0.5 distance loss 25 | parser.add_argument('--l2', default = 10.0, type = float) # 0.5 weight loss 26 | parser.add_argument('--l3', default = 1.0, type = float) # 0.005 Kl loss 27 | parser.add_argument('--l4', default = 0.001, type = float) # 0.005 l2 loss 28 | # parser.add_argument('--l5', default = 0.2, type = float) # 0.005 region loss 29 | parser.add_argument('--joint', default = 0, type = int) # jointly training 30 | parser.add_argument('--bin', default = 0, type = int) # use binary to train net 31 | parser.add_argument('--trcet', default = 1.0, type = float) # training percent of the dataset 32 | 33 | # --------------------------not include in file name------------------------------------- 34 | parser.add_argument('--lz_d', nargs='+', default = [128, 32], type=int) # dimension of latent space 35 | parser.add_argument('--layer', default = 2, type = int) # the number of mesh convolution layer 36 | parser.add_argument('--activ', default = '', type = str) # activate function of structure net : every layer 37 | parser.add_argument('--lr', default = 0.001, type = float) # learning rate need adjust if the loss is too large in the early training 38 | parser.add_argument('--fcvae', default = 0, type = int) 39 | parser.add_argument('--batch_size', default = 64, type = int) 40 | parser.add_argument('--K', default=3, type = int) 41 | parser.add_argument('--gcnn', default=0, type = int) 42 | parser.add_argument('--iddatfile', default = 'id.dat', type = str) 43 | parser.add_argument('--autoencoder', default='vae', type = str) 44 | parser.add_argument('--numvae', default = 2, type = int) 45 | parser.add_argument('--finaldim', default = 9, type = int) 46 | parser.add_argument('--filename', default = 'horse.obj', type = str) 47 | parser.add_argument('--featurefile', default = 'hips_vaefeature.mat', type = str) 48 | parser.add_argument('--controlid', nargs='+', default = [0], type=int) 49 | parser.add_argument('--epoch_deform', default=15000, type = int) 50 | parser.add_argument('--epoch_structure', default=100000, type = int) 51 | parser.add_argument('--output_dir', default='./result'+timecurrent, type = str) 52 | 53 | args = parser.parse_args() 54 | 55 | if not args.autoencoder.find('tan') == -1: 56 | args.l3 = 0.00 57 | 58 | args.featurefile = args.model + '_vaefeature.mat' 59 | args.filename = args.model + '.obj' 60 | args.iddatfile = args.model + '_vaeid.dat' 61 | theList = ['K','gcnn','nvae','fcvae','activ','lr','layer','lz_d'] 62 | if not args.output_dir.find('./result'+timecurrent) == -1: 63 | a = './' + timecurrent + "-".join(["{}_{}".format(k,args.__dict__[k]) for k in sorted(args.__dict__.keys()) if len(k) < 6 and k not in theList]) 64 | a = a.replace(' ','') 65 | a = a.replace('[','') 66 | a = a.replace(']','') 67 | a = a.replace(',','--') 68 | args.output_dir = a.replace(',','--') 69 | 70 | #args.output_dir = './1219002003K_3-fcvae_0-gcnn_0-l0_1000.0-l3_1.0-l4_0.1-layer_2-lr_0.001-lz_d_128-model_chairbacksub' 71 | 72 | # parafile = args.output_dir + '/checkpoint/convmesh-modelbest'# + str(args.maxepoch) 73 | 74 | # if not os.path.exists(parafile + '.index'): 75 | # training = True 76 | # else: 77 | # training = False 78 | 79 | # if test: 80 | # recentfolder = traversalDir_FirstDir('./') 81 | # args.output_dir = './' + recentfolder[1] 82 | # print(args.output_dir) 83 | 84 | datainfo = Config(args) 85 | 86 | print(args.output_dir) 87 | print(args.lz_d) 88 | model = modelvae.convMESH(datainfo) 89 | 90 | 91 | # print(safe_b64encode(str(para))) 92 | # print(safe_b64decode(safe_b64encode(str(para)))) 93 | 94 | 95 | # hidden_dim = args.hiddendim 96 | # featurefile = args.featurefile 97 | # neighbourfile = args.neighbourfile 98 | # neighbourvariable = args.neighbourvariable 99 | # distancefile = args.distancefile 100 | # distancevariable = args.distancevariable 101 | # lambda0 = args.l0 102 | # lambda1 = args.l1 103 | # lambda2 = args.l2 104 | # lambda3 = args.l3 105 | # lr = args.lr 106 | # finaldim = args.finaldim 107 | # layers = args.layers 108 | # maxepoch = args.maxepoch 109 | 110 | # feature, logrmin, logrmax, smin, smax, pointnum = load_data(featurefile) 111 | 112 | # neighbour, degrees, maxdegree = load_neighbour(neighbourfile, neighbourvariable, pointnum) 113 | 114 | # geodesic_weight = load_geodesic_weight(distancefile, distancevariable, pointnum) 115 | 116 | 117 | 118 | # #model.train(feature, geodesic_weight, maxepoch) 119 | if not test: 120 | model.train_scvae() 121 | # # model_stack.train_vae_inorder(datainfo.geodesic_weight) 122 | #model.individual_dimension_vae(args.output_dir + '/convmesh-model-20000', datainfo) 123 | # recover_data1(model.base) 124 | #model.output_res_feature(args.output_dir + '/convmesh-model-20000', datainfo) 125 | # parafile = args.output_dir + '/convmesh-model-' + str(max(args.epoch_deform, args.epoch_structure)) 126 | with tf.device('/cpu:0'): 127 | model.recover_mesh(datainfo) 128 | model.random_gen(datainfo) 129 | model.interpolate1(datainfo, [3, 4]) 130 | # model.interpolate1(args.output_dir + '/convmesh-model-2000', datainfo, [2,3]) 131 | # model.recover_mesh(args.output_dir + '/convmesh-model-4000', datainfo) 132 | # model.recover_mesh(args.output_dir + '/convmesh-model-6000', datainfo) 133 | # model.recover_mesh(args.output_dir + '/convmesh-model-8000', datainfo) 134 | 135 | # model.recover_mesh(args.output_dir + '/convmesh-modelbest', datainfo) 136 | # model.individual_dimension(args.output_dir + '/convmesh-modelbest', datainfo) 137 | 138 | # model.get_res_feature(args.output_dir + '/convmesh-modelbest', datainfo) 139 | 140 | 141 | 142 | # with tf.Graph().as_default(): 143 | # a = tf.constant([[1,2],[3,4],[5,6]],name='a') 144 | # b = tf.constant([[[1,2],[3,4],[5,6]],[[1,2],[3,4],[7,8]]]) 145 | # # b = tf.tile(a,[2,3]) 146 | # print(np.shape(a)) 147 | # print(np.shape(b)) 148 | # sess = tf.Session() 149 | # print(sess.run(b-a)) 150 | 151 | # mesh1 = readmesh('scape.obj') 152 | # mesh2 = readmesh('4.obj') 153 | # v1=np.zeros((2500, 3)).astype('float32') 154 | # v2=np.zeros((2500, 3)).astype('float32') 155 | # point_array1 = mesh1.points() 156 | # point_array2 = mesh2.points() 157 | 158 | # T,R,t = icp.best_fit_transform(point_array2, point_array1) 159 | # C = np.ones((np.shape(point_array2)[0], 4)) 160 | # C[:,0:3] = point_array2 161 | # align_deforma_v = (np.dot(T, C.T).T)[:,0:3] 162 | 163 | # savemesh(mesh2, 'align.obj', align_deforma_v) 164 | 165 | 166 | 167 | -------------------------------------------------------------------------------- /code/python/plane_reproduce/train_symfeature.py: -------------------------------------------------------------------------------- 1 | import tensorflow as tf 2 | import numpy as np 3 | import scipy.io as sio 4 | from six.moves import xrange 5 | import time 6 | import h5py 7 | import pickle 8 | 9 | import argparse 10 | from utils import * 11 | import model_stacknewvae as modelvae 12 | import os 13 | from config import * 14 | import icp 15 | 16 | 17 | # vae 18 | timecurrent = time.strftime('%m%d%H%M%S', time.localtime(time.time())) 19 | test = False 20 | parser = argparse.ArgumentParser() 21 | 22 | parser.add_argument('--model', default = 'chair', type = str) 23 | 24 | parser.add_argument('--lz_d', nargs='+', default = [16], type=int) 25 | parser.add_argument('--l0', default = 1000.0, type = float) # 1.0 generation loss 26 | parser.add_argument('--l3', default = 1.0, type = float) # 0.005 Kl loss 27 | parser.add_argument('--l4', default = 0.0, type = float) # 0.005 l2 loss 28 | parser.add_argument('--lr', default = 0.001, type = float) # learning rate need adjust if the loss is too large in the early training 29 | parser.add_argument('--batch_size', default = 10000, type = int) 30 | 31 | parser.add_argument('--iddatfile', default = 'id.dat', type = str) 32 | parser.add_argument('--autoencoder', default='vae', type = str) 33 | parser.add_argument('--finaldim', default = 5, type = int) 34 | parser.add_argument('--featurefile', default = 'hips_vaefeature.mat', type = str) 35 | parser.add_argument('--maxepoch', default=500000, type = int) 36 | parser.add_argument('--output_dir', default='./result'+timecurrent, type = str) 37 | 38 | # parser.add_argument('--K', default=3, type = int) 39 | # parser.add_argument('--gcnn', default=0, type = int) 40 | # parser.add_argument('--layer', default = 3, type = int) 41 | parser.add_argument('--fcvae', default = 1, type = int) 42 | parser.add_argument('--numvae', default = 1, type = int) 43 | parser.add_argument('--filename', default = 'horse.obj', type = str) 44 | parser.add_argument('--controlid', nargs='+', default = [0], type=int) 45 | 46 | args = parser.parse_args() 47 | 48 | if not args.autoencoder.find('tan') == -1: 49 | args.l3 = 0.00 50 | 51 | if not args.output_dir.find('./result'+timecurrent) == -1: 52 | a = './' + timecurrent + "-".join(["{}_{}".format(k,args.__dict__[k]) for k in sorted(args.__dict__.keys()) if len(k) < 6]) 53 | a = a.replace(' ','') 54 | a = a.replace('[','') 55 | a = a.replace(']','') 56 | a = a.replace(',','--') 57 | args.output_dir = a.replace(',','--') 58 | 59 | # args.output_dir = './1217154045l0_1000.0-l3_1.0-l4_0.0-lr_0.001-lz_d_16-model_chair' 60 | 61 | args.featurefile = args.model + '_symfeature.mat' 62 | args.iddatfile = args.model + '_symid.dat' 63 | 64 | # if test: 65 | # recentfolder = traversalDir_FirstDir('./') 66 | # args.output_dir = './' + recentfolder[1] 67 | # print(args.output_dir) 68 | 69 | datainfo = Config(args, symmetry = True) 70 | argpaser2file(args, args.output_dir+'/'+timecurrent+'.ini') 71 | 72 | print(args.output_dir) 73 | print(args.lz_d) 74 | model = modelvae.convMESH(datainfo, symmetry = True) 75 | 76 | 77 | # print(safe_b64encode(str(para))) 78 | # print(safe_b64decode(safe_b64encode(str(para)))) 79 | 80 | if not test: 81 | model.train_total_vae() 82 | 83 | parafile = args.output_dir + '/convmesh-model-' + str(args.maxepoch) 84 | model.recover_mesh(parafile, datainfo) 85 | model.random_gen(parafile, datainfo) 86 | model.interpolate1(parafile, datainfo, [469, 477]) 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /data_checkpoint_link.txt: -------------------------------------------------------------------------------- 1 | # download data 2 | https://drive.google.com/file/d/1myWnHmuk2XD7lyHJL7KAgok89DT7SETF/view?usp=sharing 3 | 4 | # download checkpoint 5 | https://drive.google.com/file/d/1ItmG9tQ7vEE31anDU_z2yER2Wdon9_Ez/view?usp=sharing -------------------------------------------------------------------------------- /install.sh: -------------------------------------------------------------------------------- 1 | # Create a virtual environment 2 | virtualenv --no-site-packages -p python3 ~/sdmnet 3 | 4 | # Activate the virtual environment 5 | source ~/sdmnet/bin/activate 6 | 7 | # Update pip 8 | pip install -U pip 9 | 10 | # download pymesh binary 11 | mkdir package 12 | wget https://github.com/PyMesh/PyMesh/releases/download/v0.2.1/pymesh2-0.2.1-cp36-cp36m-linux_x86_64.whl 13 | mv pymesh2-0.2.1-cp36-cp36m-linux_x86_64.whl ./package/pymesh2-0.2.1-cp36-cp36m-linux_x86_64.whl 14 | 15 | # install tensorflow 16 | pip install tensorflow-gpu==1.12.0 17 | 18 | # install necessary library 19 | pip install h5py==2.8.0 20 | pip install pickleshare==0.7.5 21 | pip install scipy==1.3.0 22 | pip install scikit-learn==0.21.2 23 | pip install ./package/pymesh2-0.2.1-cp36-cp36m-linux_x86_64.whl 24 | pip install numpy==1.16.0 25 | 26 | pip install openmesh 27 | pip install trimesh 28 | echo "installing sucessfully" 29 | 30 | -------------------------------------------------------------------------------- /introduction.txt: -------------------------------------------------------------------------------- 1 | title = {{SDM-NET}: Deep Generative Network for Structured Deformable Mesh} 2 | 3 | author = {Gao, Lin and Yang, Jie and Wu, Tong and Yuan, Yu-Jie and Fu, Hongbo and Lai, Yu-Kun and Zhang, Hao(Richard)} 4 | 5 | os={Linux} -------------------------------------------------------------------------------- /liability form.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gaolinorange/SDMNET_stamp/5208f1210b77e3251dde3bdafc120a48dc69e833/liability form.pdf -------------------------------------------------------------------------------- /mvdata.sh: -------------------------------------------------------------------------------- 1 | unzip data.zip 2 | cp ./data/chair* ./code/python/chair_reproduce 3 | cp ./data/plane* ./code/python/plane_reproduce 4 | 5 | unzip checkpoint.zip 6 | mv ./checkpoint/05060123_6863bin_1-joint_1-l0_100.0-l2_10.0-l3_1.0-l4_0.001-model_chair-trcet_1.0 ./code/python/chair_reproduce 7 | mv ./checkpoint/05050238_2556bin_0-joint_0-l0_100.0-l2_10.0-l3_1.0-l4_0.001-model_plane-trcet_1.0 ./code/python/plane_reproduce -------------------------------------------------------------------------------- /teaser.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gaolinorange/SDMNET_stamp/5208f1210b77e3251dde3bdafc120a48dc69e833/teaser.jpg --------------------------------------------------------------------------------