├── .gitignore ├── LICENSE ├── README.md ├── classification.py ├── dataset.py ├── gaussian.npy ├── image ├── dgcnn_cls_gaussian │ ├── shapenetcorev2_250_modelnet40_train0_laptop.jpg │ ├── shapenetcorev2_250_modelnet40_train10_bookshelf.jpg │ ├── shapenetcorev2_250_modelnet40_train11_airplane.jpg │ ├── shapenetcorev2_250_modelnet40_train12_chair.jpg │ ├── shapenetcorev2_250_modelnet40_train14_plant.jpg │ ├── shapenetcorev2_250_modelnet40_train16_table.jpg │ ├── shapenetcorev2_250_modelnet40_train19_bench.jpg │ ├── shapenetcorev2_250_modelnet40_train7_vase.jpg │ ├── shapenetcorev2_250_shapenetcorev2_test37_earphone.jpg │ ├── shapenetcorev2_250_shapenetcorev2_test57_chair.jpg │ ├── shapenetcorev2_250_shapenetcorev2_test59_lamp.jpg │ ├── shapenetcorev2_250_shapenetcorev2_train10_bag.jpg │ ├── shapenetcorev2_250_shapenetcorev2_train12_bench.jpg │ ├── shapenetcorev2_250_shapenetcorev2_train13_table.jpg │ ├── shapenetcorev2_250_shapenetcorev2_train16_airplane.jpg │ └── shapenetcorev2_250_shapenetcorev2_train4_tower.jpg ├── dgcnn_cls_plane │ ├── shapenetcorev2_250_modelnet40_train0_laptop.jpg │ ├── shapenetcorev2_250_modelnet40_train10_bookshelf.jpg │ ├── shapenetcorev2_250_modelnet40_train11_airplane.jpg │ ├── shapenetcorev2_250_modelnet40_train12_chair.jpg │ ├── shapenetcorev2_250_modelnet40_train14_plant.jpg │ ├── shapenetcorev2_250_modelnet40_train16_table.jpg │ ├── shapenetcorev2_250_modelnet40_train19_bench.jpg │ ├── shapenetcorev2_250_modelnet40_train7_vase.jpg │ ├── shapenetcorev2_250_shapenetcorev2_test37_earphone.jpg │ ├── shapenetcorev2_250_shapenetcorev2_test57_chair.jpg │ ├── shapenetcorev2_250_shapenetcorev2_test59_lamp.jpg │ ├── shapenetcorev2_250_shapenetcorev2_train10_bag.jpg │ ├── shapenetcorev2_250_shapenetcorev2_train12_bench.jpg │ ├── shapenetcorev2_250_shapenetcorev2_train13_table.jpg │ ├── shapenetcorev2_250_shapenetcorev2_train16_airplane.jpg │ └── shapenetcorev2_250_shapenetcorev2_train4_tower.jpg ├── dgcnn_cls_sphere │ ├── shapenetcorev2_250_modelnet40_train0_laptop.jpg │ ├── shapenetcorev2_250_modelnet40_train10_bookshelf.jpg │ ├── shapenetcorev2_250_modelnet40_train11_airplane.jpg │ ├── shapenetcorev2_250_modelnet40_train12_chair.jpg │ ├── shapenetcorev2_250_modelnet40_train14_plant.jpg │ ├── shapenetcorev2_250_modelnet40_train16_table.jpg │ ├── shapenetcorev2_250_modelnet40_train19_bench.jpg │ ├── shapenetcorev2_250_modelnet40_train7_vase.jpg │ ├── shapenetcorev2_250_shapenetcorev2_test37_earphone.jpg │ ├── shapenetcorev2_250_shapenetcorev2_test57_chair.jpg │ ├── shapenetcorev2_250_shapenetcorev2_test59_lamp.jpg │ ├── shapenetcorev2_250_shapenetcorev2_train10_bag.jpg │ ├── shapenetcorev2_250_shapenetcorev2_train12_bench.jpg │ ├── shapenetcorev2_250_shapenetcorev2_train13_table.jpg │ ├── shapenetcorev2_250_shapenetcorev2_train16_airplane.jpg │ └── shapenetcorev2_250_shapenetcorev2_train4_tower.jpg ├── dgcnn_seg_gaussian │ ├── shapenetcorev2_290_modelnet40_train0_laptop.jpg │ ├── shapenetcorev2_290_modelnet40_train10_bookshelf.jpg │ ├── shapenetcorev2_290_modelnet40_train11_airplane.jpg │ ├── shapenetcorev2_290_modelnet40_train12_chair.jpg │ ├── shapenetcorev2_290_modelnet40_train14_plant.jpg │ ├── shapenetcorev2_290_modelnet40_train16_table.jpg │ ├── shapenetcorev2_290_modelnet40_train19_bench.jpg │ ├── shapenetcorev2_290_modelnet40_train7_vase.jpg │ ├── shapenetcorev2_290_shapenetcorev2_test37_earphone.jpg │ ├── shapenetcorev2_290_shapenetcorev2_test57_chair.jpg │ ├── shapenetcorev2_290_shapenetcorev2_test59_lamp.jpg │ ├── shapenetcorev2_290_shapenetcorev2_train10_bag.jpg │ ├── shapenetcorev2_290_shapenetcorev2_train12_bench.jpg │ ├── shapenetcorev2_290_shapenetcorev2_train13_table.jpg │ ├── shapenetcorev2_290_shapenetcorev2_train16_airplane.jpg │ └── shapenetcorev2_290_shapenetcorev2_train4_tower.jpg ├── dgcnn_seg_plane │ ├── shapenetcorev2_290_modelnet40_train0_laptop.jpg │ ├── shapenetcorev2_290_modelnet40_train10_bookshelf.jpg │ ├── shapenetcorev2_290_modelnet40_train11_airplane.jpg │ ├── shapenetcorev2_290_modelnet40_train12_chair.jpg │ ├── shapenetcorev2_290_modelnet40_train14_plant.jpg │ ├── shapenetcorev2_290_modelnet40_train16_table.jpg │ ├── shapenetcorev2_290_modelnet40_train19_bench.jpg │ ├── shapenetcorev2_290_modelnet40_train7_vase.jpg │ ├── shapenetcorev2_290_shapenetcorev2_test37_earphone.jpg │ ├── shapenetcorev2_290_shapenetcorev2_test57_chair.jpg │ ├── shapenetcorev2_290_shapenetcorev2_test59_lamp.jpg │ ├── shapenetcorev2_290_shapenetcorev2_train10_bag.jpg │ ├── shapenetcorev2_290_shapenetcorev2_train12_bench.jpg │ ├── shapenetcorev2_290_shapenetcorev2_train13_table.jpg │ ├── shapenetcorev2_290_shapenetcorev2_train16_airplane.jpg │ └── shapenetcorev2_290_shapenetcorev2_train4_tower.jpg ├── dgcnn_seg_sphere │ ├── shapenetcorev2_290_modelnet40_train0_laptop.jpg │ ├── shapenetcorev2_290_modelnet40_train10_bookshelf.jpg │ ├── shapenetcorev2_290_modelnet40_train11_airplane.jpg │ ├── shapenetcorev2_290_modelnet40_train12_chair.jpg │ ├── shapenetcorev2_290_modelnet40_train14_plant.jpg │ ├── shapenetcorev2_290_modelnet40_train16_table.jpg │ ├── shapenetcorev2_290_modelnet40_train19_bench.jpg │ ├── shapenetcorev2_290_modelnet40_train7_vase.jpg │ ├── shapenetcorev2_290_shapenetcorev2_test37_earphone.jpg │ ├── shapenetcorev2_290_shapenetcorev2_test57_chair.jpg │ ├── shapenetcorev2_290_shapenetcorev2_test59_lamp.jpg │ ├── shapenetcorev2_290_shapenetcorev2_train10_bag.jpg │ ├── shapenetcorev2_290_shapenetcorev2_train12_bench.jpg │ ├── shapenetcorev2_290_shapenetcorev2_train13_table.jpg │ ├── shapenetcorev2_290_shapenetcorev2_train16_airplane.jpg │ └── shapenetcorev2_290_shapenetcorev2_train4_tower.jpg ├── distance.png ├── gaussian.png ├── input │ ├── modelnet40_train0_laptop_orign.jpg │ ├── modelnet40_train10_bookshelf_orign.jpg │ ├── modelnet40_train11_airplane_orign.jpg │ ├── modelnet40_train12_chair_orign.jpg │ ├── modelnet40_train14_plant_orign.jpg │ ├── modelnet40_train16_table_orign.jpg │ ├── modelnet40_train19_bench_orign.jpg │ ├── modelnet40_train7_vase_orign.jpg │ ├── shapenetcorev2_test37_earphone_orign.jpg │ ├── shapenetcorev2_test57_chair_orign.jpg │ ├── shapenetcorev2_test59_lamp_orign.jpg │ ├── shapenetcorev2_train10_bag_orign.jpg │ ├── shapenetcorev2_train12_bench_orign.jpg │ ├── shapenetcorev2_train13_table_orign.jpg │ ├── shapenetcorev2_train16_airplane_orign.jpg │ └── shapenetcorev2_train4_tower_orign.jpg ├── original_gaussian │ ├── shapenetcorev2_278_modelnet40_train0_laptop.jpg │ ├── shapenetcorev2_278_modelnet40_train10_bookshelf.jpg │ ├── shapenetcorev2_278_modelnet40_train11_airplane.jpg │ ├── shapenetcorev2_278_modelnet40_train12_chair.jpg │ ├── shapenetcorev2_278_modelnet40_train14_plant.jpg │ ├── shapenetcorev2_278_modelnet40_train16_table.jpg │ ├── shapenetcorev2_278_modelnet40_train19_bench.jpg │ ├── shapenetcorev2_278_modelnet40_train7_vase.jpg │ ├── shapenetcorev2_278_shapenetcorev2_test37_earphone.jpg │ ├── shapenetcorev2_278_shapenetcorev2_test57_chair.jpg │ ├── shapenetcorev2_278_shapenetcorev2_test59_lamp.jpg │ ├── shapenetcorev2_278_shapenetcorev2_train10_bag.jpg │ ├── shapenetcorev2_278_shapenetcorev2_train12_bench.jpg │ ├── shapenetcorev2_278_shapenetcorev2_train13_table.jpg │ ├── shapenetcorev2_278_shapenetcorev2_train16_airplane.jpg │ └── shapenetcorev2_278_shapenetcorev2_train4_tower.jpg ├── original_plane │ ├── shapenetcorev2_278_modelnet40_train0_laptop.jpg │ ├── shapenetcorev2_278_modelnet40_train10_bookshelf.jpg │ ├── shapenetcorev2_278_modelnet40_train11_airplane.jpg │ ├── shapenetcorev2_278_modelnet40_train12_chair.jpg │ ├── shapenetcorev2_278_modelnet40_train14_plant.jpg │ ├── shapenetcorev2_278_modelnet40_train16_table.jpg │ ├── shapenetcorev2_278_modelnet40_train19_bench.jpg │ ├── shapenetcorev2_278_modelnet40_train7_vase.jpg │ ├── shapenetcorev2_278_shapenetcorev2_test37_earphone.jpg │ ├── shapenetcorev2_278_shapenetcorev2_test57_chair.jpg │ ├── shapenetcorev2_278_shapenetcorev2_test59_lamp.jpg │ ├── shapenetcorev2_278_shapenetcorev2_train10_bag.jpg │ ├── shapenetcorev2_278_shapenetcorev2_train12_bench.jpg │ ├── shapenetcorev2_278_shapenetcorev2_train13_table.jpg │ ├── shapenetcorev2_278_shapenetcorev2_train16_airplane.jpg │ └── shapenetcorev2_278_shapenetcorev2_train4_tower.jpg ├── original_sphere │ ├── shapenetcorev2_278_modelnet40_train0_laptop.jpg │ ├── shapenetcorev2_278_modelnet40_train10_bookshelf.jpg │ ├── shapenetcorev2_278_modelnet40_train11_airplane.jpg │ ├── shapenetcorev2_278_modelnet40_train12_chair.jpg │ ├── shapenetcorev2_278_modelnet40_train14_plant.jpg │ ├── shapenetcorev2_278_modelnet40_train16_table.jpg │ ├── shapenetcorev2_278_modelnet40_train19_bench.jpg │ ├── shapenetcorev2_278_modelnet40_train7_vase.jpg │ ├── shapenetcorev2_278_shapenetcorev2_test37_earphone.jpg │ ├── shapenetcorev2_278_shapenetcorev2_test57_chair.jpg │ ├── shapenetcorev2_278_shapenetcorev2_test59_lamp.jpg │ ├── shapenetcorev2_278_shapenetcorev2_train10_bag.jpg │ ├── shapenetcorev2_278_shapenetcorev2_train12_bench.jpg │ ├── shapenetcorev2_278_shapenetcorev2_train13_table.jpg │ ├── shapenetcorev2_278_shapenetcorev2_train16_airplane.jpg │ └── shapenetcorev2_278_shapenetcorev2_train4_tower.jpg ├── plane.png └── sphere.png ├── inference.py ├── loss.py ├── main.py ├── model.py ├── reconstruction.py ├── sphere.npy ├── svm.py ├── tensorboard ├── Classify_dgcnn_cls_k20 │ └── events.out.tfevents.1578666096.human1 ├── Classify_dgcnn_cls_k40_1024_b32 │ └── events.out.tfevents.1579746166.server231 ├── Reconstruct_dgcnn_cls_k20_gaussian │ └── events.out.tfevents.1578226376.human1 ├── Reconstruct_dgcnn_cls_k20_plane │ └── events.out.tfevents.1577427494.human1 ├── Reconstruct_dgcnn_cls_k20_sphere │ └── events.out.tfevents.1577698740.human1 ├── Reconstruct_dgcnn_cls_k40_gaussian │ └── events.out.tfevents.1579955081.server231 ├── Reconstruct_dgcnn_cls_k40_plane │ └── events.out.tfevents.1577866606.human1 ├── Reconstruct_dgcnn_cls_k40_sphere │ └── events.out.tfevents.1577935530.human1 ├── Reconstruct_dgcnn_cls_k40_sphere_1024_b32 │ └── events.out.tfevents.1579919706.server231 ├── Reconstruct_dgcnn_seg_k20_gaussian │ ├── events.out.tfevents.1578371932.human1 │ └── events.out.tfevents.1578661771.human1 ├── Reconstruct_dgcnn_seg_k20_plane │ ├── events.out.tfevents.1578186628.human1 │ └── events.out.tfevents.1578443368.human1 ├── Reconstruct_dgcnn_seg_k20_sphere │ ├── events.out.tfevents.1578202920.human1 │ └── events.out.tfevents.1578447006.human1 ├── Reconstruct_dgcnn_seg_k40_gaussian │ └── events.out.tfevents.1580628995.server231 ├── Reconstruct_dgcnn_seg_k40_plane │ └── events.out.tfevents.1580304772.server231 ├── Reconstruct_dgcnn_seg_k40_sphere │ └── events.out.tfevents.1580304803.server231 ├── Reconstruct_original_gaussian │ └── events.out.tfevents.1578226412.human1 ├── Reconstruct_original_plane │ └── events.out.tfevents.1577003758.human1 └── Reconstruct_original_sphere │ └── events.out.tfevents.1577366104.human1 ├── utils.py └── visualization.py /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | */.DS_Store 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 An Tao 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unsupervised Point Cloud Reconstruction for Classific Feature Learning 2 | ## Introduction 3 | Can unsupervised point cloud reconstruction extract features suitable for classification? 4 | 5 | This work aims to show whether learning a unsupervised point cloud reconstruction task, for example FoldingNet, is able to extract features performing well in classification. We do all experiments under the framework of FoldingNet. 6 | 7 | Details for FoldingNet see **FoldingNet: Point Cloud Auto-encoder via Deep Grid Deformation** (https://arxiv.org/abs/1712.07262). 8 | 9 | We also tried to use [DGCNN](https://arxiv.org/abs/1831.07829) as encoder. DGCNN provides two type of networks, one for classification and one for segmentation. We use "DGCNN_Cls" to denote network for classification and "DGCNN_Seg" for segmentation. For both network, we adopt the feature extraction part as encoder in FoldingNet. 10 | 11 | Experimental results show that better reconstruction performance do not correspond with better classfication accuracy of linear SVM classifier. Feature which good at classfication contains more nonobjective information, losing the ability to reconstruct detailedly. However, it is only this nonobjective information that is capable to capture the high level characteristic of its belonging category and thus make a great contribution in classfication task. 12 | 13 | **The key contributions of this work are as follows:** 14 | 15 | - We provide a pytorch reimplementation for FoldingNet. 16 | - We also use source points for decoder from sphere surface and gaussian distribution. Results show that source points from sphere surface can reconstruct better. 17 | - We do experiments using DGCNN as encoder and provide the classification performance for linear SVM classifier. The transfer dataset performance is better than the state-of-the-art unsupervised methods. We also train our best unsupervised model supervisedly, our unsupervised results still win out. 18 | - We illustrate that better reconstruction results do not correspond with better feature for classfication. 19 | 20 | If you find this work useful, please cite: 21 | ``` 22 | @article{tao2020, 23 | Author = {An Tao}, 24 | Title = {Unsupervised Point Cloud Reconstruction for Classific Feature Learning}, 25 | Journal = {https://github.com/antao97/UnsupervisedPointCloudReconstruction}, 26 | Year = {2020} 27 | } 28 | ``` 29 | 30 |   31 | ## Requirements 32 | - Python 3.7 33 | - PyTorch 1.2 34 | - CUDA 10.0 35 | - Package: glob, h5py, tensorflow, tensorboard, tensorboardX and sklearn 36 | 37 |   38 | ## Download datasets 39 | Download the HDF5 format datasets (where each shape is sampled 2,048 points uniformly): 40 | 41 | - ShapeNetCore.v2 (0.98G) [[TsinghuaCloud]](https://cloud.tsinghua.edu.cn/f/06a3c383dc474179b97d/) [[BaiduDisk]](https://pan.baidu.com/s/154As2kzHZczMipuoZIc0kg) 42 | - ModelNet40 (194M) [[TsinghuaCloud]](https://cloud.tsinghua.edu.cn/f/b3d9fe3e2a514def8097/) [[BaiduDisk]](https://pan.baidu.com/s/1NQZgN8tvHVqQntxefcdVAg) 43 | 44 | You can find more details about the above datasets in this [repo](https://github.com/antao97/PointCloudDatasets). 45 | 46 |   47 | ## Experiment settings 48 | To evaluate the quality of extracted features, we use ShapeNetCore.v2 dataset to both train the FoldingNet auto-encoder and a linear SVM classifier. Specifically, we train the linear SVM classifier on ShapeNetCore.v2 dataset using the features (latent representations) obtained from the auto-encoder, while training the autoencoder from the ShapeNetCore.v2 dataset with 278 epoches. 49 | 50 | For transfer performance, we train the linear SVM classifier on ModelNet 40 dataset using the features (latent representations) obtained from the same auto-encoder trained from the ShapeNetCore.v2 dataset. 51 | 52 | FoldingNet has demonstrated that a 2D plane grid can be gradually folded into a meaningful point cloud. However, can uniformly sampled points from surface of sphere gradually turn into a meaningful point cloud? This is reasonable because 3D point clouds are actually sampled from surface of an object. We generate source points from surface of sphere using farthest point sampling algorithm. 53 | 54 | A cloud of points corresponding to a shape can also be thought of as samples from a distribution that corresponds to the surface of this shape. Thus the goal for reconstruction task is to train a model which is able to transform source distribution, for example gaussian distribution, into the distribution corresponds to the surface of this shape. In this work we also try to use source points for decoder sampled from gaussian distribution N(0, I). However, it's worth noting that there is no relationship among x, y and z axises for points sampled from gaussian distribution, while for points from both plane grid and sphere surfance the relationship exists. Also because points sampled from gaussian distribution are i.i.d., there is no relationship among all points. 55 | 56 | In all experiments, we follow the training scheme of FoldingNet. 57 | 58 | **Note that:** 59 | 60 | - Other than using the modified Chamfer distance in FoldingNet paper, we adopt the original Chamfer distance proposed by [A Point Set Generation Network for 3D Object Reconstruction from a Single Image](https://arxiv.xilesou.top/pdf/1612.00603.pdf): 61 | 62 |

63 | 64 |

65 | 66 | - To use the local covariance proposed in FoldingNet paper, pleanse comment line 49 and uncomment line 50 in `model.py`. See this [issue](issues/1) for detailed information. 67 | 68 | **To train the network, run** 69 | ``` 70 | python main.py --exp_name --dataset_root --encoder --k <16 | 20 | 40> --shape --dataset shapenetcorev2 --gpu 71 | ``` 72 | 73 | You can download our already trained models from [[TsinghuaCloud]](https://cloud.tsinghua.edu.cn/d/835fb3e4b7dd43e88c1e/) or [[BaiduDisk]](https://pan.baidu.com/s/1FDNgZnrkCGqbQzH-CM6uBw) and place them under `snapshot/`. 74 | 75 | **To evaluate the performance of a given trained model, run** 76 | ``` 77 | python main.py --eval --model_path --dataset_root --encoder --k <16 | 20 | 40> --shape --dataset --batch_size 4 --gpu 78 | ``` 79 | 80 | Use `--no_cuda` if you want to run in CPU. 81 | 82 | **To visulize the reconstruction performance, run** 83 | ``` 84 | python visualization.py --dataset_root --dataset --item= --split --encoder --k <16 | 20 | 40> --shape --model_path=snapshot//models --draw_original --draw_source_points 85 | ``` 86 | 87 | Our script generates XML files and you are required to use [Mitsuba](https://www.mitsuba-renderer.org/index.html) to render them. 88 | 89 | **To use Tensorboard, run** 90 | ``` 91 | tensorboard --logdir tensorboard --bind_all 92 | ``` 93 | You can find the Tensorboard records under `tensorboard/`. 94 | 95 |   96 | ## Classification accuracy of linear SVM classifier 97 | ### Results with different settings 98 | | | Encoder | K | Epochs | Shape | ShapeNetCore.v2 | ModelNet40 | 99 | | :---: | :---: | :---: | :---: | :---: | :---: | :---: | 100 | | FoldingNet paper | Original | 16 | 278 | Plane | Unknown | 88.4% | 101 | | This work | Original | 16 | 278 | Plane | 81.5% | 88.4% | 102 | | This work | Original | 16 | 278 | Sphere | 81.9% | 88.8% | 103 | | This work | Original | 16 | 278 | Gaussian | 81.2% | 87.6% | 104 | | This work | DGCNN_cls | 20 | 250 | Plane | 83.7% | 90.6% | 105 | | This work | DGCNN_cls | 20 | 250 | Sphere | 83.7% | **91.0%** | 106 | | This work | DGCNN_cls | 20 | 250 | Gaussian | **84.0%** | 90.6% | 107 | | This work | DGCNN_cls | 40 | 250 | Plane | 83.5% | 90.0% | 108 | | This work | DGCNN_cls | 40 | 250 | Sphere | 83.6% | 90.0% | 109 | | This work | DGCNN_cls | 40 | 250 | Gaussian | 83.2% | 90.0% | 110 | | This work | DGCNN_seg | 20 | 290 | Plane | 83.2% | 90.0% | 111 | | This work | DGCNN_seg | 20 | 290 | Sphere | 83.5% | 90.4% | 112 | | This work | DGCNN_seg | 20 | 290 | Gaussian | 83.3% | 89.9% | 113 | | This work | DGCNN_seg | 40 | 290 | Plane | 83.7% | 89.6% | 114 | | This work | DGCNN_seg | 40 | 290 | Sphere | 83.6% | 90.7% | 115 | | This work | DGCNN_seg | 40 | 290 | Gaussian | 83.2% | 89.8% | 116 | 117 | ### Comparison to supervised method 118 | We also train DGCNN_Cls with classification task on ShapeNetCore.v2 dataset, using the training scheme from DGCNN paper. We train two networks for classification. One uses the setting the same as reconstruction and the other uses the best setting for classification. 119 | 120 | | Task | Encoder | K | Feature Dim | Epochs | Batch Size | ShapeNetCore.v2 | ModelNet40 | 121 | | :---: | :---: | :---: | :---: | :---: | :---: | :---: | :---: | 122 | | Reconstruction | DGCNN_cls | 20 | 512 | 250 | 16 | 83.7% | 91.0% | 123 | | Classification | DGCNN_cls | 20 | 512 | 250 | 16 | 94.5% | 90.4% | 124 | | Reconstruction | DGCNN_cls | 40 | 1024 | 250 | 32 | 82.8% | 89.0% | 125 | | Classification | DGCNN_cls | 40 | 1024 | 250 | 32 | **96.8%** | **92.0%** | 126 | 127 | If you want to run this experiment, just run 128 | ``` 129 | python main.py --task --exp_name --dataset_root --encoder dgcnn_cls --feat_dims <512 | 1024> --k <20 | 40> --dataset shapenetcorev2 --batch_size <16 | 32> --gpu 130 | ``` 131 | 132 | You can also find our trained model in above mentioned links. To evaluate the performance, run 133 | ``` 134 | python main.py --eval --task --model_path --dataset_root --encoder dgcnn_cls --feat_dims <512 | 1024> --k <20 | 40> --shape sphere --dataset --batch_size 4 --gpu 135 | ``` 136 | 137 | ### Baseline Results 138 | 139 | We test classification accuracy of linear SVM classifier with untrained encoder. This table shows the baseline performance. 140 | 141 | | Encoder | K | ShapeNetCore.v2 | ModelNet40 | 142 | | :---: | :---: | :---: | :---: | 143 | | Original | 16 | 25.4% | 5.2% | 144 | | DGCNN_cls | 20 | 74.7% | 69.5% | 145 | | DGCNN_cls | 40 | **75.0%** | **73.0%** | 146 | | DGCNN_seg | 20 | 72.0% | 62.0% | 147 | | DGCNN_seg | 40 | 73.1% | 64.0% | 148 | 149 | If you want to run this experiment, just run 150 | ``` 151 | python main.py --eval --dataset_root --encoder dgcnn_cls --k <16 | 20 | 40> --dataset --gpu 152 | ``` 153 | 154 | ### Compare to other unsupervised feature learning models 155 | 156 | Models are all trained in ShapeNetCore dataset and transfered into ModelNet40 dataset. 157 | 158 | | Model | Reference | ModelNet40 | 159 | | :---: | :---: | :---: | 160 | | [SPH](https://pdfs.semanticscholar.org/da27/5dcffd835ddfd41fd73ea147c767c605d3f0.pdf) | SGP 2003| 68.2% | 161 | | [LFD](http://citeseerx.ist.psu.edu/viewdoc/download;jsessionid=46D0F4C488A2AF0FCF3A63837F391EED?doi=10.1.1.10.8872&rep=rep1&type=pdf) | CGF 2003| 75.5% | 162 | | [T-L Network](https://arxiv.xilesou.top/pdf/1603.08637) | ECCV 2016 | 74.4% | 163 | | [VConv-DAE](https://arxiv.xilesou.top/pdf/1604.03755) | ECCV 2016 | 75.5% | 164 | | [3D-GAN](http://papers.nips.cc/paper/6096-learning-a-probabilistic-latent-space-of-object-shapes-via-3d-generative-adversarial-modeling.pdf) | NIPS 2016 | 83.3% | 165 | | [Latent-GAN](https://arxiv.xilesou.top/pdf/1707.02392) | ICML 2018 | 83.7% | 166 | | [PointGrow](https://arxiv.xilesou.top/pdf/1810.05591) | ArXiv 2018 | 83.8% | 167 | | [MRTNet-VAE](http://openaccess.thecvf.com/content_ECCV_2018/papers/Matheus_Gadelha_Multiresolution_Tree_Networks_ECCV_2018_paper.pdf) | ECCV 2018 | 86.4% | 168 | | [PointFlow](https://arxiv.org/pdf/1906.12320) | ICCV 2019 | 86.8% | 169 | | [PCGAN](https://arxiv.xilesou.top/pdf/1810.05795) | ArXiv 2018 | 87.8% | 170 | | [FoldingNet](https://arxiv.org/abs/1712.07262) | CVPR 2018 | 88.4% | 171 | | [PointCapsNet](http://openaccess.thecvf.com/content_CVPR_2019/papers/Zhao_3D_Point_Capsule_Networks_CVPR_2019_paper.pdf) | CVPR 2019 | 88.9% | 172 | | [Multi-Task](https://arxiv.org/pdf/1910.08207) | ICCV 2019 | 89.1% | 173 | | [MAP-VAE](https://arxiv.xilesou.top/pdf/1907.12704.pdf) | ICCV 2019 | 90.2% | 174 | | FoldingNet (DGCNN_Cls_K20 + Sphere) | - | **91.0%** | 175 | 176 |   177 | ## Reconstruction performance 178 | ### Sourse 179 |    2D Plane   Spherical surface Gaussian distribution 180 |

181 | 182 | 183 | 184 |

185 | 186 | ### ShapeNetCore.v2 dataset 187 |            Original         DGCNN_Cls (K20)     DGCNN_Seg (K20) 188 | 189 |  Input   Plane  Sphere Gaussian  Plane  Sphere Gaussian  Plane  Sphere Gaussian 190 |

191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 |

272 | 273 | ### ModelNet40 dataset 274 |            Original         DGCNN_Cls (K20)     DGCNN_Seg (K20) 275 | 276 |  Input   Plane  Sphere Gaussian  Plane  Sphere Gaussian  Plane  Sphere Gaussian 277 |

278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 |

359 | 360 |   361 | ## CD (Chamfer Distance) scores for trained model 362 | We provide the avg CD scores in each dataset after training, which serves as the measurement of folding performance. CD scores are multiplied by 10^4. 363 | 364 | ### Results with different settings 365 | 366 | | Encoder | K | Shape | ShapeNetCore.v2 | ModelNet40 | 367 | | :---: | :---: | :---: | :---: | :---: | 368 | | Original | 16 | Plane | 11.11 | 9.88 | 369 | | Original | 16 | Sphere | 10.58 | **9.69** | 370 | | Original | 16 | Gaussian | **9.63** | 11.09 | 371 | | DGCNN_cls | 20 | Plane | 11.08 | 12.68 | 372 | | DGCNN_cls | 20 | Sphere | 11.07 | 12.68 | 373 | | DGCNN_cls | 20 | Gaussian | 11.18 | 12.77 | 374 | | DGCNN_cls | 40 | Plane | 11.74 | 13.36 | 375 | | DGCNN_cls | 40 | Sphere | 11.17 | 12.58 | 376 | | DGCNN_cls | 40 | Gaussian | 14.77 | 17.03 | 377 | | DGCNN_seg | 20 | Plane | 11.28 | 12.55 | 378 | | DGCNN_seg | 20 | Sphere | 10.88 | 12.49 | 379 | | DGCNN_seg | 20 | Gaussian | 13.36 | 15.19 | 380 | | DGCNN_seg | 40 | Plane | 11.19 | 12.69 | 381 | | DGCNN_seg | 40 | Sphere | 10.68 | 12.69 | 382 | | DGCNN_seg | 40 | Gaussian | 11.95 | 13.74 | 383 | 384 | ### Compare to other reconstruction methods 385 | Models are all trained and evaluated in ShapeNetCore dataset. 386 | 387 | | Model | Reference | ShapeNetCore.v2 | 388 | | :---: | :---: | :---: | 389 | | [Latent-GAN](https://arxiv.xilesou.top/pdf/1707.02392) | ICML 2018 | **7.12** | 390 | | [AtlasNet](https://arxiv.xilesou.top/pdf/1802.05383.pdf) | CVPR 2018 | 5.13 | 391 | | [PointFlow](https://arxiv.org/pdf/1906.12320.pdf) | ICCV 2019 | 7.54 | 392 | | FoldingNet (Gaussian) | - | 9.63 | 393 | 394 |   395 | ## Performance analysis 396 | ### Effectiveness of our reimplementation 397 | The performance on ModelNet40 dataset is enough to validate the effectiveness of our reimplementation. 398 | 399 | ### Points from sphere surface 400 | The results of sphere show that the so-called "FoldingNet" does not restrict with folding operation. The essensce of FoldingNet decoder, i.e. MLP, is to map points from original space into new space, no matter the structure of points in original space is 2D plane grid or something else. Also, this mapping does not change neighbouring relations of points, which means adjacent points in original space are also adjacent in new space. Because point clouds are sampled from surface of an object, i.e. closed surface, the closed surface can be seen as mapped from surface of sphere just like pinching a blowing glass or Chinese sugar-figure. Thus it is reasonable to map uniformly sampled points from sphere surface to target point clouds through MLP, and as a matter of course we would consider reconstruction results for source points from sphere surface is better than 2D plane grid. 401 | 402 | ### Points from gaussian distribution 403 | Because each point is sampled independently from same gaussian distribution N(0, I), i.e. i.i.d., there is no relationship among points and the values of three axises. The reconstruction model has to learn the relationship with no prior knowledge, just like drawing on a white paper. If designed properly source points from gaussian distribution can do perfect job for reconstruction, but they can not help to extract good features for classification. This is because in order to learn the relationship the model need to focus to every details, and that is the reason why the learned model lose the ablity to extract feature in a more abstract sight, which is crucial for classification. The experimental results validate that in order to extract features suitable for classification, it is better to have some proper prior knowledge for souce points in order. 404 | 405 | ### Classification v.s. reconstruction 406 | This experiment shows that training without labels can also obtain comparable results and thus validates the effectiveness of reconstruction. 407 | 408 | ### Reconstruction performance 409 | All networks run well in low curvature smooth surface, but fail in not differentiable area (crossing of planes) and high curvature surface. Because a large number of training samples have four legs, e.g. chair and table, reconstruction network also runs well in these four legs shapes. The visualized results also show characteristics of reconstructed point cloud with different corresponding source points types and encoder types. 410 | 411 | From both visualized results and avg CD sorces, the overall reconstruction performance of ShapeNetCore.v2 dataset (training dataset) is better than ModelNet40 dataset (transfer dataset). 412 | 413 |   414 | #### Reference repos: 415 | 416 | - [FoldingNet](http://www.merl.com/research/license#FoldingNet) 417 | - [XuyangBai/FoldingNet](https://github.com/XuyangBai/FoldingNet) 418 | - [WangYueFt/dgcnn](https://github.com/WangYueFt/dgcnn) 419 | - [antao97/PointCloudDatasets](https://github.com/antao97/PointCloudDatasets) 420 | - [zekunhao1995/PointFlowRenderer](https://github.com/zekunhao1995/PointFlowRenderer) 421 | -------------------------------------------------------------------------------- /classification.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | @Author: An Tao 5 | @Contact: ta19@mails.tsinghua.edu.cn 6 | @File: reconstruction.py 7 | @Time: 2020/1/2 10:26 AM 8 | """ 9 | 10 | import os 11 | import sys 12 | import time 13 | import shutil 14 | import numpy as np 15 | import torch 16 | import torch.optim as optim 17 | from torch.optim.lr_scheduler import CosineAnnealingLR 18 | import sklearn.metrics as metrics 19 | 20 | from tensorboardX import SummaryWriter 21 | 22 | from model import ClassificationNet 23 | from dataset import Dataset 24 | from utils import Logger 25 | 26 | 27 | class Classification(object): 28 | def __init__(self, args): 29 | self.dataset_name = args.dataset 30 | if args.epochs != None: 31 | self.epochs = args.epochs 32 | else: 33 | self.epochs = 250 34 | self.batch_size = args.batch_size 35 | self.snapshot_interval = args.snapshot_interval 36 | self.no_cuda = args.no_cuda 37 | self.model_path = args.model_path 38 | 39 | # create exp directory 40 | file = [f for f in args.model_path.split('/')] 41 | if args.exp_name != None: 42 | self.experiment_id = "Classify_" + args.exp_name 43 | elif file[-2] == 'models': 44 | self.experiment_id = file[-3] 45 | else: 46 | self.experiment_id = "Classify" + time.strftime('%m%d%H%M%S') 47 | snapshot_root = 'snapshot/%s' % self.experiment_id 48 | tensorboard_root = 'tensorboard/%s' % self.experiment_id 49 | self.save_dir = os.path.join(snapshot_root, 'models/') 50 | self.tboard_dir = tensorboard_root 51 | 52 | # check arguments 53 | if self.model_path == '': 54 | if not os.path.exists(self.save_dir): 55 | os.makedirs(self.save_dir) 56 | else: 57 | choose = input("Remove " + self.save_dir + " ? (y/n)") 58 | if choose == "y": 59 | shutil.rmtree(self.save_dir) 60 | os.makedirs(self.save_dir) 61 | else: 62 | sys.exit(0) 63 | if not os.path.exists(self.tboard_dir): 64 | os.makedirs(self.tboard_dir) 65 | else: 66 | shutil.rmtree(self.tboard_dir) 67 | os.makedirs(self.tboard_dir) 68 | sys.stdout = Logger(os.path.join(snapshot_root, 'log.txt')) 69 | self.writer = SummaryWriter(log_dir=self.tboard_dir) 70 | 71 | # print args 72 | print(str(args)) 73 | 74 | # get gpu id 75 | gids = ''.join(args.gpu.split()) 76 | self.gpu_ids = [int(gid) for gid in gids.split(',')] 77 | self.first_gpu = self.gpu_ids[0] 78 | 79 | # generate dataset 80 | self.train_dataset = Dataset( 81 | root=args.dataset_root, 82 | dataset_name=args.dataset, 83 | split='all', 84 | num_points=args.num_points, 85 | random_translate=True, 86 | random_rotate=args.use_rotate, 87 | random_jitter=args.use_jitter 88 | ) 89 | self.train_loader = torch.utils.data.DataLoader( 90 | self.train_dataset, 91 | batch_size=args.batch_size, 92 | shuffle=True, 93 | num_workers=args.workers 94 | ) 95 | print("Training set size:", self.train_loader.dataset.__len__()) 96 | 97 | # initialize model 98 | self.model = ClassificationNet(args) 99 | if self.model_path != '': 100 | self._load_pretrain(args.model_path) 101 | 102 | # load model to gpu 103 | if not self.no_cuda: 104 | if len(self.gpu_ids) != 1: # multiple gpus 105 | self.model = torch.nn.DataParallel(self.model.cuda(self.first_gpu), self.gpu_ids) 106 | else: 107 | self.model = self.model.cuda(self.gpu_ids[0]) 108 | 109 | # initialize optimizer 110 | self.parameter = self.model.parameters() 111 | self.optimizer = optim.SGD(self.parameter, lr=0.1, weight_decay=1e-4) 112 | self.scheduler = CosineAnnealingLR(self.optimizer, self.epochs, eta_min=1e-3) 113 | 114 | 115 | def run(self): 116 | self.train_hist = { 117 | 'loss': [], 118 | 'per_epoch_time': [], 119 | 'total_time': [] 120 | } 121 | best_loss = 1000000000 122 | print('Training start!!') 123 | start_time = time.time() 124 | self.model.train() 125 | if self.model_path != '': 126 | start_epoch = self.model_path[-7:-4] 127 | if start_epoch[0] == '_': 128 | start_epoch = start_epoch[1:] 129 | start_epoch = int(start_epoch) 130 | else: 131 | start_epoch = 0 132 | for epoch in range(start_epoch, self.epochs): 133 | loss = self.train_epoch(epoch) 134 | 135 | # save snapeshot 136 | if (epoch + 1) % self.snapshot_interval == 0: 137 | self._snapshot(epoch + 1) 138 | if loss < best_loss: 139 | best_loss = loss 140 | self._snapshot('best') 141 | 142 | # save tensorboard 143 | if self.writer: 144 | self.writer.add_scalar('Train Loss', self.train_hist['loss'][-1], epoch) 145 | self.writer.add_scalar('Learning Rate', self._get_lr(), epoch) 146 | 147 | # finish all epoch 148 | self._snapshot(epoch + 1) 149 | if loss < best_loss: 150 | best_loss = loss 151 | self._snapshot('best') 152 | self.train_hist['total_time'].append(time.time() - start_time) 153 | print("Avg one epoch time: %.2f, total %d epochs time: %.2f" % (np.mean(self.train_hist['per_epoch_time']), 154 | self.epochs, self.train_hist['total_time'][0])) 155 | print("Training finish!... save training results") 156 | 157 | 158 | def train_epoch(self, epoch): 159 | epoch_start_time = time.time() 160 | loss_buf = [] 161 | train_pred = [] 162 | train_true = [] 163 | num_batch = int(len(self.train_loader.dataset) / self.batch_size) 164 | for iter, (pts, label) in enumerate(self.train_loader): 165 | if not self.no_cuda: 166 | pts = pts.cuda(self.first_gpu) 167 | label = label.cuda(self.first_gpu) 168 | 169 | # forward 170 | self.optimizer.zero_grad() 171 | output, _ = self.model(pts) 172 | 173 | # loss 174 | if len(self.gpu_ids) != 1: # multiple gpus 175 | loss = self.model.module.get_loss(output, label) 176 | else: 177 | loss = self.model.get_loss(output, label) 178 | 179 | # backward 180 | loss.backward() 181 | self.optimizer.step() 182 | loss_buf.append(loss.detach().cpu().numpy()) 183 | 184 | preds = output.max(dim=1)[1] 185 | train_true.append(label.view(-1).cpu().numpy()) 186 | train_pred.append(preds.detach().cpu().numpy()) 187 | 188 | # finish one epoch 189 | self.scheduler.step() 190 | epoch_time = time.time() - epoch_start_time 191 | self.train_hist['per_epoch_time'].append(epoch_time) 192 | self.train_hist['loss'].append(np.mean(loss_buf)) 193 | train_true = np.concatenate(train_true) 194 | train_pred = np.concatenate(train_pred) 195 | print("Epoch %d: Loss %.6f, train acc: %.6f, train avg acc: %.6f, time %.4fs" % (epoch+1, 196 | np.mean(loss_buf), 197 | metrics.accuracy_score( 198 | train_true, train_pred), 199 | metrics.balanced_accuracy_score( 200 | train_true, train_pred), 201 | epoch_time)) 202 | return np.mean(loss_buf) 203 | 204 | 205 | def _snapshot(self, epoch): 206 | state_dict = self.model.state_dict() 207 | from collections import OrderedDict 208 | new_state_dict = OrderedDict() 209 | for key, val in state_dict.items(): 210 | if key[:6] == 'module': 211 | name = key[7:] # remove 'module.' 212 | else: 213 | name = key 214 | new_state_dict[name] = val 215 | save_dir = os.path.join(self.save_dir, self.dataset_name) 216 | torch.save(new_state_dict, save_dir + "_" + str(epoch) + '.pkl') 217 | print(f"Save model to {save_dir}_{str(epoch)}.pkl") 218 | 219 | 220 | def _load_pretrain(self, pretrain): 221 | state_dict = torch.load(pretrain, map_location='cpu') 222 | from collections import OrderedDict 223 | new_state_dict = OrderedDict() 224 | for key, val in state_dict.items(): 225 | if key[:6] == 'module': 226 | name = key[7:] # remove 'module.' 227 | else: 228 | name = key 229 | new_state_dict[name] = val 230 | self.model.load_state_dict(new_state_dict) 231 | print(f"Load model from {pretrain}") 232 | 233 | 234 | def _get_lr(self, group=0): 235 | return self.optimizer.param_groups[group]['lr'] 236 | -------------------------------------------------------------------------------- /dataset.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | @Author: An Tao 5 | @Contact: ta19@mails.tsinghua.edu.cn 6 | @File: dataset.py 7 | @Time: 2020/1/2 10:26 AM 8 | """ 9 | 10 | import os 11 | import torch 12 | import json 13 | import h5py 14 | from glob import glob 15 | import numpy as np 16 | import torch.utils.data as data 17 | 18 | 19 | def translate_pointcloud(pointcloud): 20 | xyz1 = np.random.uniform(low=2./3., high=3./2., size=[3]) 21 | xyz2 = np.random.uniform(low=-0.2, high=0.2, size=[3]) 22 | 23 | translated_pointcloud = np.add(np.multiply(pointcloud, xyz1), xyz2).astype('float32') 24 | return translated_pointcloud 25 | 26 | 27 | def jitter_pointcloud(pointcloud, sigma=0.01, clip=0.02): 28 | N, C = pointcloud.shape 29 | pointcloud += np.clip(sigma * np.random.randn(N, C), -1*clip, clip) 30 | return pointcloud 31 | 32 | 33 | def rotate_pointcloud(pointcloud): 34 | theta = np.pi*2 * np.random.choice(24) / 24 35 | rotation_matrix = np.array([[np.cos(theta), -np.sin(theta)],[np.sin(theta), np.cos(theta)]]) 36 | pointcloud[:,[0,2]] = pointcloud[:,[0,2]].dot(rotation_matrix) # random rotation (x,z) 37 | return pointcloud 38 | 39 | 40 | class Dataset(data.Dataset): 41 | def __init__(self, root, dataset_name='modelnet40', 42 | num_points=2048, split='train', load_name=False, 43 | random_rotate=False, random_jitter=False, random_translate=False): 44 | 45 | assert dataset_name.lower() in ['shapenetcorev2', 46 | 'shapenetpart', 'modelnet10', 'modelnet40'] 47 | assert num_points <= 2048 48 | 49 | if dataset_name in ['shapenetpart', 'shapenetcorev2']: 50 | assert split.lower() in ['train', 'test', 'val', 'trainval', 'all'] 51 | else: 52 | assert split.lower() in ['train', 'test', 'all'] 53 | 54 | self.root = os.path.join(root, dataset_name + '*hdf5_2048') 55 | self.dataset_name = dataset_name 56 | self.num_points = num_points 57 | self.split = split 58 | self.load_name = load_name 59 | self.random_rotate = random_rotate 60 | self.random_jitter = random_jitter 61 | self.random_translate = random_translate 62 | 63 | self.path_h5py_all = [] 64 | self.path_json_all = [] 65 | if self.split in ['train','trainval','all']: 66 | self.get_path('train') 67 | if self.dataset_name in ['shapenetpart', 'shapenetcorev2']: 68 | if self.split in ['val','trainval','all']: 69 | self.get_path('val') 70 | if self.split in ['test', 'all']: 71 | self.get_path('test') 72 | 73 | self.path_h5py_all.sort() 74 | data, label = self.load_h5py(self.path_h5py_all) 75 | if self.load_name: 76 | self.path_json_all.sort() 77 | self.name = self.load_json(self.path_json_all) # load label name 78 | 79 | self.data = np.concatenate(data, axis=0) 80 | self.label = np.concatenate(label, axis=0) 81 | 82 | def get_path(self, type): 83 | path_h5py = os.path.join(self.root, '*%s*.h5'%type) 84 | self.path_h5py_all += glob(path_h5py) 85 | if self.load_name: 86 | path_json = os.path.join(self.root, '%s*_id2name.json'%type) 87 | self.path_json_all += glob(path_json) 88 | return 89 | 90 | def load_h5py(self, path): 91 | all_data = [] 92 | all_label = [] 93 | for h5_name in path: 94 | f = h5py.File(h5_name, 'r+') 95 | data = f['data'][:].astype('float32') 96 | label = f['label'][:].astype('int64') 97 | f.close() 98 | all_data.append(data) 99 | all_label.append(label) 100 | return all_data, all_label 101 | 102 | def load_json(self, path): 103 | all_data = [] 104 | for json_name in path: 105 | j = open(json_name, 'r+') 106 | data = json.load(j) 107 | all_data += data 108 | return all_data 109 | 110 | def __getitem__(self, item): 111 | point_set = self.data[item][:self.num_points] 112 | label = self.label[item] 113 | if self.load_name: 114 | name = self.name[item] # get label name 115 | 116 | if self.random_rotate: 117 | point_set = rotate_pointcloud(point_set) 118 | if self.random_jitter: 119 | point_set = jitter_pointcloud(point_set) 120 | if self.random_translate: 121 | point_set = translate_pointcloud(point_set) 122 | 123 | # convert numpy array to pytorch Tensor 124 | point_set = torch.from_numpy(point_set) 125 | label = torch.from_numpy(np.array([label]).astype(np.int64)) 126 | label = label.squeeze(0) 127 | 128 | if self.load_name: 129 | return point_set, label, name 130 | else: 131 | return point_set, label 132 | 133 | def __len__(self): 134 | return self.data.shape[0] -------------------------------------------------------------------------------- /gaussian.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/gaussian.npy -------------------------------------------------------------------------------- /image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train0_laptop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train0_laptop.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train10_bookshelf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train10_bookshelf.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train11_airplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train11_airplane.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train12_chair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train12_chair.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train14_plant.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train14_plant.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train16_table.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train16_table.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train19_bench.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train19_bench.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train7_vase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_modelnet40_train7_vase.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_test37_earphone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_test37_earphone.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_test57_chair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_test57_chair.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_test59_lamp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_test59_lamp.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_train10_bag.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_train10_bag.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_train12_bench.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_train12_bench.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_train13_table.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_train13_table.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_train16_airplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_train16_airplane.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_train4_tower.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_gaussian/shapenetcorev2_250_shapenetcorev2_train4_tower.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train0_laptop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train0_laptop.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train10_bookshelf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train10_bookshelf.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train11_airplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train11_airplane.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train12_chair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train12_chair.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train14_plant.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train14_plant.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train16_table.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train16_table.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train19_bench.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train19_bench.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train7_vase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_modelnet40_train7_vase.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_test37_earphone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_test37_earphone.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_test57_chair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_test57_chair.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_test59_lamp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_test59_lamp.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_train10_bag.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_train10_bag.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_train12_bench.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_train12_bench.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_train13_table.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_train13_table.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_train16_airplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_train16_airplane.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_train4_tower.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_plane/shapenetcorev2_250_shapenetcorev2_train4_tower.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train0_laptop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train0_laptop.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train10_bookshelf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train10_bookshelf.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train11_airplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train11_airplane.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train12_chair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train12_chair.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train14_plant.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train14_plant.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train16_table.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train16_table.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train19_bench.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train19_bench.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train7_vase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_modelnet40_train7_vase.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_test37_earphone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_test37_earphone.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_test57_chair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_test57_chair.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_test59_lamp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_test59_lamp.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_train10_bag.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_train10_bag.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_train12_bench.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_train12_bench.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_train13_table.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_train13_table.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_train16_airplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_train16_airplane.jpg -------------------------------------------------------------------------------- /image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_train4_tower.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_cls_sphere/shapenetcorev2_250_shapenetcorev2_train4_tower.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train0_laptop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train0_laptop.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train10_bookshelf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train10_bookshelf.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train11_airplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train11_airplane.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train12_chair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train12_chair.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train14_plant.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train14_plant.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train16_table.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train16_table.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train19_bench.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train19_bench.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train7_vase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_modelnet40_train7_vase.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_test37_earphone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_test37_earphone.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_test57_chair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_test57_chair.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_test59_lamp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_test59_lamp.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_train10_bag.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_train10_bag.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_train12_bench.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_train12_bench.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_train13_table.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_train13_table.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_train16_airplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_train16_airplane.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_train4_tower.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_gaussian/shapenetcorev2_290_shapenetcorev2_train4_tower.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train0_laptop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train0_laptop.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train10_bookshelf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train10_bookshelf.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train11_airplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train11_airplane.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train12_chair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train12_chair.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train14_plant.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train14_plant.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train16_table.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train16_table.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train19_bench.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train19_bench.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train7_vase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_modelnet40_train7_vase.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_test37_earphone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_test37_earphone.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_test57_chair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_test57_chair.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_test59_lamp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_test59_lamp.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_train10_bag.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_train10_bag.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_train12_bench.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_train12_bench.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_train13_table.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_train13_table.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_train16_airplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_train16_airplane.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_train4_tower.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_plane/shapenetcorev2_290_shapenetcorev2_train4_tower.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train0_laptop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train0_laptop.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train10_bookshelf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train10_bookshelf.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train11_airplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train11_airplane.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train12_chair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train12_chair.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train14_plant.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train14_plant.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train16_table.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train16_table.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train19_bench.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train19_bench.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train7_vase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_modelnet40_train7_vase.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_test37_earphone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_test37_earphone.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_test57_chair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_test57_chair.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_test59_lamp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_test59_lamp.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_train10_bag.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_train10_bag.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_train12_bench.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_train12_bench.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_train13_table.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_train13_table.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_train16_airplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_train16_airplane.jpg -------------------------------------------------------------------------------- /image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_train4_tower.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/dgcnn_seg_sphere/shapenetcorev2_290_shapenetcorev2_train4_tower.jpg -------------------------------------------------------------------------------- /image/distance.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/distance.png -------------------------------------------------------------------------------- /image/gaussian.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/gaussian.png -------------------------------------------------------------------------------- /image/input/modelnet40_train0_laptop_orign.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/modelnet40_train0_laptop_orign.jpg -------------------------------------------------------------------------------- /image/input/modelnet40_train10_bookshelf_orign.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/modelnet40_train10_bookshelf_orign.jpg -------------------------------------------------------------------------------- /image/input/modelnet40_train11_airplane_orign.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/modelnet40_train11_airplane_orign.jpg -------------------------------------------------------------------------------- /image/input/modelnet40_train12_chair_orign.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/modelnet40_train12_chair_orign.jpg -------------------------------------------------------------------------------- /image/input/modelnet40_train14_plant_orign.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/modelnet40_train14_plant_orign.jpg -------------------------------------------------------------------------------- /image/input/modelnet40_train16_table_orign.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/modelnet40_train16_table_orign.jpg -------------------------------------------------------------------------------- /image/input/modelnet40_train19_bench_orign.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/modelnet40_train19_bench_orign.jpg -------------------------------------------------------------------------------- /image/input/modelnet40_train7_vase_orign.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/modelnet40_train7_vase_orign.jpg -------------------------------------------------------------------------------- /image/input/shapenetcorev2_test37_earphone_orign.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/shapenetcorev2_test37_earphone_orign.jpg -------------------------------------------------------------------------------- /image/input/shapenetcorev2_test57_chair_orign.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/shapenetcorev2_test57_chair_orign.jpg -------------------------------------------------------------------------------- /image/input/shapenetcorev2_test59_lamp_orign.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/shapenetcorev2_test59_lamp_orign.jpg -------------------------------------------------------------------------------- /image/input/shapenetcorev2_train10_bag_orign.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/shapenetcorev2_train10_bag_orign.jpg -------------------------------------------------------------------------------- /image/input/shapenetcorev2_train12_bench_orign.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/shapenetcorev2_train12_bench_orign.jpg -------------------------------------------------------------------------------- /image/input/shapenetcorev2_train13_table_orign.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/shapenetcorev2_train13_table_orign.jpg -------------------------------------------------------------------------------- /image/input/shapenetcorev2_train16_airplane_orign.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/shapenetcorev2_train16_airplane_orign.jpg -------------------------------------------------------------------------------- /image/input/shapenetcorev2_train4_tower_orign.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/input/shapenetcorev2_train4_tower_orign.jpg -------------------------------------------------------------------------------- /image/original_gaussian/shapenetcorev2_278_modelnet40_train0_laptop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_modelnet40_train0_laptop.jpg -------------------------------------------------------------------------------- /image/original_gaussian/shapenetcorev2_278_modelnet40_train10_bookshelf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_modelnet40_train10_bookshelf.jpg -------------------------------------------------------------------------------- /image/original_gaussian/shapenetcorev2_278_modelnet40_train11_airplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_modelnet40_train11_airplane.jpg -------------------------------------------------------------------------------- /image/original_gaussian/shapenetcorev2_278_modelnet40_train12_chair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_modelnet40_train12_chair.jpg -------------------------------------------------------------------------------- /image/original_gaussian/shapenetcorev2_278_modelnet40_train14_plant.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_modelnet40_train14_plant.jpg -------------------------------------------------------------------------------- /image/original_gaussian/shapenetcorev2_278_modelnet40_train16_table.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_modelnet40_train16_table.jpg -------------------------------------------------------------------------------- /image/original_gaussian/shapenetcorev2_278_modelnet40_train19_bench.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_modelnet40_train19_bench.jpg -------------------------------------------------------------------------------- /image/original_gaussian/shapenetcorev2_278_modelnet40_train7_vase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_modelnet40_train7_vase.jpg -------------------------------------------------------------------------------- /image/original_gaussian/shapenetcorev2_278_shapenetcorev2_test37_earphone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_test37_earphone.jpg -------------------------------------------------------------------------------- /image/original_gaussian/shapenetcorev2_278_shapenetcorev2_test57_chair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_test57_chair.jpg -------------------------------------------------------------------------------- /image/original_gaussian/shapenetcorev2_278_shapenetcorev2_test59_lamp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_test59_lamp.jpg -------------------------------------------------------------------------------- /image/original_gaussian/shapenetcorev2_278_shapenetcorev2_train10_bag.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_train10_bag.jpg -------------------------------------------------------------------------------- /image/original_gaussian/shapenetcorev2_278_shapenetcorev2_train12_bench.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_train12_bench.jpg -------------------------------------------------------------------------------- /image/original_gaussian/shapenetcorev2_278_shapenetcorev2_train13_table.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_train13_table.jpg -------------------------------------------------------------------------------- /image/original_gaussian/shapenetcorev2_278_shapenetcorev2_train16_airplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_train16_airplane.jpg -------------------------------------------------------------------------------- /image/original_gaussian/shapenetcorev2_278_shapenetcorev2_train4_tower.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_gaussian/shapenetcorev2_278_shapenetcorev2_train4_tower.jpg -------------------------------------------------------------------------------- /image/original_plane/shapenetcorev2_278_modelnet40_train0_laptop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_modelnet40_train0_laptop.jpg -------------------------------------------------------------------------------- /image/original_plane/shapenetcorev2_278_modelnet40_train10_bookshelf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_modelnet40_train10_bookshelf.jpg -------------------------------------------------------------------------------- /image/original_plane/shapenetcorev2_278_modelnet40_train11_airplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_modelnet40_train11_airplane.jpg -------------------------------------------------------------------------------- /image/original_plane/shapenetcorev2_278_modelnet40_train12_chair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_modelnet40_train12_chair.jpg -------------------------------------------------------------------------------- /image/original_plane/shapenetcorev2_278_modelnet40_train14_plant.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_modelnet40_train14_plant.jpg -------------------------------------------------------------------------------- /image/original_plane/shapenetcorev2_278_modelnet40_train16_table.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_modelnet40_train16_table.jpg -------------------------------------------------------------------------------- /image/original_plane/shapenetcorev2_278_modelnet40_train19_bench.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_modelnet40_train19_bench.jpg -------------------------------------------------------------------------------- /image/original_plane/shapenetcorev2_278_modelnet40_train7_vase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_modelnet40_train7_vase.jpg -------------------------------------------------------------------------------- /image/original_plane/shapenetcorev2_278_shapenetcorev2_test37_earphone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_shapenetcorev2_test37_earphone.jpg -------------------------------------------------------------------------------- /image/original_plane/shapenetcorev2_278_shapenetcorev2_test57_chair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_shapenetcorev2_test57_chair.jpg -------------------------------------------------------------------------------- /image/original_plane/shapenetcorev2_278_shapenetcorev2_test59_lamp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_shapenetcorev2_test59_lamp.jpg -------------------------------------------------------------------------------- /image/original_plane/shapenetcorev2_278_shapenetcorev2_train10_bag.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_shapenetcorev2_train10_bag.jpg -------------------------------------------------------------------------------- /image/original_plane/shapenetcorev2_278_shapenetcorev2_train12_bench.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_shapenetcorev2_train12_bench.jpg -------------------------------------------------------------------------------- /image/original_plane/shapenetcorev2_278_shapenetcorev2_train13_table.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_shapenetcorev2_train13_table.jpg -------------------------------------------------------------------------------- /image/original_plane/shapenetcorev2_278_shapenetcorev2_train16_airplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_shapenetcorev2_train16_airplane.jpg -------------------------------------------------------------------------------- /image/original_plane/shapenetcorev2_278_shapenetcorev2_train4_tower.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_plane/shapenetcorev2_278_shapenetcorev2_train4_tower.jpg -------------------------------------------------------------------------------- /image/original_sphere/shapenetcorev2_278_modelnet40_train0_laptop.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_modelnet40_train0_laptop.jpg -------------------------------------------------------------------------------- /image/original_sphere/shapenetcorev2_278_modelnet40_train10_bookshelf.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_modelnet40_train10_bookshelf.jpg -------------------------------------------------------------------------------- /image/original_sphere/shapenetcorev2_278_modelnet40_train11_airplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_modelnet40_train11_airplane.jpg -------------------------------------------------------------------------------- /image/original_sphere/shapenetcorev2_278_modelnet40_train12_chair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_modelnet40_train12_chair.jpg -------------------------------------------------------------------------------- /image/original_sphere/shapenetcorev2_278_modelnet40_train14_plant.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_modelnet40_train14_plant.jpg -------------------------------------------------------------------------------- /image/original_sphere/shapenetcorev2_278_modelnet40_train16_table.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_modelnet40_train16_table.jpg -------------------------------------------------------------------------------- /image/original_sphere/shapenetcorev2_278_modelnet40_train19_bench.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_modelnet40_train19_bench.jpg -------------------------------------------------------------------------------- /image/original_sphere/shapenetcorev2_278_modelnet40_train7_vase.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_modelnet40_train7_vase.jpg -------------------------------------------------------------------------------- /image/original_sphere/shapenetcorev2_278_shapenetcorev2_test37_earphone.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_shapenetcorev2_test37_earphone.jpg -------------------------------------------------------------------------------- /image/original_sphere/shapenetcorev2_278_shapenetcorev2_test57_chair.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_shapenetcorev2_test57_chair.jpg -------------------------------------------------------------------------------- /image/original_sphere/shapenetcorev2_278_shapenetcorev2_test59_lamp.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_shapenetcorev2_test59_lamp.jpg -------------------------------------------------------------------------------- /image/original_sphere/shapenetcorev2_278_shapenetcorev2_train10_bag.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_shapenetcorev2_train10_bag.jpg -------------------------------------------------------------------------------- /image/original_sphere/shapenetcorev2_278_shapenetcorev2_train12_bench.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_shapenetcorev2_train12_bench.jpg -------------------------------------------------------------------------------- /image/original_sphere/shapenetcorev2_278_shapenetcorev2_train13_table.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_shapenetcorev2_train13_table.jpg -------------------------------------------------------------------------------- /image/original_sphere/shapenetcorev2_278_shapenetcorev2_train16_airplane.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_shapenetcorev2_train16_airplane.jpg -------------------------------------------------------------------------------- /image/original_sphere/shapenetcorev2_278_shapenetcorev2_train4_tower.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/original_sphere/shapenetcorev2_278_shapenetcorev2_train4_tower.jpg -------------------------------------------------------------------------------- /image/plane.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/plane.png -------------------------------------------------------------------------------- /image/sphere.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/image/sphere.png -------------------------------------------------------------------------------- /inference.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | @Author: An Tao 5 | @Contact: ta19@mails.tsinghua.edu.cn 6 | @File: inference.py 7 | @Time: 2020/1/2 10:26 AM 8 | """ 9 | 10 | import os 11 | import sys 12 | import time 13 | import shutil 14 | import torch 15 | import numpy as np 16 | import h5py 17 | 18 | from tensorboardX import SummaryWriter 19 | 20 | from model import ReconstructionNet, ClassificationNet 21 | from dataset import Dataset 22 | from utils import Logger 23 | 24 | 25 | class Inference(object): 26 | def __init__(self, args): 27 | self.batch_size = args.batch_size 28 | self.no_cuda = args.no_cuda 29 | self.task = args.task 30 | 31 | # create exp directory 32 | file = [f for f in args.model_path.split('/')] 33 | if args.exp_name != None: 34 | self.experiment_id = args.exp_name 35 | else: 36 | self.experiment_id = time.strftime('%m%d%H%M%S') 37 | cache_root = 'cache/%s' % self.experiment_id 38 | os.makedirs(cache_root, exist_ok=True) 39 | self.feature_dir = os.path.join(cache_root, 'features/') 40 | sys.stdout = Logger(os.path.join(cache_root, 'log.txt')) 41 | 42 | # check directory 43 | if not os.path.exists(self.feature_dir): 44 | os.makedirs(self.feature_dir) 45 | else: 46 | shutil.rmtree(self.feature_dir) 47 | os.makedirs(self.feature_dir) 48 | 49 | # print args 50 | print(str(args)) 51 | 52 | # get gpu id 53 | gids = ''.join(args.gpu.split()) 54 | self.gpu_ids = [int(gid) for gid in gids.split(',')] 55 | self.first_gpu = self.gpu_ids[0] 56 | 57 | # generate dataset 58 | self.infer_dataset_train = Dataset( 59 | root=args.dataset_root, 60 | dataset_name=args.dataset, 61 | split='train', 62 | num_points=args.num_points, 63 | ) 64 | self.infer_dataset_test = Dataset( 65 | root=args.dataset_root, 66 | dataset_name=args.dataset, 67 | split='test', 68 | num_points=args.num_points, 69 | ) 70 | self.infer_loader_train = torch.utils.data.DataLoader( 71 | self.infer_dataset_train, 72 | batch_size=args.batch_size, 73 | shuffle=False, 74 | num_workers=args.workers 75 | ) 76 | self.infer_loader_test = torch.utils.data.DataLoader( 77 | self.infer_dataset_test, 78 | batch_size=args.batch_size, 79 | shuffle=False, 80 | num_workers=args.workers 81 | ) 82 | print("Inference set size (train):", self.infer_loader_train.dataset.__len__()) 83 | print("Inference set size (test):", self.infer_loader_test.dataset.__len__()) 84 | 85 | # initialize model 86 | if args.task == "reconstruct": 87 | self.model = ReconstructionNet(args) 88 | elif args.task == "classify": 89 | self.model = ClassificationNet(args) 90 | if args.model_path != '': 91 | self._load_pretrain(args.model_path) 92 | 93 | # load model to gpu 94 | if not args.no_cuda: 95 | if len(self.gpu_ids) != 1: # multiple gpus 96 | self.model = torch.nn.DataParallel(self.model.cuda(self.first_gpu), self.gpu_ids) 97 | else: 98 | self.model = self.model.cuda(self.gpu_ids[0]) 99 | 100 | def run(self): 101 | self.model.eval() 102 | 103 | # generate train set for SVM 104 | loss_buf = [] 105 | feature_train = [] 106 | lbs_train = [] 107 | n = 0 108 | for iter, (pts, lbs) in enumerate(self.infer_loader_train): 109 | if not self.no_cuda: 110 | pts = pts.cuda(self.first_gpu) 111 | lbs = lbs.cuda(self.first_gpu) 112 | if self.task == "reconstruct": 113 | output, feature = self.model(pts) 114 | elif self.task == "classify": 115 | feature = self.model(pts) 116 | feature_train.append(feature.detach().cpu().numpy().squeeze(1)) 117 | lbs_train.append(lbs.cpu().numpy().squeeze(1)) 118 | if ((iter+1) * self.batch_size % 2048) == 0 \ 119 | or (iter+1) == len(self.infer_loader_train): 120 | feature_train = np.concatenate(feature_train, axis=0) 121 | lbs_train = np.concatenate(lbs_train, axis=0) 122 | f = h5py.File(os.path.join(self.feature_dir, 'train' + str(n) + '.h5'),'w') 123 | f['data'] = feature_train 124 | f['label'] = lbs_train 125 | f.close() 126 | print("Train set {} for SVM saved.".format(n)) 127 | feature_train = [] 128 | lbs_train = [] 129 | n += 1 130 | if self.task == "reconstruct": 131 | if len(self.gpu_ids) != 1: # multiple gpus 132 | loss = self.model.module.get_loss(pts, output) 133 | else: 134 | loss = self.model.get_loss(pts, output) 135 | loss_buf.append(loss.detach().cpu().numpy()) 136 | if self.task == "reconstruct": 137 | print(f'Avg loss {np.mean(loss_buf)}') 138 | print("Finish generating train set for SVM.") 139 | 140 | # generate test set for SVM 141 | loss_buf = [] 142 | feature_test = [] 143 | lbs_test = [] 144 | n = 0 145 | for iter, (pts, lbs) in enumerate(self.infer_loader_test): 146 | if not self.no_cuda: 147 | pts = pts.cuda(self.first_gpu) 148 | lbs = lbs.cuda(self.first_gpu) 149 | if self.task == "reconstruct": 150 | output, feature = self.model(pts) 151 | elif self.task == "classify": 152 | feature = self.model(pts) 153 | feature_test.append(feature.detach().cpu().numpy().squeeze(1)) 154 | lbs_test.append(lbs.cpu().numpy().squeeze(1)) 155 | if ((iter+1) * self.batch_size % 2048) == 0 \ 156 | or (iter+1) == len(self.infer_loader_test): 157 | feature_test = np.concatenate(feature_test, axis=0) 158 | lbs_test = np.concatenate(lbs_test, axis=0) 159 | f = h5py.File(os.path.join(self.feature_dir, 'test' + str(n) + '.h5'),'w') 160 | f['data'] = feature_test 161 | f['label'] = lbs_test 162 | f.close() 163 | print("Test set {} for SVM saved.".format(n)) 164 | feature_test = [] 165 | lbs_test = [] 166 | n += 1 167 | if self.task == "reconstruct": 168 | if len(self.gpu_ids) != 1: # multiple gpus 169 | loss = self.model.module.get_loss(pts, output) 170 | else: 171 | loss = self.model.get_loss(pts, output) 172 | loss_buf.append(loss.detach().cpu().numpy()) 173 | if self.task == "reconstruct": 174 | print(f'Avg loss {np.mean(loss_buf)}') 175 | print("Finish generating test set for SVM.") 176 | 177 | return self.feature_dir 178 | 179 | 180 | def _load_pretrain(self, pretrain): 181 | state_dict = torch.load(pretrain, map_location='cpu') 182 | from collections import OrderedDict 183 | new_state_dict = OrderedDict() 184 | for key, val in state_dict.items(): 185 | if key[:6] == 'module': 186 | name = key[7:] # remove 'module.' 187 | else: 188 | name = key 189 | if key[:10] == 'classifier': 190 | continue 191 | new_state_dict[name] = val 192 | self.model.load_state_dict(new_state_dict) 193 | print(f"Load model from {pretrain}") 194 | -------------------------------------------------------------------------------- /loss.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | @Author: An Tao 5 | @Contact: ta19@mails.tsinghua.edu.cn 6 | @File: loss.py 7 | @Time: 2020/1/2 10:26 AM 8 | """ 9 | 10 | import torch 11 | import torch.nn as nn 12 | import torch.nn.functional as F 13 | 14 | 15 | class ChamferLoss(nn.Module): 16 | def __init__(self): 17 | super(ChamferLoss, self).__init__() 18 | self.use_cuda = torch.cuda.is_available() 19 | 20 | def batch_pairwise_dist(self, x, y): 21 | bs, num_points_x, points_dim = x.size() 22 | _, num_points_y, _ = y.size() 23 | xx = x.pow(2).sum(dim=-1) 24 | yy = y.pow(2).sum(dim=-1) 25 | zz = torch.bmm(x, y.transpose(2, 1)) 26 | rx = xx.unsqueeze(1).expand_as(zz.transpose(2, 1)) 27 | ry = yy.unsqueeze(1).expand_as(zz) 28 | P = (rx.transpose(2, 1) + ry - 2 * zz) 29 | return P 30 | 31 | def forward(self, preds, gts): 32 | P = self.batch_pairwise_dist(gts, preds) 33 | mins, _ = torch.min(P, 1) 34 | loss_1 = torch.sum(mins) 35 | mins, _ = torch.min(P, 2) 36 | loss_2 = torch.sum(mins) 37 | return loss_1 + loss_2 38 | 39 | 40 | class CrossEntropyLoss(nn.Module): 41 | def __init__(self, smoothing=True): 42 | super(CrossEntropyLoss, self).__init__() 43 | self.smoothing = smoothing 44 | 45 | def forward(self, preds, gts): 46 | gts = gts.contiguous().view(-1) 47 | 48 | if self.smoothing: 49 | eps = 0.2 50 | n_class = preds.size(1) 51 | 52 | one_hot = torch.zeros_like(preds).scatter(1, gts.view(-1, 1), 1) 53 | one_hot = one_hot * (1 - eps) + (1 - one_hot) * eps / (n_class - 1) 54 | log_prb = F.log_softmax(preds, dim=1) 55 | 56 | loss = -(one_hot * log_prb).sum(dim=1).mean() 57 | else: 58 | loss = F.cross_entropy(preds, gts, reduction='mean') 59 | 60 | return loss 61 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | @Author: An Tao 5 | @Contact: ta19@mails.tsinghua.edu.cn 6 | @File: main.py 7 | @Time: 2020/1/2 10:26 AM 8 | """ 9 | 10 | import argparse 11 | 12 | from reconstruction import Reconstruction 13 | from classification import Classification 14 | from inference import Inference 15 | from svm import SVM 16 | 17 | 18 | def get_parser(): 19 | parser = argparse.ArgumentParser(description='Unsupervised Point Cloud Feature Learning') 20 | parser.add_argument('--exp_name', type=str, default=None, metavar='N', 21 | help='Name of the experiment') 22 | parser.add_argument('--task', type=str, default='reconstruct', metavar='N', 23 | choices=['reconstruct', 'classify'], 24 | help='Experiment task, [reconstruct, classify]') 25 | parser.add_argument('--encoder', type=str, default='foldingnet', metavar='N', 26 | choices=['foldnet', 'dgcnn_cls', 'dgcnn_seg'], 27 | help='Encoder to use, [foldingnet, dgcnn_cls, dgcnn_seg]') 28 | parser.add_argument('--dropout', type=float, default=0.5, 29 | help='dropout rate') 30 | parser.add_argument('--feat_dims', type=int, default=512, metavar='N', 31 | help='Number of dims for feature ') 32 | parser.add_argument('--k', type=int, default=None, metavar='N', 33 | help='Num of nearest neighbors to use for KNN') 34 | parser.add_argument('--shape', type=str, default='plane', metavar='N', 35 | choices=['plane', 'sphere', 'gaussian'], 36 | help='Shape of points to input decoder, [plane, sphere, gaussian]') 37 | parser.add_argument('--dataset', type=str, default='shapenetcorev2', metavar='N', 38 | choices=['shapenetcorev2','modelnet40', 'modelnet10'], 39 | help='Encoder to use, [shapenetcorev2,modelnet40, modelnet10]') 40 | parser.add_argument('--use_rotate', action='store_true', 41 | help='Rotate the pointcloud before training') 42 | parser.add_argument('--use_translate', action='store_true', 43 | help='Translate the pointcloud before training') 44 | parser.add_argument('--use_jitter', action='store_true', 45 | help='Jitter the pointcloud before training') 46 | parser.add_argument('--dataset_root', type=str, default='../dataset', help="Dataset root path") 47 | parser.add_argument('--gpu', type=str, help='Id of gpu device to be used', default='0') 48 | parser.add_argument('--batch_size', type=int, default=16, metavar='batch_size', 49 | help='Size of batch)') 50 | parser.add_argument('--workers', type=int, help='Number of data loading workers', default=16) 51 | parser.add_argument('--epochs', type=int, default=None, metavar='N', 52 | help='Number of episode to train ') 53 | parser.add_argument('--snapshot_interval', type=int, default=10, metavar='N', 54 | help='Save snapshot interval ') 55 | parser.add_argument('--no_cuda', action='store_true', 56 | help='Enables CUDA training') 57 | parser.add_argument('--eval', action='store_true', 58 | help='Evaluate the model') 59 | parser.add_argument('--num_points', type=int, default=2048, 60 | help='Num of points to use') 61 | parser.add_argument('--model_path', type=str, default='', metavar='N', 62 | help='Path to load model') 63 | args = parser.parse_args() 64 | return args 65 | 66 | 67 | if __name__ == '__main__': 68 | args = get_parser() 69 | if args.eval == False: 70 | if args.task == 'reconstruct': 71 | reconstruction = Reconstruction(args) 72 | reconstruction.run() 73 | elif args.task == 'classify': 74 | classification = Classification(args) 75 | classification.run() 76 | else: 77 | inference = Inference(args) 78 | feature_dir = inference.run() 79 | svm = SVM(feature_dir) 80 | svm.run() 81 | -------------------------------------------------------------------------------- /model.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | @Author: An Tao 5 | @Contact: ta19@mails.tsinghua.edu.cn 6 | @File: model.py 7 | @Time: 2020/3/23 5:39 PM 8 | """ 9 | 10 | import torch 11 | import torch.nn as nn 12 | import torch.nn.init as init 13 | import torch.nn.functional as F 14 | import numpy as np 15 | import itertools 16 | from loss import ChamferLoss, CrossEntropyLoss 17 | 18 | def knn(x, k): 19 | batch_size = x.size(0) 20 | num_points = x.size(2) 21 | 22 | inner = -2*torch.matmul(x.transpose(2, 1), x) 23 | xx = torch.sum(x**2, dim=1, keepdim=True) 24 | pairwise_distance = -xx - inner - xx.transpose(2, 1) 25 | 26 | idx = pairwise_distance.topk(k=k, dim=-1)[1] # (batch_size, num_points, k) 27 | 28 | if idx.get_device() == -1: 29 | idx_base = torch.arange(0, batch_size).view(-1, 1, 1)*num_points 30 | else: 31 | idx_base = torch.arange(0, batch_size, device=idx.get_device()).view(-1, 1, 1)*num_points 32 | idx = idx + idx_base 33 | idx = idx.view(-1) 34 | 35 | return idx 36 | 37 | 38 | def local_cov(pts, idx): 39 | batch_size = pts.size(0) 40 | num_points = pts.size(2) 41 | pts = pts.view(batch_size, -1, num_points) # (batch_size, 3, num_points) 42 | 43 | _, num_dims, _ = pts.size() 44 | 45 | x = pts.transpose(2, 1).contiguous() # (batch_size, num_points, 3) 46 | x = x.view(batch_size*num_points, -1)[idx, :] # (batch_size*num_points*2, 3) 47 | x = x.view(batch_size, num_points, -1, num_dims) # (batch_size, num_points, k, 3) 48 | 49 | x = torch.matmul(x[:,:,0].unsqueeze(3), x[:,:,1].unsqueeze(2)) # (batch_size, num_points, 3, 1) * (batch_size, num_points, 1, 3) -> (batch_size, num_points, 3, 3) 50 | # x = torch.matmul(x[:,:,1:].transpose(3, 2), x[:,:,1:]) 51 | x = x.view(batch_size, num_points, 9).transpose(2, 1) # (batch_size, 9, num_points) 52 | 53 | x = torch.cat((pts, x), dim=1) # (batch_size, 12, num_points) 54 | 55 | return x 56 | 57 | 58 | def local_maxpool(x, idx): 59 | batch_size = x.size(0) 60 | num_points = x.size(2) 61 | x = x.view(batch_size, -1, num_points) 62 | 63 | _, num_dims, _ = x.size() 64 | 65 | x = x.transpose(2, 1).contiguous() # (batch_size, num_points, num_dims) 66 | x = x.view(batch_size*num_points, -1)[idx, :] # (batch_size*n, num_dims) -> (batch_size*n*k, num_dims) 67 | x = x.view(batch_size, num_points, -1, num_dims) # (batch_size, num_points, k, num_dims) 68 | x, _ = torch.max(x, dim=2) # (batch_size, num_points, num_dims) 69 | 70 | return x 71 | 72 | 73 | def get_graph_feature(x, k=20, idx=None): 74 | batch_size = x.size(0) 75 | num_points = x.size(2) 76 | x = x.view(batch_size, -1, num_points) # (batch_size, num_dims, num_points) 77 | if idx is None: 78 | idx = knn(x, k=k) # (batch_size, num_points, k) 79 | 80 | _, num_dims, _ = x.size() 81 | 82 | x = x.transpose(2, 1).contiguous() # (batch_size, num_points, num_dims) 83 | feature = x.view(batch_size*num_points, -1)[idx, :] # (batch_size*n, num_dims) -> (batch_size*n*k, num_dims) 84 | feature = feature.view(batch_size, num_points, k, num_dims) # (batch_size, num_points, k, num_dims) 85 | x = x.view(batch_size, num_points, 1, num_dims).repeat(1, 1, k, 1) # (batch_size, num_points, k, num_dims) 86 | 87 | feature = torch.cat((feature-x, x), dim=3).permute(0, 3, 1, 2) # (batch_size, num_points, k, 2*num_dims) -> (batch_size, 2*num_dims, num_points, k) 88 | 89 | return feature # (batch_size, 2*num_dims, num_points, k) 90 | 91 | 92 | class DGCNN_Cls_Encoder(nn.Module): 93 | def __init__(self, args): 94 | super(DGCNN_Cls_Encoder, self).__init__() 95 | if args.k == None: 96 | self.k = 20 97 | else: 98 | self.k = args.k 99 | self.task = args.task 100 | 101 | self.bn1 = nn.BatchNorm2d(64) 102 | self.bn2 = nn.BatchNorm2d(64) 103 | self.bn3 = nn.BatchNorm2d(128) 104 | self.bn4 = nn.BatchNorm2d(256) 105 | self.bn5 = nn.BatchNorm1d(args.feat_dims) 106 | 107 | self.conv1 = nn.Sequential(nn.Conv2d(3*2, 64, kernel_size=1, bias=False), 108 | self.bn1, 109 | nn.LeakyReLU(negative_slope=0.2)) 110 | self.conv2 = nn.Sequential(nn.Conv2d(64*2, 64, kernel_size=1, bias=False), 111 | self.bn2, 112 | nn.LeakyReLU(negative_slope=0.2)) 113 | self.conv3 = nn.Sequential(nn.Conv2d(64*2, 128, kernel_size=1, bias=False), 114 | self.bn3, 115 | nn.LeakyReLU(negative_slope=0.2)) 116 | self.conv4 = nn.Sequential(nn.Conv2d(128*2, 256, kernel_size=1, bias=False), 117 | self.bn4, 118 | nn.LeakyReLU(negative_slope=0.2)) 119 | self.conv5 = nn.Sequential(nn.Conv1d(512, args.feat_dims, kernel_size=1, bias=False), 120 | self.bn5, 121 | nn.LeakyReLU(negative_slope=0.2)) 122 | 123 | def forward(self, x): 124 | x = x.transpose(2, 1) 125 | 126 | batch_size = x.size(0) 127 | x = get_graph_feature(x, k=self.k) # (batch_size, 3, num_points) -> (batch_size, 3*2, num_points, k) 128 | x = self.conv1(x) # (batch_size, 3*2, num_points, k) -> (batch_size, 64, num_points, k) 129 | x1 = x.max(dim=-1, keepdim=False)[0] # (batch_size, 64, num_points, k) -> (batch_size, 64, num_points) 130 | 131 | x = get_graph_feature(x1, k=self.k) # (batch_size, 64, num_points) -> (batch_size, 64*2, num_points, k) 132 | x = self.conv2(x) # (batch_size, 64*2, num_points, k) -> (batch_size, 64, num_points, k) 133 | x2 = x.max(dim=-1, keepdim=False)[0] # (batch_size, 64, num_points, k) -> (batch_size, 64, num_points) 134 | 135 | x = get_graph_feature(x2, k=self.k) # (batch_size, 64, num_points) -> (batch_size, 64*2, num_points, k) 136 | x = self.conv3(x) # (batch_size, 64*2, num_points, k) -> (batch_size, 128, num_points, k) 137 | x3 = x.max(dim=-1, keepdim=False)[0] # (batch_size, 128, num_points, k) -> (batch_size, 128, num_points) 138 | 139 | x = get_graph_feature(x3, k=self.k) # (batch_size, 128, num_points) -> (batch_size, 128*2, num_points, k) 140 | x = self.conv4(x) # (batch_size, 128*2, num_points, k) -> (batch_size, 256, num_points, k) 141 | x4 = x.max(dim=-1, keepdim=False)[0] # (batch_size, 256, num_points, k) -> (batch_size, 256, num_points) 142 | 143 | x = torch.cat((x1, x2, x3, x4), dim=1) # (batch_size, 512, num_points) 144 | 145 | x0 = self.conv5(x) # (batch_size, 512, num_points) -> (batch_size, feat_dims, num_points) 146 | x = x0.max(dim=-1, keepdim=False)[0] # (batch_size, feat_dims, num_points) -> (batch_size, feat_dims) 147 | feat = x.unsqueeze(1) # (batch_size, feat_dims) -> (batch_size, 1, feat_dims) 148 | 149 | if self.task == 'classify': 150 | return feat, x0 151 | elif self.task == 'reconstruct': 152 | return feat # (batch_size, 1, feat_dims) 153 | 154 | 155 | class Point_Transform_Net(nn.Module): 156 | def __init__(self): 157 | super(Point_Transform_Net, self).__init__() 158 | self.k = 3 159 | 160 | self.bn1 = nn.BatchNorm2d(64) 161 | self.bn2 = nn.BatchNorm2d(128) 162 | self.bn3 = nn.BatchNorm1d(1024) 163 | 164 | self.conv1 = nn.Sequential(nn.Conv2d(6, 64, kernel_size=1, bias=False), 165 | self.bn1, 166 | nn.LeakyReLU(negative_slope=0.2)) 167 | self.conv2 = nn.Sequential(nn.Conv2d(64, 128, kernel_size=1, bias=False), 168 | self.bn2, 169 | nn.LeakyReLU(negative_slope=0.2)) 170 | self.conv3 = nn.Sequential(nn.Conv1d(128, 1024, kernel_size=1, bias=False), 171 | self.bn3, 172 | nn.LeakyReLU(negative_slope=0.2)) 173 | 174 | self.linear1 = nn.Linear(1024, 512, bias=False) 175 | self.bn3 = nn.BatchNorm1d(512) 176 | self.linear2 = nn.Linear(512, 256, bias=False) 177 | self.bn4 = nn.BatchNorm1d(256) 178 | 179 | self.transform = nn.Linear(256, 3*3) 180 | init.constant_(self.transform.weight, 0) 181 | init.eye_(self.transform.bias.view(3, 3)) 182 | 183 | def forward(self, x): 184 | batch_size = x.size(0) 185 | 186 | x = self.conv1(x) # (batch_size, 3*2, num_points, k) -> (batch_size, 64, num_points, k) 187 | x = self.conv2(x) # (batch_size, 64, num_points, k) -> (batch_size, 128, num_points, k) 188 | x = x.max(dim=-1, keepdim=False)[0] # (batch_size, 128, num_points, k) -> (batch_size, 128, num_points) 189 | 190 | x = self.conv3(x) # (batch_size, 128, num_points) -> (batch_size, 1024, num_points) 191 | x = x.max(dim=-1, keepdim=False)[0] # (batch_size, 1024, num_points) -> (batch_size, 1024) 192 | 193 | x = F.leaky_relu(self.bn3(self.linear1(x)), negative_slope=0.2) # (batch_size, 1024) -> (batch_size, 512) 194 | x = F.leaky_relu(self.bn4(self.linear2(x)), negative_slope=0.2) # (batch_size, 512) -> (batch_size, 256) 195 | 196 | x = self.transform(x) # (batch_size, 256) -> (batch_size, 3*3) 197 | x = x.view(batch_size, 3, 3) # (batch_size, 3*3) -> (batch_size, 3, 3) 198 | 199 | return x # (batch_size, 3, 3) 200 | 201 | 202 | class DGCNN_Seg_Encoder(nn.Module): 203 | def __init__(self, args): 204 | super(DGCNN_Seg_Encoder, self).__init__() 205 | if args.k == None: 206 | self.k = 20 207 | else: 208 | self.k = args.k 209 | self.transform_net = Point_Transform_Net() 210 | 211 | self.bn1 = nn.BatchNorm2d(64) 212 | self.bn2 = nn.BatchNorm2d(64) 213 | self.bn3 = nn.BatchNorm2d(64) 214 | self.bn4 = nn.BatchNorm2d(64) 215 | self.bn5 = nn.BatchNorm2d(64) 216 | self.bn6 = nn.BatchNorm1d(args.feat_dims) 217 | 218 | self.conv1 = nn.Sequential(nn.Conv2d(6, 64, kernel_size=1, bias=False), 219 | self.bn1, 220 | nn.LeakyReLU(negative_slope=0.2)) 221 | self.conv2 = nn.Sequential(nn.Conv2d(64, 64, kernel_size=1, bias=False), 222 | self.bn2, 223 | nn.LeakyReLU(negative_slope=0.2)) 224 | self.conv3 = nn.Sequential(nn.Conv2d(64*2, 64, kernel_size=1, bias=False), 225 | self.bn3, 226 | nn.LeakyReLU(negative_slope=0.2)) 227 | self.conv4 = nn.Sequential(nn.Conv2d(64, 64, kernel_size=1, bias=False), 228 | self.bn4, 229 | nn.LeakyReLU(negative_slope=0.2)) 230 | self.conv5 = nn.Sequential(nn.Conv2d(64*2, 64, kernel_size=1, bias=False), 231 | self.bn5, 232 | nn.LeakyReLU(negative_slope=0.2)) 233 | self.conv6 = nn.Sequential(nn.Conv1d(192, args.feat_dims, kernel_size=1, bias=False), 234 | self.bn6, 235 | nn.LeakyReLU(negative_slope=0.2)) 236 | 237 | 238 | def forward(self, x): 239 | x = x.transpose(2, 1) 240 | 241 | batch_size = x.size(0) 242 | num_points = x.size(2) 243 | 244 | x0 = get_graph_feature(x, k=self.k) # (batch_size, 3, num_points) -> (batch_size, 3*2, num_points, k) 245 | t = self.transform_net(x0) # (batch_size, 3, 3) 246 | x = x.transpose(2, 1) # (batch_size, 3, num_points) -> (batch_size, num_points, 3) 247 | x = torch.bmm(x, t) # (batch_size, num_points, 3) * (batch_size, 3, 3) -> (batch_size, num_points, 3) 248 | x = x.transpose(2, 1) # (batch_size, num_points, 3) -> (batch_size, 3, num_points) 249 | 250 | x = get_graph_feature(x, k=self.k) # (batch_size, 3, num_points) -> (batch_size, 3*2, num_points, k) 251 | x = self.conv1(x) # (batch_size, 3*2, num_points, k) -> (batch_size, 64, num_points, k) 252 | x = self.conv2(x) # (batch_size, 64, num_points, k) -> (batch_size, 64, num_points, k) 253 | x1 = x.max(dim=-1, keepdim=False)[0] # (batch_size, 64, num_points, k) -> (batch_size, 64, num_points) 254 | 255 | x = get_graph_feature(x1, k=self.k) # (batch_size, 64, num_points) -> (batch_size, 64*2, num_points, k) 256 | x = self.conv3(x) # (batch_size, 64*2, num_points, k) -> (batch_size, 64, num_points, k) 257 | x = self.conv4(x) # (batch_size, 64, num_points, k) -> (batch_size, 64, num_points, k) 258 | x2 = x.max(dim=-1, keepdim=False)[0] # (batch_size, 64, num_points, k) -> (batch_size, 64, num_points) 259 | 260 | x = get_graph_feature(x2, k=self.k) # (batch_size, 64, num_points) -> (batch_size, 64*2, num_points, k) 261 | x = self.conv5(x) # (batch_size, 64*2, num_points, k) -> (batch_size, 64, num_points, k) 262 | x3 = x.max(dim=-1, keepdim=False)[0] # (batch_size, 64, num_points, k) -> (batch_size, 64, num_points) 263 | 264 | x = torch.cat((x1, x2, x3), dim=1) # (batch_size, 64*3, num_points) 265 | 266 | x = self.conv6(x) # (batch_size, 64*3, num_points) -> (batch_size, emb_dims, num_points) 267 | x = x.max(dim=-1, keepdim=False)[0] # (batch_size, emb_dims, num_points) -> (batch_size, emb_dims) 268 | 269 | feat = x.unsqueeze(1) # (batch_size, num_points) -> (batch_size, 1, emb_dims) 270 | 271 | return feat # (batch_size, 1, emb_dims) 272 | 273 | 274 | class FoldNet_Encoder(nn.Module): 275 | def __init__(self, args): 276 | super(FoldNet_Encoder, self).__init__() 277 | if args.k == None: 278 | self.k = 16 279 | else: 280 | self.k = args.k 281 | self.n = 2048 # input point cloud size 282 | self.mlp1 = nn.Sequential( 283 | nn.Conv1d(12, 64, 1), 284 | nn.ReLU(), 285 | nn.Conv1d(64, 64, 1), 286 | nn.ReLU(), 287 | nn.Conv1d(64, 64, 1), 288 | nn.ReLU(), 289 | ) 290 | self.linear1 = nn.Linear(64, 64) 291 | self.conv1 = nn.Conv1d(64, 128, 1) 292 | self.linear2 = nn.Linear(128, 128) 293 | self.conv2 = nn.Conv1d(128, 1024, 1) 294 | self.mlp2 = nn.Sequential( 295 | nn.Conv1d(1024, args.feat_dims, 1), 296 | nn.ReLU(), 297 | nn.Conv1d(args.feat_dims, args.feat_dims, 1), 298 | ) 299 | 300 | def graph_layer(self, x, idx): 301 | x = local_maxpool(x, idx) 302 | x = self.linear1(x) 303 | x = x.transpose(2, 1) 304 | x = F.relu(self.conv1(x)) 305 | x = local_maxpool(x, idx) 306 | x = self.linear2(x) 307 | x = x.transpose(2, 1) 308 | x = self.conv2(x) 309 | return x 310 | 311 | def forward(self, pts): 312 | pts = pts.transpose(2, 1) # (batch_size, 3, num_points) 313 | idx = knn(pts, k=self.k) 314 | x = local_cov(pts, idx) # (batch_size, 3, num_points) -> (batch_size, 12, num_points]) 315 | x = self.mlp1(x) # (batch_size, 12, num_points) -> (batch_size, 64, num_points]) 316 | x = self.graph_layer(x, idx) # (batch_size, 64, num_points) -> (batch_size, 1024, num_points) 317 | x = torch.max(x, 2, keepdim=True)[0] # (batch_size, 1024, num_points) -> (batch_size, 1024, 1) 318 | x = self.mlp2(x) # (batch_size, 1024, 1) -> (batch_size, feat_dims, 1) 319 | feat = x.transpose(2,1) # (batch_size, feat_dims, 1) -> (batch_size, 1, feat_dims) 320 | return feat # (batch_size, 1, feat_dims) 321 | 322 | 323 | class FoldNet_Decoder(nn.Module): 324 | def __init__(self, args): 325 | super(FoldNet_Decoder, self).__init__() 326 | self.m = 2025 # 45 * 45. 327 | self.shape = args.shape 328 | self.meshgrid = [[-0.3, 0.3, 45], [-0.3, 0.3, 45]] 329 | self.sphere = np.load("sphere.npy") 330 | self.gaussian = np.load("gaussian.npy") 331 | if self.shape == 'plane': 332 | self.folding1 = nn.Sequential( 333 | nn.Conv1d(args.feat_dims+2, args.feat_dims, 1), 334 | nn.ReLU(), 335 | nn.Conv1d(args.feat_dims, args.feat_dims, 1), 336 | nn.ReLU(), 337 | nn.Conv1d(args.feat_dims, 3, 1), 338 | ) 339 | else: 340 | self.folding1 = nn.Sequential( 341 | nn.Conv1d(args.feat_dims+3, args.feat_dims, 1), 342 | nn.ReLU(), 343 | nn.Conv1d(args.feat_dims, args.feat_dims, 1), 344 | nn.ReLU(), 345 | nn.Conv1d(args.feat_dims, 3, 1), 346 | ) 347 | self.folding2 = nn.Sequential( 348 | nn.Conv1d(args.feat_dims+3, args.feat_dims, 1), 349 | nn.ReLU(), 350 | nn.Conv1d(args.feat_dims, args.feat_dims, 1), 351 | nn.ReLU(), 352 | nn.Conv1d(args.feat_dims, 3, 1), 353 | ) 354 | 355 | def build_grid(self, batch_size): 356 | if self.shape == 'plane': 357 | x = np.linspace(*self.meshgrid[0]) 358 | y = np.linspace(*self.meshgrid[1]) 359 | points = np.array(list(itertools.product(x, y))) 360 | elif self.shape == 'sphere': 361 | points = self.sphere 362 | elif self.shape == 'gaussian': 363 | points = self.gaussian 364 | points = np.repeat(points[np.newaxis, ...], repeats=batch_size, axis=0) 365 | points = torch.tensor(points) 366 | return points.float() 367 | 368 | def forward(self, x): 369 | x = x.transpose(1, 2).repeat(1, 1, self.m) # (batch_size, feat_dims, num_points) 370 | points = self.build_grid(x.shape[0]).transpose(1, 2) # (batch_size, 2, num_points) or (batch_size, 3, num_points) 371 | if x.get_device() != -1: 372 | points = points.cuda(x.get_device()) 373 | cat1 = torch.cat((x, points), dim=1) # (batch_size, feat_dims+2, num_points) or (batch_size, feat_dims+3, num_points) 374 | folding_result1 = self.folding1(cat1) # (batch_size, 3, num_points) 375 | cat2 = torch.cat((x, folding_result1), dim=1) # (batch_size, 515, num_points) 376 | folding_result2 = self.folding2(cat2) # (batch_size, 3, num_points) 377 | return folding_result2.transpose(1, 2) # (batch_size, num_points ,3) 378 | 379 | 380 | class DGCNN_Cls_Classifier(nn.Module): 381 | def __init__(self, args): 382 | super(DGCNN_Cls_Classifier, self).__init__() 383 | if args.dataset == 'modelnet40': 384 | output_channels = 40 385 | elif args.dataset == 'modelnet10': 386 | output_channels = 10 387 | elif args.dataset == 'shapenetcorev2': 388 | output_channels = 55 389 | elif args.dataset == 'shapenetpart': 390 | output_channels = 16 391 | 392 | self.linear1 = nn.Linear(args.feat_dims*2, 512, bias=False) 393 | self.bn6 = nn.BatchNorm1d(512) 394 | self.dp1 = nn.Dropout(p=args.dropout) 395 | self.linear2 = nn.Linear(512, 256) 396 | self.bn7 = nn.BatchNorm1d(256) 397 | self.dp2 = nn.Dropout(p=args.dropout) 398 | self.linear3 = nn.Linear(256, output_channels) 399 | 400 | def forward(self, x): 401 | batch_size = x.size(0) 402 | 403 | x1 = F.adaptive_max_pool1d(x, 1).view(batch_size, -1) 404 | x2 = F.adaptive_avg_pool1d(x, 1).view(batch_size, -1) 405 | x = torch.cat((x1, x2), 1) 406 | 407 | x = F.leaky_relu(self.bn6(self.linear1(x)), negative_slope=0.2) 408 | x = self.dp1(x) 409 | x = F.leaky_relu(self.bn7(self.linear2(x)), negative_slope=0.2) 410 | x = self.dp2(x) 411 | x = self.linear3(x) 412 | return x 413 | 414 | 415 | class ReconstructionNet(nn.Module): 416 | def __init__(self, args): 417 | super(ReconstructionNet, self).__init__() 418 | if args.encoder == 'foldnet': 419 | self.encoder = FoldNet_Encoder(args) 420 | elif args.encoder == 'dgcnn_cls': 421 | self.encoder = DGCNN_Cls_Encoder(args) 422 | elif args.encoder == 'dgcnn_seg': 423 | self.encoder = DGCNN_Seg_Encoder(args) 424 | self.decoder = FoldNet_Decoder(args) 425 | self.loss = ChamferLoss() 426 | 427 | def forward(self, input): 428 | feature = self.encoder(input) 429 | output = self.decoder(feature) 430 | return output, feature 431 | 432 | def get_parameter(self): 433 | return list(self.encoder.parameters()) + list(self.decoder.parameters()) 434 | 435 | def get_loss(self, input, output): 436 | # input shape (batch_size, 2048, 3) 437 | # output shape (batch_size, 2025, 3) 438 | return self.loss(input, output) 439 | 440 | 441 | class ClassificationNet(nn.Module): 442 | def __init__(self, args): 443 | super(ClassificationNet, self).__init__() 444 | self.is_eval = args.eval 445 | if args.encoder == 'foldnet': 446 | self.encoder = FoldNet_Encoder(args) 447 | elif args.encoder == 'dgcnn_cls': 448 | self.encoder = DGCNN_Cls_Encoder(args) 449 | elif args.encoder == 'dgcnn_seg': 450 | self.encoder = DGCNN_Seg_Encoder(args) 451 | if not self.is_eval: 452 | self.classifier = DGCNN_Cls_Classifier(args) 453 | self.loss = CrossEntropyLoss() 454 | 455 | def forward(self, input): 456 | feature, latent = self.encoder(input) 457 | if not self.is_eval: 458 | output = self.classifier(latent) 459 | return output, feature 460 | else: 461 | return feature 462 | 463 | def get_parameter(self): 464 | return list(self.encoder.parameters()) + list(self.classifier.parameters()) 465 | 466 | def get_loss(self, input, output): 467 | # input shape (batch_size, 2048) 468 | # output shape (batch_size, 2025) 469 | return self.loss(input, output) 470 | -------------------------------------------------------------------------------- /reconstruction.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | @Author: An Tao 5 | @Contact: ta19@mails.tsinghua.edu.cn 6 | @File: reconstruction.py 7 | @Time: 2020/1/2 10:26 AM 8 | """ 9 | 10 | import os 11 | import sys 12 | import time 13 | import shutil 14 | import torch 15 | import torch.optim as optim 16 | import numpy as np 17 | 18 | from tensorboardX import SummaryWriter 19 | 20 | from model import ReconstructionNet 21 | from dataset import Dataset 22 | from utils import Logger 23 | 24 | 25 | class Reconstruction(object): 26 | def __init__(self, args): 27 | self.dataset_name = args.dataset 28 | if args.epochs != None: 29 | self.epochs = args.epochs 30 | elif args.encoder == 'foldnet': 31 | self.epochs = 278 32 | elif args.encoder == 'dgcnn_cls': 33 | self.epochs = 250 34 | elif args.encoder == 'dgcnn_seg': 35 | self.epochs = 290 36 | self.batch_size = args.batch_size 37 | self.snapshot_interval = args.snapshot_interval 38 | self.no_cuda = args.no_cuda 39 | self.model_path = args.model_path 40 | 41 | # create exp directory 42 | file = [f for f in args.model_path.split('/')] 43 | if args.exp_name != None: 44 | self.experiment_id = "Reconstruct_" + args.exp_name 45 | elif file[-2] == 'models': 46 | self.experiment_id = file[-3] 47 | else: 48 | self.experiment_id = "Reconstruct" + time.strftime('%m%d%H%M%S') 49 | snapshot_root = 'snapshot/%s' % self.experiment_id 50 | tensorboard_root = 'tensorboard/%s' % self.experiment_id 51 | self.save_dir = os.path.join(snapshot_root, 'models/') 52 | self.tboard_dir = tensorboard_root 53 | 54 | # check arguments 55 | if self.model_path == '': 56 | if not os.path.exists(self.save_dir): 57 | os.makedirs(self.save_dir) 58 | else: 59 | choose = input("Remove " + self.save_dir + " ? (y/n)") 60 | if choose == "y": 61 | shutil.rmtree(self.save_dir) 62 | os.makedirs(self.save_dir) 63 | else: 64 | sys.exit(0) 65 | if not os.path.exists(self.tboard_dir): 66 | os.makedirs(self.tboard_dir) 67 | else: 68 | shutil.rmtree(self.tboard_dir) 69 | os.makedirs(self.tboard_dir) 70 | sys.stdout = Logger(os.path.join(snapshot_root, 'log.txt')) 71 | self.writer = SummaryWriter(log_dir=self.tboard_dir) 72 | 73 | # print args 74 | print(str(args)) 75 | 76 | # get gpu id 77 | gids = ''.join(args.gpu.split()) 78 | self.gpu_ids = [int(gid) for gid in gids.split(',')] 79 | self.first_gpu = self.gpu_ids[0] 80 | 81 | # generate dataset 82 | self.train_dataset = Dataset( 83 | root=args.dataset_root, 84 | dataset_name=args.dataset, 85 | split='all', 86 | num_points=args.num_points, 87 | random_translate=args.use_translate, 88 | random_rotate=True, 89 | random_jitter=args.use_jitter 90 | ) 91 | self.train_loader = torch.utils.data.DataLoader( 92 | self.train_dataset, 93 | batch_size=args.batch_size, 94 | shuffle=True, 95 | num_workers=args.workers 96 | ) 97 | print("Training set size:", self.train_loader.dataset.__len__()) 98 | 99 | # initialize model 100 | self.model = ReconstructionNet(args) 101 | if self.model_path != '': 102 | self._load_pretrain(args.model_path) 103 | 104 | # load model to gpu 105 | if not self.no_cuda: 106 | if len(self.gpu_ids) != 1: # multiple gpus 107 | self.model = torch.nn.DataParallel(self.model.cuda(self.first_gpu), self.gpu_ids) 108 | else: 109 | self.model = self.model.cuda(self.gpu_ids[0]) 110 | 111 | # initialize optimizer 112 | self.parameter = self.model.parameters() 113 | self.optimizer = optim.Adam(self.parameter, lr=0.0001*16/args.batch_size, betas=(0.9, 0.999), weight_decay=1e-6) 114 | 115 | 116 | def run(self): 117 | self.train_hist = { 118 | 'loss': [], 119 | 'per_epoch_time': [], 120 | 'total_time': [] 121 | } 122 | best_loss = 1000000000 123 | print('Training start!!') 124 | start_time = time.time() 125 | self.model.train() 126 | if self.model_path != '': 127 | start_epoch = self.model_path[-7:-4] 128 | if start_epoch[0] == '_': 129 | start_epoch = start_epoch[1:] 130 | start_epoch = int(start_epoch) 131 | else: 132 | start_epoch = 0 133 | for epoch in range(start_epoch, self.epochs): 134 | loss = self.train_epoch(epoch) 135 | 136 | # save snapeshot 137 | if (epoch + 1) % self.snapshot_interval == 0: 138 | self._snapshot(epoch + 1) 139 | if loss < best_loss: 140 | best_loss = loss 141 | self._snapshot('best') 142 | 143 | # save tensorboard 144 | if self.writer: 145 | self.writer.add_scalar('Train Loss', self.train_hist['loss'][-1], epoch) 146 | self.writer.add_scalar('Learning Rate', self._get_lr(), epoch) 147 | 148 | # finish all epoch 149 | self._snapshot(epoch + 1) 150 | if loss < best_loss: 151 | best_loss = loss 152 | self._snapshot('best') 153 | self.train_hist['total_time'].append(time.time() - start_time) 154 | print("Avg one epoch time: %.2f, total %d epochs time: %.2f" % (np.mean(self.train_hist['per_epoch_time']), 155 | self.epochs, self.train_hist['total_time'][0])) 156 | print("Training finish!... save training results") 157 | 158 | 159 | def train_epoch(self, epoch): 160 | epoch_start_time = time.time() 161 | loss_buf = [] 162 | num_batch = int(len(self.train_loader.dataset) / self.batch_size) 163 | for iter, (pts, _) in enumerate(self.train_loader): 164 | if not self.no_cuda: 165 | pts = pts.cuda(self.first_gpu) 166 | 167 | # forward 168 | self.optimizer.zero_grad() 169 | output, _ = self.model(pts) 170 | 171 | # loss 172 | if len(self.gpu_ids) != 1: # multiple gpus 173 | loss = self.model.module.get_loss(pts, output) 174 | else: 175 | loss = self.model.get_loss(pts, output) 176 | 177 | # backward 178 | loss.backward() 179 | self.optimizer.step() 180 | loss_buf.append(loss.detach().cpu().numpy()) 181 | 182 | # finish one epoch 183 | epoch_time = time.time() - epoch_start_time 184 | self.train_hist['per_epoch_time'].append(epoch_time) 185 | self.train_hist['loss'].append(np.mean(loss_buf)) 186 | print(f'Epoch {epoch+1}: Loss {np.mean(loss_buf)}, time {epoch_time:.4f}s') 187 | return np.mean(loss_buf) 188 | 189 | 190 | def _snapshot(self, epoch): 191 | state_dict = self.model.state_dict() 192 | from collections import OrderedDict 193 | new_state_dict = OrderedDict() 194 | for key, val in state_dict.items(): 195 | if key[:6] == 'module': 196 | name = key[7:] # remove 'module.' 197 | else: 198 | name = key 199 | new_state_dict[name] = val 200 | save_dir = os.path.join(self.save_dir, self.dataset_name) 201 | torch.save(new_state_dict, save_dir + "_" + str(epoch) + '.pkl') 202 | print(f"Save model to {save_dir}_{str(epoch)}.pkl") 203 | 204 | 205 | def _load_pretrain(self, pretrain): 206 | state_dict = torch.load(pretrain, map_location='cpu') 207 | from collections import OrderedDict 208 | new_state_dict = OrderedDict() 209 | for key, val in state_dict.items(): 210 | if key[:6] == 'module': 211 | name = key[7:] # remove 'module.' 212 | else: 213 | name = key 214 | new_state_dict[name] = val 215 | self.model.load_state_dict(new_state_dict) 216 | print(f"Load model from {pretrain}") 217 | 218 | 219 | def _get_lr(self, group=0): 220 | return self.optimizer.param_groups[group]['lr'] 221 | -------------------------------------------------------------------------------- /sphere.npy: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/sphere.npy -------------------------------------------------------------------------------- /svm.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | @Author: An Tao 5 | @Contact: ta19@mails.tsinghua.edu.cn 6 | @File: svm.py 7 | @Time: 2020/1/2 10:26 AM 8 | """ 9 | 10 | import os 11 | import h5py 12 | import numpy as np 13 | from glob import glob 14 | from sklearn.svm import LinearSVC 15 | 16 | 17 | class SVM(object): 18 | def __init__(self, feature_dir): 19 | self.feature_dir = feature_dir 20 | 21 | self.train_path = glob(os.path.join(self.feature_dir, 'train*.h5')) 22 | self.test_path = glob(os.path.join(self.feature_dir, 'test*.h5')) 23 | 24 | print("Loading feature dataset...") 25 | train_data = [] 26 | train_label = [] 27 | for path in self.train_path: 28 | f = h5py.File(path, 'r+') 29 | data = f['data'][:].astype('float32') 30 | label = f['label'][:].astype('int64') 31 | f.close() 32 | train_data.append(data) 33 | train_label.append(label) 34 | self.train_data = np.concatenate(train_data, axis=0) 35 | self.train_label = np.concatenate(train_label, axis=0) 36 | print("Training set size:", np.size(self.train_data, 0)) 37 | 38 | test_data = [] 39 | test_label = [] 40 | for path in self.test_path: 41 | f = h5py.File(path, 'r+') 42 | data = f['data'][:].astype('float32') 43 | label = f['label'][:].astype('int64') 44 | f.close() 45 | test_data.append(data) 46 | test_label.append(label) 47 | self.test_data = np.concatenate(test_data, axis=0) 48 | self.test_label = np.concatenate(test_label, axis=0) 49 | print("Testing set size:", np.size(self.test_data, 0)) 50 | 51 | def run(self): 52 | clf = LinearSVC(random_state=0) 53 | clf.fit(self.train_data, self.train_label) 54 | result = clf.predict(self.test_data) 55 | accuracy = np.sum(result==self.test_label).astype(float) / np.size(self.test_label) 56 | print("Transfer linear SVM accuracy: {:.2f}%".format(accuracy*100)) 57 | 58 | 59 | -------------------------------------------------------------------------------- /tensorboard/Classify_dgcnn_cls_k20/events.out.tfevents.1578666096.human1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Classify_dgcnn_cls_k20/events.out.tfevents.1578666096.human1 -------------------------------------------------------------------------------- /tensorboard/Classify_dgcnn_cls_k40_1024_b32/events.out.tfevents.1579746166.server231: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Classify_dgcnn_cls_k40_1024_b32/events.out.tfevents.1579746166.server231 -------------------------------------------------------------------------------- /tensorboard/Reconstruct_dgcnn_cls_k20_gaussian/events.out.tfevents.1578226376.human1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_cls_k20_gaussian/events.out.tfevents.1578226376.human1 -------------------------------------------------------------------------------- /tensorboard/Reconstruct_dgcnn_cls_k20_plane/events.out.tfevents.1577427494.human1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_cls_k20_plane/events.out.tfevents.1577427494.human1 -------------------------------------------------------------------------------- /tensorboard/Reconstruct_dgcnn_cls_k20_sphere/events.out.tfevents.1577698740.human1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_cls_k20_sphere/events.out.tfevents.1577698740.human1 -------------------------------------------------------------------------------- /tensorboard/Reconstruct_dgcnn_cls_k40_gaussian/events.out.tfevents.1579955081.server231: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_cls_k40_gaussian/events.out.tfevents.1579955081.server231 -------------------------------------------------------------------------------- /tensorboard/Reconstruct_dgcnn_cls_k40_plane/events.out.tfevents.1577866606.human1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_cls_k40_plane/events.out.tfevents.1577866606.human1 -------------------------------------------------------------------------------- /tensorboard/Reconstruct_dgcnn_cls_k40_sphere/events.out.tfevents.1577935530.human1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_cls_k40_sphere/events.out.tfevents.1577935530.human1 -------------------------------------------------------------------------------- /tensorboard/Reconstruct_dgcnn_cls_k40_sphere_1024_b32/events.out.tfevents.1579919706.server231: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_cls_k40_sphere_1024_b32/events.out.tfevents.1579919706.server231 -------------------------------------------------------------------------------- /tensorboard/Reconstruct_dgcnn_seg_k20_gaussian/events.out.tfevents.1578371932.human1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_seg_k20_gaussian/events.out.tfevents.1578371932.human1 -------------------------------------------------------------------------------- /tensorboard/Reconstruct_dgcnn_seg_k20_gaussian/events.out.tfevents.1578661771.human1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_seg_k20_gaussian/events.out.tfevents.1578661771.human1 -------------------------------------------------------------------------------- /tensorboard/Reconstruct_dgcnn_seg_k20_plane/events.out.tfevents.1578186628.human1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_seg_k20_plane/events.out.tfevents.1578186628.human1 -------------------------------------------------------------------------------- /tensorboard/Reconstruct_dgcnn_seg_k20_plane/events.out.tfevents.1578443368.human1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_seg_k20_plane/events.out.tfevents.1578443368.human1 -------------------------------------------------------------------------------- /tensorboard/Reconstruct_dgcnn_seg_k20_sphere/events.out.tfevents.1578202920.human1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_seg_k20_sphere/events.out.tfevents.1578202920.human1 -------------------------------------------------------------------------------- /tensorboard/Reconstruct_dgcnn_seg_k20_sphere/events.out.tfevents.1578447006.human1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_seg_k20_sphere/events.out.tfevents.1578447006.human1 -------------------------------------------------------------------------------- /tensorboard/Reconstruct_dgcnn_seg_k40_gaussian/events.out.tfevents.1580628995.server231: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_seg_k40_gaussian/events.out.tfevents.1580628995.server231 -------------------------------------------------------------------------------- /tensorboard/Reconstruct_dgcnn_seg_k40_plane/events.out.tfevents.1580304772.server231: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_seg_k40_plane/events.out.tfevents.1580304772.server231 -------------------------------------------------------------------------------- /tensorboard/Reconstruct_dgcnn_seg_k40_sphere/events.out.tfevents.1580304803.server231: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_dgcnn_seg_k40_sphere/events.out.tfevents.1580304803.server231 -------------------------------------------------------------------------------- /tensorboard/Reconstruct_original_gaussian/events.out.tfevents.1578226412.human1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_original_gaussian/events.out.tfevents.1578226412.human1 -------------------------------------------------------------------------------- /tensorboard/Reconstruct_original_plane/events.out.tfevents.1577003758.human1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_original_plane/events.out.tfevents.1577003758.human1 -------------------------------------------------------------------------------- /tensorboard/Reconstruct_original_sphere/events.out.tfevents.1577366104.human1: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/antao97/UnsupervisedPointCloudReconstruction/980194040b22b8448282501a8291e26bd227b6a6/tensorboard/Reconstruct_original_sphere/events.out.tfevents.1577366104.human1 -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | @Author: An Tao 5 | @Contact: ta19@mails.tsinghua.edu.cn 6 | @File: utils.py 7 | @Time: 2020/1/2 10:26 AM 8 | """ 9 | 10 | import os 11 | import sys 12 | 13 | 14 | class AverageMeter(object): 15 | """Computes and stores the average and current value""" 16 | def __init__(self): 17 | self.reset() 18 | 19 | def reset(self): 20 | self.val = 0 21 | self.avg = 0 22 | self.sum = 0 23 | self.count = 0 24 | 25 | def update(self, val, n=1): 26 | self.val = val 27 | self.sum += val * n 28 | self.count += n 29 | self.avg = self.sum / self.count 30 | 31 | 32 | def learning_rate_decay(optimizer, t, lr_0): 33 | for param_group in optimizer.param_groups: 34 | lr = lr_0 / np.sqrt(1 + lr_0 * param_group['weight_decay'] * t) 35 | param_group['lr'] = lr 36 | 37 | 38 | class Logger(object): 39 | def __init__(self, fpath=None): 40 | self.console = sys.stdout 41 | self.file = None 42 | if fpath is not None: 43 | self.file = open(fpath, 'w') 44 | 45 | def __del__(self): 46 | self.close() 47 | 48 | def __enter__(self): 49 | pass 50 | 51 | def __exit__(self, *args): 52 | self.close() 53 | 54 | def write(self, msg): 55 | self.console.write(msg) 56 | if self.file is not None: 57 | self.file.write(msg) 58 | 59 | def flush(self): 60 | self.console.flush() 61 | if self.file is not None: 62 | self.file.flush() 63 | os.fsync(self.file.fileno()) 64 | 65 | def close(self): 66 | self.console.close() 67 | if self.file is not None: 68 | self.file.close() -------------------------------------------------------------------------------- /visualization.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | """ 4 | @Author: An Tao 5 | @Contact: ta19@mails.tsinghua.edu.cn 6 | @File: visualization.py 7 | @Time: 2020/1/2 10:26 AM 8 | """ 9 | 10 | import os 11 | import time 12 | import numpy as np 13 | import torch 14 | import itertools 15 | import argparse 16 | from glob import glob 17 | 18 | from model import ReconstructionNet 19 | 20 | def standardize_bbox(pcl, points_per_object): 21 | pt_indices = np.random.choice(pcl.shape[0], points_per_object, replace=False) 22 | np.random.shuffle(pt_indices) 23 | pcl = pcl[pt_indices] # n by 3 24 | mins = np.amin(pcl, axis=0) 25 | maxs = np.amax(pcl, axis=0) 26 | center = ( mins + maxs ) / 2. 27 | scale = np.amax(maxs-mins) 28 | print("Center: {}, Scale: {}".format(center, scale)) 29 | result = ((pcl - center)/scale).astype(np.float32) # [-0.5, 0.5] 30 | return result 31 | 32 | xml_head = \ 33 | """ 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | """ 65 | 66 | xml_ball_segment = \ 67 | """ 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | """ 79 | 80 | xml_tail = \ 81 | """ 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | """ 101 | 102 | def colormap(x,y,z): 103 | vec = np.array([x,y,z]) 104 | vec = np.clip(vec, 0.001,1.0) 105 | norm = np.sqrt(np.sum(vec**2)) 106 | vec /= norm 107 | return [vec[0], vec[1], vec[2]] 108 | 109 | def mitsuba(pcl, path, clr=None): 110 | xml_segments = [xml_head] 111 | 112 | # pcl = standardize_bbox(pcl, 2048) 113 | # pcl = pcl - np.expand_dims(np.mean(pcl, axis=0), 0) # center 114 | # dist = np.max(np.sqrt(np.sum(pcl ** 2, axis=1)), 0) 115 | # pcl = pcl / dist # scale 116 | 117 | pcl = pcl[:,[2,0,1]] 118 | pcl[:,0] *= -1 119 | h = np.min(pcl[:,2]) 120 | 121 | if clr == "plane": 122 | clrgrid = [[0, 1, 45], [1, 0, 45]] 123 | b = np.linspace(*clrgrid[0]) 124 | c = np.linspace(*clrgrid[1]) 125 | color_all = np.array(list(itertools.product(b, c))) 126 | color_all = np.concatenate((np.linspace(1, 0, 2025)[..., np.newaxis], color_all), axis=1) 127 | elif clr == "sphere": 128 | color_all = np.load("sphere.npy") 129 | color_all = (color_all + 0.3) / 0.6 130 | elif clr == "gaussian": 131 | color_all = np.load("gaussian.npy") 132 | color_all = (color_all + 0.3) / 0.6 133 | 134 | for i in range(pcl.shape[0]): 135 | if clr == None: 136 | color = colormap(pcl[i,0]+0.5,pcl[i,1]+0.5,pcl[i,2]+0.5) 137 | elif clr in ["plane", "sphere", "gaussian"]: 138 | color = color_all[i] 139 | else: 140 | color = clr 141 | if h < -0.25: 142 | xml_segments.append(xml_ball_segment.format(pcl[i,0],pcl[i,1],pcl[i,2]-h-0.6875, *color)) 143 | else: 144 | xml_segments.append(xml_ball_segment.format(pcl[i,0],pcl[i,1],pcl[i,2], *color)) 145 | xml_segments.append(xml_tail) 146 | 147 | xml_content = str.join('', xml_segments) 148 | 149 | with open(path, 'w') as f: 150 | f.write(xml_content) 151 | 152 | def load_pretrain(model, pretrain): 153 | state_dict = torch.load(pretrain, map_location='cpu') 154 | from collections import OrderedDict 155 | new_state_dict = OrderedDict() 156 | for key, val in state_dict.items(): 157 | if key[:6] == 'module': 158 | name = key[7:] # remove 'module.' 159 | else: 160 | name = key 161 | new_state_dict[name] = val 162 | model.load_state_dict(new_state_dict) 163 | print(f"Load model from {pretrain}") 164 | return model 165 | 166 | 167 | def visualize(args): 168 | # create exp directory 169 | file = [f for f in args.model_path.split('/')] 170 | if args.exp_name != None: 171 | experiment_id = args.exp_name 172 | elif file[-1] == '': 173 | experiment_id = time.strftime('%m%d%H%M%S') 174 | one_model = True 175 | elif file[-1][-4:] == '.pkl': 176 | experiment_id = file[-3] 177 | one_model = True 178 | elif file[-1] == 'models': 179 | experiment_id = file[-2] 180 | one_model = False 181 | else: 182 | experiment_id = time.strftime('%m%d%H%M%S') 183 | save_root = os.path.join('mitsuba', experiment_id, args.dataset, args.split + str(args.item)) 184 | os.makedirs(save_root, exist_ok=True) 185 | 186 | # initialize dataset 187 | from dataset import Dataset 188 | dataset = Dataset(root=args.dataset_root, dataset_name=args.dataset, 189 | num_points=args.num_points, split=args.split, load_name=True) 190 | 191 | # load data from dataset 192 | pts, lb, n = dataset[args.item] 193 | print(f"Dataset: {args.dataset}, split: {args.split}, item: {args.item}, category: {n}") 194 | 195 | # generate XML file for original point cloud 196 | if args.draw_original: 197 | save_path = os.path.join(save_root, args.dataset + '_' + args.split + str(args.item) + '_' + str(n) + '_origin.xml') 198 | color = [0.4, 0.4, 0.6] 199 | mitsuba(pts.numpy(), save_path, color) 200 | 201 | # generate XML file for decoder souce point 202 | if args.draw_source_points: 203 | if args.shape == 'plane': 204 | meshgrid = [[-0.3, 0.3, 45], [-0.3, 0.3, 45]] 205 | x = np.linspace(*meshgrid[0]) 206 | y = np.linspace(*meshgrid[1]) 207 | points = np.array(list(itertools.product(x, y))) 208 | points = np.concatenate((points,np.zeros(2025)[..., np.newaxis]), axis=1) 209 | elif args.shape == 'sphere': 210 | points = np.load("sphere.npy") 211 | elif args.shape == 'gaussian': 212 | points = np.load("gaussian.npy") 213 | save_path = os.path.join(save_root, args.dataset + '_' + args.split + str(args.item) + '_' + str(n) + '_epoch0.xml') 214 | mitsuba(points, save_path, clr=args.shape) 215 | 216 | # initialize model 217 | model = ReconstructionNet(args) 218 | 219 | if one_model: 220 | if file[0] != '': 221 | model = load_pretrain(model, args.model_path) 222 | model.eval() 223 | reconstructed_pl, _ = model(pts.view(1, 2048, 3)) 224 | save_path = os.path.join(save_root, file[-1][:-4] + args.split + str(args.item) + '_' + str(n) + '.xml') 225 | mitsuba(reconstructed_pl[0].detach().numpy(), save_path, clr=args.shape) 226 | else: 227 | load_path = glob(os.path.join(args.model_path, '*.pkl')) 228 | load_path.sort() 229 | for path in load_path: 230 | model_name = [p for p in path.split('/')][-1] 231 | model = load_pretrain(model, path) 232 | model.eval() 233 | reconstructed_pl, _ = model(pts.view(1, 2048, 3)) 234 | save_path = os.path.join(save_root, model_name[:-4] + '_' + args.dataset + '_' + args.split + str(args.item) + '_' + str(n) + '.xml') 235 | mitsuba(reconstructed_pl[0].detach().numpy(), save_path, clr=args.shape) 236 | 237 | 238 | if __name__ == '__main__': 239 | parser = argparse.ArgumentParser(description='Unsupervised Point Cloud Feature Learning') 240 | parser.add_argument('--exp_name', type=str, default=None, metavar='N', 241 | help='Name of the experiment') 242 | parser.add_argument('--item', type=int, default=0, metavar='N', 243 | help='Item of point cloud to load') 244 | parser.add_argument('--split', type=str, default='train', metavar='N', 245 | choices=['train','test', 'val', 'trainval', 'all'], 246 | help='Split to use, [foldingnet, dgcnn_cls, dgcnn_seg]') 247 | parser.add_argument('--encoder', type=str, default='foldingnet', metavar='N', 248 | choices=['foldnet', 'dgcnn_cls', 'dgcnn_seg'], 249 | help='Encoder to use, [foldingnet, dgcnn_cls, dgcnn_seg]') 250 | parser.add_argument('--feat_dims', type=int, default=512, metavar='N', 251 | help='Number of dims for feature ') 252 | parser.add_argument('--k', type=int, default=None, metavar='N', 253 | help='Num of nearest neighbors to use for KNN') 254 | parser.add_argument('--shape', type=str, default='plane', metavar='N', 255 | choices=['plane', 'sphere', 'gaussian'], 256 | help='Shape of points to input decoder, [plane, sphere, gaussian]') 257 | parser.add_argument('--dataset', type=str, default='shapenetcorev2', metavar='N', 258 | choices=['shapenetcorev2','modelnet40', 'modelnet10'], 259 | help='Encoder to use, [shapenetcorev2,modelnet40, modelnet10]') 260 | parser.add_argument('--dataset_root', type=str, default='../dataset', help="Dataset root path") 261 | parser.add_argument('--num_points', type=int, default=2048, 262 | help='Num of points to use') 263 | parser.add_argument('--model_path', type=str, default='', metavar='N', 264 | help='Path to load model') 265 | parser.add_argument('--draw_original', action='store_true', 266 | help='Draw original point cloud') 267 | parser.add_argument('--draw_source_points', action='store_true', 268 | help='Draw source points for decoder') 269 | args = parser.parse_args() 270 | 271 | print(str(args)) 272 | 273 | visualize(args) --------------------------------------------------------------------------------