├── LICENSE ├── README.md ├── configs ├── __init__.py ├── config_files │ ├── ISCNet.yaml │ ├── ISCNet_completion.yaml │ ├── ISCNet_detection.yaml │ └── ISCNet_test.yaml ├── config_utils.py ├── path_config.py └── scannet_config.py ├── datasets ├── scannet │ ├── raw_lablemap_to_synsetoffset.pkl │ ├── scannet_means.npz │ └── scannetv2-labels.combined.tsv └── splits │ ├── fullscan │ ├── scannetv2_test.json │ ├── scannetv2_train.json │ └── scannetv2_val.json │ └── scannet │ ├── scannetv2_train.txt │ └── scannetv2_val.txt ├── demo.py ├── demo ├── inputs │ ├── scene0549_00.off │ └── scene0575_00.off ├── outputs │ ├── scene0549_00 │ │ ├── 000000_pc.ply │ │ ├── 000000_pred_confident_nms_bbox.npz │ │ ├── pred.png │ │ ├── proposal_107_mesh.ply │ │ ├── proposal_113_mesh.ply │ │ ├── proposal_118_mesh.ply │ │ ├── proposal_200_mesh.ply │ │ ├── proposal_201_mesh.ply │ │ ├── proposal_225_mesh.ply │ │ ├── proposal_22_mesh.ply │ │ ├── proposal_230_mesh.ply │ │ ├── proposal_232_mesh.ply │ │ ├── proposal_253_mesh.ply │ │ ├── proposal_38_mesh.ply │ │ ├── proposal_97_mesh.ply │ │ └── proposal_99_mesh.ply │ └── scene0575_00 │ │ ├── 000000_pc.ply │ │ ├── 000000_pred_confident_nms_bbox.npz │ │ ├── pred.png │ │ ├── proposal_133_mesh.ply │ │ ├── proposal_139_mesh.ply │ │ ├── proposal_147_mesh.ply │ │ ├── proposal_159_mesh.ply │ │ ├── proposal_163_mesh.ply │ │ ├── proposal_182_mesh.ply │ │ ├── proposal_188_mesh.ply │ │ ├── proposal_196_mesh.ply │ │ ├── proposal_221_mesh.ply │ │ ├── proposal_228_mesh.ply │ │ ├── proposal_233_mesh.ply │ │ ├── proposal_24_mesh.ply │ │ ├── proposal_253_mesh.ply │ │ ├── proposal_25_mesh.ply │ │ └── proposal_97_mesh.ply └── screenshots │ ├── screenshot_demo.png │ └── screenshot_scan2cad.png ├── environment.yml ├── external ├── binvox_rw.py ├── common.py ├── libkdtree │ ├── .travis.yml │ ├── LICENSE.txt │ ├── MANIFEST.in │ ├── Makefile │ ├── README │ ├── README.rst │ ├── appveyor.yml │ ├── appveyor │ │ ├── install.ps1 │ │ ├── missing-headers.ps1 │ │ └── run_with_compiler.cmd │ ├── pykdtree │ │ ├── __init__.py │ │ ├── __pycache__ │ │ │ └── __init__.cpython-36.pyc │ │ ├── _kdtree_core.c │ │ ├── _kdtree_core.c.mako │ │ ├── kdtree.c │ │ ├── kdtree.cpython-36m-x86_64-linux-gnu.so │ │ ├── kdtree.pyx │ │ ├── render_template.py │ │ └── test_tree.py │ ├── scripts │ │ └── build-manylinux-wheels.sh │ ├── setup.cfg │ └── setup.py ├── libmesh │ ├── .gitignore │ ├── __init__.py │ ├── inside_mesh.py │ ├── triangle_hash.cpython-36m-x86_64-linux-gnu.so │ └── triangle_hash.pyx ├── libmise │ ├── .gitignore │ ├── __init__.py │ ├── __pycache__ │ │ └── __init__.cpython-36.pyc │ ├── mise.cpython-36m-x86_64-linux-gnu.so │ ├── mise.pyx │ └── test.py ├── librender │ ├── __init__.py │ ├── build │ │ └── temp.linux-x86_64-3.6 │ │ │ ├── offscreen.o │ │ │ └── pyrender.o │ ├── offscreen.cpp │ ├── offscreen.h │ ├── pyrender.cpp │ ├── pyrender.cpython-36m-x86_64-linux-gnu.so │ ├── pyrender.pyx │ ├── setup.py │ └── test.py ├── libsimplify │ ├── Simplify.h │ ├── __init__.py │ ├── __pycache__ │ │ └── __init__.cpython-36.pyc │ ├── simplify_mesh.cpp │ ├── simplify_mesh.cpython-36m-x86_64-linux-gnu.so │ ├── simplify_mesh.pyx │ └── test.py ├── libvoxelize │ ├── .gitignore │ ├── __init__.py │ ├── tribox2.h │ ├── voxelize.cpython-36m-x86_64-linux-gnu.so │ └── voxelize.pyx ├── pointnet2_ops_lib │ ├── MANIFEST.in │ ├── pointnet2_ops │ │ ├── __init__.py │ │ ├── __pycache__ │ │ │ ├── __init__.cpython-36.pyc │ │ │ ├── pointnet2_modules.cpython-36.pyc │ │ │ └── pointnet2_utils.cpython-36.pyc │ │ ├── _ext-src │ │ │ ├── include │ │ │ │ ├── ball_query.h │ │ │ │ ├── cuda_utils.h │ │ │ │ ├── group_points.h │ │ │ │ ├── interpolate.h │ │ │ │ ├── sampling.h │ │ │ │ └── utils.h │ │ │ └── src │ │ │ │ ├── ball_query.cpp │ │ │ │ ├── ball_query_gpu.cu │ │ │ │ ├── bindings.cpp │ │ │ │ ├── group_points.cpp │ │ │ │ ├── group_points_gpu.cu │ │ │ │ ├── interpolate.cpp │ │ │ │ ├── interpolate_gpu.cu │ │ │ │ ├── sampling.cpp │ │ │ │ └── sampling_gpu.cu │ │ ├── _version.py │ │ ├── pointnet2_modules.py │ │ ├── pointnet2_utils.py │ │ └── pytorch_utils.py │ └── setup.py ├── pyTorchChamferDistance │ ├── .gitignore │ ├── LICENSE.md │ ├── README.md │ └── chamfer_distance │ │ ├── __init__.py │ │ ├── __pycache__ │ │ ├── __init__.cpython-36.pyc │ │ └── chamfer_distance.cpython-36.pyc │ │ ├── chamfer_distance.cpp │ │ ├── chamfer_distance.cu │ │ └── chamfer_distance.py ├── pyfusion │ ├── .gitignore │ ├── CMakeLists.txt │ ├── LICENSE │ ├── README.md │ ├── __init__.py │ ├── cyfusion.cpython-36m-x86_64-linux-gnu.so │ ├── cyfusion.pyx │ ├── fusion.cpp │ ├── fusion.cu │ ├── fusion.h │ ├── fusion_zach_tvl1.cu │ ├── gpu_common.h │ └── setup.py ├── pyrender │ ├── .gitignore │ ├── README.md │ ├── offscreen.cpp │ ├── offscreen.h │ ├── pyrender.pyx │ └── setup.py └── voxels.py ├── main.py ├── models ├── __init__.py ├── datasets.py ├── iscnet │ ├── __init__.py │ ├── config.py │ ├── dataloader.py │ ├── modules │ │ ├── __init__.py │ │ ├── encoder_latent.py │ │ ├── generator.py │ │ ├── layers.py │ │ ├── network.py │ │ ├── occ_decoder.py │ │ ├── occupancy_net.py │ │ ├── pointnet2backbone.py │ │ ├── pointseg.py │ │ ├── proposal_module.py │ │ ├── skip_propagation.py │ │ └── vote_module.py │ ├── testing.py │ └── training.py ├── loss.py ├── network.py ├── optimizers.py ├── registers.py ├── testing.py └── training.py ├── net_utils ├── __init__.py ├── ap_helper.py ├── box_util.py ├── eval_det.py ├── libs.py ├── metric_util.py ├── nms.py ├── nn_distance.py ├── registry.py ├── transforms.py ├── utils.py └── visualization.py ├── out └── samples │ ├── scene0001_00 │ └── verify.png │ └── scene0549_00 │ ├── camera_center │ ├── gt.png │ ├── points.png │ ├── pred.png │ └── verify.png ├── requirements.txt ├── setup.py ├── test.py ├── test_epoch.py ├── train.py ├── train_epoch.py └── utils ├── __init__.py ├── clean_log.py ├── pc_util.py ├── read_and_write.py ├── scannet ├── __init__.py ├── __pycache__ │ ├── __init__.cpython-36.pyc │ ├── load_scannet_data.cpython-36.pyc │ ├── scannet_utils.cpython-36.pyc │ └── tools.cpython-36.pyc ├── gen_scannet_w_orientation.py ├── load_scannet_data.py ├── scannet_utils.py ├── split_data.py ├── tools.py └── visualization │ ├── __init__.py │ ├── __pycache__ │ ├── __init__.cpython-36.pyc │ └── vis_scannet.cpython-36.pyc │ ├── vis_for_comparison.py │ ├── vis_for_demo.py │ ├── vis_gt.py │ ├── vis_prediction.py │ ├── vis_scan2cad.py │ └── vis_scannet.py └── shapenet ├── 1_fuse_shapenetv2.py ├── 2_sample_mesh.py ├── 3_simplify_fusion.py ├── __init__.py ├── __pycache__ ├── __init__.cpython-36.pyc └── common.cpython-36.pyc ├── common.py ├── simplification.mlx └── tools.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Yinyu Nie 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 | -------------------------------------------------------------------------------- /configs/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/configs/__init__.py -------------------------------------------------------------------------------- /configs/config_files/ISCNet.yaml: -------------------------------------------------------------------------------- 1 | method: ISCNet 2 | resume: False 3 | finetune: True 4 | weight: ['out/iscnet/2021-03-30T22:48:41.879548/model_best.pth'] 5 | seed: 10 6 | device: 7 | use_gpu: True 8 | gpu_ids: '0,1' 9 | num_workers: 8 10 | data: 11 | dataset: scannet 12 | split: datasets/splits/fullscan 13 | num_point: 80000 14 | num_target: 256 15 | vote_factor: 1 16 | cluster_sampling: vote_fps 17 | ap_iou_thresh: 0.25 18 | no_height: False 19 | use_color_detection: False 20 | use_color_completion: False 21 | shapenet_path: datasets/ShapeNetv2_data 22 | points_unpackbits: True 23 | points_subsample: [1024, 1024] 24 | hidden_dim: 512 25 | c_dim: 512 26 | z_dim: 32 27 | threshold: 0.5 28 | completion_limit_in_train: 10 29 | use_cls_for_completion: False 30 | skip_propagate: True 31 | model: 32 | backbone: 33 | method: Pointnet2Backbone 34 | loss: Null 35 | voting: 36 | method: VotingModule 37 | loss: Null 38 | detection: 39 | method: ProposalModule 40 | loss: DetectionLoss 41 | skip_propagation: 42 | method: SkipPropagation 43 | loss: Null 44 | completion: 45 | method: ONet 46 | loss: ONet_Loss 47 | weight: 0.005 48 | optimizer: 49 | method: Adam 50 | lr: 5e-5 51 | betas: [0.9, 0.999] 52 | eps: 1e-08 53 | weight_decay: 0 54 | scheduler: 55 | patience: 20 56 | factor: 0.1 57 | threshold: 0.01 58 | bnscheduler: 59 | bn_decay_step: 20 60 | bn_decay_rate: 0.5 61 | bn_momentum_init: 0.5 62 | bn_momentum_max: 0.001 63 | train: 64 | epochs: 240 65 | phase: 'completion' 66 | freeze: [] 67 | batch_size: 8 68 | val: 69 | phase: 'completion' 70 | batch_size: 8 71 | use_cls_nms: True 72 | use_3d_nms: True 73 | ap_iou_thresholds: [0.25, 0.5] 74 | faster_eval: True 75 | nms_iou: 0.25 76 | use_old_type_nms: False 77 | per_class_proposal: True 78 | conf_thresh: 0.05 79 | demo: 80 | phase: 'completion' 81 | log: 82 | vis_path: visualization 83 | save_results: True 84 | vis_step: 500 85 | print_step: 10 86 | path: out/iscnet 87 | -------------------------------------------------------------------------------- /configs/config_files/ISCNet_completion.yaml: -------------------------------------------------------------------------------- 1 | method: ISCNet 2 | resume: False 3 | finetune: True 4 | weight: ['out/iscnet/2021-03-28T15:52:57.350715/model_best.pth'] 5 | seed: 10 6 | device: 7 | use_gpu: True 8 | gpu_ids: '0,1' 9 | num_workers: 8 10 | data: 11 | dataset: scannet 12 | split: datasets/splits/fullscan 13 | num_point: 80000 14 | num_target: 256 15 | vote_factor: 1 16 | cluster_sampling: vote_fps 17 | ap_iou_thresh: 0.25 18 | no_height: False 19 | use_color_detection: False 20 | use_color_completion: False 21 | shapenet_path: datasets/ShapeNetv2_data 22 | points_unpackbits: True 23 | points_subsample: [1024, 1024] 24 | hidden_dim: 512 25 | c_dim: 512 26 | z_dim: 32 27 | threshold: 0.5 28 | completion_limit_in_train: 10 29 | use_cls_for_completion: False 30 | skip_propagate: True 31 | model: 32 | backbone: 33 | method: Pointnet2Backbone 34 | loss: Null 35 | voting: 36 | method: VotingModule 37 | loss: Null 38 | detection: 39 | method: ProposalModule 40 | loss: DetectionLoss 41 | skip_propagation: 42 | method: SkipPropagation 43 | loss: Null 44 | completion: 45 | method: ONet 46 | loss: ONet_Loss 47 | weight: 1 48 | optimizer: 49 | method: Adam 50 | lr: 1e-4 51 | betas: [0.9, 0.999] 52 | eps: 1e-08 53 | weight_decay: 0 54 | scheduler: 55 | patience: 20 56 | factor: 0.1 57 | threshold: 0.01 58 | bnscheduler: 59 | bn_decay_step: 20 60 | bn_decay_rate: 0.5 61 | bn_momentum_init: 0.5 62 | bn_momentum_max: 0.001 63 | train: 64 | epochs: 240 65 | phase: 'completion' 66 | freeze: ['backbone', 'voting', 'detection'] 67 | batch_size: 8 68 | val: 69 | phase: 'completion' 70 | batch_size: 8 71 | use_cls_nms: True 72 | use_3d_nms: True 73 | ap_iou_thresholds: [0.25, 0.5] 74 | faster_eval: True 75 | nms_iou: 0.25 76 | use_old_type_nms: False 77 | per_class_proposal: True 78 | conf_thresh: 0.05 79 | demo: 80 | phase: 'completion' 81 | log: 82 | vis_path: visualization 83 | save_results: True 84 | vis_step: 500 85 | print_step: 10 86 | path: out/iscnet 87 | -------------------------------------------------------------------------------- /configs/config_files/ISCNet_detection.yaml: -------------------------------------------------------------------------------- 1 | method: ISCNet 2 | resume: False 3 | finetune: False 4 | weight: [] 5 | seed: 10 6 | device: 7 | use_gpu: True 8 | gpu_ids: '0,1' 9 | num_workers: 8 10 | data: 11 | dataset: scannet 12 | split: datasets/splits/fullscan 13 | num_point: 80000 14 | num_target: 256 15 | vote_factor: 1 16 | cluster_sampling: vote_fps 17 | ap_iou_thresh: 0.25 18 | no_height: False 19 | use_color_detection: False 20 | use_color_completion: False 21 | shapenet_path: datasets/ShapeNetv2_data 22 | points_unpackbits: True 23 | points_subsample: [1024, 1024] 24 | hidden_dim: 512 25 | c_dim: 512 26 | z_dim: 32 27 | threshold: 0.5 28 | completion_limit_in_train: 10 29 | use_cls_for_completion: False 30 | skip_propagate: True 31 | model: 32 | backbone: 33 | method: Pointnet2Backbone 34 | loss: Null 35 | voting: 36 | method: VotingModule 37 | loss: Null 38 | detection: 39 | method: ProposalModule 40 | loss: DetectionLoss 41 | skip_propagation: 42 | method: SkipPropagation 43 | loss: Null 44 | completion: 45 | method: ONet 46 | loss: ONet_Loss 47 | weight: 1 48 | optimizer: 49 | method: Adam 50 | lr: 1e-3 51 | betas: [0.9, 0.999] 52 | eps: 1e-08 53 | weight_decay: 0 54 | scheduler: 55 | patience: 20 56 | factor: 0.1 57 | threshold: 0.01 58 | bnscheduler: 59 | bn_decay_step: 20 60 | bn_decay_rate: 0.5 61 | bn_momentum_init: 0.5 62 | bn_momentum_max: 0.001 63 | train: 64 | epochs: 240 65 | phase: 'detection' 66 | freeze: [] 67 | batch_size: 8 68 | val: 69 | phase: 'detection' 70 | batch_size: 8 71 | use_cls_nms: True 72 | use_3d_nms: True 73 | ap_iou_thresholds: [0.25, 0.5] 74 | faster_eval: True 75 | nms_iou: 0.25 76 | use_old_type_nms: False 77 | per_class_proposal: True 78 | conf_thresh: 0.05 79 | demo: 80 | phase: 'detection' 81 | log: 82 | vis_path: visualization 83 | save_results: True 84 | vis_step: 500 85 | print_step: 10 86 | path: out/iscnet 87 | -------------------------------------------------------------------------------- /configs/config_files/ISCNet_test.yaml: -------------------------------------------------------------------------------- 1 | method: ISCNet 2 | resume: False 3 | finetune: True 4 | weight: ['out/pretrained_models/pretrained_weight.pth'] 5 | seed: 10 6 | device: 7 | use_gpu: True 8 | gpu_ids: '0' 9 | num_workers: 0 10 | data: 11 | dataset: scannet 12 | split: datasets/splits/fullscan 13 | num_point: 80000 14 | num_target: 256 15 | vote_factor: 1 16 | cluster_sampling: seed_fps 17 | ap_iou_thresh: 0.25 18 | no_height: False 19 | use_color_detection: False 20 | use_color_completion: False 21 | shapenet_path: datasets/ShapeNetv2_data 22 | points_unpackbits: True 23 | points_subsample: [1024, 1024] 24 | hidden_dim: 512 25 | c_dim: 512 26 | z_dim: 32 27 | threshold: 0.5 28 | completion_limit_in_train: 10 29 | use_cls_for_completion: False 30 | skip_propagate: True 31 | model: 32 | backbone: 33 | method: Pointnet2Backbone 34 | loss: Null 35 | voting: 36 | method: VotingModule 37 | loss: Null 38 | detection: 39 | method: ProposalModule 40 | loss: DetectionLoss 41 | skip_propagation: 42 | method: SkipPropagation 43 | loss: Null 44 | completion: 45 | method: ONet 46 | loss: ONet_Loss 47 | weight: 0.005 48 | test: 49 | phase: 'completion' 50 | batch_size: 1 51 | use_cls_nms: True 52 | use_3d_nms: True 53 | ap_iou_thresholds: [0.5] 54 | faster_eval: False 55 | nms_iou: 0.25 56 | use_old_type_nms: False 57 | per_class_proposal: True 58 | conf_thresh: 0.05 59 | evaluate_mesh_mAP: False 60 | generation: 61 | generate_mesh: True 62 | resolution_0: 32 63 | upsampling_steps: 0 64 | use_sampling: False 65 | refinement_step: 0 66 | simplify_nfaces: Null 67 | dump_threshold: 0.5 68 | dump_results: True 69 | demo: 70 | phase: 'completion' 71 | log: 72 | vis_path: visualization 73 | save_results: True 74 | vis_step: 100 75 | print_step: 10 76 | path: out/iscnet 77 | -------------------------------------------------------------------------------- /configs/path_config.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Path configs for the whole project. 3 | author: ynie 4 | date: July, 2020 5 | ''' 6 | import os 7 | from glob import glob 8 | import pickle 9 | 10 | import numpy as np 11 | from utils.scannet.scannet_utils import read_label_mapping 12 | 13 | SHAPENETCLASSES = ['void', 14 | 'table', 'jar', 'skateboard', 'car', 'bottle', 15 | 'tower', 'chair', 'bookshelf', 'camera', 'airplane', 16 | 'laptop', 'basket', 'sofa', 'knife', 'can', 17 | 'rifle', 'train', 'pillow', 'lamp', 'trash_bin', 18 | 'mailbox', 'watercraft', 'motorbike', 'dishwasher', 'bench', 19 | 'pistol', 'rocket', 'loudspeaker', 'file cabinet', 'bag', 20 | 'cabinet', 'bed', 'birdhouse', 'display', 'piano', 21 | 'earphone', 'telephone', 'stove', 'microphone', 'bus', 22 | 'mug', 'remote', 'bathtub', 'bowl', 'keyboard', 23 | 'guitar', 'washer', 'bicycle', 'faucet', 'printer', 24 | 'cap', 'clock', 'helmet', 'flowerpot', 'microwaves'] 25 | 26 | ScanNet_OBJ_CLASS_IDS = np.array([ 1, 7, 8, 13, 20, 31, 34, 43]) 27 | ShapeNetIDMap = {'4379243': 'table', '3593526': 'jar', '4225987': 'skateboard', '2958343': 'car', '2876657': 'bottle', '4460130': 'tower', '3001627': 'chair', '2871439': 'bookshelf', '2942699': 'camera', '2691156': 'airplane', '3642806': 'laptop', '2801938': 'basket', '4256520': 'sofa', '3624134': 'knife', '2946921': 'can', '4090263': 'rifle', '4468005': 'train', '3938244': 'pillow', '3636649': 'lamp', '2747177': 'trash_bin', '3710193': 'mailbox', '4530566': 'watercraft', '3790512': 'motorbike', '3207941': 'dishwasher', '2828884': 'bench', '3948459': 'pistol', '4099429': 'rocket', '3691459': 'loudspeaker', '3337140': 'file cabinet', '2773838': 'bag', '2933112': 'cabinet', '2818832': 'bed', '2843684': 'birdhouse', '3211117': 'display', '3928116': 'piano', '3261776': 'earphone', '4401088': 'telephone', '4330267': 'stove', '3759954': 'microphone', '2924116': 'bus', '3797390': 'mug', '4074963': 'remote', '2808440': 'bathtub', '2880940': 'bowl', '3085013': 'keyboard', '3467517': 'guitar', '4554684': 'washer', '2834778': 'bicycle', '3325088': 'faucet', '4004475': 'printer', '2954340': 'cap', '3046257': 'clock', '3513137': 'helmet', '3991062': 'flowerpot', '3761084': 'microwaves'} 28 | 29 | class PathConfig(object): 30 | def __init__(self, dataset): 31 | if dataset == 'scannet': 32 | self.metadata_root = 'datasets/scannet' 33 | self.split_files = ['datasets/splits/scannet/scannetv2_train.txt', 34 | 'datasets/splits/scannet/scannetv2_val.txt'] 35 | all_scenes = [] 36 | for split_file in self.split_files: 37 | all_scenes += list(np.loadtxt(split_file, dtype=str)) 38 | 39 | scene_paths = np.sort(glob(os.path.join(self.metadata_root, 'scans', '*'))) 40 | self.scene_paths = [scene_path for scene_path in scene_paths if os.path.basename(scene_path) in all_scenes] 41 | self.scan2cad_annotation_path = os.path.join(self.metadata_root, 'scan2cad_download_link/full_annotations.json') 42 | self.processed_data_path = os.path.join(self.metadata_root, 'processed_data') 43 | 44 | label_type = 'synsetoffset' 45 | self.raw_label_map_file = os.path.join(self.metadata_root, 'raw_lablemap_to_' + label_type + '.pkl') 46 | self.OBJ_CLASS_IDS = ScanNet_OBJ_CLASS_IDS 47 | 48 | if not os.path.exists(self.raw_label_map_file): 49 | LABEL_MAP_FILE = os.path.join(self.metadata_root, 'scannetv2-labels.combined.tsv') 50 | assert os.path.exists(LABEL_MAP_FILE) 51 | raw_label_map = read_label_mapping(LABEL_MAP_FILE, label_from='raw_category', label_to=label_type) 52 | label_map = {} 53 | for key, item in raw_label_map.items(): 54 | if item in ShapeNetIDMap: 55 | label_map[key] = SHAPENETCLASSES.index(ShapeNetIDMap[item]) 56 | else: 57 | label_map[key] = 0 58 | with open(self.raw_label_map_file, 'wb') as file: 59 | pickle.dump(label_map, file) 60 | 61 | if not os.path.exists(self.processed_data_path): 62 | os.mkdir(self.processed_data_path) 63 | 64 | if __name__ == '__main__': 65 | path_config = PathConfig('scannet') 66 | print(path_config.scene_paths) 67 | -------------------------------------------------------------------------------- /configs/scannet_config.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | # 3 | # This source code is licensed under the MIT license found in the 4 | # LICENSE file in the root directory of this source tree. 5 | 6 | import numpy as np 7 | from configs.path_config import SHAPENETCLASSES 8 | from configs.path_config import ScanNet_OBJ_CLASS_IDS as OBJ_CLASS_IDS 9 | import torch 10 | 11 | class ScannetConfig(object): 12 | def __init__(self): 13 | self.num_class = len(OBJ_CLASS_IDS) 14 | self.num_heading_bin = 12 15 | self.num_size_cluster = len(OBJ_CLASS_IDS) 16 | 17 | self.type2class = {SHAPENETCLASSES[cls]:index for index, cls in enumerate(OBJ_CLASS_IDS)} 18 | self.class2type = {self.type2class[t]: t for t in self.type2class} 19 | self.class_ids = OBJ_CLASS_IDS 20 | self.shapenetid2class = {class_id: i for i, class_id in enumerate(list(self.class_ids))} 21 | self.mean_size_arr = np.load('datasets/scannet/scannet_means.npz')['arr_0'] 22 | self.type_mean_size = {} 23 | self.data_path = 'datasets/scannet/processed_data' 24 | for i in range(self.num_size_cluster): 25 | self.type_mean_size[self.class2type[i]] = self.mean_size_arr[i, :] 26 | 27 | def angle2class(self, angle): 28 | ''' Convert continuous angle to discrete class 29 | [optinal] also small regression number from 30 | class center angle to current angle. 31 | 32 | angle is from 0-2pi (or -pi~pi), class center at 0, 1*(2pi/N), 2*(2pi/N) ... (N-1)*(2pi/N) 33 | return is class of int32 of 0,1,...,N-1 and a number such that 34 | class*(2pi/N) + number = angle 35 | ''' 36 | num_class = self.num_heading_bin 37 | angle = angle % (2 * np.pi) 38 | assert False not in (angle >= 0) * (angle <= 2 * np.pi) 39 | angle_per_class = 2 * np.pi / float(num_class) 40 | shifted_angle = (angle + angle_per_class / 2) % (2 * np.pi) 41 | class_id = np.int16(shifted_angle / angle_per_class) 42 | residual_angle = shifted_angle - (class_id * angle_per_class + angle_per_class / 2) 43 | return class_id, residual_angle 44 | 45 | def class2angle(self, pred_cls, residual, to_label_format=True): 46 | ''' Inverse function to angle2class ''' 47 | num_class = self.num_heading_bin 48 | angle_per_class = 2*np.pi/float(num_class) 49 | angle_center = pred_cls * angle_per_class 50 | angle = angle_center + residual 51 | if to_label_format and angle>np.pi: 52 | angle = angle - 2*np.pi 53 | return angle 54 | 55 | def class2angle_cuda(self, pred_cls, residual, to_label_format=True): 56 | ''' Inverse function to angle2class.''' 57 | num_class = self.num_heading_bin 58 | angle_per_class = 2 * np.pi / float(num_class) 59 | angle_center = pred_cls.float() * angle_per_class 60 | angle = angle_center + residual 61 | if to_label_format: 62 | angle = angle - 2*np.pi*(angle>np.pi).float() 63 | return angle 64 | 65 | def size2class(self, size, type_name): 66 | ''' Convert 3D box size (l,w,h) to size class and size residual ''' 67 | size_class = self.type2class[type_name] 68 | size_residual = size - self.type_mean_size[type_name] 69 | return size_class, size_residual 70 | 71 | def class2size(self, pred_cls, residual): 72 | ''' Inverse function to size2class ''' 73 | return self.mean_size_arr[pred_cls, :] + residual 74 | 75 | def class2size_cuda(self, pred_cls, residual): 76 | ''' Inverse function to size2class ''' 77 | mean_size_arr = torch.from_numpy(self.mean_size_arr).to(residual.device).float() 78 | return mean_size_arr[pred_cls.view(-1), :].view(*pred_cls.size(), 3) + residual 79 | 80 | def param2obb(self, center, heading_class, heading_residual, size_class, size_residual): 81 | heading_angle = self.class2angle(heading_class, heading_residual) 82 | box_size = self.class2size(int(size_class), size_residual) 83 | obb = np.zeros((7,)) 84 | obb[0:3] = center 85 | obb[3:6] = box_size 86 | obb[6] = heading_angle 87 | return obb 88 | 89 | 90 | def rotate_aligned_boxes(input_boxes, rot_mat): 91 | centers, lengths = input_boxes[:, 0:3], input_boxes[:, 3:6] 92 | new_centers = np.dot(centers, np.transpose(rot_mat)) 93 | 94 | dx, dy = lengths[:, 0] / 2.0, lengths[:, 1] / 2.0 95 | new_x = np.zeros((dx.shape[0], 4)) 96 | new_y = np.zeros((dx.shape[0], 4)) 97 | 98 | for i, crnr in enumerate([(-1, -1), (1, -1), (1, 1), (-1, 1)]): 99 | crnrs = np.zeros((dx.shape[0], 3)) 100 | crnrs[:, 0] = crnr[0] * dx 101 | crnrs[:, 1] = crnr[1] * dy 102 | crnrs = np.dot(crnrs, np.transpose(rot_mat)) 103 | new_x[:, i] = crnrs[:, 0] 104 | new_y[:, i] = crnrs[:, 1] 105 | 106 | new_dx = 2.0 * np.max(new_x, 1) 107 | new_dy = 2.0 * np.max(new_y, 1) 108 | new_lengths = np.stack((new_dx, new_dy, lengths[:, 2]), axis=1) 109 | 110 | return np.concatenate([new_centers, new_lengths], axis=1) 111 | 112 | if __name__ == '__main__': 113 | cfg = ScannetConfig() -------------------------------------------------------------------------------- /datasets/scannet/raw_lablemap_to_synsetoffset.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/datasets/scannet/raw_lablemap_to_synsetoffset.pkl -------------------------------------------------------------------------------- /datasets/scannet/scannet_means.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/datasets/scannet/scannet_means.npz -------------------------------------------------------------------------------- /demo/outputs/scene0549_00/000000_pred_confident_nms_bbox.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0549_00/000000_pred_confident_nms_bbox.npz -------------------------------------------------------------------------------- /demo/outputs/scene0549_00/pred.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0549_00/pred.png -------------------------------------------------------------------------------- /demo/outputs/scene0549_00/proposal_107_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0549_00/proposal_107_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0549_00/proposal_113_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0549_00/proposal_113_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0549_00/proposal_118_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0549_00/proposal_118_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0549_00/proposal_200_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0549_00/proposal_200_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0549_00/proposal_201_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0549_00/proposal_201_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0549_00/proposal_225_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0549_00/proposal_225_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0549_00/proposal_22_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0549_00/proposal_22_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0549_00/proposal_230_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0549_00/proposal_230_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0549_00/proposal_232_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0549_00/proposal_232_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0549_00/proposal_253_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0549_00/proposal_253_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0549_00/proposal_38_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0549_00/proposal_38_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0549_00/proposal_97_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0549_00/proposal_97_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0549_00/proposal_99_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0549_00/proposal_99_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0575_00/000000_pred_confident_nms_bbox.npz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0575_00/000000_pred_confident_nms_bbox.npz -------------------------------------------------------------------------------- /demo/outputs/scene0575_00/pred.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0575_00/pred.png -------------------------------------------------------------------------------- /demo/outputs/scene0575_00/proposal_133_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0575_00/proposal_133_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0575_00/proposal_139_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0575_00/proposal_139_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0575_00/proposal_147_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0575_00/proposal_147_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0575_00/proposal_159_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0575_00/proposal_159_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0575_00/proposal_163_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0575_00/proposal_163_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0575_00/proposal_182_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0575_00/proposal_182_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0575_00/proposal_188_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0575_00/proposal_188_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0575_00/proposal_196_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0575_00/proposal_196_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0575_00/proposal_221_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0575_00/proposal_221_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0575_00/proposal_228_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0575_00/proposal_228_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0575_00/proposal_233_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0575_00/proposal_233_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0575_00/proposal_24_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0575_00/proposal_24_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0575_00/proposal_253_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0575_00/proposal_253_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0575_00/proposal_25_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0575_00/proposal_25_mesh.ply -------------------------------------------------------------------------------- /demo/outputs/scene0575_00/proposal_97_mesh.ply: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/outputs/scene0575_00/proposal_97_mesh.ply -------------------------------------------------------------------------------- /demo/screenshots/screenshot_demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/screenshots/screenshot_demo.png -------------------------------------------------------------------------------- /demo/screenshots/screenshot_scan2cad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/demo/screenshots/screenshot_scan2cad.png -------------------------------------------------------------------------------- /environment.yml: -------------------------------------------------------------------------------- 1 | name: rfdnet 2 | channels: 3 | - pytorch 4 | - defaults 5 | dependencies: 6 | - _libgcc_mutex=0.1 7 | - blas=1.0 8 | - ca-certificates=2021.1.19 9 | - certifi=2020.12.5 10 | - cudatoolkit=11.0.221 11 | - dataclasses=0.8 12 | - freetype=2.10.4 13 | - intel-openmp=2020.2 14 | - jpeg=9b 15 | - lcms2=2.11 16 | - ld_impl_linux-64=2.33.1 17 | - libffi=3.3 18 | - libgcc-ng=9.1.0 19 | - libpng=1.6.37 20 | - libstdcxx-ng=9.1.0 21 | - libtiff=4.2.0 22 | - libuv=1.40.0 23 | - libwebp-base=1.2.0 24 | - lz4-c=1.9.3 25 | - mkl=2020.2 26 | - mkl-service=2.3.0 27 | - mkl_fft=1.3.0 28 | - mkl_random=1.1.1 29 | - ncurses=6.2 30 | - ninja=1.10.2 31 | - numpy=1.19.2 32 | - numpy-base=1.19.2 33 | - olefile=0.46 34 | - openssl=1.1.1j 35 | - pillow=8.1.2 36 | - pip=21.0.1 37 | - python=3.6.13 38 | - pytorch=1.7.1 39 | - readline=8.1 40 | - setuptools=52.0.0 41 | - six=1.15.0 42 | - sqlite=3.35.2 43 | - tk=8.6.10 44 | - torchaudio=0.7.2 45 | - torchvision=0.8.2 46 | - typing_extensions=3.7.4.3 47 | - wheel=0.36.2 48 | - xz=5.2.5 49 | - zlib=1.2.11 50 | - zstd=1.4.5 51 | - pip: 52 | - absl-py==0.12.0 53 | - cachetools==4.2.1 54 | - chardet==4.0.0 55 | - cycler==0.10.0 56 | - cython==0.29.22 57 | - decorator==4.4.2 58 | - google-auth==1.28.0 59 | - google-auth-oauthlib==0.4.3 60 | - grpcio==1.36.1 61 | - idna==2.10 62 | - imageio==2.9.0 63 | - importlib-metadata==3.7.3 64 | - kiwisolver==1.3.1 65 | - llvmlite==0.36.0 66 | - markdown==3.3.4 67 | - matplotlib==3.3.4 68 | - networkx==2.5 69 | - numba==0.53.0 70 | - numpy-quaternion==2021.3.17.16.51.43 71 | - oauthlib==3.1.0 72 | - pandas==1.1.5 73 | - plyfile==0.7.3 74 | - protobuf==3.15.6 75 | - pyasn1==0.4.8 76 | - pyasn1-modules==0.2.8 77 | - pymcubes==0.1.2 78 | - pyparsing==2.4.7 79 | - python-dateutil==2.8.1 80 | - pytz==2021.1 81 | - pywavelets==1.1.1 82 | - pyyaml==5.4.1 83 | - requests==2.25.1 84 | - requests-oauthlib==1.3.0 85 | - rsa==4.7.2 86 | - scikit-image==0.17.2 87 | - scipy==1.5.4 88 | - seaborn==0.11.1 89 | - shapely==1.7.1 90 | - tensorboard==2.4.1 91 | - tensorboard-plugin-wit==1.8.0 92 | - tifffile==2020.9.3 93 | - tqdm==4.59.0 94 | - trimesh==3.9.9 95 | - urllib3==1.26.4 96 | - vtk==9.0.1 97 | - werkzeug==1.0.1 98 | - zipp==3.4.1 99 | -------------------------------------------------------------------------------- /external/libkdtree/.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - '2.7' 4 | - '3.6' 5 | 6 | env: 7 | - USE_OMP=0 8 | - USE_OMP=1 OMP_NUM_THREADS=4 9 | 10 | before_install: 11 | - sudo apt-get install python-dev 12 | 13 | install: 14 | - python setup.py install 15 | 16 | script: python setup.py test 17 | -------------------------------------------------------------------------------- /external/libkdtree/MANIFEST.in: -------------------------------------------------------------------------------- 1 | exclude pykdtree/render_template.py 2 | include LICENSE.txt 3 | include README.rst 4 | include pykdtree/*.pyx 5 | -------------------------------------------------------------------------------- /external/libkdtree/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: clean build 2 | 3 | build: pykdtree/kdtree.c pykdtree/_kdtree_core.c 4 | python setup.py build 5 | 6 | pykdtree/kdtree.c: pykdtree/kdtree.pyx 7 | cython pykdtree/kdtree.pyx 8 | 9 | pykdtree/_kdtree_core.c: pykdtree/_kdtree_core.c.mako 10 | cd pykdtree && python render_template.py 11 | 12 | clean: 13 | rm -rf build/ 14 | rm -f pykdtree/*.so 15 | -------------------------------------------------------------------------------- /external/libkdtree/README: -------------------------------------------------------------------------------- 1 | README.rst -------------------------------------------------------------------------------- /external/libkdtree/appveyor.yml: -------------------------------------------------------------------------------- 1 | environment: 2 | global: 3 | # SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the 4 | # /E:ON and /V:ON options are not enabled in the batch script intepreter 5 | # See: http://stackoverflow.com/a/13751649/163740 6 | CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\appveyor\\run_with_compiler.cmd" 7 | # Don't build with openmp because it isn't supported in appveyor's compilers 8 | USE_OMP: "0" 9 | 10 | matrix: 11 | - PYTHON: "C:\\Python27_32" 12 | PYTHON_VERSION: "2.7.8" 13 | PYTHON_ARCH: "32" 14 | MINICONDA_VERSION: "2" 15 | 16 | - PYTHON: "C:\\Python27_64" 17 | PYTHON_VERSION: "2.7.8" 18 | PYTHON_ARCH: "64" 19 | MINICONDA_VERSION: "2" 20 | 21 | - PYTHON: "C:\\Python36_32" 22 | PYTHON_VERSION: "3.6" 23 | PYTHON_ARCH: "32" 24 | MINICONDA_VERSION: "3" 25 | USE_OMP: "0" 26 | 27 | - PYTHON: "C:\\Python36_64" 28 | PYTHON_VERSION: "3.6" 29 | PYTHON_ARCH: "64" 30 | MINICONDA_VERSION: "3" 31 | USE_OMP: "0" 32 | 33 | - PYTHON: "C:\\Python36_32" 34 | PYTHON_VERSION: "3.6" 35 | PYTHON_ARCH: "32" 36 | MINICONDA_VERSION: "3" 37 | USE_OMP: "1" 38 | OMP_NUM_THREADS: "4" 39 | 40 | - PYTHON: "C:\\Python36_64" 41 | PYTHON_VERSION: "3.6" 42 | PYTHON_ARCH: "64" 43 | MINICONDA_VERSION: "3" 44 | USE_OMP: "1" 45 | OMP_NUM_THREADS: "4" 46 | 47 | install: 48 | - "git submodule update --init --recursive" 49 | - ECHO "Filesystem root:" 50 | - ps: "ls \"C:/\"" 51 | 52 | - ECHO "Installed SDKs:" 53 | - ps: "ls \"C:/Program Files/Microsoft SDKs/Windows\"" 54 | 55 | # install miniconda with the powershell script install.ps1 56 | - "powershell ./appveyor/install.ps1" 57 | # install missing headers that aren't included with MSVC 2008 58 | # https://github.com/omnia-md/conda-recipes/pull/524 59 | - "powershell ./appveyor/missing-headers.ps1" 60 | 61 | # Prepend newly installed Python to the PATH of this build (this cannot be 62 | # done from inside the powershell script as it would require to restart 63 | # the parent CMD process). 64 | - "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%" 65 | 66 | # Check that we have the expected version and architecture for Python 67 | - "python --version" 68 | - "python -c \"import struct; print(struct.calcsize('P') * 8)\"" 69 | 70 | # Install the build dependencies of the project. If some dependencies contain 71 | # compiled extensions and are not provided as pre-built wheel packages, 72 | # pip will build them from source using the MSVC compiler matching the 73 | # target Python version and architecture 74 | - "conda update --yes conda" 75 | - "conda config --add channels conda-forge" 76 | - "conda create -q --yes -n test python=%PYTHON_VERSION% numpy nose" 77 | - "activate test" 78 | - "pip install coveralls" 79 | - "where python" 80 | 81 | build: false # Not a C# project, build stuff at the test step instead. 82 | 83 | test_script: 84 | # Build the compiled extension and run the project tests 85 | - "%CMD_IN_ENV% python setup.py test" 86 | 87 | after_test: 88 | # If tests are successful, create a whl package for the project. 89 | - "%CMD_IN_ENV% python setup.py bdist_wheel bdist_wininst" 90 | - ps: "ls dist" 91 | 92 | artifacts: 93 | # Archive the generated wheel package in the ci.appveyor.com build report. 94 | - path: dist\* 95 | 96 | #on_success: 97 | # - TODO: upload the content of dist/*.whl to a public wheelhouse 98 | # 99 | -------------------------------------------------------------------------------- /external/libkdtree/appveyor/install.ps1: -------------------------------------------------------------------------------- 1 | # Sample script to install anaconda under windows 2 | # Authors: Stuart Mumford 3 | # Borrwed from: Olivier Grisel and Kyle Kastner 4 | # License: BSD 3 clause 5 | 6 | $MINICONDA_URL = "http://repo.continuum.io/miniconda/" 7 | 8 | function DownloadMiniconda ($miniconda_version, $platform_suffix) { 9 | $webclient = New-Object System.Net.WebClient 10 | $filename = "Miniconda" + $miniconda_version + "-latest" + "-Windows-" + $platform_suffix + ".exe" 11 | 12 | $url = $MINICONDA_URL + $filename 13 | 14 | $basedir = $pwd.Path + "\" 15 | $filepath = $basedir + $filename 16 | if (Test-Path $filename) { 17 | Write-Host "Reusing" $filepath 18 | return $filepath 19 | } 20 | 21 | # Download and retry up to 3 times in case of network transient errors. 22 | Write-Host "Downloading" $filename "from" $url 23 | $retry_attempts = 2 24 | for($i=0; $i -lt $retry_attempts; $i++){ 25 | try { 26 | $webclient.DownloadFile($url, $filepath) 27 | break 28 | } 29 | Catch [Exception]{ 30 | Start-Sleep 1 31 | } 32 | } 33 | if (Test-Path $filepath) { 34 | Write-Host "File saved at" $filepath 35 | } else { 36 | # Retry once to get the error message if any at the last try 37 | $webclient.DownloadFile($url, $filepath) 38 | } 39 | return $filepath 40 | } 41 | 42 | function InstallMiniconda ($miniconda_version, $architecture, $python_home) { 43 | Write-Host "Installing miniconda" $miniconda_version "for" $architecture "bit architecture to" $python_home 44 | if (Test-Path $python_home) { 45 | Write-Host $python_home "already exists, skipping." 46 | return $false 47 | } 48 | if ($architecture -eq "32") { 49 | $platform_suffix = "x86" 50 | } else { 51 | $platform_suffix = "x86_64" 52 | } 53 | $filepath = DownloadMiniconda $miniconda_version $platform_suffix 54 | Write-Host "Installing" $filepath "to" $python_home 55 | $args = "/InstallationType=AllUsers /S /AddToPath=1 /RegisterPython=1 /D=" + $python_home 56 | Write-Host $filepath $args 57 | Start-Process -FilePath $filepath -ArgumentList $args -Wait -Passthru 58 | #Start-Sleep -s 15 59 | if (Test-Path $python_home) { 60 | Write-Host "Miniconda $miniconda_version ($architecture) installation complete" 61 | } else { 62 | Write-Host "Failed to install Python in $python_home" 63 | Exit 1 64 | } 65 | } 66 | 67 | function main () { 68 | InstallMiniconda $env:MINICONDA_VERSION $env:PYTHON_ARCH $env:PYTHON 69 | } 70 | 71 | main 72 | -------------------------------------------------------------------------------- /external/libkdtree/appveyor/missing-headers.ps1: -------------------------------------------------------------------------------- 1 | function InstallMissingHeaders () { 2 | # Visual Studio 2008 is missing stdint.h, but you can just download one 3 | # from the web. 4 | # http://stackoverflow.com/questions/126279/c99-stdint-h-header-and-ms-visual-studio 5 | $webclient = New-Object System.Net.WebClient 6 | 7 | $include_dirs = @("C:\Program Files\Microsoft SDKs\Windows\v7.0\Include", 8 | "C:\Program Files\Microsoft SDKs\Windows\v7.1\Include", 9 | "C:\Users\appveyor\AppData\Local\Programs\Common\Microsoft\Visual C++ for Python\9.0\VC\include", 10 | "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\include", 11 | "C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include") 12 | 13 | Foreach ($include_dir in $include_dirs) { 14 | $urls = @(@("https://raw.githubusercontent.com/chemeris/msinttypes/master/stdint.h", "stdint.h"), 15 | @("https://raw.githubusercontent.com/chemeris/msinttypes/master/inttypes.h", "inttypes.h")) 16 | 17 | Foreach ($i in $urls) { 18 | $url = $i[0] 19 | $filename = $i[1] 20 | 21 | $filepath = "$include_dir\$filename" 22 | if (Test-Path $filepath) { 23 | Write-Host $filename "already exists in" $include_dir 24 | continue 25 | } 26 | 27 | Write-Host "Downloading remedial " $filename " from" $url "to" $filepath 28 | $retry_attempts = 2 29 | for($i=0; $i -lt $retry_attempts; $i++){ 30 | try { 31 | $webclient.DownloadFile($url, $filepath) 32 | break 33 | } 34 | Catch [Exception]{ 35 | Start-Sleep 1 36 | } 37 | } 38 | 39 | if (Test-Path $filepath) { 40 | Write-Host "File saved at" $filepath 41 | } else { 42 | # Retry once to get the error message if any at the last try 43 | $webclient.DownloadFile($url, $filepath) 44 | } 45 | } 46 | } 47 | } 48 | 49 | function main() { 50 | InstallMissingHeaders 51 | } 52 | 53 | main 54 | -------------------------------------------------------------------------------- /external/libkdtree/appveyor/run_with_compiler.cmd: -------------------------------------------------------------------------------- 1 | :: To build extensions for 64 bit Python 3, we need to configure environment 2 | :: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of: 3 | :: MS Windows SDK for Windows 7 and .NET Framework 4 (SDK v7.1) 4 | :: 5 | :: To build extensions for 64 bit Python 2, we need to configure environment 6 | :: variables to use the MSVC 2008 C++ compilers from GRMSDKX_EN_DVD.iso of: 7 | :: MS Windows SDK for Windows 7 and .NET Framework 3.5 (SDK v7.0) 8 | :: 9 | :: 32 bit builds do not require specific environment configurations. 10 | :: 11 | :: Note: this script needs to be run with the /E:ON and /V:ON flags for the 12 | :: cmd interpreter, at least for (SDK v7.0) 13 | :: 14 | :: More details at: 15 | :: https://github.com/cython/cython/wiki/64BitCythonExtensionsOnWindows 16 | :: http://stackoverflow.com/a/13751649/163740 17 | :: 18 | :: Author: Olivier Grisel 19 | :: License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/ 20 | @ECHO OFF 21 | 22 | SET COMMAND_TO_RUN=%* 23 | SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows 24 | 25 | SET MAJOR_PYTHON_VERSION="%PYTHON_VERSION:~0,1%" 26 | SET MINOR_PYTHON_VERSION=%PYTHON_VERSION:~2,1% 27 | IF %MAJOR_PYTHON_VERSION% == "2" ( 28 | SET WINDOWS_SDK_VERSION="v7.0" 29 | SET SET_SDK_64=Y 30 | ) ELSE IF %MAJOR_PYTHON_VERSION% == "3" ( 31 | SET WINDOWS_SDK_VERSION="v7.1" 32 | IF %MINOR_PYTHON_VERSION% LEQ 4 ( 33 | SET SET_SDK_64=Y 34 | ) ELSE ( 35 | SET SET_SDK_64=N 36 | ) 37 | ) ELSE ( 38 | ECHO Unsupported Python version: "%MAJOR_PYTHON_VERSION%" 39 | EXIT 1 40 | ) 41 | 42 | IF "%PYTHON_ARCH%"=="64" ( 43 | IF %SET_SDK_64% == Y ( 44 | ECHO Configuring Windows SDK %WINDOWS_SDK_VERSION% for Python %MAJOR_PYTHON_VERSION% on a 64 bit architecture 45 | SET DISTUTILS_USE_SDK=1 46 | SET MSSdk=1 47 | "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION% 48 | "%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release 49 | ECHO Executing: %COMMAND_TO_RUN% 50 | call %COMMAND_TO_RUN% || EXIT 1 51 | ) ELSE ( 52 | ECHO Using default MSVC build environment for 64 bit architecture 53 | ECHO Executing: %COMMAND_TO_RUN% 54 | call %COMMAND_TO_RUN% || EXIT 1 55 | ) 56 | ) ELSE ( 57 | ECHO Using default MSVC build environment for 32 bit architecture 58 | ECHO Executing: %COMMAND_TO_RUN% 59 | call %COMMAND_TO_RUN% || EXIT 1 60 | ) 61 | -------------------------------------------------------------------------------- /external/libkdtree/pykdtree/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/external/libkdtree/pykdtree/__init__.py -------------------------------------------------------------------------------- /external/libkdtree/pykdtree/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/external/libkdtree/pykdtree/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /external/libkdtree/pykdtree/kdtree.cpython-36m-x86_64-linux-gnu.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/external/libkdtree/pykdtree/kdtree.cpython-36m-x86_64-linux-gnu.so -------------------------------------------------------------------------------- /external/libkdtree/pykdtree/render_template.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | from mako.template import Template 4 | 5 | mytemplate = Template(filename='_kdtree_core.c.mako') 6 | with open('_kdtree_core.c', 'w') as fp: 7 | fp.write(mytemplate.render()) 8 | -------------------------------------------------------------------------------- /external/libkdtree/scripts/build-manylinux-wheels.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e -x 3 | 4 | # This is to be run by Docker inside a Docker image. 5 | # You can test it locally on a Linux machine by installing docker and running from this repo's root: 6 | # $ docker run -e PLAT=manylinux1_x86_64 -v `pwd`:/io quay.io/pypa/manylinux1_x86_64 /io/scripts/build-manylinux-wheels.sh 7 | 8 | # * The -e just defines an environment variable PLAT=[docker name] inside the 9 | # docker - auditwheel can't detect the docker name automatically. 10 | # * The -v gives a directory alias for passing files in and out of the docker 11 | # (/io is arbitrary). E.g the `setup.py` script would be accessed in the 12 | # docker via `/io/setup.py`. 13 | # * quay.io/pypa/manylinux1_x86_64 is the full docker image name. Docker 14 | # downloads it automatically. 15 | # * The last argument is a shell command that the Docker will execute. 16 | # Filenames must be from the Docker's perspective. 17 | 18 | # Wheels are initially generated as you would usually, but put in a temp 19 | # directory temp-wheels. The pip-cache is optional but can speed up local builds 20 | # having a real permanent pip-cache dir. 21 | mkdir -p /io/pip-cache 22 | mkdir -p /io/temp-wheels 23 | 24 | # Clean out any old existing wheels. 25 | find /io/temp-wheels/ -type f -delete 26 | 27 | # Iterate through available pythons. 28 | for PYBIN in /opt/python/cp3[6789]*/bin; do 29 | "${PYBIN}/pip" install -q -U setuptools wheel nose --cache-dir /io/pip-cache 30 | # Run the following in root of this repo. 31 | (cd /io/ && USE_OMP=$USE_OMP "${PYBIN}/pip" install -q .) 32 | (cd /io/ && USE_OMP=$USE_OMP "${PYBIN}/python" setup.py nosetests) 33 | (cd /io/ && USE_OMP=$USE_OMP "${PYBIN}/python" setup.py -q bdist_wheel -d /io/temp-wheels) 34 | done 35 | 36 | "$PYBIN/pip" install -q auditwheel 37 | 38 | # Wheels aren't considered manylinux unless they have been through 39 | # auditwheel. Audited wheels go in /io/dist/. 40 | mkdir -p /io/dist/ 41 | 42 | for whl in /io/temp-wheels/*.whl; do 43 | auditwheel repair "$whl" --plat "$PLAT" -w /io/dist/ 44 | done 45 | -------------------------------------------------------------------------------- /external/libkdtree/setup.cfg: -------------------------------------------------------------------------------- 1 | [bdist_rpm] 2 | requires=python3-numpy 3 | release=1 4 | 5 | 6 | -------------------------------------------------------------------------------- /external/libkdtree/setup.py: -------------------------------------------------------------------------------- 1 | #pykdtree, Fast kd-tree implementation with OpenMP-enabled queries 2 | # 3 | #Copyright (C) 2013 - present Esben S. Nielsen 4 | # 5 | # This program is free software: you can redistribute it and/or modify it under 6 | # the terms of the GNU Lesser General Public License as published by the Free 7 | # Software Foundation, either version 3 of the License, or 8 | #(at your option) any later version. 9 | # 10 | # This program is distributed in the hope that it will be useful, but WITHOUT 11 | # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 12 | # FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more 13 | # details. 14 | # 15 | # You should have received a copy of the GNU Lesser General Public License along 16 | # with this program. If not, see . 17 | 18 | import os 19 | import sys 20 | from setuptools import setup, Extension 21 | from setuptools.command.build_ext import build_ext 22 | 23 | 24 | def is_conda_interpreter(): 25 | """Is the running interpreter from Anaconda or miniconda? 26 | 27 | See https://stackoverflow.com/a/21318941/433202 28 | 29 | Examples:: 30 | 31 | 2.7.6 |Anaconda 1.8.0 (x86_64)| (default, Jan 10 2014, 11:23:15) 32 | 2.7.6 |Continuum Analytics, Inc.| (default, Jan 10 2014, 11:23:15) 33 | 3.6.6 | packaged by conda-forge | (default, Jul 26 2018, 09:55:02) 34 | 35 | """ 36 | return 'conda' in sys.version or 'Continuum' in sys.version 37 | 38 | 39 | # Get OpenMP setting from environment 40 | try: 41 | use_omp = int(os.environ['USE_OMP']) 42 | except KeyError: 43 | # OpenMP is not supported with default clang 44 | # Conda provides its own compiler which does support openmp 45 | use_omp = 'darwin' not in sys.platform or is_conda_interpreter() 46 | 47 | 48 | def set_builtin(name, value): 49 | if isinstance(__builtins__, dict): 50 | __builtins__[name] = value 51 | else: 52 | setattr(__builtins__, name, value) 53 | 54 | 55 | # Custom builder to handler compiler flags. Edit if needed. 56 | class build_ext_subclass(build_ext): 57 | def build_extensions(self): 58 | comp = self.compiler.compiler_type 59 | if comp in ('unix', 'cygwin', 'mingw32'): 60 | # Check if build is with OpenMP 61 | if use_omp: 62 | extra_compile_args = ['-std=c99', '-O3', '-fopenmp'] 63 | extra_link_args=['-lgomp'] 64 | else: 65 | extra_compile_args = ['-std=c99', '-O3'] 66 | extra_link_args = [] 67 | elif comp == 'msvc': 68 | extra_compile_args = ['/Ox'] 69 | extra_link_args = [] 70 | if use_omp: 71 | extra_compile_args.append('/openmp') 72 | else: 73 | # Add support for more compilers here 74 | raise ValueError('Compiler flags undefined for %s. Please modify setup.py and add compiler flags' 75 | % comp) 76 | self.extensions[0].extra_compile_args = extra_compile_args 77 | self.extensions[0].extra_link_args = extra_link_args 78 | build_ext.build_extensions(self) 79 | 80 | def finalize_options(self): 81 | ''' 82 | In order to avoid premature import of numpy before it gets installed as a dependency 83 | get numpy include directories during the extensions building process 84 | http://stackoverflow.com/questions/19919905/how-to-bootstrap-numpy-installation-in-setup-py 85 | ''' 86 | build_ext.finalize_options(self) 87 | # Prevent numpy from thinking it is still in its setup process: 88 | set_builtin('__NUMPY_SETUP__', False) 89 | import numpy 90 | self.include_dirs.append(numpy.get_include()) 91 | 92 | with open('README.rst', 'r') as readme_file: 93 | readme = readme_file.read() 94 | 95 | setup( 96 | name='pykdtree', 97 | version='1.3.4', 98 | url="https://github.com/storpipfugl/pykdtree", 99 | description='Fast kd-tree implementation with OpenMP-enabled queries', 100 | long_description=readme, 101 | author='Esben S. Nielsen', 102 | author_email='storpipfugl@gmail.com', 103 | packages=['pykdtree'], 104 | python_requires='>=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*', 105 | install_requires=['numpy'], 106 | setup_requires=['numpy'], 107 | tests_require=['nose'], 108 | zip_safe=False, 109 | test_suite='nose.collector', 110 | ext_modules=[Extension('pykdtree.kdtree', 111 | ['pykdtree/kdtree.c', 'pykdtree/_kdtree_core.c'])], 112 | cmdclass={'build_ext': build_ext_subclass}, 113 | classifiers=[ 114 | 'Development Status :: 5 - Production/Stable', 115 | ('License :: OSI Approved :: ' 116 | 'GNU Lesser General Public License v3 (LGPLv3)'), 117 | 'Programming Language :: Python', 118 | 'Operating System :: OS Independent', 119 | 'Intended Audience :: Science/Research', 120 | 'Topic :: Scientific/Engineering' 121 | ] 122 | ) 123 | -------------------------------------------------------------------------------- /external/libmesh/.gitignore: -------------------------------------------------------------------------------- 1 | triangle_hash.cpp 2 | build 3 | -------------------------------------------------------------------------------- /external/libmesh/__init__.py: -------------------------------------------------------------------------------- 1 | from .inside_mesh import ( 2 | check_mesh_contains, MeshIntersector, TriangleIntersector2d 3 | ) 4 | 5 | 6 | __all__ = [ 7 | check_mesh_contains, MeshIntersector, TriangleIntersector2d 8 | ] 9 | -------------------------------------------------------------------------------- /external/libmesh/triangle_hash.cpython-36m-x86_64-linux-gnu.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/external/libmesh/triangle_hash.cpython-36m-x86_64-linux-gnu.so -------------------------------------------------------------------------------- /external/libmesh/triangle_hash.pyx: -------------------------------------------------------------------------------- 1 | 2 | # distutils: language=c++ 3 | import numpy as np 4 | cimport numpy as np 5 | cimport cython 6 | from libcpp.vector cimport vector 7 | from libc.math cimport floor, ceil 8 | 9 | cdef class TriangleHash: 10 | cdef vector[vector[int]] spatial_hash 11 | cdef int resolution 12 | 13 | def __cinit__(self, double[:, :, :] triangles, int resolution): 14 | self.spatial_hash.resize(resolution * resolution) 15 | self.resolution = resolution 16 | self._build_hash(triangles) 17 | 18 | @cython.boundscheck(False) # Deactivate bounds checking 19 | @cython.wraparound(False) # Deactivate negative indexing. 20 | cdef int _build_hash(self, double[:, :, :] triangles): 21 | assert(triangles.shape[1] == 3) 22 | assert(triangles.shape[2] == 2) 23 | 24 | cdef int n_tri = triangles.shape[0] 25 | cdef int bbox_min[2] 26 | cdef int bbox_max[2] 27 | 28 | cdef int i_tri, j, x, y 29 | cdef int spatial_idx 30 | 31 | for i_tri in range(n_tri): 32 | # Compute bounding box 33 | for j in range(2): 34 | bbox_min[j] = min( 35 | triangles[i_tri, 0, j], triangles[i_tri, 1, j], triangles[i_tri, 2, j] 36 | ) 37 | bbox_max[j] = max( 38 | triangles[i_tri, 0, j], triangles[i_tri, 1, j], triangles[i_tri, 2, j] 39 | ) 40 | bbox_min[j] = min(max(bbox_min[j], 0), self.resolution - 1) 41 | bbox_max[j] = min(max(bbox_max[j], 0), self.resolution - 1) 42 | 43 | # Find all voxels where bounding box intersects 44 | for x in range(bbox_min[0], bbox_max[0] + 1): 45 | for y in range(bbox_min[1], bbox_max[1] + 1): 46 | spatial_idx = self.resolution * x + y 47 | self.spatial_hash[spatial_idx].push_back(i_tri) 48 | 49 | @cython.boundscheck(False) # Deactivate bounds checking 50 | @cython.wraparound(False) # Deactivate negative indexing. 51 | cpdef query(self, double[:, :] points): 52 | assert(points.shape[1] == 2) 53 | cdef int n_points = points.shape[0] 54 | 55 | cdef vector[int] points_indices 56 | cdef vector[int] tri_indices 57 | # cdef int[:] points_indices_np 58 | # cdef int[:] tri_indices_np 59 | 60 | cdef int i_point, k, x, y 61 | cdef int spatial_idx 62 | 63 | for i_point in range(n_points): 64 | x = int(points[i_point, 0]) 65 | y = int(points[i_point, 1]) 66 | if not (0 <= x < self.resolution and 0 <= y < self.resolution): 67 | continue 68 | 69 | spatial_idx = self.resolution * x + y 70 | for i_tri in self.spatial_hash[spatial_idx]: 71 | points_indices.push_back(i_point) 72 | tri_indices.push_back(i_tri) 73 | 74 | points_indices_np = np.zeros(points_indices.size(), dtype=np.int32) 75 | tri_indices_np = np.zeros(tri_indices.size(), dtype=np.int32) 76 | 77 | cdef int[:] points_indices_view = points_indices_np 78 | cdef int[:] tri_indices_view = tri_indices_np 79 | 80 | for k in range(points_indices.size()): 81 | points_indices_view[k] = points_indices[k] 82 | 83 | for k in range(tri_indices.size()): 84 | tri_indices_view[k] = tri_indices[k] 85 | 86 | return points_indices_np, tri_indices_np 87 | -------------------------------------------------------------------------------- /external/libmise/.gitignore: -------------------------------------------------------------------------------- 1 | mise.c 2 | mise.cpp 3 | mise.html 4 | -------------------------------------------------------------------------------- /external/libmise/__init__.py: -------------------------------------------------------------------------------- 1 | from .mise import MISE 2 | 3 | 4 | __all__ = [ 5 | MISE 6 | ] 7 | -------------------------------------------------------------------------------- /external/libmise/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/external/libmise/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /external/libmise/mise.cpython-36m-x86_64-linux-gnu.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/external/libmise/mise.cpython-36m-x86_64-linux-gnu.so -------------------------------------------------------------------------------- /external/libmise/test.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from mise import MISE 3 | import time 4 | 5 | t0 = time.time() 6 | extractor = MISE(1, 2, 0.) 7 | 8 | p = extractor.query() 9 | i = 0 10 | 11 | while p.shape[0] != 0: 12 | print(i) 13 | print(p) 14 | v = 2 * (p.sum(axis=-1) > 2).astype(np.float64) - 1 15 | extractor.update(p, v) 16 | p = extractor.query() 17 | i += 1 18 | if (i >= 8): 19 | break 20 | 21 | print(extractor.to_dense()) 22 | # p, v = extractor.get_points() 23 | # print(p) 24 | # print(v) 25 | print('Total time: %f' % (time.time() - t0)) 26 | -------------------------------------------------------------------------------- /external/librender/__init__.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | import os 3 | 4 | #pyrender_dir = os.path.dirname(os.path.realpath(__file__)) 5 | #ctypes.cdll.LoadLibrary(os.path.join(pyrender_dir, 'pyrender.so')) 6 | from external.librender.pyrender import * 7 | -------------------------------------------------------------------------------- /external/librender/build/temp.linux-x86_64-3.6/offscreen.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/external/librender/build/temp.linux-x86_64-3.6/offscreen.o -------------------------------------------------------------------------------- /external/librender/build/temp.linux-x86_64-3.6/pyrender.o: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/external/librender/build/temp.linux-x86_64-3.6/pyrender.o -------------------------------------------------------------------------------- /external/librender/offscreen.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBRENDER_OFFSCREEN_H 2 | #define LIBRENDER_OFFSCREEN_H 3 | 4 | #include "GL/glew.h" 5 | #include "GL/gl.h" 6 | #include "GL/glu.h" 7 | #include "GL/glut.h" 8 | 9 | class OffscreenGL { 10 | 11 | public: 12 | OffscreenGL(int maxHeight, int maxWidth); 13 | ~OffscreenGL(); 14 | 15 | private: 16 | static int glutWin; 17 | static bool glutInitialized; 18 | GLuint fb; 19 | GLuint renderTex; 20 | GLuint depthTex; 21 | }; 22 | 23 | 24 | void renderDepthMesh(double *FM, int fNum, double *VM, int vNum, double *CM, double *intrinsics, int *imgSizeV, double *zNearFarV, unsigned char * imgBuffer, float *depthBuffer, bool *maskBuffer, double linewidth, bool coloring); 25 | 26 | #endif -------------------------------------------------------------------------------- /external/librender/pyrender.cpython-36m-x86_64-linux-gnu.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/external/librender/pyrender.cpython-36m-x86_64-linux-gnu.so -------------------------------------------------------------------------------- /external/librender/pyrender.pyx: -------------------------------------------------------------------------------- 1 | cimport cython 2 | import numpy as np 3 | cimport numpy as np 4 | 5 | from libc.stdlib cimport free, malloc 6 | from libcpp cimport bool 7 | from cpython cimport PyObject, Py_INCREF 8 | 9 | CREATE_INIT = True # workaround, so cython builds a init function 10 | 11 | np.import_array() 12 | 13 | 14 | cdef extern from "offscreen.h": 15 | void renderDepthMesh(double *FM, int fNum, double *VM, int vNum, double *CM, double *intrinsics, int *imgSizeV, double *zNearFarV, unsigned char * imgBuffer, float *depthBuffer, bool *maskBuffer, double linewidth, bool coloring); 16 | 17 | 18 | def render(double[:,::1] vertices, double[:,::1] faces, double[::1] cam_intr, double[::1] znf, int[::1] img_size): 19 | if vertices.shape[0] != 3: 20 | raise Exception('vertices must be a 3xM double array') 21 | if faces.shape[0] != 3: 22 | raise Exception('faces must be a 3xM double array') 23 | if cam_intr.shape[0] != 4: 24 | raise Exception('cam_intr must be a 4x1 double vector') 25 | if img_size.shape[0] != 2: 26 | raise Exception('img_size must be a 2x1 int vector') 27 | 28 | cdef double* VM = &(vertices[0,0]) 29 | cdef int vNum = vertices.shape[1] 30 | cdef double* FM = &(faces[0,0]) 31 | cdef int fNum = faces.shape[1] 32 | cdef double* intrinsics = &(cam_intr[0]) 33 | cdef double* zNearVarV = &(znf[0]) 34 | cdef int* imgSize = &(img_size[0]) 35 | 36 | cdef bool coloring = False 37 | cdef double* CM = NULL 38 | 39 | depth = np.empty((img_size[1], img_size[0]), dtype=np.float32) 40 | mask = np.empty((img_size[1], img_size[0]), dtype=np.uint8) 41 | img = np.empty((3, img_size[1], img_size[0]), dtype=np.uint8) 42 | cdef float[:,::1] depth_view = depth 43 | cdef unsigned char[:,::1] mask_view = mask 44 | cdef unsigned char[:,:,::1] img_view = img 45 | cdef float* depthBuffer = &(depth_view[0,0]) 46 | cdef bool* maskBuffer = &(mask_view[0,0]) 47 | cdef unsigned char* imgBuffer = &(img_view[0,0,0]) 48 | 49 | renderDepthMesh(FM, fNum, VM, vNum, CM, intrinsics, imgSize, zNearVarV, imgBuffer, depthBuffer, maskBuffer, 0, coloring); 50 | 51 | return depth.T, mask.T, img.transpose((2,1,0)) 52 | -------------------------------------------------------------------------------- /external/librender/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | from distutils.extension import Extension 3 | from Cython.Distutils import build_ext 4 | import numpy as np 5 | 6 | extra_compile_args = ["-ffast-math", '-msse', '-msse2', '-msse3', '-msse4.2', '-O4', '-fopenmp'] 7 | extra_link_args = ['-lGLEW', '-lglut', '-lGL', '-lGLU', '-fopenmp'] 8 | 9 | setup( 10 | name="pyrender", 11 | cmdclass= {'build_ext': build_ext}, 12 | ext_modules=[ 13 | Extension('pyrender', 14 | [ 15 | 'pyrender.pyx', 16 | 'offscreen.cpp', 17 | ], 18 | language='c++', 19 | include_dirs=[np.get_include()], 20 | extra_compile_args=extra_compile_args, 21 | extra_link_args=extra_link_args 22 | ) 23 | ] 24 | ) 25 | 26 | 27 | -------------------------------------------------------------------------------- /external/librender/test.py: -------------------------------------------------------------------------------- 1 | import pyrender 2 | import numpy as np 3 | from matplotlib import pyplot 4 | import math 5 | 6 | # render settings 7 | img_h = 480 8 | img_w = 480 9 | fx = 480. 10 | fy = 480. 11 | cx = 240 12 | cy = 240 13 | 14 | def model(): 15 | 16 | # note that xx is height here! 17 | xx = -0.2 18 | yy = -0.2 19 | zz = -0.2 20 | 21 | v000 = (xx, yy, zz) # 0 22 | v001 = (xx, yy, zz + 0.4) # 1 23 | v010 = (xx, yy + 0.4, zz) # 2 24 | v011 = (xx, yy + 0.4, zz + 0.4) # 3 25 | v100 = (xx + 0.4, yy, zz) # 4 26 | v101 = (xx + 0.4, yy, zz + 0.4) # 5 27 | v110 = (xx + 0.4, yy + 0.4, zz) # 6 28 | v111 = (xx + 0.4, yy + 0.4, zz + 0.4) # 7 29 | 30 | f1 = [0, 2, 4] 31 | f2 = [4, 2, 6] 32 | f3 = [1, 3, 5] 33 | f4 = [5, 3, 7] 34 | f5 = [0, 1, 2] 35 | f6 = [1, 3, 2] 36 | f7 = [4, 5, 7] 37 | f8 = [4, 7, 6] 38 | f9 = [4, 0, 1] 39 | f10 = [4, 5, 1] 40 | f11 = [2, 3, 6] 41 | f12 = [3, 7, 6] 42 | 43 | vertices = [] 44 | vertices.append(v000) 45 | vertices.append(v001) 46 | vertices.append(v010) 47 | vertices.append(v011) 48 | vertices.append(v100) 49 | vertices.append(v101) 50 | vertices.append(v110) 51 | vertices.append(v111) 52 | 53 | faces = [] 54 | faces.append(f1) 55 | faces.append(f2) 56 | faces.append(f3) 57 | faces.append(f4) 58 | faces.append(f5) 59 | faces.append(f6) 60 | faces.append(f7) 61 | faces.append(f8) 62 | faces.append(f9) 63 | faces.append(f10) 64 | faces.append(f11) 65 | faces.append(f12) 66 | 67 | return vertices, faces 68 | 69 | def render(vertices, faces): 70 | 71 | x = 0 72 | y = math.pi/4 73 | z = 0 74 | R_x = np.array([[1, 0, 0], [0, math.cos(x), -math.sin(x)], [0, math.sin(x), math.cos(x)]]) 75 | R_y = np.array([[math.cos(y), 0, math.sin(y)], [0, 1, 0], [-math.sin(y), 0, math.cos(y)]]) 76 | R_z = np.array([[math.cos(z), -math.sin(z), 0], [math.sin(z), math.cos(z), 0], [0, 0, 1]]) 77 | R = R_z.dot(R_y.dot(R_x)) 78 | 79 | np_vertices = np.array(vertices).astype(np.float64) 80 | np_vertices = R.dot(np_vertices.T).T 81 | np_vertices[:, 2] += 1.5 82 | np_faces = np.array(faces).astype(np.float64) 83 | np_faces += 1 84 | 85 | depthmap, mask, img = pyrender.render(np_vertices.T.copy(), np_faces.T.copy(), np.array([fx, fy, cx, cy]), np.array([1., 2.]), np.array([img_h, img_w], dtype=np.int32)) 86 | pyplot.imshow(depthmap) 87 | pyplot.show() 88 | pyplot.imshow(img) 89 | pyplot.show() 90 | 91 | if __name__ == '__main__': 92 | vertices, faces = model() 93 | render(vertices, faces) 94 | -------------------------------------------------------------------------------- /external/libsimplify/__init__.py: -------------------------------------------------------------------------------- 1 | from .simplify_mesh import ( 2 | mesh_simplify 3 | ) 4 | import trimesh 5 | 6 | 7 | def simplify_mesh(mesh, f_target=10000, agressiveness=7.): 8 | vertices = mesh.vertices 9 | faces = mesh.faces 10 | 11 | vertices, faces = mesh_simplify(vertices, faces, f_target, agressiveness) 12 | 13 | mesh_simplified = trimesh.Trimesh(vertices, faces, process=False) 14 | 15 | return mesh_simplified 16 | -------------------------------------------------------------------------------- /external/libsimplify/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/external/libsimplify/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /external/libsimplify/simplify_mesh.cpython-36m-x86_64-linux-gnu.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/external/libsimplify/simplify_mesh.cpython-36m-x86_64-linux-gnu.so -------------------------------------------------------------------------------- /external/libsimplify/simplify_mesh.pyx: -------------------------------------------------------------------------------- 1 | # distutils: language = c++ 2 | from libcpp.vector cimport vector 3 | import numpy as np 4 | cimport numpy as np 5 | 6 | 7 | cdef extern from "Simplify.h": 8 | cdef struct vec3f: 9 | double x, y, z 10 | 11 | cdef cppclass SymetricMatrix: 12 | SymetricMatrix() except + 13 | 14 | 15 | cdef extern from "Simplify.h" namespace "Simplify": 16 | cdef struct Triangle: 17 | int v[3] 18 | double err[4] 19 | int deleted, dirty, attr 20 | vec3f uvs[3] 21 | int material 22 | 23 | cdef struct Vertex: 24 | vec3f p 25 | int tstart, tcount 26 | SymetricMatrix q 27 | int border 28 | 29 | cdef vector[Triangle] triangles 30 | cdef vector[Vertex] vertices 31 | cdef void simplify_mesh(int, double) 32 | 33 | 34 | cpdef mesh_simplify(double[:, ::1] vertices_in, long[:, ::1] triangles_in, 35 | int f_target, double agressiveness=7.) except +: 36 | vertices.clear() 37 | triangles.clear() 38 | 39 | # Read in vertices and triangles 40 | cdef Vertex v 41 | for iv in range(vertices_in.shape[0]): 42 | v = Vertex() 43 | v.p.x = vertices_in[iv, 0] 44 | v.p.y = vertices_in[iv, 1] 45 | v.p.z = vertices_in[iv, 2] 46 | vertices.push_back(v) 47 | 48 | cdef Triangle t 49 | for it in range(triangles_in.shape[0]): 50 | t = Triangle() 51 | t.v[0] = triangles_in[it, 0] 52 | t.v[1] = triangles_in[it, 1] 53 | t.v[2] = triangles_in[it, 2] 54 | triangles.push_back(t) 55 | 56 | # Simplify 57 | # print('Simplify...') 58 | simplify_mesh(f_target, agressiveness) 59 | 60 | # Only use triangles that are not deleted 61 | cdef vector[Triangle] triangles_notdel 62 | triangles_notdel.reserve(triangles.size()) 63 | 64 | for t in triangles: 65 | if not t.deleted: 66 | triangles_notdel.push_back(t) 67 | 68 | # Read out triangles 69 | vertices_out = np.empty((vertices.size(), 3), dtype=np.float64) 70 | triangles_out = np.empty((triangles_notdel.size(), 3), dtype=np.int64) 71 | 72 | cdef double[:, :] vertices_out_view = vertices_out 73 | cdef long[:, :] triangles_out_view = triangles_out 74 | 75 | for iv in range(vertices.size()): 76 | vertices_out_view[iv, 0] = vertices[iv].p.x 77 | vertices_out_view[iv, 1] = vertices[iv].p.y 78 | vertices_out_view[iv, 2] = vertices[iv].p.z 79 | 80 | for it in range(triangles_notdel.size()): 81 | triangles_out_view[it, 0] = triangles_notdel[it].v[0] 82 | triangles_out_view[it, 1] = triangles_notdel[it].v[1] 83 | triangles_out_view[it, 2] = triangles_notdel[it].v[2] 84 | 85 | # Clear vertices and triangles 86 | vertices.clear() 87 | triangles.clear() 88 | 89 | return vertices_out, triangles_out -------------------------------------------------------------------------------- /external/libsimplify/test.py: -------------------------------------------------------------------------------- 1 | from simplify_mesh import mesh_simplify 2 | import numpy as np 3 | 4 | v = np.random.rand(100, 3) 5 | f = np.random.choice(range(100), (50, 3)) 6 | 7 | mesh_simplify(v, f, 50) -------------------------------------------------------------------------------- /external/libvoxelize/.gitignore: -------------------------------------------------------------------------------- 1 | voxelize.c 2 | voxelize.html 3 | build 4 | -------------------------------------------------------------------------------- /external/libvoxelize/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/external/libvoxelize/__init__.py -------------------------------------------------------------------------------- /external/libvoxelize/voxelize.cpython-36m-x86_64-linux-gnu.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/external/libvoxelize/voxelize.cpython-36m-x86_64-linux-gnu.so -------------------------------------------------------------------------------- /external/libvoxelize/voxelize.pyx: -------------------------------------------------------------------------------- 1 | cimport cython 2 | from libc.math cimport floor, ceil 3 | from cython.view cimport array as cvarray 4 | 5 | cdef extern from "tribox2.h": 6 | int triBoxOverlap(float boxcenter[3], float boxhalfsize[3], 7 | float tri0[3], float tri1[3], float tri2[3]) 8 | 9 | 10 | @cython.boundscheck(False) # Deactivate bounds checking 11 | @cython.wraparound(False) # Deactivate negative indexing. 12 | cpdef int voxelize_mesh_(bint[:, :, :] occ, float[:, :, ::1] faces): 13 | assert(faces.shape[1] == 3) 14 | assert(faces.shape[2] == 3) 15 | 16 | n_faces = faces.shape[0] 17 | cdef int i 18 | for i in range(n_faces): 19 | voxelize_triangle_(occ, faces[i]) 20 | 21 | 22 | @cython.boundscheck(False) # Deactivate bounds checking 23 | @cython.wraparound(False) # Deactivate negative indexing. 24 | cpdef int voxelize_triangle_(bint[:, :, :] occupancies, float[:, ::1] triverts): 25 | cdef int bbox_min[3] 26 | cdef int bbox_max[3] 27 | cdef int i, j, k 28 | cdef float boxhalfsize[3] 29 | cdef float boxcenter[3] 30 | cdef bint intersection 31 | 32 | boxhalfsize[:] = (0.5, 0.5, 0.5) 33 | 34 | for i in range(3): 35 | bbox_min[i] = ( 36 | min(triverts[0, i], triverts[1, i], triverts[2, i]) 37 | ) 38 | bbox_min[i] = min(max(bbox_min[i], 0), occupancies.shape[i] - 1) 39 | 40 | for i in range(3): 41 | bbox_max[i] = ( 42 | max(triverts[0, i], triverts[1, i], triverts[2, i]) 43 | ) 44 | bbox_max[i] = min(max(bbox_max[i], 0), occupancies.shape[i] - 1) 45 | 46 | for i in range(bbox_min[0], bbox_max[0] + 1): 47 | for j in range(bbox_min[1], bbox_max[1] + 1): 48 | for k in range(bbox_min[2], bbox_max[2] + 1): 49 | boxcenter[:] = (i + 0.5, j + 0.5, k + 0.5) 50 | intersection = triBoxOverlap(&boxcenter[0], &boxhalfsize[0], 51 | &triverts[0, 0], &triverts[1, 0], &triverts[2, 0]) 52 | occupancies[i, j, k] |= intersection 53 | 54 | 55 | @cython.boundscheck(False) # Deactivate bounds checking 56 | @cython.wraparound(False) # Deactivate negative indexing. 57 | cdef int test_triangle_aabb(float[::1] boxcenter, float[::1] boxhalfsize, float[:, ::1] triverts): 58 | assert(boxcenter.shape[0] == 3) 59 | assert(boxhalfsize.shape[0] == 3) 60 | assert(triverts.shape[0] == triverts.shape[1] == 3) 61 | 62 | # print(triverts) 63 | # Call functions 64 | cdef int result = triBoxOverlap(&boxcenter[0], &boxhalfsize[0], 65 | &triverts[0, 0], &triverts[1, 0], &triverts[2, 0]) 66 | return result 67 | -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/MANIFEST.in: -------------------------------------------------------------------------------- 1 | graft pointnet2_ops/_ext-src 2 | -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/pointnet2_ops/__init__.py: -------------------------------------------------------------------------------- 1 | import pointnet2_ops.pointnet2_modules 2 | import pointnet2_ops.pointnet2_utils 3 | from pointnet2_ops._version import __version__ 4 | -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/pointnet2_ops/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/external/pointnet2_ops_lib/pointnet2_ops/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/pointnet2_ops/__pycache__/pointnet2_modules.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/external/pointnet2_ops_lib/pointnet2_ops/__pycache__/pointnet2_modules.cpython-36.pyc -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/pointnet2_ops/__pycache__/pointnet2_utils.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/external/pointnet2_ops_lib/pointnet2_ops/__pycache__/pointnet2_utils.cpython-36.pyc -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/pointnet2_ops/_ext-src/include/ball_query.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | at::Tensor ball_query(at::Tensor new_xyz, at::Tensor xyz, const float radius, 5 | const int nsample); 6 | -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/pointnet2_ops/_ext-src/include/cuda_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef _CUDA_UTILS_H 2 | #define _CUDA_UTILS_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | #define TOTAL_THREADS 512 14 | 15 | inline int opt_n_threads(int work_size) { 16 | const int pow_2 = std::log(static_cast(work_size)) / std::log(2.0); 17 | 18 | return max(min(1 << pow_2, TOTAL_THREADS), 1); 19 | } 20 | 21 | inline dim3 opt_block_config(int x, int y) { 22 | const int x_threads = opt_n_threads(x); 23 | const int y_threads = 24 | max(min(opt_n_threads(y), TOTAL_THREADS / x_threads), 1); 25 | dim3 block_config(x_threads, y_threads, 1); 26 | 27 | return block_config; 28 | } 29 | 30 | #define CUDA_CHECK_ERRORS() \ 31 | do { \ 32 | cudaError_t err = cudaGetLastError(); \ 33 | if (cudaSuccess != err) { \ 34 | fprintf(stderr, "CUDA kernel failed : %s\n%s at L:%d in %s\n", \ 35 | cudaGetErrorString(err), __PRETTY_FUNCTION__, __LINE__, \ 36 | __FILE__); \ 37 | exit(-1); \ 38 | } \ 39 | } while (0) 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/pointnet2_ops/_ext-src/include/group_points.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | at::Tensor group_points(at::Tensor points, at::Tensor idx); 5 | at::Tensor group_points_grad(at::Tensor grad_out, at::Tensor idx, const int n); 6 | -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/pointnet2_ops/_ext-src/include/interpolate.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | std::vector three_nn(at::Tensor unknowns, at::Tensor knows); 7 | at::Tensor three_interpolate(at::Tensor points, at::Tensor idx, 8 | at::Tensor weight); 9 | at::Tensor three_interpolate_grad(at::Tensor grad_out, at::Tensor idx, 10 | at::Tensor weight, const int m); 11 | -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/pointnet2_ops/_ext-src/include/sampling.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | 4 | at::Tensor gather_points(at::Tensor points, at::Tensor idx); 5 | at::Tensor gather_points_grad(at::Tensor grad_out, at::Tensor idx, const int n); 6 | at::Tensor furthest_point_sampling(at::Tensor points, const int nsamples); 7 | -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/pointnet2_ops/_ext-src/include/utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | #include 3 | #include 4 | 5 | #define CHECK_CUDA(x) \ 6 | do { \ 7 | AT_ASSERT(x.is_cuda(), #x " must be a CUDA tensor"); \ 8 | } while (0) 9 | 10 | #define CHECK_CONTIGUOUS(x) \ 11 | do { \ 12 | AT_ASSERT(x.is_contiguous(), #x " must be a contiguous tensor"); \ 13 | } while (0) 14 | 15 | #define CHECK_IS_INT(x) \ 16 | do { \ 17 | AT_ASSERT(x.scalar_type() == at::ScalarType::Int, \ 18 | #x " must be an int tensor"); \ 19 | } while (0) 20 | 21 | #define CHECK_IS_FLOAT(x) \ 22 | do { \ 23 | AT_ASSERT(x.scalar_type() == at::ScalarType::Float, \ 24 | #x " must be a float tensor"); \ 25 | } while (0) 26 | -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/pointnet2_ops/_ext-src/src/ball_query.cpp: -------------------------------------------------------------------------------- 1 | #include "ball_query.h" 2 | #include "utils.h" 3 | 4 | void query_ball_point_kernel_wrapper(int b, int n, int m, float radius, 5 | int nsample, const float *new_xyz, 6 | const float *xyz, int *idx); 7 | 8 | at::Tensor ball_query(at::Tensor new_xyz, at::Tensor xyz, const float radius, 9 | const int nsample) { 10 | CHECK_CONTIGUOUS(new_xyz); 11 | CHECK_CONTIGUOUS(xyz); 12 | CHECK_IS_FLOAT(new_xyz); 13 | CHECK_IS_FLOAT(xyz); 14 | 15 | if (new_xyz.is_cuda()) { 16 | CHECK_CUDA(xyz); 17 | } 18 | 19 | at::Tensor idx = 20 | torch::zeros({new_xyz.size(0), new_xyz.size(1), nsample}, 21 | at::device(new_xyz.device()).dtype(at::ScalarType::Int)); 22 | 23 | if (new_xyz.is_cuda()) { 24 | query_ball_point_kernel_wrapper(xyz.size(0), xyz.size(1), new_xyz.size(1), 25 | radius, nsample, new_xyz.data_ptr(), 26 | xyz.data_ptr(), idx.data_ptr()); 27 | } else { 28 | AT_ASSERT(false, "CPU not supported"); 29 | } 30 | 31 | return idx; 32 | } 33 | -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/pointnet2_ops/_ext-src/src/ball_query_gpu.cu: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include "cuda_utils.h" 6 | 7 | // input: new_xyz(b, m, 3) xyz(b, n, 3) 8 | // output: idx(b, m, nsample) 9 | __global__ void query_ball_point_kernel(int b, int n, int m, float radius, 10 | int nsample, 11 | const float *__restrict__ new_xyz, 12 | const float *__restrict__ xyz, 13 | int *__restrict__ idx) { 14 | int batch_index = blockIdx.x; 15 | xyz += batch_index * n * 3; 16 | new_xyz += batch_index * m * 3; 17 | idx += m * nsample * batch_index; 18 | 19 | int index = threadIdx.x; 20 | int stride = blockDim.x; 21 | 22 | float radius2 = radius * radius; 23 | for (int j = index; j < m; j += stride) { 24 | float new_x = new_xyz[j * 3 + 0]; 25 | float new_y = new_xyz[j * 3 + 1]; 26 | float new_z = new_xyz[j * 3 + 2]; 27 | for (int k = 0, cnt = 0; k < n && cnt < nsample; ++k) { 28 | float x = xyz[k * 3 + 0]; 29 | float y = xyz[k * 3 + 1]; 30 | float z = xyz[k * 3 + 2]; 31 | float d2 = (new_x - x) * (new_x - x) + (new_y - y) * (new_y - y) + 32 | (new_z - z) * (new_z - z); 33 | if (d2 < radius2) { 34 | if (cnt == 0) { 35 | for (int l = 0; l < nsample; ++l) { 36 | idx[j * nsample + l] = k; 37 | } 38 | } 39 | idx[j * nsample + cnt] = k; 40 | ++cnt; 41 | } 42 | } 43 | } 44 | } 45 | 46 | void query_ball_point_kernel_wrapper(int b, int n, int m, float radius, 47 | int nsample, const float *new_xyz, 48 | const float *xyz, int *idx) { 49 | cudaStream_t stream = at::cuda::getCurrentCUDAStream(); 50 | query_ball_point_kernel<<>>( 51 | b, n, m, radius, nsample, new_xyz, xyz, idx); 52 | 53 | CUDA_CHECK_ERRORS(); 54 | } 55 | -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/pointnet2_ops/_ext-src/src/bindings.cpp: -------------------------------------------------------------------------------- 1 | #include "ball_query.h" 2 | #include "group_points.h" 3 | #include "interpolate.h" 4 | #include "sampling.h" 5 | 6 | PYBIND11_MODULE(TORCH_EXTENSION_NAME, m) { 7 | m.def("gather_points", &gather_points); 8 | m.def("gather_points_grad", &gather_points_grad); 9 | m.def("furthest_point_sampling", &furthest_point_sampling); 10 | 11 | m.def("three_nn", &three_nn); 12 | m.def("three_interpolate", &three_interpolate); 13 | m.def("three_interpolate_grad", &three_interpolate_grad); 14 | 15 | m.def("ball_query", &ball_query); 16 | 17 | m.def("group_points", &group_points); 18 | m.def("group_points_grad", &group_points_grad); 19 | } 20 | -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/pointnet2_ops/_ext-src/src/group_points.cpp: -------------------------------------------------------------------------------- 1 | #include "group_points.h" 2 | #include "utils.h" 3 | 4 | void group_points_kernel_wrapper(int b, int c, int n, int npoints, int nsample, 5 | const float *points, const int *idx, 6 | float *out); 7 | 8 | void group_points_grad_kernel_wrapper(int b, int c, int n, int npoints, 9 | int nsample, const float *grad_out, 10 | const int *idx, float *grad_points); 11 | 12 | at::Tensor group_points(at::Tensor points, at::Tensor idx) { 13 | CHECK_CONTIGUOUS(points); 14 | CHECK_CONTIGUOUS(idx); 15 | CHECK_IS_FLOAT(points); 16 | CHECK_IS_INT(idx); 17 | 18 | if (points.is_cuda()) { 19 | CHECK_CUDA(idx); 20 | } 21 | 22 | at::Tensor output = 23 | torch::zeros({points.size(0), points.size(1), idx.size(1), idx.size(2)}, 24 | at::device(points.device()).dtype(at::ScalarType::Float)); 25 | 26 | if (points.is_cuda()) { 27 | group_points_kernel_wrapper(points.size(0), points.size(1), points.size(2), 28 | idx.size(1), idx.size(2), 29 | points.data_ptr(), idx.data_ptr(), 30 | output.data_ptr()); 31 | } else { 32 | AT_ASSERT(false, "CPU not supported"); 33 | } 34 | 35 | return output; 36 | } 37 | 38 | at::Tensor group_points_grad(at::Tensor grad_out, at::Tensor idx, const int n) { 39 | CHECK_CONTIGUOUS(grad_out); 40 | CHECK_CONTIGUOUS(idx); 41 | CHECK_IS_FLOAT(grad_out); 42 | CHECK_IS_INT(idx); 43 | 44 | if (grad_out.is_cuda()) { 45 | CHECK_CUDA(idx); 46 | } 47 | 48 | at::Tensor output = 49 | torch::zeros({grad_out.size(0), grad_out.size(1), n}, 50 | at::device(grad_out.device()).dtype(at::ScalarType::Float)); 51 | 52 | if (grad_out.is_cuda()) { 53 | group_points_grad_kernel_wrapper( 54 | grad_out.size(0), grad_out.size(1), n, idx.size(1), idx.size(2), 55 | grad_out.data_ptr(), idx.data_ptr(), 56 | output.data_ptr()); 57 | } else { 58 | AT_ASSERT(false, "CPU not supported"); 59 | } 60 | 61 | return output; 62 | } 63 | -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/pointnet2_ops/_ext-src/src/group_points_gpu.cu: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "cuda_utils.h" 5 | 6 | // input: points(b, c, n) idx(b, npoints, nsample) 7 | // output: out(b, c, npoints, nsample) 8 | __global__ void group_points_kernel(int b, int c, int n, int npoints, 9 | int nsample, 10 | const float *__restrict__ points, 11 | const int *__restrict__ idx, 12 | float *__restrict__ out) { 13 | int batch_index = blockIdx.x; 14 | points += batch_index * n * c; 15 | idx += batch_index * npoints * nsample; 16 | out += batch_index * npoints * nsample * c; 17 | 18 | const int index = threadIdx.y * blockDim.x + threadIdx.x; 19 | const int stride = blockDim.y * blockDim.x; 20 | for (int i = index; i < c * npoints; i += stride) { 21 | const int l = i / npoints; 22 | const int j = i % npoints; 23 | for (int k = 0; k < nsample; ++k) { 24 | int ii = idx[j * nsample + k]; 25 | out[(l * npoints + j) * nsample + k] = points[l * n + ii]; 26 | } 27 | } 28 | } 29 | 30 | void group_points_kernel_wrapper(int b, int c, int n, int npoints, int nsample, 31 | const float *points, const int *idx, 32 | float *out) { 33 | cudaStream_t stream = at::cuda::getCurrentCUDAStream(); 34 | 35 | group_points_kernel<<>>( 36 | b, c, n, npoints, nsample, points, idx, out); 37 | 38 | CUDA_CHECK_ERRORS(); 39 | } 40 | 41 | // input: grad_out(b, c, npoints, nsample), idx(b, npoints, nsample) 42 | // output: grad_points(b, c, n) 43 | __global__ void group_points_grad_kernel(int b, int c, int n, int npoints, 44 | int nsample, 45 | const float *__restrict__ grad_out, 46 | const int *__restrict__ idx, 47 | float *__restrict__ grad_points) { 48 | int batch_index = blockIdx.x; 49 | grad_out += batch_index * npoints * nsample * c; 50 | idx += batch_index * npoints * nsample; 51 | grad_points += batch_index * n * c; 52 | 53 | const int index = threadIdx.y * blockDim.x + threadIdx.x; 54 | const int stride = blockDim.y * blockDim.x; 55 | for (int i = index; i < c * npoints; i += stride) { 56 | const int l = i / npoints; 57 | const int j = i % npoints; 58 | for (int k = 0; k < nsample; ++k) { 59 | int ii = idx[j * nsample + k]; 60 | atomicAdd(grad_points + l * n + ii, 61 | grad_out[(l * npoints + j) * nsample + k]); 62 | } 63 | } 64 | } 65 | 66 | void group_points_grad_kernel_wrapper(int b, int c, int n, int npoints, 67 | int nsample, const float *grad_out, 68 | const int *idx, float *grad_points) { 69 | cudaStream_t stream = at::cuda::getCurrentCUDAStream(); 70 | 71 | group_points_grad_kernel<<>>( 72 | b, c, n, npoints, nsample, grad_out, idx, grad_points); 73 | 74 | CUDA_CHECK_ERRORS(); 75 | } 76 | -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/pointnet2_ops/_ext-src/src/interpolate.cpp: -------------------------------------------------------------------------------- 1 | #include "interpolate.h" 2 | #include "utils.h" 3 | 4 | void three_nn_kernel_wrapper(int b, int n, int m, const float *unknown, 5 | const float *known, float *dist2, int *idx); 6 | void three_interpolate_kernel_wrapper(int b, int c, int m, int n, 7 | const float *points, const int *idx, 8 | const float *weight, float *out); 9 | void three_interpolate_grad_kernel_wrapper(int b, int c, int n, int m, 10 | const float *grad_out, 11 | const int *idx, const float *weight, 12 | float *grad_points); 13 | 14 | std::vector three_nn(at::Tensor unknowns, at::Tensor knows) { 15 | CHECK_CONTIGUOUS(unknowns); 16 | CHECK_CONTIGUOUS(knows); 17 | CHECK_IS_FLOAT(unknowns); 18 | CHECK_IS_FLOAT(knows); 19 | 20 | if (unknowns.is_cuda()) { 21 | CHECK_CUDA(knows); 22 | } 23 | 24 | at::Tensor idx = 25 | torch::zeros({unknowns.size(0), unknowns.size(1), 3}, 26 | at::device(unknowns.device()).dtype(at::ScalarType::Int)); 27 | at::Tensor dist2 = 28 | torch::zeros({unknowns.size(0), unknowns.size(1), 3}, 29 | at::device(unknowns.device()).dtype(at::ScalarType::Float)); 30 | 31 | if (unknowns.is_cuda()) { 32 | three_nn_kernel_wrapper(unknowns.size(0), unknowns.size(1), knows.size(1), 33 | unknowns.data_ptr(), knows.data_ptr(), 34 | dist2.data_ptr(), idx.data_ptr()); 35 | } else { 36 | AT_ASSERT(false, "CPU not supported"); 37 | } 38 | 39 | return {dist2, idx}; 40 | } 41 | 42 | at::Tensor three_interpolate(at::Tensor points, at::Tensor idx, 43 | at::Tensor weight) { 44 | CHECK_CONTIGUOUS(points); 45 | CHECK_CONTIGUOUS(idx); 46 | CHECK_CONTIGUOUS(weight); 47 | CHECK_IS_FLOAT(points); 48 | CHECK_IS_INT(idx); 49 | CHECK_IS_FLOAT(weight); 50 | 51 | if (points.is_cuda()) { 52 | CHECK_CUDA(idx); 53 | CHECK_CUDA(weight); 54 | } 55 | 56 | at::Tensor output = 57 | torch::zeros({points.size(0), points.size(1), idx.size(1)}, 58 | at::device(points.device()).dtype(at::ScalarType::Float)); 59 | 60 | if (points.is_cuda()) { 61 | three_interpolate_kernel_wrapper( 62 | points.size(0), points.size(1), points.size(2), idx.size(1), 63 | points.data_ptr(), idx.data_ptr(), weight.data_ptr(), 64 | output.data_ptr()); 65 | } else { 66 | AT_ASSERT(false, "CPU not supported"); 67 | } 68 | 69 | return output; 70 | } 71 | at::Tensor three_interpolate_grad(at::Tensor grad_out, at::Tensor idx, 72 | at::Tensor weight, const int m) { 73 | CHECK_CONTIGUOUS(grad_out); 74 | CHECK_CONTIGUOUS(idx); 75 | CHECK_CONTIGUOUS(weight); 76 | CHECK_IS_FLOAT(grad_out); 77 | CHECK_IS_INT(idx); 78 | CHECK_IS_FLOAT(weight); 79 | 80 | if (grad_out.is_cuda()) { 81 | CHECK_CUDA(idx); 82 | CHECK_CUDA(weight); 83 | } 84 | 85 | at::Tensor output = 86 | torch::zeros({grad_out.size(0), grad_out.size(1), m}, 87 | at::device(grad_out.device()).dtype(at::ScalarType::Float)); 88 | 89 | if (grad_out.is_cuda()) { 90 | three_interpolate_grad_kernel_wrapper( 91 | grad_out.size(0), grad_out.size(1), grad_out.size(2), m, 92 | grad_out.data_ptr(), idx.data_ptr(), 93 | weight.data_ptr(), output.data_ptr()); 94 | } else { 95 | AT_ASSERT(false, "CPU not supported"); 96 | } 97 | 98 | return output; 99 | } 100 | -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/pointnet2_ops/_ext-src/src/sampling.cpp: -------------------------------------------------------------------------------- 1 | #include "sampling.h" 2 | #include "utils.h" 3 | 4 | void gather_points_kernel_wrapper(int b, int c, int n, int npoints, 5 | const float *points, const int *idx, 6 | float *out); 7 | void gather_points_grad_kernel_wrapper(int b, int c, int n, int npoints, 8 | const float *grad_out, const int *idx, 9 | float *grad_points); 10 | 11 | void furthest_point_sampling_kernel_wrapper(int b, int n, int m, 12 | const float *dataset, float *temp, 13 | int *idxs); 14 | 15 | at::Tensor gather_points(at::Tensor points, at::Tensor idx) { 16 | CHECK_CONTIGUOUS(points); 17 | CHECK_CONTIGUOUS(idx); 18 | CHECK_IS_FLOAT(points); 19 | CHECK_IS_INT(idx); 20 | 21 | if (points.is_cuda()) { 22 | CHECK_CUDA(idx); 23 | } 24 | 25 | at::Tensor output = 26 | torch::zeros({points.size(0), points.size(1), idx.size(1)}, 27 | at::device(points.device()).dtype(at::ScalarType::Float)); 28 | 29 | if (points.is_cuda()) { 30 | gather_points_kernel_wrapper(points.size(0), points.size(1), points.size(2), 31 | idx.size(1), points.data_ptr(), 32 | idx.data_ptr(), output.data_ptr()); 33 | } else { 34 | AT_ASSERT(false, "CPU not supported"); 35 | } 36 | 37 | return output; 38 | } 39 | 40 | at::Tensor gather_points_grad(at::Tensor grad_out, at::Tensor idx, 41 | const int n) { 42 | CHECK_CONTIGUOUS(grad_out); 43 | CHECK_CONTIGUOUS(idx); 44 | CHECK_IS_FLOAT(grad_out); 45 | CHECK_IS_INT(idx); 46 | 47 | if (grad_out.is_cuda()) { 48 | CHECK_CUDA(idx); 49 | } 50 | 51 | at::Tensor output = 52 | torch::zeros({grad_out.size(0), grad_out.size(1), n}, 53 | at::device(grad_out.device()).dtype(at::ScalarType::Float)); 54 | 55 | if (grad_out.is_cuda()) { 56 | gather_points_grad_kernel_wrapper(grad_out.size(0), grad_out.size(1), n, 57 | idx.size(1), grad_out.data_ptr(), 58 | idx.data_ptr(), 59 | output.data_ptr()); 60 | } else { 61 | AT_ASSERT(false, "CPU not supported"); 62 | } 63 | 64 | return output; 65 | } 66 | at::Tensor furthest_point_sampling(at::Tensor points, const int nsamples) { 67 | CHECK_CONTIGUOUS(points); 68 | CHECK_IS_FLOAT(points); 69 | 70 | at::Tensor output = 71 | torch::zeros({points.size(0), nsamples}, 72 | at::device(points.device()).dtype(at::ScalarType::Int)); 73 | 74 | at::Tensor tmp = 75 | torch::full({points.size(0), points.size(1)}, 1e10, 76 | at::device(points.device()).dtype(at::ScalarType::Float)); 77 | 78 | if (points.is_cuda()) { 79 | furthest_point_sampling_kernel_wrapper( 80 | points.size(0), points.size(1), nsamples, points.data_ptr(), 81 | tmp.data_ptr(), output.data_ptr()); 82 | } else { 83 | AT_ASSERT(false, "CPU not supported"); 84 | } 85 | 86 | return output; 87 | } 88 | -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/pointnet2_ops/_version.py: -------------------------------------------------------------------------------- 1 | __version__ = "3.0.0" 2 | -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/pointnet2_ops/pytorch_utils.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) 5.2021. Yinyu Nie 2 | # License: MIT 3 | # Modified based on Ref: https://github.com/erikwijmans/Pointnet2_PyTorch ''' 4 | import torch.nn as nn 5 | 6 | def set_bn_momentum_default(bn_momentum): 7 | 8 | def fn(m): 9 | if isinstance(m, (nn.BatchNorm1d, nn.BatchNorm2d, nn.BatchNorm3d)): 10 | m.momentum = bn_momentum 11 | 12 | return fn 13 | 14 | 15 | class BNMomentumScheduler(object): 16 | 17 | def __init__( 18 | self, cfg, model, bn_lambda, last_epoch=-1, 19 | setter=set_bn_momentum_default 20 | ): 21 | if not isinstance(model, nn.Module): 22 | raise RuntimeError( 23 | "Class '{}' is not a PyTorch nn Module".format( 24 | type(model).__name__ 25 | ) 26 | ) 27 | self.cfg = cfg 28 | self.model = model 29 | self.setter = setter 30 | self.lmbd = bn_lambda 31 | 32 | self.step(last_epoch + 1) 33 | self.last_epoch = last_epoch 34 | 35 | def step(self, epoch=None): 36 | if epoch is None: 37 | epoch = self.last_epoch + 1 38 | 39 | self.last_epoch = epoch 40 | self.model.apply(self.setter(self.lmbd(epoch))) 41 | 42 | def show_momentum(self): 43 | self.cfg.log_string('Current BN decay momentum :%f.' % (self.lmbd(self.last_epoch))) -------------------------------------------------------------------------------- /external/pointnet2_ops_lib/setup.py: -------------------------------------------------------------------------------- 1 | import glob 2 | import os 3 | import os.path as osp 4 | 5 | from setuptools import find_packages, setup 6 | from torch.utils.cpp_extension import BuildExtension, CUDAExtension 7 | 8 | this_dir = osp.dirname(osp.abspath(__file__)) 9 | _ext_src_root = osp.join("pointnet2_ops", "_ext-src") 10 | _ext_sources = glob.glob(osp.join(_ext_src_root, "src", "*.cpp")) + glob.glob( 11 | osp.join(_ext_src_root, "src", "*.cu") 12 | ) 13 | _ext_headers = glob.glob(osp.join(_ext_src_root, "include", "*")) 14 | 15 | requirements = ["torch>=1.4"] 16 | 17 | exec(open(osp.join("pointnet2_ops", "_version.py")).read()) 18 | 19 | os.environ["TORCH_CUDA_ARCH_LIST"] = "3.7+PTX;5.0;6.0;6.1;6.2;7.0;7.5" 20 | setup( 21 | name="pointnet2_ops", 22 | version=__version__, 23 | author="Erik Wijmans", 24 | packages=find_packages(), 25 | install_requires=requirements, 26 | ext_modules=[ 27 | CUDAExtension( 28 | name="pointnet2_ops._ext", 29 | sources=_ext_sources, 30 | extra_compile_args={ 31 | "cxx": ["-O3"], 32 | "nvcc": ["-O3", "-Xfatbin", "-compress-all"], 33 | }, 34 | include_dirs=[osp.join(this_dir, _ext_src_root, "include")], 35 | ) 36 | ], 37 | cmdclass={"build_ext": BuildExtension}, 38 | include_package_data=True, 39 | ) 40 | -------------------------------------------------------------------------------- /external/pyTorchChamferDistance/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | ._* 3 | 4 | -------------------------------------------------------------------------------- /external/pyTorchChamferDistance/LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [year] [fullname] 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 | -------------------------------------------------------------------------------- /external/pyTorchChamferDistance/README.md: -------------------------------------------------------------------------------- 1 | # Chamfer Distance for pyTorch 2 | 3 | This is an implementation of the Chamfer Distance as a module for pyTorch. It is written as a custom C++/CUDA extension. 4 | 5 | As it is using pyTorch's [JIT compilation](https://pytorch.org/tutorials/advanced/cpp_extension.html), there are no additional prerequisite steps that have to be taken. Simply import the module as shown below; CUDA and C++ code will be compiled on the first run. 6 | 7 | ### Usage 8 | ```python 9 | from chamfer_distance import ChamferDistance 10 | chamfer_dist = ChamferDistance() 11 | 12 | #... 13 | # points and points_reconstructed are n_points x 3 matrices 14 | 15 | dist1, dist2 = chamfer_dist(points, points_reconstructed) 16 | loss = (torch.mean(dist1)) + (torch.mean(dist2)) 17 | 18 | 19 | #... 20 | ``` 21 | 22 | ### Integration 23 | This code has been integrated into the [Kaolin](https://github.com/NVIDIAGameWorks/kaolin) library for 3D Deep Learning by NVIDIAGameWorks. You should probably take a look at it if you are working on anything 3D :) 24 | -------------------------------------------------------------------------------- /external/pyTorchChamferDistance/chamfer_distance/__init__.py: -------------------------------------------------------------------------------- 1 | from .chamfer_distance import ChamferDistance 2 | -------------------------------------------------------------------------------- /external/pyTorchChamferDistance/chamfer_distance/__pycache__/__init__.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/external/pyTorchChamferDistance/chamfer_distance/__pycache__/__init__.cpython-36.pyc -------------------------------------------------------------------------------- /external/pyTorchChamferDistance/chamfer_distance/__pycache__/chamfer_distance.cpython-36.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/external/pyTorchChamferDistance/chamfer_distance/__pycache__/chamfer_distance.cpython-36.pyc -------------------------------------------------------------------------------- /external/pyTorchChamferDistance/chamfer_distance/chamfer_distance.py: -------------------------------------------------------------------------------- 1 | 2 | import torch 3 | 4 | from torch.utils.cpp_extension import load 5 | cd = load(name="cd", 6 | sources=["external/pyTorchChamferDistance/chamfer_distance/chamfer_distance.cpp", 7 | "external/pyTorchChamferDistance/chamfer_distance/chamfer_distance.cu"]) 8 | 9 | class ChamferDistanceFunction(torch.autograd.Function): 10 | @staticmethod 11 | def forward(ctx, xyz1, xyz2): 12 | batchsize, n, _ = xyz1.size() 13 | _, m, _ = xyz2.size() 14 | xyz1 = xyz1.contiguous() 15 | xyz2 = xyz2.contiguous() 16 | dist1 = torch.zeros(batchsize, n) 17 | dist2 = torch.zeros(batchsize, m) 18 | 19 | idx1 = torch.zeros(batchsize, n, dtype=torch.int) 20 | idx2 = torch.zeros(batchsize, m, dtype=torch.int) 21 | 22 | if not xyz1.is_cuda: 23 | cd.forward(xyz1, xyz2, dist1, dist2, idx1, idx2) 24 | else: 25 | dist1 = dist1.cuda() 26 | dist2 = dist2.cuda() 27 | idx1 = idx1.cuda() 28 | idx2 = idx2.cuda() 29 | cd.forward_cuda(xyz1, xyz2, dist1, dist2, idx1, idx2) 30 | 31 | ctx.save_for_backward(xyz1, xyz2, idx1, idx2) 32 | 33 | return dist1, dist2 34 | 35 | @staticmethod 36 | def backward(ctx, graddist1, graddist2): 37 | xyz1, xyz2, idx1, idx2 = ctx.saved_tensors 38 | 39 | graddist1 = graddist1.contiguous() 40 | graddist2 = graddist2.contiguous() 41 | 42 | gradxyz1 = torch.zeros(xyz1.size()) 43 | gradxyz2 = torch.zeros(xyz2.size()) 44 | 45 | if not graddist1.is_cuda: 46 | cd.backward(xyz1, xyz2, gradxyz1, gradxyz2, graddist1, graddist2, idx1, idx2) 47 | else: 48 | gradxyz1 = gradxyz1.cuda() 49 | gradxyz2 = gradxyz2.cuda() 50 | cd.backward_cuda(xyz1, xyz2, gradxyz1, gradxyz2, graddist1, graddist2, idx1, idx2) 51 | 52 | return gradxyz1, gradxyz2 53 | 54 | 55 | class ChamferDistance(torch.nn.Module): 56 | def forward(self, xyz1, xyz2): 57 | return ChamferDistanceFunction.apply(xyz1, xyz2) 58 | -------------------------------------------------------------------------------- /external/pyfusion/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | cyfusion.so 3 | cyfusion.cpp 4 | .DS_Store 5 | -------------------------------------------------------------------------------- /external/pyfusion/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2017, The OctNet authors 2 | # All rights reserved. 3 | # 4 | # Redistribution and use in source and binary forms, with or without 5 | # modification, are permitted provided that the following conditions are met: 6 | # * Redistributions of source code must retain the above copyright 7 | # notice, this list of conditions and the following disclaimer. 8 | # * Redistributions in binary form must reproduce the above copyright 9 | # notice, this list of conditions and the following disclaimer in the 10 | # documentation and/or other materials provided with the distribution. 11 | # * Neither the name of the nor the 12 | # names of its contributors may be used to endorse or promote products 13 | # derived from this software without specific prior written permission. 14 | # 15 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | # DISCLAIMED. IN NO EVENT SHALL OCTNET AUTHORS BE LIABLE FOR ANY 19 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 20 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 21 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 22 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 | 26 | cmake_minimum_required(VERSION 2.8) 27 | set(CMAKE_MACOSX_RPATH 1) 28 | 29 | set(CMAKE_CXX_STANDARD 11) 30 | 31 | # set(CMAKE_BUILD_TYPE Debug) 32 | set(CMAKE_BUILD_TYPE Release) 33 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -msse -msse2 -msse3 -msse4.2 -fPIC") 34 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -msse -msse2 -msse3 -msse4.2 -fPIC") 35 | 36 | find_package(OpenMP) 37 | if (OPENMP_FOUND) 38 | set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") 39 | set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") 40 | endif() 41 | 42 | find_package(CUDA 6.5 REQUIRED) 43 | set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS};-std=c++11") 44 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -D_FORCE_INLINES -Wall") 45 | 46 | set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS}; -gencode=arch=compute_30,code=sm_30") 47 | set(CUDA_NVCC_FLAGS "${CUDA_NVCC_FLAGS}; -gencode=arch=compute_30,code=compute_30") 48 | 49 | set(FUSION_CPU_SRC 50 | fusion.cpp 51 | ) 52 | 53 | set(FUSION_GPU_SRC 54 | fusion.cu 55 | fusion_zach_tvl1.cu 56 | ) 57 | 58 | cuda_add_library(fusion_cpu SHARED ${FUSION_CPU_SRC}) 59 | 60 | cuda_add_library(fusion_gpu SHARED ${FUSION_GPU_SRC}) 61 | target_link_libraries(fusion_gpu ${CUDA_LIBRARIES}) 62 | -------------------------------------------------------------------------------- /external/pyfusion/LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2017, Gernot 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /external/pyfusion/README.md: -------------------------------------------------------------------------------- 1 | # PyFusion 2 | 3 | PyFusion is a Python framework for volumetric depth fusion. 4 | It contains simple occupancy and TSDF fusion methods that can be executed on a CPU as well as on a GPU. 5 | 6 | To use the code, first compile the native code via 7 | 8 | ```bash 9 | cd build 10 | cmake .. 11 | make 12 | ``` 13 | Afterwards you can compile the Cython code via 14 | 15 | ```bash 16 | python setup.py build_ext --inplace 17 | ``` 18 | 19 | You can then use the fusion functions 20 | 21 | ```python 22 | import pyfusion 23 | 24 | # create a views object 25 | # depthmaps: a NxHxW numpy float tensor of N depthmaps, invalid depth values are marked by negative numbers 26 | # Ks: the camera intric matrices, Nx3x3 float tensor 27 | # Rs: the camera rotation matrices, Nx3x3 float tensor 28 | # Ts: the camera translation vectors, Nx3 float tensor 29 | views = pyfusion.PyViews(depthmaps, Ks,Rs,Ts) 30 | 31 | # afterwards you can fuse the depth maps for example by 32 | # depth,height,width: number of voxels in each dimension 33 | # truncation: TSDF truncation value 34 | tsdf = pyfusion.tsdf_gpu(views, depth,height,width, vx_size, truncation, False) 35 | 36 | # the same code can also be run on the CPU 37 | tsdf = pyfusion.tsdf_cpu(views, depth,height,width, vx_size, truncation, False, n_threads=8) 38 | ``` 39 | 40 | Make sure `pyfusion` is in your `$PYTHONPATH`. 41 | -------------------------------------------------------------------------------- /external/pyfusion/__init__.py: -------------------------------------------------------------------------------- 1 | import ctypes 2 | import os 3 | 4 | pyfusion_dir = os.path.dirname(os.path.realpath(__file__)) 5 | 6 | ctypes.cdll.LoadLibrary(os.path.join(pyfusion_dir, 'build', 'libfusion_cpu.so')) 7 | ctypes.cdll.LoadLibrary(os.path.join(pyfusion_dir, 'build', 'libfusion_gpu.so')) 8 | from external.pyfusion.cyfusion import * 9 | -------------------------------------------------------------------------------- /external/pyfusion/cyfusion.cpython-36m-x86_64-linux-gnu.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/external/pyfusion/cyfusion.cpython-36m-x86_64-linux-gnu.so -------------------------------------------------------------------------------- /external/pyfusion/fusion.cpp: -------------------------------------------------------------------------------- 1 | #include "fusion.h" 2 | 3 | #include 4 | #include 5 | 6 | #if defined(_OPENMP) 7 | #include 8 | #endif 9 | 10 | 11 | template 12 | void fusion_cpu(const Views& views, const FusionFunctorT functor, float vx_size, int n_threads, Volume& vol) { 13 | int vx_res3 = vol.depth_ * vol.height_ * vol.width_; 14 | 15 | #if defined(_OPENMP) 16 | omp_set_num_threads(n_threads); 17 | #endif 18 | #pragma omp parallel for 19 | for(int idx = 0; idx < vx_res3; ++idx) { 20 | int d,h,w; 21 | fusion_idx2dhw(idx, vol.width_,vol.height_, d,h,w); 22 | float x,y,z; 23 | fusion_dhw2xyz(d,h,w, vx_size, x,y,z); 24 | 25 | functor.before_sample(&vol, d,h,w); 26 | bool run = true; 27 | int n_valid_views = 0; 28 | for(int vidx = 0; vidx < views.n_views_ && run; ++vidx) { 29 | float ur, vr, vx_d; 30 | fusion_project(&views, vidx, x,y,z, ur,vr,vx_d); 31 | 32 | int u = int(ur + 0.5f); 33 | int v = int(vr + 0.5f); 34 | // printf(" vx %d,%d,%d has center %f,%f,%f and projects to uvd=%f,%f,%f\n", w,h,d, x,y,z, ur,vr,vx_d); 35 | 36 | if(u >= 0 && v >= 0 && u < views.cols_ && v < views.rows_) { 37 | int dm_idx = (vidx * views.rows_ + v) * views.cols_ + u; 38 | float dm_d = views.depthmaps_[dm_idx]; 39 | // printf(" is on depthmap[%d,%d] with depth=%f, diff=%f\n", views.cols_,views.rows_, dm_d, dm_d - vx_d); 40 | run = functor.new_sample(&vol, vx_d, dm_d, d,h,w, &n_valid_views); 41 | } 42 | } // for vidx 43 | functor.after_sample(&vol, d,h,w, n_valid_views); 44 | } 45 | } 46 | 47 | void fusion_projectionmask_cpu(const Views& views, float vx_size, bool unknown_is_free, int n_threads, Volume& vol) { 48 | ProjectionMaskFusionFunctor functor(unknown_is_free); 49 | fusion_cpu(views, functor, vx_size, n_threads, vol); 50 | } 51 | 52 | void fusion_occupancy_cpu(const Views& views, float vx_size, float truncation, bool unknown_is_free, int n_threads, Volume& vol) { 53 | OccupancyFusionFunctor functor(truncation, unknown_is_free); 54 | fusion_cpu(views, functor, vx_size, n_threads, vol); 55 | } 56 | 57 | void fusion_tsdfmask_cpu(const Views& views, float vx_size, float truncation, bool unknown_is_free, int n_threads, Volume& vol) { 58 | TsdfMaskFusionFunctor functor(truncation, unknown_is_free); 59 | fusion_cpu(views, functor, vx_size, n_threads, vol); 60 | } 61 | 62 | void fusion_tsdf_cpu(const Views& views, float vx_size, float truncation, bool unknown_is_free, int n_threads, Volume& vol) { 63 | TsdfFusionFunctor functor(truncation, unknown_is_free); 64 | fusion_cpu(views, functor, vx_size, n_threads, vol); 65 | } 66 | 67 | void fusion_tsdf_hist_cpu(const Views& views, float vx_size, float truncation, bool unknown_is_free, float* bin_centers, int n_bins, bool unobserved_is_occupied, int n_threads, Volume& vol) { 68 | TsdfHistFusionFunctor functor(truncation, unknown_is_free, bin_centers, n_bins, unobserved_is_occupied); 69 | fusion_cpu(views, functor, vx_size, n_threads, vol); 70 | } 71 | -------------------------------------------------------------------------------- /external/pyfusion/fusion.cu: -------------------------------------------------------------------------------- 1 | #include "gpu_common.h" 2 | 3 | #include 4 | #include 5 | 6 | 7 | 8 | template 9 | __global__ void kernel_fusion(int vx_res3, const Views views, const FusionFunctorT functor, float vx_size, Volume vol) { 10 | CUDA_KERNEL_LOOP(idx, vx_res3) { 11 | int d,h,w; 12 | fusion_idx2dhw(idx, vol.width_,vol.height_, d,h,w); 13 | float x,y,z; 14 | fusion_dhw2xyz(d,h,w, vx_size, x,y,z); 15 | 16 | functor.before_sample(&vol, d,h,w); 17 | bool run = true; 18 | int n_valid_views = 0; 19 | for(int vidx = 0; vidx < views.n_views_ && run; ++vidx) { 20 | float ur, vr, vx_d; 21 | fusion_project(&views, vidx, x,y,z, ur,vr,vx_d); 22 | //NOTE: ur,vr,vx_d might differ to CPP (subtle differences in precision) 23 | 24 | int u = int(ur + 0.5f); 25 | int v = int(vr + 0.5f); 26 | 27 | if(u >= 0 && v >= 0 && u < views.cols_ && v < views.rows_) { 28 | int dm_idx = (vidx * views.rows_ + v) * views.cols_ + u; 29 | float dm_d = views.depthmaps_[dm_idx]; 30 | // if(d==103 && h==130 && w==153) printf(" dm_d=%f, dm_idx=%d, u=%d, v=%d, ur=%f, vr=%f\n", dm_d, dm_idx, u,v, ur,vr); 31 | run = functor.new_sample(&vol, vx_d, dm_d, d,h,w, &n_valid_views); 32 | } 33 | } // for vidx 34 | functor.after_sample(&vol, d,h,w, n_valid_views); 35 | } 36 | } 37 | 38 | 39 | 40 | template 41 | void fusion_gpu(const Views& views, const FusionFunctorT functor, float vx_size, Volume& vol) { 42 | Views views_gpu; 43 | views_to_gpu(views, views_gpu, true); 44 | Volume vol_gpu; 45 | volume_alloc_like_gpu(vol, vol_gpu); 46 | 47 | int vx_res3 = vol.depth_ * vol.height_ * vol.width_; 48 | kernel_fusion<<>>( 49 | vx_res3, views_gpu, functor, vx_size, vol_gpu 50 | ); 51 | CUDA_POST_KERNEL_CHECK; 52 | 53 | volume_to_cpu(vol_gpu, vol, false); 54 | 55 | views_free_gpu(views_gpu); 56 | volume_free_gpu(vol_gpu); 57 | } 58 | 59 | void fusion_projectionmask_gpu(const Views& views, float vx_size, bool unknown_is_free, Volume& vol) { 60 | ProjectionMaskFusionFunctor functor(unknown_is_free); 61 | fusion_gpu(views, functor, vx_size, vol); 62 | } 63 | 64 | void fusion_occupancy_gpu(const Views& views, float vx_size, float truncation, bool unknown_is_free, Volume& vol) { 65 | OccupancyFusionFunctor functor(truncation, unknown_is_free); 66 | fusion_gpu(views, functor, vx_size, vol); 67 | } 68 | 69 | void fusion_tsdfmask_gpu(const Views& views, float vx_size, float truncation, bool unknown_is_free, Volume& vol) { 70 | TsdfMaskFusionFunctor functor(truncation, unknown_is_free); 71 | fusion_gpu(views, functor, vx_size, vol); 72 | } 73 | 74 | void fusion_tsdf_gpu(const Views& views, float vx_size, float truncation, bool unknown_is_free, Volume& vol) { 75 | TsdfFusionFunctor functor(truncation, unknown_is_free); 76 | fusion_gpu(views, functor, vx_size, vol); 77 | } 78 | 79 | void fusion_tsdf_hist_gpu(const Views& views, float vx_size, float truncation, bool unknown_is_free, float* bin_centers, int n_bins, bool unobserved_is_occupied, Volume& vol) { 80 | float* bin_centers_gpu = host_to_device_malloc(bin_centers, n_bins); 81 | TsdfHistFusionFunctor functor(truncation, unknown_is_free, bin_centers_gpu, n_bins, unobserved_is_occupied); 82 | fusion_gpu(views, functor, vx_size, vol); 83 | device_free(bin_centers_gpu); 84 | } 85 | -------------------------------------------------------------------------------- /external/pyfusion/setup.py: -------------------------------------------------------------------------------- 1 | # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 2 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 3 | # DISCLAIMED. IN NO EVENT SHALL OCTNET AUTHORS BE LIABLE FOR ANY 4 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 5 | # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 6 | # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 7 | # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 8 | # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 9 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 10 | 11 | from distutils.core import setup 12 | from Cython.Build import cythonize 13 | from distutils.extension import Extension 14 | from Cython.Distutils import build_ext 15 | import numpy as np 16 | import platform 17 | 18 | extra_compile_args = ["-ffast-math", '-msse', '-msse2', '-msse3', '-msse4.2'] 19 | extra_link_args = [] 20 | if 'Linux' in platform.system(): 21 | print('Added OpenMP') 22 | extra_compile_args.append('-fopenmp') 23 | extra_link_args.append('-fopenmp') 24 | 25 | 26 | setup( 27 | name="cyfusion", 28 | cmdclass= {'build_ext': build_ext}, 29 | ext_modules=[ 30 | Extension('cyfusion', 31 | ['cyfusion.pyx'], 32 | language='c++', 33 | library_dirs=['./build/'], 34 | libraries=['m', "fusion_cpu", "fusion_gpu"], 35 | include_dirs=[np.get_include()], 36 | extra_compile_args=extra_compile_args, 37 | extra_link_args=extra_link_args 38 | ) 39 | ] 40 | ) 41 | -------------------------------------------------------------------------------- /external/pyrender/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | pyrender.cpp 3 | *.so 4 | -------------------------------------------------------------------------------- /external/pyrender/README.md: -------------------------------------------------------------------------------- 1 | # PyRender 2 | 3 | This project contains a Cython version of [librender by Andreas Geiger and Chaohui Wang 2014](http://www.cvlibs.net/software/librender/). 4 | The code enables the efficient rendering of depth maps from 3D triangle meshes. 5 | 6 | To use the code, first compile the Cython code via 7 | 8 | ```bash 9 | python setup.py build_ext --inplace 10 | ``` 11 | 12 | You can then use the rendering function 13 | 14 | ```python 15 | import pyrender 16 | ... 17 | # vertices: a Nx3 double numpy array 18 | # faces: a Nx3 int array (indices of vertices array) 19 | # cam_intr: (fx, fy, px, py) double vector 20 | # img_size: (height, width) int vector 21 | depth, mask = pyrender.render(vertices, faces, cam_intr, img_size) 22 | ``` 23 | 24 | Make sure `pyrender` is in your `$PYTHONPATH`. 25 | -------------------------------------------------------------------------------- /external/pyrender/offscreen.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBRENDER_OFFSCREEN_H 2 | #define LIBRENDER_OFFSCREEN_H 3 | 4 | #include 5 | #if defined(__APPLE__) 6 | #include 7 | #include 8 | #else 9 | #include 10 | #include 11 | #endif 12 | #include 13 | 14 | class OffscreenGL { 15 | 16 | public: 17 | OffscreenGL(int maxHeight, int maxWidth); 18 | ~OffscreenGL(); 19 | 20 | private: 21 | static int glutWin; 22 | static bool glutInitialized; 23 | GLuint fb; 24 | GLuint renderTex; 25 | GLuint depthTex; 26 | }; 27 | 28 | 29 | void renderDepthMesh(int *FM, int fNum, double *VM, int vNum, double *intrinsics, int *imgSizeV, double *zNearFarV, float *depthBuffer); 30 | 31 | #endif 32 | -------------------------------------------------------------------------------- /external/pyrender/pyrender.pyx: -------------------------------------------------------------------------------- 1 | cimport cython 2 | import numpy as np 3 | cimport numpy as np 4 | 5 | from libc.stdlib cimport free, malloc 6 | from libcpp cimport bool 7 | from cpython cimport PyObject, Py_INCREF 8 | 9 | CREATE_INIT = True # workaround, so cython builds a init function 10 | 11 | np.import_array() 12 | 13 | 14 | cdef extern from "offscreen.h": 15 | void renderDepthMesh(int *FM, int fNum, double *VM, int vNum, double *intrinsics, int *imgSizeV, double *zNearFarV, float *depthBuffer); 16 | 17 | 18 | def render(double[:,::1] vertices, int[:,::1] faces, double[::1] cam_intr, int[::1] img_size): 19 | if vertices.shape[1] != 3: 20 | raise Exception('vertices must be a Mx3 double array') 21 | if faces.shape[1] != 3: 22 | raise Exception('faces must be a Mx3 int array') 23 | if cam_intr.shape[0] != 4: 24 | raise Exception('cam_intr must be a 4x1 double vector') 25 | if img_size.shape[0] != 2: 26 | raise Exception('img_size must be a 2x1 int vector') 27 | 28 | cdef double* VM = &(vertices[0,0]) 29 | cdef int vNum = vertices.shape[0] 30 | cdef int* FM = &(faces[0,0]) 31 | cdef int fNum = faces.shape[0] 32 | cdef double* intrinsics = &(cam_intr[0]) 33 | cdef int* imgSize = &(img_size[0]) 34 | 35 | cdef double znf[2] 36 | znf[0] = 1e10 37 | znf[1] = -1e10 38 | cdef double z 39 | for i in range(vNum): 40 | z = VM[2*vNum+i] 41 | if (zznf[1]): 44 | znf[1] = z 45 | 46 | znf[0] -= 0.1; 47 | znf[1] += 0.1; 48 | znf[0] = max(znf[0],0.1); 49 | znf[1] = max(znf[1],znf[0]+0.1); 50 | 51 | depth = np.empty((img_size[0], img_size[1]), dtype=np.float32) 52 | cdef float[:,::1] depth_view = depth 53 | cdef float* depthBuffer = &(depth_view[0,0]) 54 | 55 | renderDepthMesh(FM, fNum, VM, vNum, intrinsics, imgSize, znf, depthBuffer); 56 | 57 | return depth 58 | -------------------------------------------------------------------------------- /external/pyrender/setup.py: -------------------------------------------------------------------------------- 1 | from distutils.core import setup 2 | from Cython.Build import cythonize 3 | from distutils.extension import Extension 4 | from Cython.Distutils import build_ext 5 | import numpy as np 6 | import platform 7 | 8 | extra_compile_args = ['-O3', '-std=c++11'] 9 | extra_link_args = ['-lGLEW', '-lglut'] 10 | 11 | if platform.system() == 'Darwin': 12 | extra_link_args.append('-F/System/Library/Frameworks') 13 | extra_compile_args.append('-stdlib=libc++') 14 | extra_link_args.append('-stdlib=libc++') 15 | else: 16 | extra_link_args.append('-lGL') 17 | extra_link_args.append('-lGLU') 18 | extra_link_args.append('-fopenmp') 19 | extra_compile_args.append('-fopenmp') 20 | 21 | setup( 22 | name="pyrender", 23 | cmdclass= {'build_ext': build_ext}, 24 | ext_modules=[ 25 | Extension('pyrender', 26 | ['pyrender.pyx', 27 | 'offscreen.cpp', 28 | ], 29 | language='c++', 30 | include_dirs=[np.get_include(),], 31 | extra_compile_args=extra_compile_args, 32 | extra_link_args=extra_link_args 33 | ) 34 | ] 35 | ) 36 | 37 | 38 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | # Main file for training and testing 2 | # author: ynie 3 | # date: July, 2020 4 | 5 | import argparse 6 | from configs.config_utils import CONFIG 7 | 8 | def parse_args(): 9 | '''PARAMETERS''' 10 | parser = argparse.ArgumentParser('Instance Scene Completion.') 11 | parser.add_argument('--config', type=str, default='configs/config_files/ISCNet.yaml', 12 | help='configure file for training or testing.') 13 | parser.add_argument('--mode', type=str, default='train', help='train, test or demo.') 14 | parser.add_argument('--demo_path', type=str, default='demo/inputs/scene0549_00.off', help='Please specify the demo path.') 15 | return parser.parse_args() 16 | 17 | if __name__ == '__main__': 18 | args = parse_args() 19 | cfg = CONFIG(args.config) 20 | cfg.update_config(args.__dict__) 21 | from net_utils.utils import initiate_environment 22 | initiate_environment(cfg.config) 23 | 24 | '''Configuration''' 25 | cfg.log_string('Loading configurations.') 26 | cfg.log_string(cfg.config) 27 | cfg.write_config() 28 | 29 | '''Run''' 30 | if cfg.config['mode'] == 'train': 31 | import train 32 | train.run(cfg) 33 | if cfg.config['mode'] == 'test': 34 | import test 35 | test.run(cfg) 36 | if cfg.config['mode'] == 'demo': 37 | import demo 38 | demo.run(cfg) 39 | 40 | -------------------------------------------------------------------------------- /models/__init__.py: -------------------------------------------------------------------------------- 1 | from . import iscnet 2 | from . import loss 3 | 4 | method_paths = { 5 | 'ISCNet': iscnet 6 | } 7 | 8 | __all__ = ['method_paths'] -------------------------------------------------------------------------------- /models/datasets.py: -------------------------------------------------------------------------------- 1 | # Base data of networks 2 | # author: ynie 3 | # date: Feb, 2020 4 | import os 5 | from torch.utils.data import Dataset 6 | import json 7 | from utils.read_and_write import read_json 8 | 9 | class ScanNet(Dataset): 10 | def __init__(self, cfg, mode): 11 | ''' 12 | initiate SUNRGBD dataset for data loading 13 | :param cfg: config file 14 | :param mode: train/val/test mode 15 | ''' 16 | self.config = cfg.config 17 | self.dataset_config = cfg.dataset_config 18 | self.mode = mode 19 | split_file = os.path.join(cfg.config['data']['split'], 'scannetv2_' + mode + '.json') 20 | self.split = read_json(split_file) 21 | 22 | def __len__(self): 23 | return len(self.split) -------------------------------------------------------------------------------- /models/iscnet/__init__.py: -------------------------------------------------------------------------------- 1 | from . import modules, training, config, dataloader 2 | 3 | __all__ = ['modules', 'training', 'config', 'dataloader'] -------------------------------------------------------------------------------- /models/iscnet/config.py: -------------------------------------------------------------------------------- 1 | # Configure trainer and tester 2 | # author: ynie 3 | # date: Feb, 2020 4 | from .dataloader import ISCNet_dataloader 5 | from .testing import Tester 6 | from .training import Trainer 7 | 8 | 9 | def get_trainer(cfg, net, optimizer, device=None): 10 | return Trainer(cfg=cfg, net=net, optimizer=optimizer, device=device) 11 | 12 | 13 | def get_tester(cfg, net, device=None): 14 | return Tester(cfg=cfg, net=net, device=device) 15 | 16 | 17 | def get_dataloader(cfg, mode): 18 | return ISCNet_dataloader(cfg=cfg, mode=mode) 19 | -------------------------------------------------------------------------------- /models/iscnet/modules/__init__.py: -------------------------------------------------------------------------------- 1 | from .network import ISCNet 2 | from .pointnet2backbone import Pointnet2Backbone 3 | from .proposal_module import ProposalModule 4 | from .vote_module import VotingModule 5 | from .occupancy_net import ONet 6 | from .skip_propagation import SkipPropagation 7 | 8 | __all__ = ['ISCNet', 'Pointnet2Backbone', 'ProposalModule', 'VotingModule', 'ONet', 'SkipPropagation'] -------------------------------------------------------------------------------- /models/iscnet/modules/encoder_latent.py: -------------------------------------------------------------------------------- 1 | import torch 2 | import torch.nn as nn 3 | import torch.nn.functional as F 4 | 5 | 6 | # Max Pooling operation 7 | def maxpool(x, dim=-1, keepdim=False): 8 | out, _ = x.max(dim=dim, keepdim=keepdim) 9 | return out 10 | 11 | 12 | class Encoder_Latent(nn.Module): 13 | ''' Latent encoder class. 14 | 15 | It encodes the input points and returns mean and standard deviation for the 16 | posterior Gaussian distribution. 17 | 18 | Args: 19 | z_dim (int): dimension if output code z 20 | c_dim (int): dimension of latent conditioned code c 21 | dim (int): input dimension 22 | leaky (bool): whether to use leaky ReLUs 23 | ''' 24 | def __init__(self, z_dim=128, c_dim=128, dim=3, leaky=False): 25 | super().__init__() 26 | self.z_dim = z_dim 27 | self.c_dim = c_dim 28 | 29 | # Submodules 30 | self.fc_pos = nn.Linear(dim, 128) 31 | 32 | if c_dim != 0: 33 | self.fc_c = nn.Linear(c_dim, 128) 34 | 35 | self.fc_0 = nn.Linear(1, 128) 36 | self.fc_1 = nn.Linear(128, 128) 37 | self.fc_2 = nn.Linear(256, 128) 38 | self.fc_3 = nn.Linear(256, 128) 39 | self.fc_mean = nn.Linear(128, z_dim) 40 | self.fc_logstd = nn.Linear(128, z_dim) 41 | 42 | if not leaky: 43 | self.actvn = F.relu 44 | self.pool = maxpool 45 | else: 46 | self.actvn = lambda x: F.leaky_relu(x, 0.2) 47 | self.pool = torch.mean 48 | 49 | def forward(self, p, x, c=None, **kwargs): 50 | # output size: B x T X F 51 | net = self.fc_0(x.unsqueeze(-1)) 52 | net = net + self.fc_pos(p) 53 | 54 | if self.c_dim != 0: 55 | net = net + self.fc_c(c).unsqueeze(1) 56 | 57 | net = self.fc_1(self.actvn(net)) 58 | pooled = self.pool(net, dim=1, keepdim=True).expand(net.size()) 59 | net = torch.cat([net, pooled], dim=2) 60 | 61 | net = self.fc_2(self.actvn(net)) 62 | pooled = self.pool(net, dim=1, keepdim=True).expand(net.size()) 63 | net = torch.cat([net, pooled], dim=2) 64 | 65 | net = self.fc_3(self.actvn(net)) 66 | # Reduce 67 | # to B x F 68 | net = self.pool(net, dim=1) 69 | 70 | mean = self.fc_mean(net) 71 | logstd = self.fc_logstd(net) 72 | 73 | return mean, logstd 74 | -------------------------------------------------------------------------------- /models/iscnet/modules/occ_decoder.py: -------------------------------------------------------------------------------- 1 | import torch.nn as nn 2 | from .layers import ( 3 | CResnetBlockConv1d, 4 | CBatchNorm1d, CBatchNorm1d_legacy, 5 | ) 6 | import torch.nn.functional as F 7 | from models.iscnet.modules.layers import ResnetBlockFC 8 | 9 | class SimpleDecoder(nn.Module): 10 | ''' Decoder class. 11 | 12 | It does not perform any form of normalization. 13 | 14 | Args: 15 | dim (int): input dimension 16 | z_dim (int): dimension of latent code z 17 | c_dim (int): dimension of latent conditioned code c 18 | hidden_size (int): hidden size of Decoder network 19 | leaky (bool): whether to use leaky ReLUs 20 | ''' 21 | 22 | def __init__(self, dim=3, z_dim=128, c_dim=128, 23 | hidden_size=128, leaky=False): 24 | super().__init__() 25 | self.z_dim = z_dim 26 | self.c_dim = c_dim 27 | 28 | # Submodules 29 | self.fc_p = nn.Linear(dim, hidden_size) 30 | 31 | if not z_dim == 0: 32 | self.fc_z = nn.Linear(z_dim, hidden_size) 33 | 34 | if not c_dim == 0: 35 | self.fc_c = nn.Linear(c_dim, hidden_size) 36 | 37 | self.block0 = ResnetBlockFC(hidden_size) 38 | self.block1 = ResnetBlockFC(hidden_size) 39 | self.block2 = ResnetBlockFC(hidden_size) 40 | self.block3 = ResnetBlockFC(hidden_size) 41 | self.block4 = ResnetBlockFC(hidden_size) 42 | 43 | self.fc_out = nn.Linear(hidden_size, 1) 44 | 45 | if not leaky: 46 | self.actvn = F.relu 47 | else: 48 | self.actvn = lambda x: F.leaky_relu(x, 0.2) 49 | 50 | def forward(self, p, z, c=None, **kwargs): 51 | net = self.fc_p(p) 52 | 53 | if self.z_dim != 0: 54 | net_z = self.fc_z(z).unsqueeze(1) 55 | net = net + net_z 56 | 57 | if self.c_dim != 0: 58 | net_c = self.fc_c(c).unsqueeze(1) 59 | net = net + net_c 60 | 61 | net = self.block0(net) 62 | net = self.block1(net) 63 | net = self.block2(net) 64 | net = self.block3(net) 65 | net = self.block4(net) 66 | 67 | out = self.fc_out(self.actvn(net)) 68 | out = out.squeeze(-1) 69 | 70 | return out 71 | 72 | class DecoderCBatchNorm(nn.Module): 73 | ''' Decoder with conditional batch normalization (CBN) class. 74 | 75 | Args: 76 | dim (int): input dimension 77 | z_dim (int): dimension of latent code z 78 | c_dim (int): dimension of latent conditioned code c 79 | hidden_size (int): hidden size of Decoder network 80 | n_blocks (int): number of CResNet blocks. 81 | leaky (bool): whether to use leaky ReLUs 82 | legacy (bool): whether to use the legacy structure 83 | ''' 84 | 85 | def __init__(self, dim=3, z_dim=128, c_dim=128, 86 | hidden_size=256, n_blocks=5, leaky=False, legacy=False): 87 | super().__init__() 88 | self.z_dim = z_dim 89 | if not z_dim == 0: 90 | self.fc_z = nn.Linear(z_dim, hidden_size) 91 | 92 | self.fc_p = nn.Conv1d(dim, hidden_size, 1) 93 | 94 | self.blocks = nn.ModuleList([ 95 | CResnetBlockConv1d(c_dim, hidden_size) for i in range(n_blocks) 96 | ]) 97 | 98 | if not legacy: 99 | self.bn = CBatchNorm1d(c_dim, hidden_size) 100 | else: 101 | self.bn = CBatchNorm1d_legacy(c_dim, hidden_size) 102 | 103 | self.fc_out = nn.Conv1d(hidden_size, 1, 1) 104 | 105 | if not leaky: 106 | self.actvn = nn.ReLU(inplace=True) 107 | else: 108 | self.actvn = nn.LeakyReLU(0.2, inplace=True) 109 | 110 | def forward(self, p, z, c, **kwargs): 111 | p = p.transpose(1, 2) 112 | net = self.fc_p(p) 113 | 114 | if self.z_dim != 0: 115 | net = net + self.fc_z(z).unsqueeze(2) 116 | 117 | for block in self.blocks: 118 | net = block(net, c) 119 | 120 | out = self.fc_out(self.actvn(self.bn(net, c))) 121 | out = out.squeeze(1) 122 | 123 | return out -------------------------------------------------------------------------------- /models/iscnet/modules/pointnet2backbone.py: -------------------------------------------------------------------------------- 1 | # pointnet backbone 2 | # author: ynie 3 | # date: March, 2020 4 | # cite: VoteNet 5 | import torch 6 | import torch.nn as nn 7 | from models.registers import MODULES 8 | from external.pointnet2_ops_lib.pointnet2_ops.pointnet2_modules import PointnetSAModuleVotes, PointnetFPModule 9 | 10 | @MODULES.register_module 11 | class Pointnet2Backbone(nn.Module): 12 | def __init__(self, cfg, optim_spec = None): 13 | ''' 14 | Skeleton Extraction Net to obtain partial skeleton from a partial scan (refer to PointNet++). 15 | :param cfg: configuration file. 16 | :param optim_spec: optimizer parameters. 17 | ''' 18 | super(Pointnet2Backbone, self).__init__() 19 | 20 | '''Optimizer parameters used in training''' 21 | self.optim_spec = optim_spec 22 | 23 | '''Network parameters''' 24 | self.input_feature_dim = int(cfg.config['data']['use_color_detection']) * 3 + int(not cfg.config['data']['no_height']) * 1 25 | 26 | '''Modules''' 27 | self.sa1 = PointnetSAModuleVotes( 28 | npoint=2048, 29 | radius=0.2, 30 | nsample=64, 31 | mlp=[self.input_feature_dim, 64, 64, 128], 32 | use_xyz=True, 33 | normalize_xyz=True 34 | ) 35 | 36 | self.sa2 = PointnetSAModuleVotes( 37 | npoint=1024, 38 | radius=0.4, 39 | nsample=32, 40 | mlp=[128, 128, 128, 256], 41 | use_xyz=True, 42 | normalize_xyz=True 43 | ) 44 | 45 | self.sa3 = PointnetSAModuleVotes( 46 | npoint=512, 47 | radius=0.8, 48 | nsample=16, 49 | mlp=[256, 128, 128, 256], 50 | use_xyz=True, 51 | normalize_xyz=True 52 | ) 53 | 54 | self.sa4 = PointnetSAModuleVotes( 55 | npoint=256, 56 | radius=1.2, 57 | nsample=16, 58 | mlp=[256, 128, 128, 256], 59 | use_xyz=True, 60 | normalize_xyz=True 61 | ) 62 | 63 | self.fp1 = PointnetFPModule(mlp=[256+256,256,256]) 64 | self.fp2 = PointnetFPModule(mlp=[256+256,256,256]) 65 | 66 | def _break_up_pc(self, pc): 67 | xyz = pc[..., 0:3].contiguous() 68 | features = ( 69 | pc[..., 3:3+self.input_feature_dim].transpose(1, 2).contiguous() 70 | if pc.size(-1) > 3 else None 71 | ) 72 | 73 | return xyz, features 74 | 75 | def forward(self, pointcloud: torch.cuda.FloatTensor, end_points=None): 76 | r""" 77 | Forward pass of the network 78 | 79 | Parameters 80 | ---------- 81 | pointcloud: Variable(torch.cuda.FloatTensor) 82 | (B, N, 3 + input_feature_dim) tensor 83 | Point cloud to run predicts on 84 | Each point in the point-cloud MUST 85 | be formated as (x, y, z, features...) 86 | 87 | Returns 88 | ---------- 89 | end_points: {XXX_xyz, XXX_features, XXX_inds} 90 | XXX_xyz: float32 Tensor of shape (B,K,3) 91 | XXX_features: float32 Tensor of shape (B,K,D) 92 | XXX-inds: int64 Tensor of shape (B,K) values in [0,N-1] 93 | """ 94 | if not end_points: end_points = {} 95 | 96 | xyz, features = self._break_up_pc(pointcloud) 97 | 98 | # --------- 4 SET ABSTRACTION LAYERS --------- 99 | xyz, features, fps_inds = self.sa1(xyz, features) 100 | end_points['sa1_inds'] = fps_inds 101 | end_points['sa1_xyz'] = xyz 102 | end_points['sa1_features'] = features 103 | 104 | xyz, features, fps_inds = self.sa2(xyz, features) # this fps_inds is just 0,1,...,1023 105 | end_points['sa2_inds'] = fps_inds 106 | end_points['sa2_xyz'] = xyz 107 | end_points['sa2_features'] = features 108 | 109 | xyz, features, fps_inds = self.sa3(xyz, features) # this fps_inds is just 0,1,...,511 110 | end_points['sa3_xyz'] = xyz 111 | end_points['sa3_features'] = features 112 | 113 | xyz, features, fps_inds = self.sa4(xyz, features) # this fps_inds is just 0,1,...,255 114 | end_points['sa4_xyz'] = xyz 115 | end_points['sa4_features'] = features 116 | 117 | # --------- 2 FEATURE UPSAMPLING LAYERS -------- 118 | features = self.fp1(end_points['sa3_xyz'], end_points['sa4_xyz'], end_points['sa3_features'], 119 | end_points['sa4_features']) 120 | features = self.fp2(end_points['sa2_xyz'], end_points['sa3_xyz'], end_points['sa2_features'], features) 121 | end_points['fp2_features'] = features 122 | end_points['fp2_xyz'] = end_points['sa2_xyz'] 123 | num_seed = end_points['fp2_xyz'].shape[1] 124 | end_points['fp2_inds'] = end_points['sa1_inds'][:, 0:num_seed] # indices among the entire input point clouds 125 | return end_points 126 | 127 | -------------------------------------------------------------------------------- /models/iscnet/modules/vote_module.py: -------------------------------------------------------------------------------- 1 | # pointnet backbone 2 | # author: ynie 3 | # date: March, 2020 4 | # cite: VoteNet 5 | import torch 6 | import torch.nn as nn 7 | from models.registers import MODULES 8 | import torch.nn.functional as F 9 | 10 | 11 | @MODULES.register_module 12 | class VotingModule(nn.Module): 13 | def __init__(self, cfg, optim_spec = None): 14 | ''' 15 | Skeleton Extraction Net to obtain partial skeleton from a partial scan (refer to PointNet++). 16 | :param config: configuration file. 17 | :param optim_spec: optimizer parameters. 18 | ''' 19 | super(VotingModule, self).__init__() 20 | 21 | '''Optimizer parameters used in training''' 22 | self.optim_spec = optim_spec 23 | 24 | '''Modules''' 25 | self.vote_factor = cfg.config['data']['vote_factor'] 26 | self.in_dim = 256 27 | self.out_dim = self.in_dim # due to residual feature, in_dim has to be == out_dim 28 | self.conv1 = torch.nn.Conv1d(self.in_dim, self.in_dim, 1) 29 | self.conv2 = torch.nn.Conv1d(self.in_dim, self.in_dim, 1) 30 | self.conv3 = torch.nn.Conv1d(self.in_dim, (3+self.out_dim) * self.vote_factor, 1) 31 | self.bn1 = torch.nn.BatchNorm1d(self.in_dim) 32 | self.bn2 = torch.nn.BatchNorm1d(self.in_dim) 33 | 34 | def forward(self, seed_xyz, seed_features): 35 | """ Forward pass. 36 | 37 | Arguments: 38 | seed_xyz: (batch_size, num_seed, 3) Pytorch tensor 39 | seed_features: (batch_size, feature_dim, num_seed) Pytorch tensor 40 | Returns: 41 | vote_xyz: (batch_size, num_seed*vote_factor, 3) 42 | vote_features: (batch_size, vote_feature_dim, num_seed*vote_factor) 43 | """ 44 | batch_size = seed_xyz.shape[0] 45 | num_seed = seed_xyz.shape[1] 46 | num_vote = num_seed * self.vote_factor 47 | net = F.relu(self.bn1(self.conv1(seed_features))) 48 | net = F.relu(self.bn2(self.conv2(net))) 49 | net = self.conv3(net) # (batch_size, (3+out_dim)*vote_factor, num_seed) 50 | 51 | net = net.transpose(2, 1).view(batch_size, num_seed, self.vote_factor, 3 + self.out_dim) 52 | offset = net[:, :, :, 0:3] 53 | vote_xyz = seed_xyz.unsqueeze(2) + offset 54 | vote_xyz = vote_xyz.contiguous().view(batch_size, num_vote, 3) 55 | 56 | residual_features = net[:, :, :, 3:] # (batch_size, num_seed, vote_factor, out_dim) 57 | vote_features = seed_features.transpose(2, 1).unsqueeze(2) + residual_features 58 | vote_features = vote_features.contiguous().view(batch_size, num_vote, self.out_dim) 59 | vote_features = vote_features.transpose(2, 1).contiguous() 60 | 61 | return vote_xyz, vote_features 62 | 63 | -------------------------------------------------------------------------------- /models/iscnet/training.py: -------------------------------------------------------------------------------- 1 | # Trainer for Total3D. 2 | # author: ynie 3 | # date: Feb, 2020 4 | from models.training import BaseTrainer 5 | import torch 6 | import numpy as np 7 | import os 8 | from net_utils import visualization as vis 9 | 10 | class Trainer(BaseTrainer): 11 | ''' 12 | Trainer object for total3d. 13 | ''' 14 | 15 | def eval_step(self, data): 16 | ''' 17 | performs a step in evaluation 18 | :param data (dict): data dictionary 19 | :return: 20 | ''' 21 | loss = self.compute_loss(data) 22 | loss['total'] = loss['total'].item() 23 | return loss 24 | 25 | def visualize_step(self, epoch, phase, iter, data): 26 | ''' Performs a visualization step. 27 | ''' 28 | '''load input and ground-truth data''' 29 | data = self.to_device(data) 30 | 31 | with torch.no_grad(): 32 | '''network forwarding''' 33 | est_data = self.net({**data, 'export_shape':True}) 34 | voxels_out, proposal_to_gt_box_w_cls_list = est_data[2:4] 35 | 36 | if proposal_to_gt_box_w_cls_list is None: 37 | return 38 | 39 | sample_ids = np.random.choice(voxels_out.shape[0], 3, replace=False) if voxels_out.shape[0]>=3 else range(voxels_out.shape[0]) 40 | n_shapes_per_batch = self.cfg.config['data']['completion_limit_in_train'] 41 | for idx, i in enumerate(sample_ids): 42 | voxel_path = os.path.join(self.cfg.config['log']['vis_path'], '%s_%s_%s_%03d_pred.png' % (epoch, phase, iter, idx)) 43 | vis.visualize_voxels(voxels_out[i].cpu().numpy(), voxel_path) 44 | 45 | batch_index = i // n_shapes_per_batch 46 | in_batch_id = i % n_shapes_per_batch 47 | box_id = proposal_to_gt_box_w_cls_list[batch_index][in_batch_id][1].item() 48 | cls_id = proposal_to_gt_box_w_cls_list[batch_index][in_batch_id][2].item() 49 | 50 | voxels_gt = data['object_voxels'][batch_index][box_id].cpu().numpy() 51 | voxel_path = os.path.join(self.cfg.config['log']['vis_path'], '%s_%s_%s_%03d_gt_cls%d.png' % (epoch, phase, iter, idx, cls_id)) 52 | vis.visualize_voxels(voxels_gt, voxel_path) 53 | 54 | def to_device(self, data): 55 | device = self.device 56 | for key in data: 57 | if key not in ['object_voxels', 'shapenet_catids', 'shapenet_ids']: 58 | data[key] = data[key].to(device) 59 | return data 60 | 61 | def compute_loss(self, data): 62 | ''' 63 | compute the overall loss. 64 | :param data (dict): data dictionary 65 | :return: 66 | ''' 67 | '''load input and ground-truth data''' 68 | data = self.to_device(data) 69 | 70 | '''network forwarding''' 71 | est_data = self.net(data) 72 | 73 | '''computer losses''' 74 | loss = self.net.module.loss(est_data, data) 75 | return loss 76 | -------------------------------------------------------------------------------- /models/network.py: -------------------------------------------------------------------------------- 1 | # Base Network for other networks. 2 | # author: ynie 3 | # date: Feb, 2020 4 | 5 | from models.registers import MODULES, LOSSES 6 | import torch.nn as nn 7 | 8 | def multi_getattr(layer, attr, default=None): 9 | attributes = attr.split(".") 10 | for i in attributes: 11 | try: 12 | layer = getattr(layer, i) 13 | except AttributeError: 14 | if default: 15 | return default 16 | else: 17 | raise 18 | return layer 19 | 20 | def multi_hasattr(layer, attr): 21 | attributes = attr.split(".") 22 | hasattr_flag = True 23 | for i in attributes: 24 | if hasattr(layer, i): 25 | layer = getattr(layer, i) 26 | else: 27 | hasattr_flag = False 28 | return hasattr_flag 29 | 30 | class BaseNetwork(nn.Module): 31 | ''' 32 | Base Network Module for other networks 33 | ''' 34 | def __init__(self, cfg): 35 | ''' 36 | load submodules for the network. 37 | :param config: customized configurations. 38 | ''' 39 | super(BaseNetwork, self).__init__() 40 | self.cfg = cfg 41 | 42 | '''load network blocks''' 43 | for phase_name, net_spec in cfg.config['model'].items(): 44 | method_name = net_spec['method'] 45 | # load specific optimizer parameters 46 | optim_spec = self.load_optim_spec(cfg.config, net_spec) 47 | subnet = MODULES.get(method_name)(cfg.config, optim_spec) 48 | self.add_module(phase_name, subnet) 49 | 50 | '''load corresponding loss functions''' 51 | setattr(self, phase_name + '_loss', LOSSES.get(self.cfg.config['model'][phase_name]['loss'], 'Null')( 52 | self.cfg.config['model'][phase_name].get('weight', 1))) 53 | 54 | '''freeze submodules or not''' 55 | self.freeze_modules(cfg) 56 | 57 | def freeze_modules(self, cfg): 58 | ''' 59 | Freeze modules in training 60 | ''' 61 | if cfg.config['mode'] == 'train': 62 | freeze_layers = cfg.config['train']['freeze'] 63 | for layer in freeze_layers: 64 | if not multi_hasattr(self, layer): 65 | continue 66 | for param in multi_getattr(self, layer).parameters(): 67 | param.requires_grad = False 68 | cfg.log_string('The module: %s is fixed.' % (layer)) 69 | 70 | def set_mode(self): 71 | ''' 72 | Set train/eval mode for the network. 73 | :param phase: train or eval 74 | :return: 75 | ''' 76 | freeze_layers = self.cfg.config['train']['freeze'] 77 | for name, child in self.named_children(): 78 | if name in freeze_layers: 79 | child.train(False) 80 | 81 | def load_weight(self, pretrained_model): 82 | model_dict = self.state_dict() 83 | # remove the 'module' string. 84 | pretrained_dict = {'.'.join(k.split('.')[1:]): v for k, v in pretrained_model.items() if 85 | '.'.join(k.split('.')[1:]) in model_dict} 86 | self.cfg.log_string( 87 | str(set([key.split('.')[0] for key in model_dict if key not in pretrained_dict])) + ' subnet missed.') 88 | model_dict.update(pretrained_dict) 89 | self.load_state_dict(model_dict) 90 | 91 | def load_optim_spec(self, config, net_spec): 92 | # load specific optimizer parameters 93 | if config['mode'] == 'train': 94 | if 'optimizer' in net_spec.keys(): 95 | optim_spec = net_spec['optimizer'] 96 | else: 97 | optim_spec = config['optimizer'] # else load default optimizer 98 | else: 99 | optim_spec = None 100 | 101 | return optim_spec 102 | 103 | def forward(self, *args, **kwargs): 104 | ''' Performs a forward step. 105 | ''' 106 | raise NotImplementedError 107 | 108 | def loss(self, *args, **kwargs): 109 | ''' calculate losses. 110 | ''' 111 | raise NotImplementedError -------------------------------------------------------------------------------- /models/optimizers.py: -------------------------------------------------------------------------------- 1 | # Optimizer definitions 2 | # author: ynie 3 | # date: Feb, 2020 4 | import torch 5 | from external.pointnet2_ops_lib.pointnet2_ops.pytorch_utils import BNMomentumScheduler 6 | 7 | def has_optim_in_children(subnet): 8 | ''' 9 | check if there is specific optim parameters in a subnet. 10 | :param subnet: 11 | :return: 12 | ''' 13 | label = False 14 | for module in subnet.children(): 15 | if hasattr(module, 'optim_spec') and module.optim_spec: 16 | label = True 17 | break 18 | else: 19 | label = has_optim_in_children(module) 20 | 21 | return label 22 | 23 | def find_optim_module(net): 24 | ''' 25 | classify modules in a net into has specific optim specs or not. 26 | :param net: 27 | :return: 28 | ''' 29 | module_optim_pairs = [] 30 | other_modules = [] 31 | for module in net.children(): 32 | if hasattr(module, 'optim_spec'): 33 | module_optim_pairs += [{'module':module, 'optim_spec':module.optim_spec}] 34 | elif not has_optim_in_children(module): 35 | other_modules += [module] 36 | else: 37 | module_optim_pairs += find_optim_module(module)[0] 38 | other_modules += find_optim_module(module)[1] 39 | 40 | return module_optim_pairs, other_modules 41 | 42 | def load_scheduler(config, optimizer): 43 | ''' 44 | get scheduler for optimizer. 45 | :param config: configuration file 46 | :param optimizer: torch optimizer 47 | :return: 48 | ''' 49 | scheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode='min', 50 | factor=float(config['scheduler']['factor']), 51 | patience=config['scheduler']['patience'], 52 | threshold=float(config['scheduler']['threshold']), 53 | verbose=True) 54 | return scheduler 55 | 56 | def load_bnm_scheduler(cfg, net, start_epoch): 57 | bn_lbmd = lambda it: max(cfg.config['bnscheduler']['bn_momentum_init'] * cfg.config['bnscheduler']['bn_decay_rate'] ** ( 58 | int(it / cfg.config['bnscheduler']['bn_decay_step'])), cfg.config['bnscheduler']['bn_momentum_max']) 59 | bnm_scheduler = BNMomentumScheduler(cfg, net, bn_lambda=bn_lbmd, last_epoch=start_epoch - 1) 60 | return bnm_scheduler 61 | 62 | def load_optimizer(config, net): 63 | ''' 64 | get optimizer for networks 65 | :param config: configuration file 66 | :param model: nn.Module network 67 | :return: 68 | ''' 69 | 70 | module_optim_pairs, other_modules = find_optim_module(net) 71 | default_optim_spec = config['optimizer'] 72 | 73 | optim_params = [] 74 | 75 | if config['optimizer']['method'] == 'Adam': 76 | '''collect parameters with specific optimizer spec''' 77 | for module in module_optim_pairs: 78 | optim_params.append({'params': filter(lambda p: p.requires_grad, module['module'].parameters()), 79 | 'lr': float(module['optim_spec']['lr']), 80 | 'betas': tuple(module['optim_spec']['betas']), 81 | 'eps': float(module['optim_spec']['eps']), 82 | 'weight_decay': float(module['optim_spec']['weight_decay'])}) 83 | 84 | '''collect parameters with default optimizer spec''' 85 | other_params = list() 86 | for module in other_modules: 87 | other_params += list(module.parameters()) 88 | 89 | optim_params.append({'params': filter(lambda p: p.requires_grad, other_params)}) 90 | 91 | '''define optimizer''' 92 | optimizer = torch.optim.Adam(optim_params, 93 | lr=float(default_optim_spec['lr']), 94 | betas=tuple(default_optim_spec['betas']), 95 | eps=float(default_optim_spec['eps']), 96 | weight_decay=float(default_optim_spec['weight_decay'])) 97 | 98 | else: 99 | # use SGD optimizer. 100 | for module in module_optim_pairs: 101 | optim_params.append({'params': filter(lambda p: p.requires_grad, module['module'].parameters()), 102 | 'lr': float(module['optim_spec']['lr'])}) 103 | 104 | other_params = list() 105 | for module in other_modules: 106 | other_params += list(module.parameters()) 107 | 108 | optim_params.append({'params': filter(lambda p: p.requires_grad, other_params)}) 109 | optimizer = torch.optim.SGD(optim_params, 110 | lr=config['optimizer']['lr'], 111 | momentum=0.9) 112 | 113 | return optimizer 114 | -------------------------------------------------------------------------------- /models/registers.py: -------------------------------------------------------------------------------- 1 | # Register different methods, and relevant modules 2 | # author: ynie 3 | # date: Feb, 2020 4 | 5 | from net_utils.registry import Registry 6 | 7 | METHODS = Registry('method') 8 | MODULES = Registry('module') 9 | LOSSES = Registry('loss') -------------------------------------------------------------------------------- /models/testing.py: -------------------------------------------------------------------------------- 1 | # Base tester for methods. 2 | # author: ynie 3 | # date: April, 2020 4 | 5 | class BaseTester(object): 6 | ''' 7 | Base tester for all networks. 8 | ''' 9 | def __init__(self, cfg, net, device=None): 10 | self.cfg = cfg 11 | self.net = net 12 | self.device = device 13 | 14 | def visualize_step(self, *args, **kwargs): 15 | ''' Performs a visualization step. 16 | ''' 17 | raise NotImplementedError 18 | 19 | def get_metric_values(self, est_data, gt_data): 20 | ''' Performs a evaluation step. 21 | ''' 22 | # camera orientation error 23 | raise NotImplementedError 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /models/training.py: -------------------------------------------------------------------------------- 1 | # Base trainer for methods. 2 | # author: ynie 3 | # date: Feb, 2020 4 | 5 | class BaseTrainer(object): 6 | ''' 7 | Base trainer for all networks. 8 | ''' 9 | def __init__(self, cfg, net, optimizer, device=None): 10 | self.cfg = cfg 11 | self.net = net 12 | self.optimizer = optimizer 13 | self.device = device 14 | 15 | def show_lr(self): 16 | ''' 17 | display current learning rates 18 | :return: 19 | ''' 20 | lrs = [self.optimizer.param_groups[i]['lr'] for i in range(len(self.optimizer.param_groups))] 21 | self.cfg.log_string('Current learning rates are: ' + str(lrs) + '.') 22 | 23 | def train_step(self, data): 24 | ''' 25 | performs a step training 26 | :param data (dict): data dictionary 27 | :return: 28 | ''' 29 | self.optimizer.zero_grad() 30 | loss = self.compute_loss(data) 31 | if loss['total'].requires_grad: 32 | loss['total'].backward() 33 | self.optimizer.step() 34 | 35 | loss['total'] = loss['total'].item() 36 | return loss 37 | 38 | def eval_loss_parser(self, loss_recorder): 39 | ''' 40 | get the eval 41 | :param loss_recorder: loss recorder for all losses. 42 | :return: 43 | ''' 44 | return loss_recorder['total'].avg 45 | 46 | def compute_loss(self, *args, **kwargs): 47 | ''' Performs a training step. 48 | ''' 49 | raise NotImplementedError 50 | 51 | def eval_step(self, *args, **kwargs): 52 | ''' Performs an evaluation step. 53 | ''' 54 | raise NotImplementedError 55 | 56 | def visualize_step(self, *args, **kwargs): 57 | ''' Performs a visualization step. 58 | ''' 59 | raise NotImplementedError -------------------------------------------------------------------------------- /net_utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/net_utils/__init__.py -------------------------------------------------------------------------------- /net_utils/metric_util.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | # 3 | # This source code is licensed under the MIT license found in the 4 | # LICENSE file in the root directory of this source tree. 5 | 6 | """ Utility functions for metric evaluation. 7 | 8 | Author: Or Litany and Charles R. Qi 9 | """ 10 | import numpy as np 11 | 12 | def calc_iou(box_a, box_b): 13 | """Computes IoU of two axis aligned bboxes. 14 | Args: 15 | box_a, box_b: 6D of center and lengths 16 | Returns: 17 | iou 18 | """ 19 | 20 | max_a = box_a[0:3] + box_a[3:6] / 2 21 | max_b = box_b[0:3] + box_b[3:6] / 2 22 | min_max = np.array([max_a, max_b]).min(0) 23 | 24 | min_a = box_a[0:3] - box_a[3:6] / 2 25 | min_b = box_b[0:3] - box_b[3:6] / 2 26 | max_min = np.array([min_a, min_b]).max(0) 27 | if not ((min_max > max_min).all()): 28 | return 0.0 29 | 30 | intersection = (min_max - max_min).prod() 31 | vol_a = box_a[3:6].prod() 32 | vol_b = box_b[3:6].prod() 33 | union = vol_a + vol_b - intersection 34 | return 1.0 * intersection / union -------------------------------------------------------------------------------- /net_utils/nms.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | # 3 | # This source code is licensed under the MIT license found in the 4 | # LICENSE file in the root directory of this source tree. 5 | import numpy as np 6 | 7 | def nms_2d_faster(boxes, overlap_threshold, old_type=False): 8 | x1 = boxes[:,0] 9 | y1 = boxes[:,1] 10 | x2 = boxes[:,2] 11 | y2 = boxes[:,3] 12 | score = boxes[:,4] 13 | area = (x2-x1)*(y2-y1) 14 | 15 | I = np.argsort(score) 16 | pick = [] 17 | while (I.size!=0): 18 | last = I.size 19 | i = I[-1] 20 | pick.append(i) 21 | 22 | xx1 = np.maximum(x1[i], x1[I[:last-1]]) 23 | yy1 = np.maximum(y1[i], y1[I[:last-1]]) 24 | xx2 = np.minimum(x2[i], x2[I[:last-1]]) 25 | yy2 = np.minimum(y2[i], y2[I[:last-1]]) 26 | 27 | w = np.maximum(0, xx2-xx1) 28 | h = np.maximum(0, yy2-yy1) 29 | 30 | if old_type: 31 | o = (w*h)/area[I[:last-1]] 32 | else: 33 | inter = w*h 34 | o = inter / (area[i] + area[I[:last-1]] - inter) 35 | 36 | I = np.delete(I, np.concatenate(([last-1], np.where(o>overlap_threshold)[0]))) 37 | 38 | return pick 39 | 40 | 41 | def nms_3d_faster(boxes, overlap_threshold, old_type=False): 42 | x1 = boxes[:,0] 43 | y1 = boxes[:,1] 44 | z1 = boxes[:,2] 45 | x2 = boxes[:,3] 46 | y2 = boxes[:,4] 47 | z2 = boxes[:,5] 48 | score = boxes[:,6] 49 | area = (x2-x1)*(y2-y1)*(z2-z1) 50 | 51 | I = np.argsort(score) 52 | pick = [] 53 | while (I.size!=0): 54 | last = I.size 55 | i = I[-1] 56 | pick.append(i) 57 | 58 | xx1 = np.maximum(x1[i], x1[I[:last-1]]) 59 | yy1 = np.maximum(y1[i], y1[I[:last-1]]) 60 | zz1 = np.maximum(z1[i], z1[I[:last-1]]) 61 | xx2 = np.minimum(x2[i], x2[I[:last-1]]) 62 | yy2 = np.minimum(y2[i], y2[I[:last-1]]) 63 | zz2 = np.minimum(z2[i], z2[I[:last-1]]) 64 | 65 | l = np.maximum(0, xx2-xx1) 66 | w = np.maximum(0, yy2-yy1) 67 | h = np.maximum(0, zz2-zz1) 68 | 69 | if old_type: 70 | o = (l*w*h)/area[I[:last-1]] 71 | else: 72 | inter = l*w*h 73 | o = inter / (area[i] + area[I[:last-1]] - inter) 74 | 75 | I = np.delete(I, np.concatenate(([last-1], np.where(o>overlap_threshold)[0]))) 76 | 77 | return pick 78 | 79 | def nms_3d_faster_samecls(boxes, overlap_threshold, old_type=False): 80 | x1 = boxes[:,0] 81 | y1 = boxes[:,1] 82 | z1 = boxes[:,2] 83 | x2 = boxes[:,3] 84 | y2 = boxes[:,4] 85 | z2 = boxes[:,5] 86 | score = boxes[:,6] 87 | cls = boxes[:,7] 88 | area = (x2-x1)*(y2-y1)*(z2-z1) 89 | 90 | I = np.argsort(score) 91 | pick = [] 92 | while (I.size!=0): 93 | last = I.size 94 | i = I[-1] 95 | pick.append(i) 96 | 97 | xx1 = np.maximum(x1[i], x1[I[:last-1]]) 98 | yy1 = np.maximum(y1[i], y1[I[:last-1]]) 99 | zz1 = np.maximum(z1[i], z1[I[:last-1]]) 100 | xx2 = np.minimum(x2[i], x2[I[:last-1]]) 101 | yy2 = np.minimum(y2[i], y2[I[:last-1]]) 102 | zz2 = np.minimum(z2[i], z2[I[:last-1]]) 103 | cls1 = cls[i] 104 | cls2 = cls[I[:last-1]] 105 | 106 | l = np.maximum(0, xx2-xx1) 107 | w = np.maximum(0, yy2-yy1) 108 | h = np.maximum(0, zz2-zz1) 109 | 110 | if old_type: 111 | o = (l*w*h)/area[I[:last-1]] 112 | else: 113 | inter = l*w*h 114 | o = inter / (area[i] + area[I[:last-1]] - inter) 115 | o = o * (cls1==cls2) 116 | 117 | I = np.delete(I, np.concatenate(([last-1], np.where(o>overlap_threshold)[0]))) 118 | 119 | return pick -------------------------------------------------------------------------------- /net_utils/nn_distance.py: -------------------------------------------------------------------------------- 1 | # Copyright (c) Facebook, Inc. and its affiliates. 2 | # 3 | # This source code is licensed under the MIT license found in the 4 | # LICENSE file in the root directory of this source tree. 5 | 6 | """ Chamfer distance in Pytorch. 7 | Author: Charles R. Qi 8 | """ 9 | 10 | import torch 11 | import torch.nn as nn 12 | import numpy as np 13 | 14 | 15 | def huber_loss(error, delta=1.0): 16 | """ 17 | Args: 18 | error: Torch tensor (d1,d2,...,dk) 19 | Returns: 20 | loss: Torch tensor (d1,d2,...,dk) 21 | 22 | x = error = pred - gt or dist(pred,gt) 23 | 0.5 * |x|^2 if |x|<=d 24 | 0.5 * d^2 + d * (|x|-d) if |x|>d 25 | Ref: https://github.com/charlesq34/frustum-pointnets/blob/master/models/model_util.py 26 | """ 27 | abs_error = torch.abs(error) 28 | #quadratic = torch.min(abs_error, torch.FloatTensor([delta])) 29 | quadratic = torch.clamp(abs_error, max=delta) 30 | linear = (abs_error - quadratic) 31 | loss = 0.5 * quadratic**2 + delta * linear 32 | return loss 33 | 34 | def nn_distance(pc1, pc2, l1smooth=False, delta=1.0, l1=False): 35 | """ 36 | Input: 37 | pc1: (B,N,C) torch tensor 38 | pc2: (B,M,C) torch tensor 39 | l1smooth: bool, whether to use l1smooth loss 40 | delta: scalar, the delta used in l1smooth loss 41 | Output: 42 | dist1: (B,N) torch float32 tensor 43 | idx1: (B,N) torch int64 tensor 44 | dist2: (B,M) torch float32 tensor 45 | idx2: (B,M) torch int64 tensor 46 | """ 47 | N = pc1.shape[1] 48 | M = pc2.shape[1] 49 | pc1_expand_tile = pc1.unsqueeze(2).repeat(1,1,M,1) 50 | pc2_expand_tile = pc2.unsqueeze(1).repeat(1,N,1,1) 51 | pc_diff = pc1_expand_tile - pc2_expand_tile 52 | 53 | if l1smooth: 54 | pc_dist = torch.sum(huber_loss(pc_diff, delta), dim=-1) # (B,N,M) 55 | elif l1: 56 | pc_dist = torch.sum(torch.abs(pc_diff), dim=-1) # (B,N,M) 57 | else: 58 | pc_dist = torch.sum(pc_diff**2, dim=-1) # (B,N,M) 59 | dist1, idx1 = torch.min(pc_dist, dim=2) # (B,N) 60 | dist2, idx2 = torch.min(pc_dist, dim=1) # (B,M) 61 | return dist1, idx1, dist2, idx2 62 | 63 | def demo_nn_distance(): 64 | np.random.seed(0) 65 | pc1arr = np.random.random((1,5,3)) 66 | pc2arr = np.random.random((1,6,3)) 67 | pc1 = torch.from_numpy(pc1arr.astype(np.float32)) 68 | pc2 = torch.from_numpy(pc2arr.astype(np.float32)) 69 | dist1, idx1, dist2, idx2 = nn_distance(pc1, pc2) 70 | print(dist1) 71 | print(idx1) 72 | dist = np.zeros((5,6)) 73 | for i in range(5): 74 | for j in range(6): 75 | dist[i,j] = np.sum((pc1arr[0,i,:] - pc2arr[0,j,:]) ** 2) 76 | print(dist) 77 | print('-'*30) 78 | print('L1smooth dists:') 79 | dist1, idx1, dist2, idx2 = nn_distance(pc1, pc2, True) 80 | print(dist1) 81 | print(idx1) 82 | dist = np.zeros((5,6)) 83 | for i in range(5): 84 | for j in range(6): 85 | error = np.abs(pc1arr[0,i,:] - pc2arr[0,j,:]) 86 | quad = np.minimum(error, 1.0) 87 | linear = error - quad 88 | loss = 0.5*quad**2 + 1.0*linear 89 | dist[i,j] = np.sum(loss) 90 | print(dist) 91 | 92 | 93 | if __name__ == '__main__': 94 | demo_nn_distance() 95 | -------------------------------------------------------------------------------- /net_utils/registry.py: -------------------------------------------------------------------------------- 1 | # registry networks for different methods 2 | # author: ynie 3 | # date: Feb, 2020 4 | import inspect 5 | 6 | class Registry(object): 7 | 8 | def __init__(self, name): 9 | self._name = name 10 | self._module_dict = dict() 11 | 12 | def __repr__(self): 13 | format_str = self.__class__.__name__ + '(name={}, items={})'.format( 14 | self._name, list(self._module_dict.keys())) 15 | return format_str 16 | 17 | @property 18 | def name(self): 19 | return self._name 20 | 21 | @property 22 | def module_dict(self): 23 | return self._module_dict 24 | 25 | def get(self, key, alter_key = None): 26 | if key in self._module_dict: 27 | return self._module_dict.get(key) 28 | else: 29 | return self._module_dict.get(alter_key, None) 30 | 31 | def _register_module(self, module_class): 32 | ''' 33 | register a module. 34 | :param module_class (`nn.Module`): Module to be registered. 35 | :return: 36 | ''' 37 | if not inspect.isclass(module_class): 38 | raise TypeError('module must be a class, but got {}'.format( 39 | type(module_class))) 40 | module_name = module_class.__name__ 41 | if module_name in self._module_dict: 42 | raise KeyError('{} is already registered in {}'.format( 43 | module_name, self.name)) 44 | self._module_dict[module_name] = module_class 45 | 46 | def register_module(self, cls): 47 | self._register_module(cls) 48 | return cls -------------------------------------------------------------------------------- /net_utils/transforms.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | class SubsamplePoints(object): 4 | ''' Points subsampling transformation class. 5 | 6 | It subsamples the points data. 7 | 8 | Args: 9 | N (int): number of points to be subsampled 10 | ''' 11 | def __init__(self, N, mode): 12 | self.N = N 13 | self.mode = mode 14 | 15 | def __call__(self, data): 16 | ''' Calls the transformation. 17 | 18 | Args: 19 | data (dictionary): data dictionary 20 | ''' 21 | points = data['points'] 22 | occ = data['occ'] 23 | 24 | data_out = data.copy() 25 | if isinstance(self.N, int): 26 | if self.mode == 'test': 27 | idx = np.arange(0, self.N) 28 | else: 29 | idx = np.random.randint(points.shape[0], size=self.N) 30 | data_out.update({ 31 | 'points': points[idx, :], 32 | 'occ': occ[idx], 33 | }) 34 | else: 35 | Nt_out, Nt_in = self.N 36 | occ_binary = (occ >= 0.5) 37 | points0 = points[~occ_binary] 38 | points1 = points[occ_binary] 39 | 40 | if self.mode == 'test': 41 | idx0 = np.arange(0, Nt_out) 42 | idx1 = np.arange(0, Nt_in) 43 | else: 44 | idx0 = np.random.randint(points0.shape[0], size=Nt_out) 45 | idx1 = np.random.randint(points1.shape[0], size=Nt_in) 46 | 47 | points0 = points0[idx0, :] 48 | points1 = points1[idx1, :] 49 | points = np.concatenate([points0, points1], axis=0) 50 | 51 | occ0 = np.zeros(Nt_out, dtype=np.float32) 52 | occ1 = np.ones(Nt_in, dtype=np.float32) 53 | occ = np.concatenate([occ0, occ1], axis=0) 54 | 55 | volume = occ_binary.sum() / len(occ_binary) 56 | volume = volume.astype(np.float32) 57 | 58 | data_out.update({ 59 | 'points': points, 60 | 'occ': occ, 61 | 'volume': volume, 62 | }) 63 | return data_out -------------------------------------------------------------------------------- /net_utils/visualization.py: -------------------------------------------------------------------------------- 1 | # Visualization functions 2 | # author: ynie 3 | # date: Feb, 2020 4 | 5 | import numpy as np 6 | from matplotlib import pyplot as plt 7 | plt.switch_backend('agg') 8 | from mpl_toolkits.mplot3d import Axes3D 9 | from torchvision.utils import save_image 10 | 11 | def visualize_voxels(voxels, out_file=None, show=False): 12 | ''' 13 | Visualizes voxel data. 14 | :param voxels (tensor): voxel data 15 | :param out_file (string): output file 16 | :param show (bool): whether the plot should be shown 17 | :return: 18 | ''' 19 | # Use numpy 20 | voxels = np.asarray(voxels) 21 | # Create plot 22 | fig = plt.figure() 23 | ax = fig.gca(projection=Axes3D.name) 24 | voxels = voxels.transpose(2, 0, 1) 25 | ax.voxels(voxels, edgecolor='k') 26 | ax.set_xlabel('Z') 27 | ax.set_ylabel('X') 28 | ax.set_zlabel('Y') 29 | ax.view_init(elev=30, azim=45) 30 | if out_file is not None: 31 | plt.savefig(out_file) 32 | if show: 33 | plt.show() 34 | plt.close(fig) 35 | 36 | def visualize_pointcloud(points, normals=None, 37 | out_file=None, show=False): 38 | ''' 39 | Visualizes point cloud data. 40 | :param points (tensor): point data 41 | :param normals (tensor): normal data (if existing) 42 | :param out_file (string): output file 43 | :param show (bool): whether the plot should be shown 44 | :return: 45 | ''' 46 | # Use numpy 47 | points = np.asarray(points) 48 | # Create plot 49 | fig = plt.figure() 50 | ax = fig.gca(projection=Axes3D.name) 51 | ax.scatter(points[:, 0], points[:, 1], points[:, 2], s=1) 52 | if normals is not None: 53 | ax.quiver( 54 | points[:, 0], points[:, 1], points[:, 2], 55 | normals[:, 0], normals[:, 1], normals[:, 2], 56 | length=0.1, color='k' 57 | ) 58 | ax.set_xlabel('X') 59 | ax.set_ylabel('Y') 60 | ax.set_zlabel('Z') 61 | ax.set_xlim(-0.5, 0.5) 62 | ax.set_ylim(-0.5, 0.5) 63 | ax.set_zlim(-0.5, 0.5) 64 | ax.view_init(elev=30, azim=45) 65 | if out_file is not None: 66 | plt.savefig(out_file) 67 | if show: 68 | plt.show() 69 | plt.close(fig) 70 | 71 | def visualize_data(data, data_type, out_file): 72 | ''' 73 | Visualizes the data with regard to its type. 74 | :param data (tensor): batch of data 75 | :param data_type (string): data type (img, voxels or pointcloud) 76 | :param out_file (string): output file 77 | :return: 78 | ''' 79 | if data_type == 'img': 80 | if data.dim() == 3: 81 | data = data.unsqueeze(0) 82 | save_image(data, out_file, nrow=4) 83 | elif data_type == 'voxels': 84 | visualize_voxels(data, out_file=out_file) 85 | elif data_type == 'pointcloud': 86 | visualize_pointcloud(data, out_file=out_file) 87 | elif data_type is None or data_type == 'idx': 88 | pass 89 | else: 90 | raise ValueError('Invalid data_type "%s"' % data_type) -------------------------------------------------------------------------------- /out/samples/scene0001_00/verify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/out/samples/scene0001_00/verify.png -------------------------------------------------------------------------------- /out/samples/scene0549_00/camera_center: -------------------------------------------------------------------------------- 1 | 0.000000000000000000e+00 2 | -3.000000000000000000e+00 3 | 3.000000000000000000e+00 4 | -------------------------------------------------------------------------------- /out/samples/scene0549_00/gt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/out/samples/scene0549_00/gt.png -------------------------------------------------------------------------------- /out/samples/scene0549_00/points.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/out/samples/scene0549_00/points.png -------------------------------------------------------------------------------- /out/samples/scene0549_00/pred.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/out/samples/scene0549_00/pred.png -------------------------------------------------------------------------------- /out/samples/scene0549_00/verify.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GAP-LAB-CUHK-SZ/RfDNet/241d698bf5f2bd4fc076bc2dc18dfa9cc925c703/out/samples/scene0549_00/verify.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | absl-py==0.12.0 2 | cachetools==4.2.1 3 | certifi==2020.12.5 4 | chardet==4.0.0 5 | cycler==0.10.0 6 | Cython==0.29.22 7 | dataclasses @ file:///tmp/build/80754af9/dataclasses_1614363715916/work 8 | decorator==4.4.2 9 | google-auth==1.28.0 10 | google-auth-oauthlib==0.4.3 11 | grpcio==1.36.1 12 | idna==2.10 13 | imageio==2.9.0 14 | importlib-metadata==3.7.3 15 | kiwisolver==1.3.1 16 | llvmlite==0.36.0 17 | Markdown==3.3.4 18 | matplotlib==3.3.4 19 | mkl-fft==1.3.0 20 | mkl-random==1.1.1 21 | mkl-service==2.3.0 22 | networkx==2.5 23 | numba==0.53.0 24 | numpy @ file:///tmp/build/80754af9/numpy_and_numpy_base_1603487797006/work 25 | numpy-quaternion==2021.3.17.16.51.43 26 | oauthlib==3.1.0 27 | olefile==0.46 28 | pandas==1.1.5 29 | Pillow @ file:///tmp/build/80754af9/pillow_1615224027575/work 30 | plyfile==0.7.3 31 | pointnet2-ops @ file:///home/ynie/Project/RfDNet/external/pointnet2_ops_lib 32 | protobuf==3.15.6 33 | pyasn1==0.4.8 34 | pyasn1-modules==0.2.8 35 | PyMCubes==0.1.2 36 | pyparsing==2.4.7 37 | python-dateutil==2.8.1 38 | pytz==2021.1 39 | PyWavelets==1.1.1 40 | PyYAML==5.4.1 41 | requests==2.25.1 42 | requests-oauthlib==1.3.0 43 | rsa==4.7.2 44 | scikit-image==0.17.2 45 | scipy==1.5.4 46 | seaborn==0.11.1 47 | Shapely==1.7.1 48 | six @ file:///tmp/build/80754af9/six_1605205335545/work 49 | tensorboard==2.4.1 50 | tensorboard-plugin-wit==1.8.0 51 | tifffile==2020.9.3 52 | torch==1.7.1 53 | torchaudio==0.7.0a0+a853dff 54 | torchvision==0.8.2 55 | tqdm==4.59.0 56 | trimesh==3.9.9 57 | typing-extensions @ file:///home/ktietz/src/ci_mi/typing_extensions_1612808209620/work 58 | urllib3==1.26.4 59 | vtk==9.0.1 60 | Werkzeug==1.0.1 61 | zipp==3.4.1 62 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | try: 2 | from setuptools import setup 3 | except ImportError: 4 | from distutils.core import setup 5 | from distutils.extension import Extension 6 | from Cython.Build import cythonize 7 | from setuptools.command.build_ext import build_ext 8 | import numpy 9 | numpy_include_dir = numpy.get_include() 10 | 11 | # Extensions 12 | # triangle hash (efficient mesh intersection) 13 | triangle_hash_module = Extension( 14 | 'external.libmesh.triangle_hash', 15 | sources=[ 16 | 'external/libmesh/triangle_hash.pyx' 17 | ], 18 | libraries=['m'], # Unix-like specific 19 | include_dirs=[numpy_include_dir] 20 | ) 21 | 22 | # voxelization (efficient mesh voxelization) 23 | voxelize_module = Extension( 24 | 'external.libvoxelize.voxelize', 25 | sources=[ 26 | 'external/libvoxelize/voxelize.pyx' 27 | ], 28 | libraries=['m'] # Unix-like specific 29 | ) 30 | 31 | # pykdtree (kd tree) 32 | pykdtree = Extension( 33 | 'external.libkdtree.pykdtree.kdtree', 34 | sources=[ 35 | 'external/libkdtree/pykdtree/kdtree.c', 36 | 'external/libkdtree/pykdtree/_kdtree_core.c' 37 | ], 38 | language='c', 39 | extra_compile_args=['-std=c99', '-O3', '-fopenmp'], 40 | extra_link_args=['-lgomp'], 41 | include_dirs=[numpy_include_dir] 42 | ) 43 | 44 | # simplify (efficient mesh simplification) 45 | simplify_mesh_module = Extension( 46 | 'external.libsimplify.simplify_mesh', 47 | sources=[ 48 | 'external/libsimplify/simplify_mesh.pyx' 49 | ], 50 | include_dirs=[numpy_include_dir] 51 | ) 52 | 53 | # mise (efficient mesh extraction) 54 | mise_module = Extension( 55 | 'external.libmise.mise', 56 | sources=[ 57 | 'external/libmise/mise.pyx' 58 | ], 59 | ) 60 | 61 | # Gather all extension modules 62 | ext_modules = [ 63 | pykdtree, 64 | triangle_hash_module, 65 | voxelize_module, 66 | simplify_mesh_module, 67 | mise_module 68 | ] 69 | 70 | def set_builtin(name, value): 71 | if isinstance(__builtins__, dict): 72 | __builtins__[name] = value 73 | else: 74 | setattr(__builtins__, name, value) 75 | 76 | 77 | class build_ext_subclass(build_ext): 78 | def build_extensions(self): 79 | comp = self.compiler.compiler_type 80 | if comp in ('unix', 'cygwin', 'mingw32'): 81 | # Check if build is with OpenMP 82 | extra_compile_args = ['-std=c99', '-O3', '-fopenmp'] 83 | extra_link_args=['-lgomp'] 84 | elif comp == 'msvc': 85 | extra_compile_args = ['/Ox'] 86 | extra_link_args = [] 87 | extra_compile_args.append('/openmp') 88 | else: 89 | # Add support for more compilers here 90 | raise ValueError('Compiler flags undefined for %s. Please modify setup.py and add compiler flags' 91 | % comp) 92 | self.extensions[0].extra_compile_args = extra_compile_args 93 | self.extensions[0].extra_link_args = extra_link_args 94 | build_ext.build_extensions(self) 95 | 96 | def finalize_options(self): 97 | ''' 98 | In order to avoid premature import of numpy before it gets installed as a dependency 99 | get numpy include directories during the extensions building process 100 | http://stackoverflow.com/questions/19919905/how-to-bootstrap-numpy-installation-in-setup-py 101 | ''' 102 | build_ext.finalize_options(self) 103 | # Prevent numpy from thinking it is still in its setup process: 104 | set_builtin('__NUMPY_SETUP__', False) 105 | import numpy 106 | self.include_dirs.append(numpy.get_include()) 107 | 108 | setup( 109 | ext_modules=cythonize(ext_modules), 110 | cmdclass={ 111 | 'build_ext': build_ext_subclass 112 | } 113 | ) 114 | -------------------------------------------------------------------------------- /test.py: -------------------------------------------------------------------------------- 1 | # Testing script. 2 | # author: ynie 3 | # date: Feb, 2020 4 | from net_utils.utils import load_device, load_model, load_tester, load_dataloader 5 | from net_utils.utils import CheckpointIO 6 | from test_epoch import test 7 | from configs.config_utils import mount_external_config 8 | 9 | def run(cfg): 10 | '''Begin to run network.''' 11 | checkpoint = CheckpointIO(cfg) 12 | 13 | '''Mount external config data''' 14 | cfg = mount_external_config(cfg) 15 | 16 | '''Load save path''' 17 | cfg.log_string('Data save path: %s' % (cfg.save_path)) 18 | 19 | '''Load device''' 20 | cfg.log_string('Loading device settings.') 21 | device = load_device(cfg) 22 | 23 | '''Load data''' 24 | cfg.log_string('Loading dataset.') 25 | test_loader = load_dataloader(cfg, mode='test') 26 | 27 | '''Load net''' 28 | cfg.log_string('Loading model.') 29 | net = load_model(cfg, device=device) 30 | checkpoint.register_modules(net=net) 31 | cfg.log_string(net) 32 | 33 | '''Load existing checkpoint''' 34 | checkpoint.parse_checkpoint() 35 | 36 | '''Load tester''' 37 | cfg.log_string('Loading tester.') 38 | tester = load_tester(cfg=cfg, net=net, device=device) 39 | 40 | '''Start to test''' 41 | cfg.log_string('Start to test.') 42 | cfg.log_string('Total number of parameters in {0:s}: {1:d}.'.format(cfg.config['method'], sum(p.numel() for p in net.parameters()))) 43 | 44 | test(cfg=cfg, tester=tester, test_loader=test_loader) 45 | 46 | cfg.write_config() 47 | cfg.log_string('Testing finished.') 48 | 49 | 50 | -------------------------------------------------------------------------------- /test_epoch.py: -------------------------------------------------------------------------------- 1 | # Testing functions. 2 | # author: ynie 3 | # date: April, 2020 4 | from net_utils.utils import LossRecorder 5 | from time import time 6 | import torch 7 | from net_utils.ap_helper import APCalculator 8 | import numpy as np 9 | 10 | def test_func(cfg, tester, test_loader): 11 | ''' 12 | test function. 13 | :param cfg: configuration file 14 | :param tester: specific tester for networks 15 | :param test_loader: dataloader for testing 16 | :return: 17 | ''' 18 | mode = cfg.config['mode'] 19 | batch_size = cfg.config[mode]['batch_size'] 20 | loss_recorder = LossRecorder(batch_size) 21 | AP_IOU_THRESHOLDS = cfg.config[mode]['ap_iou_thresholds'] 22 | evaluate_mesh_mAP = True if cfg.config[mode]['phase'] == 'completion' and cfg.config['generation'][ 23 | 'generate_mesh'] and cfg.config[mode]['evaluate_mesh_mAP'] else False 24 | ap_calculator_list = [APCalculator(iou_thresh, cfg.dataset_config.class2type, evaluate_mesh_mAP) for iou_thresh in 25 | AP_IOU_THRESHOLDS] 26 | cfg.log_string('-'*100) 27 | for iter, data in enumerate(test_loader): 28 | loss, est_data = tester.test_step(data) 29 | eval_dict = est_data[4] 30 | for ap_calculator in ap_calculator_list: 31 | ap_calculator.step(eval_dict['batch_pred_map_cls'], eval_dict['batch_gt_map_cls']) 32 | # visualize intermediate results. 33 | if cfg.config['generation']['dump_results']: 34 | tester.visualize_step(mode, iter, data, est_data, eval_dict) 35 | 36 | loss_recorder.update_loss(loss) 37 | 38 | if ((iter + 1) % cfg.config['log']['print_step']) == 0: 39 | cfg.log_string('Process: Phase: %s. Epoch %d: %d/%d. Current loss: %s.' % ( 40 | mode, 0, iter + 1, len(test_loader), str({key: np.mean(item) for key, item in loss.items()}))) 41 | 42 | return loss_recorder.loss_recorder, ap_calculator_list 43 | 44 | def test(cfg, tester, test_loader): 45 | ''' 46 | train epochs for network 47 | :param cfg: configuration file 48 | :param tester: specific tester for networks 49 | :param test_loader: dataloader for testing 50 | :return: 51 | ''' 52 | cfg.log_string('-' * 100) 53 | # set mode 54 | mode = cfg.config['mode'] 55 | tester.net.train(mode == 'train') 56 | start = time() 57 | test_loss_recoder, ap_calculator_list = test_func(cfg, tester, test_loader) 58 | cfg.log_string('Test time elapsed: (%f).' % (time()-start)) 59 | for key, test_loss in test_loss_recoder.items(): 60 | cfg.log_string('Test loss (%s): %f' % (key, test_loss.avg)) 61 | 62 | # Evaluate average precision 63 | AP_IOU_THRESHOLDS = cfg.config[mode]['ap_iou_thresholds'] 64 | for i, ap_calculator in enumerate(ap_calculator_list): 65 | cfg.log_string(('-'*10 + 'iou_thresh: %f' + '-'*10) % (AP_IOU_THRESHOLDS[i])) 66 | metrics_dict = ap_calculator.compute_metrics() 67 | for key in metrics_dict: 68 | cfg.log_string('eval %s: %f' % (key, metrics_dict[key])) -------------------------------------------------------------------------------- /train.py: -------------------------------------------------------------------------------- 1 | # Training script 2 | # author: ynie 3 | # date: Feb, 2020 4 | from models.optimizers import load_optimizer, load_scheduler, load_bnm_scheduler 5 | from net_utils.utils import load_device, load_model, load_trainer, load_dataloader 6 | from net_utils.utils import CheckpointIO 7 | from train_epoch import train 8 | from configs.config_utils import mount_external_config 9 | 10 | def run(cfg): 11 | '''Begin to run network.''' 12 | checkpoint = CheckpointIO(cfg) 13 | 14 | '''Mount external config data''' 15 | cfg = mount_external_config(cfg) 16 | 17 | '''Load save path''' 18 | cfg.log_string('Data save path: %s' % (cfg.save_path)) 19 | 20 | '''Load device''' 21 | cfg.log_string('Loading device settings.') 22 | device = load_device(cfg) 23 | 24 | '''Load data''' 25 | cfg.log_string('Loading dataset.') 26 | train_loader = load_dataloader(cfg, mode='train') 27 | val_loader = load_dataloader(cfg, mode='val') 28 | 29 | '''Load net''' 30 | cfg.log_string('Loading model.') 31 | net = load_model(cfg, device=device) 32 | checkpoint.register_modules(net=net) 33 | cfg.log_string(net) 34 | 35 | '''Load optimizer''' 36 | cfg.log_string('Loading optimizer.') 37 | optimizer = load_optimizer(config=cfg.config, net=net) 38 | checkpoint.register_modules(optimizer=optimizer) 39 | 40 | '''Load scheduler''' 41 | cfg.log_string('Loading optimizer scheduler.') 42 | scheduler = load_scheduler(config=cfg.config, optimizer=optimizer) 43 | checkpoint.register_modules(scheduler=scheduler) 44 | 45 | '''Check existing checkpoint (resume or finetune)''' 46 | checkpoint.parse_checkpoint() 47 | 48 | '''BN momentum scheduler''' 49 | bnm_scheduler = load_bnm_scheduler(cfg=cfg, net=net, start_epoch=scheduler.last_epoch) 50 | 51 | '''Load trainer''' 52 | cfg.log_string('Loading trainer.') 53 | trainer = load_trainer(cfg=cfg, net=net, optimizer=optimizer, device=device) 54 | 55 | '''Start to train''' 56 | cfg.log_string('Start to train.') 57 | cfg.log_string('Total number of parameters in {0:s}: {1:d}.'.format(cfg.config['method'], sum(p.numel() for p in net.parameters()))) 58 | 59 | train(cfg=cfg, trainer=trainer, scheduler=scheduler, bnm_scheduler=bnm_scheduler, checkpoint=checkpoint, train_loader=train_loader, val_loader=val_loader) 60 | 61 | cfg.log_string('Training finished.') -------------------------------------------------------------------------------- /train_epoch.py: -------------------------------------------------------------------------------- 1 | # Training functions. 2 | # author: ynie 3 | # date: Feb, 2020 4 | 5 | from net_utils.utils import LossRecorder, LogBoard 6 | from time import time 7 | log_board = LogBoard() 8 | 9 | def train_epoch(cfg, epoch, trainer, dataloaders): 10 | ''' 11 | train by epoch 12 | :param cfg: configuration file 13 | :param epoch: epoch id. 14 | :param trainer: specific trainer for networks 15 | :param dataloaders: dataloader for training and validation 16 | :return: 17 | ''' 18 | for phase in ['train', 'val']: 19 | dataloader = dataloaders[phase] 20 | batch_size = cfg.config[phase]['batch_size'] 21 | loss_recorder = LossRecorder(batch_size) 22 | # set mode 23 | trainer.net.train(phase == 'train') 24 | # set subnet mode 25 | trainer.net.module.set_mode() 26 | cfg.log_string('-' * 100) 27 | cfg.log_string('Switch Phase to %s.' % (phase)) 28 | cfg.log_string('-'*100) 29 | for iter, data in enumerate(dataloader): 30 | if phase == 'train': 31 | loss = trainer.train_step(data) 32 | else: 33 | loss = trainer.eval_step(data) 34 | 35 | # visualize intermediate results. 36 | if ((iter + 1) % cfg.config['log']['vis_step']) == 0: 37 | trainer.visualize_step(epoch, phase, iter, data) 38 | 39 | loss_recorder.update_loss(loss) 40 | 41 | if ((iter + 1) % cfg.config['log']['print_step']) == 0: 42 | cfg.log_string('Process: Phase: %s. Epoch %d: %d/%d. Current loss: %s.' % (phase, epoch, iter + 1, len(dataloader), str(loss))) 43 | log_board.update(loss, cfg.config['log']['print_step'], phase) 44 | 45 | cfg.log_string('=' * 100) 46 | for loss_name, loss_value in loss_recorder.loss_recorder.items(): 47 | cfg.log_string('Currently the last %s loss (%s) is: %f' % (phase, loss_name, loss_value.avg)) 48 | cfg.log_string('=' * 100) 49 | 50 | return loss_recorder.loss_recorder 51 | 52 | def train(cfg, trainer, scheduler, bnm_scheduler, checkpoint, train_loader, val_loader): 53 | ''' 54 | train epochs for network 55 | :param cfg: configuration file 56 | :param scheduler: scheduler for optimizer 57 | :param bnm_scheduler: scheduler for batch normalization module 58 | :param trainer: specific trainer for networks 59 | :param checkpoint: network weights. 60 | :param train_loader: dataloader for training 61 | :param val_loader: dataloader for validation 62 | :return: 63 | ''' 64 | start_epoch = scheduler.last_epoch 65 | total_epochs = cfg.config['train']['epochs'] 66 | min_eval_loss = checkpoint.get('min_loss') 67 | 68 | dataloaders = {'train': train_loader, 'val': val_loader} 69 | 70 | for epoch in range(start_epoch, total_epochs): 71 | cfg.log_string('-' * 100) 72 | cfg.log_string('Epoch (%d/%s):' % (epoch + 1, total_epochs)) 73 | trainer.show_lr() 74 | bnm_scheduler.show_momentum() 75 | start = time() 76 | eval_loss_recorder = train_epoch(cfg, epoch + 1, trainer, dataloaders) 77 | eval_loss = trainer.eval_loss_parser(eval_loss_recorder) 78 | scheduler.step(eval_loss) 79 | bnm_scheduler.step() 80 | cfg.log_string('Epoch (%d/%s) Time elapsed: (%f).' % (epoch + 1, total_epochs, time()-start)) 81 | 82 | # save checkpoint 83 | checkpoint.register_modules(epoch=epoch, min_loss=eval_loss) 84 | checkpoint.save('last') 85 | cfg.log_string('Saved the latest checkpoint.') 86 | if epoch==0 or eval_loss 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /utils/shapenet/tools.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | def pc_from_dep(depth_maps, cam_Ks, cam_Rs, znf, store_camera=False): 4 | ''' 5 | get point cloud from depth maps 6 | :param depth_maps: depth map list 7 | :param cam_Ks: corresponding camera intrinsics 8 | :param cam_RTs: corresponding camera rotations and translations 9 | :param znf: [nearest camera distance, furthest distance] 10 | :param store_camera: if calculate camera position and orientations. 11 | :return: aligned point clouds in the canonical system with color intensities. 12 | ''' 13 | point_list_canonical = [] 14 | camera_positions = [] 15 | 16 | for depth_map, cam_K, cam_R in zip(depth_maps, cam_Ks, cam_Rs): 17 | cam_RT = np.hstack([cam_R, np.array([[0, 0, 1]]).T]) 18 | 19 | u, v = np.meshgrid(range(depth_map.shape[1]), range(depth_map.shape[0])) 20 | u = u.reshape([1, -1])[0] 21 | v = v.reshape([1, -1])[0] 22 | 23 | z = depth_map[v, u] 24 | 25 | # remove infinitive pixels 26 | non_inf_indices = np.argwhere(z < znf[1]).T[0] 27 | 28 | z = z[non_inf_indices] 29 | u = u[non_inf_indices] 30 | v = v[non_inf_indices] 31 | 32 | # calculate coordinates 33 | x = (u - cam_K[0][2]) * z / cam_K[0][0] 34 | y = (v - cam_K[1][2]) * z / cam_K[1][1] 35 | 36 | point_cam = np.vstack([x, y, z]).T 37 | 38 | point_canonical = (point_cam - cam_RT[:, -1]).dot(cam_RT[:, :-1]) 39 | 40 | if store_camera: 41 | cam_pos = - cam_RT[:, -1].dot(cam_RT[:, :-1]) 42 | focal_point = ([0, 0, 1] - cam_RT[:, -1]).dot(cam_RT[:, :-1]) 43 | up = np.array([0, -1, 0]).dot(cam_RT[:, :-1]) 44 | cam_pos = {'pos': cam_pos, 'fp': focal_point, 'up': up} 45 | else: 46 | cam_pos = {} 47 | 48 | point_list_canonical.append(point_canonical) 49 | camera_positions.append(cam_pos) 50 | 51 | output = {'pc': point_list_canonical} 52 | 53 | if store_camera: 54 | output['cam'] = camera_positions 55 | 56 | return output --------------------------------------------------------------------------------