openpoints 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openpoints/__init__.py +3 -0
- openpoints/cpp/__init__.py +6 -0
- openpoints/cpp/chamfer_dist/__init__.py +110 -0
- openpoints/cpp/chamfer_dist/setup.py +19 -0
- openpoints/cpp/chamfer_dist/test.py +34 -0
- openpoints/cpp/emd/__init__.py +3 -0
- openpoints/cpp/emd/emd.py +88 -0
- openpoints/cpp/emd/setup.py +27 -0
- openpoints/cpp/emd/test_emd_loss.py +45 -0
- openpoints/cpp/pointnet2_batch/__init__.py +24 -0
- openpoints/cpp/pointnet2_batch/setup.py +23 -0
- openpoints/cpp/pointops/__init__.py +0 -0
- openpoints/cpp/pointops/functions/__init__.py +0 -0
- openpoints/cpp/pointops/functions/pointops.py +314 -0
- openpoints/cpp/pointops/setup.py +37 -0
- openpoints/cpp/pointops/src/__init__.py +0 -0
- openpoints/dataset/__init__.py +10 -0
- openpoints/dataset/atom3d/__init__.py +1 -0
- openpoints/dataset/atom3d/psr.py +38 -0
- openpoints/dataset/build.py +98 -0
- openpoints/dataset/data_util.py +192 -0
- openpoints/dataset/datalist.py +67 -0
- openpoints/dataset/dataset_base.py +96 -0
- openpoints/dataset/graph_dataset/__init__.py +3 -0
- openpoints/dataset/graph_dataset/graph_dataset.py +93 -0
- openpoints/dataset/graph_dataset/stack_with_pad.py +91 -0
- openpoints/dataset/graph_dataset/structural_dataset.py +73 -0
- openpoints/dataset/graph_dataset/svd_encodings_dataset.py +110 -0
- openpoints/dataset/grid_sample.py +21 -0
- openpoints/dataset/matterport3d/__init__.py +1 -0
- openpoints/dataset/matterport3d/category_mapping.tsv +1660 -0
- openpoints/dataset/matterport3d/matterport3d.py +210 -0
- openpoints/dataset/matterport3d/matterport3d_dataprocessing.py +105 -0
- openpoints/dataset/modelnet/__init__.py +3 -0
- openpoints/dataset/modelnet/modelnet40_normal_resampled_loader.py +124 -0
- openpoints/dataset/modelnet/modelnet40_ply_2048_loader.py +160 -0
- openpoints/dataset/molhiv/__init__.py +1 -0
- openpoints/dataset/molhiv/data.py +59 -0
- openpoints/dataset/molpcba/__init__.py +1 -0
- openpoints/dataset/molpcba/data.py +59 -0
- openpoints/dataset/parsers/__init__.py +1 -0
- openpoints/dataset/parsers/class_map.py +19 -0
- openpoints/dataset/parsers/constants.py +1 -0
- openpoints/dataset/parsers/parser.py +17 -0
- openpoints/dataset/parsers/parser_factory.py +29 -0
- openpoints/dataset/parsers/parser_image_folder.py +69 -0
- openpoints/dataset/parsers/parser_image_in_tar.py +222 -0
- openpoints/dataset/parsers/parser_image_tar.py +72 -0
- openpoints/dataset/parsers/parser_tfds.py +297 -0
- openpoints/dataset/pcqm4m/__init__.py +1 -0
- openpoints/dataset/pcqm4m/data.py +62 -0
- openpoints/dataset/pcqm4mv2/__init__.py +1 -0
- openpoints/dataset/pcqm4mv2/data.py +87 -0
- openpoints/dataset/s3dis/__init__.py +2 -0
- openpoints/dataset/s3dis/s3dis.py +156 -0
- openpoints/dataset/s3dis/s3dis_block.py +96 -0
- openpoints/dataset/s3dis/s3dis_sphere.py +349 -0
- openpoints/dataset/scannetv2/__init__.py +1 -0
- openpoints/dataset/scannetv2/scannet.py +176 -0
- openpoints/dataset/scanobjectnn/__init__.py +3 -0
- openpoints/dataset/scanobjectnn/scanobjectnn.py +110 -0
- openpoints/dataset/semantic_kitti/__init__.py +1 -0
- openpoints/dataset/semantic_kitti/helper_tool.py +286 -0
- openpoints/dataset/semantic_kitti/label_mapping.yaml +211 -0
- openpoints/dataset/semantic_kitti/semantickitti.py +229 -0
- openpoints/dataset/semantic_kitti/utils/meta/anno_paths.txt +272 -0
- openpoints/dataset/semantic_kitti/utils/meta/class_names.txt +13 -0
- openpoints/dataset/semantic_kitti/utils/semantic-kitti.yaml +211 -0
- openpoints/dataset/shapenet/__init__.py +1 -0
- openpoints/dataset/shapenet/shapenet55.py +76 -0
- openpoints/dataset/shapenet/shapenetpart.py +121 -0
- openpoints/dataset/shapenetpart/__init__.py +1 -0
- openpoints/dataset/shapenetpart/shapenet55.py +75 -0
- openpoints/dataset/shapenetpart/shapenetpart.py +388 -0
- openpoints/dataset/vis2d.py +17 -0
- openpoints/dataset/vis3d.py +153 -0
- openpoints/loss/__init__.py +3 -0
- openpoints/loss/build.py +281 -0
- openpoints/loss/cross_entropy.py +38 -0
- openpoints/loss/distill_loss.py +76 -0
- openpoints/models/__init__.py +10 -0
- openpoints/models/backbone/Stratified_transformer.py +558 -0
- openpoints/models/backbone/__init__.py +11 -0
- openpoints/models/backbone/baafnet.py +527 -0
- openpoints/models/backbone/ball_dgcnn.py +123 -0
- openpoints/models/backbone/curvenet.py +793 -0
- openpoints/models/backbone/debug_invvit.py +114 -0
- openpoints/models/backbone/deepgcn.py +143 -0
- openpoints/models/backbone/dgcnn.py +119 -0
- openpoints/models/backbone/graphvit3d.py +134 -0
- openpoints/models/backbone/grouppointnet.py +100 -0
- openpoints/models/backbone/pct.py +163 -0
- openpoints/models/backbone/pointmlp.py +417 -0
- openpoints/models/backbone/pointnet.py +199 -0
- openpoints/models/backbone/pointnetv2.py +511 -0
- openpoints/models/backbone/pointnext.py +663 -0
- openpoints/models/backbone/pointnextPyG.py +555 -0
- openpoints/models/backbone/pointtransformer.py +293 -0
- openpoints/models/backbone/pointvector.py +853 -0
- openpoints/models/backbone/pointvit.py +392 -0
- openpoints/models/backbone/pointvit_inv.py +942 -0
- openpoints/models/backbone/pointvit_inv_old.py +784 -0
- openpoints/models/backbone/randlenet.py +318 -0
- openpoints/models/backbone/resnet.py +342 -0
- openpoints/models/backbone/simpleview.py +153 -0
- openpoints/models/backbone/simpleview_util.py +292 -0
- openpoints/models/build.py +13 -0
- openpoints/models/classification/__init__.py +5 -0
- openpoints/models/classification/cls_base.py +136 -0
- openpoints/models/classification/point_bert.py +154 -0
- openpoints/models/layers/__init__.py +14 -0
- openpoints/models/layers/activation.py +57 -0
- openpoints/models/layers/attention.py +103 -0
- openpoints/models/layers/conv.py +167 -0
- openpoints/models/layers/drop.py +164 -0
- openpoints/models/layers/graph_conv.py +122 -0
- openpoints/models/layers/group.py +415 -0
- openpoints/models/layers/group_embed.py +286 -0
- openpoints/models/layers/helpers.py +43 -0
- openpoints/models/layers/kmeans.py +119 -0
- openpoints/models/layers/knn.py +110 -0
- openpoints/models/layers/local_aggregation.py +286 -0
- openpoints/models/layers/mlp.py +129 -0
- openpoints/models/layers/norm.py +106 -0
- openpoints/models/layers/padding.py +56 -0
- openpoints/models/layers/patch_embed.py +37 -0
- openpoints/models/layers/registry.py +168 -0
- openpoints/models/layers/subsample.py +185 -0
- openpoints/models/layers/upsampling.py +106 -0
- openpoints/models/layers/weight_init.py +89 -0
- openpoints/models/reconstruction/__init__.py +8 -0
- openpoints/models/reconstruction/base_recontruct.py +216 -0
- openpoints/models/reconstruction/maskedpoint.py +116 -0
- openpoints/models/reconstruction/maskedpointgroup.py +168 -0
- openpoints/models/reconstruction/maskedpointvit.py +253 -0
- openpoints/models/reconstruction/nodeshuffle.py +11 -0
- openpoints/models/registry.py +149 -0
- openpoints/models/segmentation/__init__.py +6 -0
- openpoints/models/segmentation/base_seg.py +278 -0
- openpoints/models/segmentation/vit_seg.py +126 -0
- openpoints/optim/__init__.py +15 -0
- openpoints/optim/adabelief.py +201 -0
- openpoints/optim/adafactor.py +167 -0
- openpoints/optim/adahessian.py +156 -0
- openpoints/optim/adamp.py +105 -0
- openpoints/optim/adamw.py +122 -0
- openpoints/optim/lamb.py +192 -0
- openpoints/optim/lars.py +135 -0
- openpoints/optim/lookahead.py +61 -0
- openpoints/optim/madgrad.py +184 -0
- openpoints/optim/nadam.py +92 -0
- openpoints/optim/nvnovograd.py +120 -0
- openpoints/optim/optim_factory.py +306 -0
- openpoints/optim/radam.py +89 -0
- openpoints/optim/rmsprop_tf.py +139 -0
- openpoints/optim/sgdp.py +70 -0
- openpoints/scheduler/__init__.py +8 -0
- openpoints/scheduler/cosine_lr.py +124 -0
- openpoints/scheduler/multistep_lr.py +65 -0
- openpoints/scheduler/plateau_lr.py +113 -0
- openpoints/scheduler/poly_lr.py +116 -0
- openpoints/scheduler/scheduler.py +110 -0
- openpoints/scheduler/scheduler_factory.py +118 -0
- openpoints/scheduler/step_lr.py +65 -0
- openpoints/scheduler/tanh_lr.py +117 -0
- openpoints/transforms/__init__.py +7 -0
- openpoints/transforms/point_transform_cpu.py +332 -0
- openpoints/transforms/point_transformer_gpu.py +764 -0
- openpoints/transforms/transforms_factory.py +60 -0
- openpoints/utils/__init__.py +8 -0
- openpoints/utils/ckpt_util.py +438 -0
- openpoints/utils/config.py +113 -0
- openpoints/utils/dist_utils.py +54 -0
- openpoints/utils/logger.py +170 -0
- openpoints/utils/metrics.py +311 -0
- openpoints/utils/random.py +16 -0
- openpoints/utils/registry.py +294 -0
- openpoints/utils/str2bool.py +11 -0
- openpoints/utils/wandb.py +88 -0
- openpoints-0.1.0.dist-info/METADATA +150 -0
- openpoints-0.1.0.dist-info/RECORD +184 -0
- openpoints-0.1.0.dist-info/WHEEL +5 -0
- openpoints-0.1.0.dist-info/licenses/LICENSE +21 -0
- openpoints-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"""_summary_
|
|
2
|
+
"""
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import numpy as np
|
|
7
|
+
import pickle
|
|
8
|
+
import logging
|
|
9
|
+
import pathlib
|
|
10
|
+
import glob
|
|
11
|
+
import random
|
|
12
|
+
import h5py
|
|
13
|
+
import pandas as pd
|
|
14
|
+
import torch
|
|
15
|
+
from tqdm import tqdm
|
|
16
|
+
from torch.utils.data import Dataset
|
|
17
|
+
from ..build import DATASETS
|
|
18
|
+
from openpoints.models.layers import fps
|
|
19
|
+
import warnings
|
|
20
|
+
warnings.filterwarnings('ignore')
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def pc_normalize(pc):
|
|
24
|
+
centroid = np.mean(pc, axis=0)
|
|
25
|
+
pc = pc - centroid
|
|
26
|
+
m = np.max(np.sqrt(np.sum(pc ** 2, axis=1)))
|
|
27
|
+
pc = pc / m
|
|
28
|
+
return pc
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@DATASETS.register_module()
|
|
32
|
+
class MP40(Dataset):
|
|
33
|
+
classes = ["wall",
|
|
34
|
+
"floor",
|
|
35
|
+
"chair",
|
|
36
|
+
"door"
|
|
37
|
+
"table",
|
|
38
|
+
"picture",
|
|
39
|
+
"cabinet",
|
|
40
|
+
"cushion",
|
|
41
|
+
"window",
|
|
42
|
+
"sofa"
|
|
43
|
+
"bed"
|
|
44
|
+
"curtain",
|
|
45
|
+
"chest_of_drawers",
|
|
46
|
+
"plant",
|
|
47
|
+
"sink"
|
|
48
|
+
"stairs",
|
|
49
|
+
"ceiling",
|
|
50
|
+
"toilet",
|
|
51
|
+
"stool",
|
|
52
|
+
"towel",
|
|
53
|
+
"mirror",
|
|
54
|
+
"tv_monitor",
|
|
55
|
+
"shower",
|
|
56
|
+
"column",
|
|
57
|
+
"bathtub",
|
|
58
|
+
"counter",
|
|
59
|
+
"fireplace",
|
|
60
|
+
"lighting",
|
|
61
|
+
"beam"
|
|
62
|
+
"railing",
|
|
63
|
+
"shelving",
|
|
64
|
+
"blinds",
|
|
65
|
+
"gym_equipment",
|
|
66
|
+
"seating",
|
|
67
|
+
"board_panel",
|
|
68
|
+
"furniture",
|
|
69
|
+
"appliances",
|
|
70
|
+
"clothes",
|
|
71
|
+
"objects",
|
|
72
|
+
"misc"
|
|
73
|
+
]
|
|
74
|
+
|
|
75
|
+
def __init__(self,
|
|
76
|
+
data_dir,
|
|
77
|
+
num_points=1024,
|
|
78
|
+
split='train',
|
|
79
|
+
transform=None,
|
|
80
|
+
use_normal=False,
|
|
81
|
+
**kwargs
|
|
82
|
+
):
|
|
83
|
+
self.npoints = num_points
|
|
84
|
+
self.preprocess = True
|
|
85
|
+
self.uniform = True
|
|
86
|
+
self.split = split
|
|
87
|
+
self.use_normal = use_normal
|
|
88
|
+
self.transform = transform
|
|
89
|
+
|
|
90
|
+
root_dir = pathlib.Path(data_dir)
|
|
91
|
+
data_dir = root_dir / 'raw'
|
|
92
|
+
data_list = root_dir / f'mattportobject_{split}_list.txt'
|
|
93
|
+
|
|
94
|
+
if not data_list.exists():
|
|
95
|
+
all_files = [i.name for i in data_dir.glob('*.npy')]
|
|
96
|
+
random.shuffle(all_files)
|
|
97
|
+
n_files = len(all_files)
|
|
98
|
+
n_train = int(0.8 * n_files)
|
|
99
|
+
n_val = int(0.1 * n_files)
|
|
100
|
+
train_files = all_files[:n_train]
|
|
101
|
+
val_files = all_files[n_train:n_train+n_val]
|
|
102
|
+
test_files = all_files[n_train+n_val:]
|
|
103
|
+
train_list = str(root_dir / (f'mattportobject_train_list.txt'))
|
|
104
|
+
val_list = str(root_dir / (f'mattportobject_val_list.txt'))
|
|
105
|
+
test_list = str(root_dir / (f'mattportobject_test_list.txt'))
|
|
106
|
+
with open(train_list, 'w') as f:
|
|
107
|
+
f.writelines('\n'.join(train_files))
|
|
108
|
+
with open(val_list, 'w') as f:
|
|
109
|
+
f.writelines('\n'.join(val_files))
|
|
110
|
+
with open(test_list, 'w') as f:
|
|
111
|
+
f.writelines('\n'.join(test_files))
|
|
112
|
+
with open(data_list, 'r') as f:
|
|
113
|
+
lines = f.read().splitlines()
|
|
114
|
+
self.datapath = [data_dir / l for l in lines]
|
|
115
|
+
|
|
116
|
+
if self.uniform:
|
|
117
|
+
self.save_path = os.path.join(
|
|
118
|
+
root_dir, 'matterport3dobjects_%s_%dpts_fps.h5' % (split, 2048))
|
|
119
|
+
else:
|
|
120
|
+
self.save_path = os.path.join(
|
|
121
|
+
root_dir, 'matterport3dobjects_%s_%dpts.h5' % (split, 2048))
|
|
122
|
+
|
|
123
|
+
npoints = 2048
|
|
124
|
+
if not os.path.exists(self.save_path):
|
|
125
|
+
logging.info(
|
|
126
|
+
'Processing data %s (only running in the first time)...' % self.save_path)
|
|
127
|
+
list_of_points = []
|
|
128
|
+
list_of_labels = []
|
|
129
|
+
|
|
130
|
+
for index in tqdm(range(len(self.datapath)), total=len(self.datapath)):
|
|
131
|
+
fn = self.datapath[index]
|
|
132
|
+
data = np.load(fn, allow_pickle=True).item()
|
|
133
|
+
cls = data['label']
|
|
134
|
+
point_set = data['points'].astype(np.float32)
|
|
135
|
+
if self.uniform:
|
|
136
|
+
point_set = fps(torch.from_numpy(point_set).unsqueeze(
|
|
137
|
+
0).cuda(), npoints).squeeze(0).cpu().numpy()
|
|
138
|
+
else:
|
|
139
|
+
point_set = point_set[:npoints, :]
|
|
140
|
+
|
|
141
|
+
list_of_points.append(point_set)
|
|
142
|
+
list_of_labels.append(cls)
|
|
143
|
+
|
|
144
|
+
all_points = np.stack(list_of_points)
|
|
145
|
+
all_labels = np.stack(list_of_labels)
|
|
146
|
+
all_data = {'data': all_points, 'label': all_labels}
|
|
147
|
+
hf = h5py.File(self.save_path, 'w')
|
|
148
|
+
data = hf.create_group('data')
|
|
149
|
+
for k, v in all_data.items():
|
|
150
|
+
data[k] = v
|
|
151
|
+
hf.close()
|
|
152
|
+
logging.info('Load processed data from %s...' % self.save_path)
|
|
153
|
+
with h5py.File(self.save_path, 'r') as f:
|
|
154
|
+
data = f['data']['data'][:].astype('float32')
|
|
155
|
+
label = f['data']['label'][:].astype('int32')
|
|
156
|
+
|
|
157
|
+
# TODO: make this in preprocessing step. not here.
|
|
158
|
+
cls_mapping = pd.read_csv(str(pathlib.Path(__file__).parent / "category_mapping.tsv"),
|
|
159
|
+
skiprows=1, header=None, sep='\t', usecols=[0, 16]).values.astype(int)
|
|
160
|
+
|
|
161
|
+
# step 1 remove negative label (useless)
|
|
162
|
+
idx = np.argwhere(label > 0).squeeze()
|
|
163
|
+
data = data[idx]
|
|
164
|
+
label = label[idx]
|
|
165
|
+
|
|
166
|
+
# step 2 mapping label to mat40
|
|
167
|
+
# cls_mapping is a np array. row 0 = wall = label(wall) --> mpcat40
|
|
168
|
+
label = cls_mapping[label-1][:, 1]
|
|
169
|
+
|
|
170
|
+
# step 3, remove the label not in mat40 (0, and 41)
|
|
171
|
+
label_bigger_0 = label > 0
|
|
172
|
+
label_smaller_41 = label < 41
|
|
173
|
+
idx = []
|
|
174
|
+
for i in range(len(label)):
|
|
175
|
+
if label_bigger_0[i] and label_smaller_41[i]:
|
|
176
|
+
idx.append(i)
|
|
177
|
+
self.data = data[idx]
|
|
178
|
+
self.label = label[idx] - 1
|
|
179
|
+
|
|
180
|
+
def __len__(self):
|
|
181
|
+
return len(self.data)
|
|
182
|
+
|
|
183
|
+
@property
|
|
184
|
+
def num_classes(self):
|
|
185
|
+
return self.label.max() + 1
|
|
186
|
+
|
|
187
|
+
def __getitem__(self, index):
|
|
188
|
+
points, label = self.data[index][:self.npoints], self.label[index]
|
|
189
|
+
if self.split == 'train':
|
|
190
|
+
np.random.shuffle(points)
|
|
191
|
+
data = {'pos': points[:, :3],
|
|
192
|
+
'x': points[:, 3:6 + 3 * self.use_normal],
|
|
193
|
+
'y': label
|
|
194
|
+
}
|
|
195
|
+
if self.transform is not None:
|
|
196
|
+
data = self.transform(data)
|
|
197
|
+
"""_summary_
|
|
198
|
+
from openpoints.dataset.vis3d import vis_points
|
|
199
|
+
|
|
200
|
+
for i, idx in enumerate(np.where(self.label==22)[0]):
|
|
201
|
+
if i >5:
|
|
202
|
+
break
|
|
203
|
+
vis_points(self.data[idx, :, :3], self.data[idx, :, 3:6]/255.)
|
|
204
|
+
"""
|
|
205
|
+
if 'heights' in data.keys():
|
|
206
|
+
data['x'] = torch.cat(
|
|
207
|
+
(data['pos'], data['heights'], data['x']), dim=1)
|
|
208
|
+
else:
|
|
209
|
+
data['x'] = torch.cat((data['pos'], data['x']), dim=1)
|
|
210
|
+
return data
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
|
|
2
|
+
import os, sys, zipfile, h5py, numpy as np, multiprocessing
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from tqdm import tqdm
|
|
5
|
+
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '../../../')))
|
|
6
|
+
from openpoints.dataset.utils3d import *
|
|
7
|
+
from openpoints.dataset.vis3d import *
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def unzip_folders(data_dir, unzipped_path):
|
|
11
|
+
for dirpath, dirs, files in os.walk(data_dir):
|
|
12
|
+
for file in files:
|
|
13
|
+
if file.endswith('zip'):
|
|
14
|
+
file_path = os.path.join(dirpath, file)
|
|
15
|
+
zip_file = zipfile.ZipFile(file_path)
|
|
16
|
+
for names in zip_file.namelist():
|
|
17
|
+
zip_file.extract(names, unzipped_path)
|
|
18
|
+
zip_file.close()
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def save_room_objects(mesh_path, save_name):
|
|
22
|
+
"""save the objects in a rooom together
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
mesh_path (_type_): _description_
|
|
26
|
+
save_name (_type_): _description_
|
|
27
|
+
"""
|
|
28
|
+
all_points = []
|
|
29
|
+
all_ins_labels = []
|
|
30
|
+
all_cls_labels = []
|
|
31
|
+
|
|
32
|
+
points, faces, f_cls_id, f_ins_id = read_mesh_vf(mesh_path)
|
|
33
|
+
# category id: https://github.com/niessner/Matterport/blob/master/metadata/category_mapping.tsv
|
|
34
|
+
# vis_points(points[:, :3], points[:, 3:6])
|
|
35
|
+
f_cls_id_unique = np.unique(f_cls_id) # the unique category ids (eg. pillow, wall)
|
|
36
|
+
for cls in f_cls_id_unique:
|
|
37
|
+
face_cls_flag = f_cls_id==cls # wheter face is current cls
|
|
38
|
+
face_cls = faces[face_cls_flag] # pick the face which is current cls
|
|
39
|
+
face_cls_ins = f_ins_id[face_cls_flag] # pick the instance label of the face
|
|
40
|
+
for ins_id in np.unique(face_cls_ins): # for each instance
|
|
41
|
+
point_idx = face_cls[face_cls_ins==ins_id].reshape(-1)
|
|
42
|
+
points_cls_ins = points[point_idx]
|
|
43
|
+
all_points.append(points_cls_ins)
|
|
44
|
+
all_ins_labels.append(ins_id)
|
|
45
|
+
all_cls_labels.append(cls)
|
|
46
|
+
data = {'points': all_points, 'ins_labels': all_ins_labels, 'y': all_cls_labels}
|
|
47
|
+
np.save(f'{save_name}.npy', data)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def save_per_object(mesh_path, save_name):
|
|
51
|
+
"""save each object in a h5 file.
|
|
52
|
+
|
|
53
|
+
Args:
|
|
54
|
+
mesh_path (_type_): _description_
|
|
55
|
+
save_name (_type_): _description_
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
points, faces, f_cls_id, f_ins_id = read_mesh_vf(mesh_path)
|
|
59
|
+
# category id: https://github.com/niessner/Matterport/blob/master/metadata/category_mapping.tsv
|
|
60
|
+
# vis_points(points[:, :3], points[:, 3:6])
|
|
61
|
+
f_cls_id_unique = np.unique(f_cls_id) # the unique category ids (eg. pillow, wall)
|
|
62
|
+
for cls in f_cls_id_unique:
|
|
63
|
+
face_cls_flag = f_cls_id==cls # wheter face is current cls
|
|
64
|
+
face_cls = faces[face_cls_flag] # pick the face which is current cls
|
|
65
|
+
face_cls_ins = f_ins_id[face_cls_flag] # pick the instance label of the face
|
|
66
|
+
|
|
67
|
+
for ins_id in np.unique(face_cls_ins): # for each instance
|
|
68
|
+
point_idx = face_cls[face_cls_ins==ins_id].reshape(-1)
|
|
69
|
+
points_cls_ins = points[point_idx]
|
|
70
|
+
vis_points(points_cls_ins[:, :3], points_cls_ins[:, 3:6])
|
|
71
|
+
data = {'points': points_cls_ins, 'ins_label': ins_id, 'label': cls}
|
|
72
|
+
|
|
73
|
+
# TODO: debug comment for now.
|
|
74
|
+
np.save(f'{save_name}_C{cls}_I{ins_id}.npy', data)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
if __name__ == "__main__":
|
|
78
|
+
# unzip data at first.
|
|
79
|
+
# root_path = '/data/3D/Matterport3d/v1/scans'
|
|
80
|
+
# unzipped_path = '/data/3D/Matterport3d/v1/scans_unzipped'
|
|
81
|
+
# unzip_folders(root_path, unzipped_path)
|
|
82
|
+
|
|
83
|
+
# loading all points to a single h5 file
|
|
84
|
+
|
|
85
|
+
root_path = Path('/data/3D/Matterport3d/v1/')
|
|
86
|
+
|
|
87
|
+
raw_path = root_path.joinpath('scans_unzipped')
|
|
88
|
+
save_dir = root_path.joinpath('objects')
|
|
89
|
+
save_dir.mkdir(exist_ok=True)
|
|
90
|
+
|
|
91
|
+
all_points = []
|
|
92
|
+
all_ins_labels = []
|
|
93
|
+
all_cls_labels = []
|
|
94
|
+
|
|
95
|
+
# p = multiprocessing.Pool()
|
|
96
|
+
for path in Path(raw_path).rglob('*.ply'):
|
|
97
|
+
file_path = path.parent.joinpath(path.name)
|
|
98
|
+
file_name = '/'.join(path.parts[-3:])
|
|
99
|
+
save_name = '_'.join([path.parts[-3], path.parts[-1].split('.')[0]])
|
|
100
|
+
save_path = os.path.join(save_dir, save_name)
|
|
101
|
+
print(f'===> processing {file_name} ...')
|
|
102
|
+
save_per_object(file_path, save_path)
|
|
103
|
+
# p.apply_async(save_per_object, [file_path, save_path])
|
|
104
|
+
# p.close()
|
|
105
|
+
# p.join() # Wait for all child processes to close.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
'''
|
|
2
|
+
Borrowed from PointBERT
|
|
3
|
+
@file: ModelNet.py
|
|
4
|
+
@time: 2021/3/19 15:51
|
|
5
|
+
'''
|
|
6
|
+
import os
|
|
7
|
+
import numpy as np
|
|
8
|
+
import warnings
|
|
9
|
+
import pickle
|
|
10
|
+
from tqdm import tqdm
|
|
11
|
+
from torch.utils.data import Dataset
|
|
12
|
+
from ..build import DATASETS
|
|
13
|
+
import torch
|
|
14
|
+
import logging
|
|
15
|
+
warnings.filterwarnings('ignore')
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def pc_normalize(pc):
|
|
19
|
+
centroid = np.mean(pc, axis=0)
|
|
20
|
+
pc = pc - centroid
|
|
21
|
+
m = np.max(np.sqrt(np.sum(pc ** 2, axis=1)))
|
|
22
|
+
pc = pc / m
|
|
23
|
+
return pc
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def farthest_point_sample(point, npoint):
|
|
27
|
+
"""
|
|
28
|
+
Input:
|
|
29
|
+
xyz: pointcloud data, [N, D]
|
|
30
|
+
npoint: number of samples
|
|
31
|
+
Return:
|
|
32
|
+
centroids: sampled pointcloud index, [npoint, D]
|
|
33
|
+
"""
|
|
34
|
+
N, D = point.shape
|
|
35
|
+
xyz = point[:, :3]
|
|
36
|
+
centroids = np.zeros((npoint,))
|
|
37
|
+
distance = np.ones((N,)) * 1e10
|
|
38
|
+
farthest = np.random.randint(0, N)
|
|
39
|
+
for i in range(npoint):
|
|
40
|
+
centroids[i] = farthest
|
|
41
|
+
centroid = xyz[farthest, :]
|
|
42
|
+
dist = np.sum((xyz - centroid) ** 2, -1)
|
|
43
|
+
mask = dist < distance
|
|
44
|
+
distance[mask] = dist[mask]
|
|
45
|
+
farthest = np.argmax(distance, -1)
|
|
46
|
+
point = point[centroids.astype(np.int32)]
|
|
47
|
+
return point
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@DATASETS.register_module()
|
|
51
|
+
class ModelNet(Dataset):
|
|
52
|
+
def __init__(self,
|
|
53
|
+
data_dir, num_points, num_classes,
|
|
54
|
+
use_normals=False,
|
|
55
|
+
split='train',
|
|
56
|
+
transform=None
|
|
57
|
+
):
|
|
58
|
+
self.root = os.path.join(data_dir, 'modelnet40_normal_resampled')
|
|
59
|
+
self.npoints = num_points
|
|
60
|
+
self.use_normals = use_normals
|
|
61
|
+
self.num_category = num_classes
|
|
62
|
+
split = 'train' if split.lower() == 'train' else 'test' # val = test
|
|
63
|
+
self.split = split
|
|
64
|
+
|
|
65
|
+
if self.num_category == 10:
|
|
66
|
+
self.catfile = os.path.join(
|
|
67
|
+
self.root, 'modelnet10_shape_names.txt')
|
|
68
|
+
else:
|
|
69
|
+
self.catfile = os.path.join(
|
|
70
|
+
self.root, 'modelnet40_shape_names.txt')
|
|
71
|
+
|
|
72
|
+
self.cat = [line.rstrip() for line in open(self.catfile)]
|
|
73
|
+
self.classes = dict(zip(self.cat, range(len(self.cat))))
|
|
74
|
+
|
|
75
|
+
shape_ids = {}
|
|
76
|
+
if self.num_category == 10:
|
|
77
|
+
shape_ids['train'] = [line.rstrip() for line in open(
|
|
78
|
+
os.path.join(self.root, 'modelnet10_train.txt'))]
|
|
79
|
+
shape_ids['test'] = [line.rstrip() for line in open(
|
|
80
|
+
os.path.join(self.root, 'modelnet10_test.txt'))]
|
|
81
|
+
else:
|
|
82
|
+
shape_ids['train'] = [line.rstrip() for line in open(
|
|
83
|
+
os.path.join(self.root, 'modelnet40_train.txt'))]
|
|
84
|
+
shape_ids['test'] = [line.rstrip() for line in open(
|
|
85
|
+
os.path.join(self.root, 'modelnet40_test.txt'))]
|
|
86
|
+
|
|
87
|
+
assert (split == 'train' or split == 'test')
|
|
88
|
+
shape_names = ['_'.join(x.split('_')[0:-1]) for x in shape_ids[split]]
|
|
89
|
+
self.datapath = [(shape_names[i], os.path.join(self.root, shape_names[i], shape_ids[split][i]) + '.txt') for i
|
|
90
|
+
in range(len(shape_ids[split]))]
|
|
91
|
+
logging.info('The size of %s data is %d' % (split, len(self.datapath)))
|
|
92
|
+
self.transform = transform
|
|
93
|
+
|
|
94
|
+
def __len__(self):
|
|
95
|
+
return len(self.datapath)
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def num_classes(self):
|
|
99
|
+
return self.list_of_labels.max() + 1
|
|
100
|
+
|
|
101
|
+
def _get_item(self, index):
|
|
102
|
+
fn = self.datapath[index]
|
|
103
|
+
cls = self.classes[self.datapath[index][0]]
|
|
104
|
+
label = np.array([cls]).astype(np.int64)
|
|
105
|
+
point_set = np.loadtxt(fn[1], delimiter=',').astype(np.float32)
|
|
106
|
+
return point_set[:, 0:3], point_set[:, 3:], label[0]
|
|
107
|
+
|
|
108
|
+
def __getitem__(self, index):
|
|
109
|
+
points, feats, label = self._get_item(index)
|
|
110
|
+
if self.split == 'train':
|
|
111
|
+
np.random.shuffle(points)
|
|
112
|
+
data = {'pos': points,
|
|
113
|
+
'y': label
|
|
114
|
+
}
|
|
115
|
+
if self.use_normals:
|
|
116
|
+
data['x'] = feats
|
|
117
|
+
if self.transform is not None:
|
|
118
|
+
data = self.transform(data)
|
|
119
|
+
|
|
120
|
+
if self.use_normals:
|
|
121
|
+
data['x'] = torch.cat((data['pos'], data['x']), dim=1)
|
|
122
|
+
if 'heights' in data.keys():
|
|
123
|
+
data['x'] = torch.cat((data['x'], data['heights']), dim=1)
|
|
124
|
+
return data
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"""Modified from DeepGCN and DGCNN
|
|
2
|
+
Reference: https://github.com/lightaime/deep_gcns_torch/tree/master/examples/classification
|
|
3
|
+
"""
|
|
4
|
+
import os
|
|
5
|
+
import glob
|
|
6
|
+
import h5py
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pickle
|
|
9
|
+
import logging
|
|
10
|
+
import ssl
|
|
11
|
+
import urllib
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from tqdm import tqdm
|
|
14
|
+
import torch
|
|
15
|
+
from torch.utils.data import Dataset
|
|
16
|
+
from torchvision.datasets.utils import extract_archive, check_integrity
|
|
17
|
+
from ..build import DATASETS
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def download_and_extract_archive(url, path, md5=None):
|
|
21
|
+
# Works when the SSL certificate is expired for the link
|
|
22
|
+
path = Path(path)
|
|
23
|
+
extract_path = path
|
|
24
|
+
if not path.exists():
|
|
25
|
+
path.mkdir(parents=True, exist_ok=True)
|
|
26
|
+
file_path = path / Path(url).name
|
|
27
|
+
if not file_path.exists() or not check_integrity(file_path, md5):
|
|
28
|
+
print(f'{file_path} not found or corrupted')
|
|
29
|
+
print(f'downloading from {url}')
|
|
30
|
+
context = ssl.SSLContext()
|
|
31
|
+
with urllib.request.urlopen(url, context=context) as response:
|
|
32
|
+
with tqdm(total=response.length) as pbar:
|
|
33
|
+
with open(file_path, 'wb') as file:
|
|
34
|
+
chunk_size = 1024
|
|
35
|
+
chunks = iter(lambda: response.read(chunk_size), '')
|
|
36
|
+
for chunk in chunks:
|
|
37
|
+
if not chunk:
|
|
38
|
+
break
|
|
39
|
+
pbar.update(chunk_size)
|
|
40
|
+
file.write(chunk)
|
|
41
|
+
extract_archive(str(file_path), str(extract_path))
|
|
42
|
+
return extract_path
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def load_data(data_dir, partition, url):
|
|
46
|
+
download_and_extract_archive(url, data_dir)
|
|
47
|
+
all_data = []
|
|
48
|
+
all_label = []
|
|
49
|
+
for h5_name in glob.glob(os.path.join(data_dir, 'modelnet40_ply_hdf5_2048', 'ply_data_%s*.h5' % partition)):
|
|
50
|
+
with h5py.File(h5_name, 'r') as f:
|
|
51
|
+
data = f['data'][:].astype('float32')
|
|
52
|
+
label = f['label'][:].astype('int64')
|
|
53
|
+
all_data.append(data)
|
|
54
|
+
all_label.append(label)
|
|
55
|
+
all_data = np.concatenate(all_data, axis=0)
|
|
56
|
+
all_label = np.concatenate(all_label, axis=0).squeeze(-1)
|
|
57
|
+
return all_data, all_label
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
@DATASETS.register_module()
|
|
61
|
+
class ModelNet40Ply2048(Dataset):
|
|
62
|
+
"""
|
|
63
|
+
This is the data loader for ModelNet 40
|
|
64
|
+
ModelNet40 contains 12,311 meshed CAD models from 40 categories.
|
|
65
|
+
num_points: 1024 by default
|
|
66
|
+
data_dir
|
|
67
|
+
paritition: train or test
|
|
68
|
+
"""
|
|
69
|
+
dir_name = 'modelnet40_ply_hdf5_2048'
|
|
70
|
+
md5 = 'c9ab8e6dfb16f67afdab25e155c79e59'
|
|
71
|
+
url = f'https://shapenet.cs.stanford.edu/media/{dir_name}.zip'
|
|
72
|
+
classes = ['airplane',
|
|
73
|
+
'bathtub',
|
|
74
|
+
'bed',
|
|
75
|
+
'bench',
|
|
76
|
+
'bookshelf',
|
|
77
|
+
'bottle',
|
|
78
|
+
'bowl',
|
|
79
|
+
'car',
|
|
80
|
+
'chair',
|
|
81
|
+
'cone',
|
|
82
|
+
'cup',
|
|
83
|
+
'curtain',
|
|
84
|
+
'desk',
|
|
85
|
+
'door',
|
|
86
|
+
'dresser',
|
|
87
|
+
'flower_pot',
|
|
88
|
+
'glass_box',
|
|
89
|
+
'guitar',
|
|
90
|
+
'keyboard',
|
|
91
|
+
'lamp',
|
|
92
|
+
'laptop',
|
|
93
|
+
'mantel',
|
|
94
|
+
'monitor',
|
|
95
|
+
'night_stand',
|
|
96
|
+
'person',
|
|
97
|
+
'piano',
|
|
98
|
+
'plant',
|
|
99
|
+
'radio',
|
|
100
|
+
'range_hood',
|
|
101
|
+
'sink',
|
|
102
|
+
'sofa',
|
|
103
|
+
'stairs',
|
|
104
|
+
'stool',
|
|
105
|
+
'table',
|
|
106
|
+
'tent',
|
|
107
|
+
'toilet',
|
|
108
|
+
'tv_stand',
|
|
109
|
+
'vase',
|
|
110
|
+
'wardrobe',
|
|
111
|
+
'xbox']
|
|
112
|
+
|
|
113
|
+
def __init__(self,
|
|
114
|
+
num_points=1024,
|
|
115
|
+
data_dir="./data/ModelNet40Ply2048",
|
|
116
|
+
split='train',
|
|
117
|
+
transform=None
|
|
118
|
+
):
|
|
119
|
+
data_dir = os.path.join(
|
|
120
|
+
os.getcwd(), data_dir) if data_dir.startswith('.') else data_dir
|
|
121
|
+
self.partition = 'train' if split.lower() == 'train' else 'test' # val = test
|
|
122
|
+
self.data, self.label = load_data(data_dir, self.partition, self.url)
|
|
123
|
+
self.num_points = num_points
|
|
124
|
+
logging.info(f'==> sucessfully loaded {self.partition} data')
|
|
125
|
+
self.transform = transform
|
|
126
|
+
|
|
127
|
+
def __getitem__(self, item):
|
|
128
|
+
pointcloud = self.data[item][:self.num_points]
|
|
129
|
+
label = self.label[item]
|
|
130
|
+
|
|
131
|
+
if self.partition == 'train':
|
|
132
|
+
np.random.shuffle(pointcloud)
|
|
133
|
+
data = {'pos': pointcloud,
|
|
134
|
+
'y': label
|
|
135
|
+
}
|
|
136
|
+
if self.transform is not None:
|
|
137
|
+
data = self.transform(data)
|
|
138
|
+
|
|
139
|
+
if 'heights' in data.keys():
|
|
140
|
+
data['x'] = torch.cat((data['pos'], data['heights']), dim=1)
|
|
141
|
+
else:
|
|
142
|
+
data['x'] = data['pos']
|
|
143
|
+
return data
|
|
144
|
+
|
|
145
|
+
def __len__(self):
|
|
146
|
+
return self.data.shape[0]
|
|
147
|
+
|
|
148
|
+
@property
|
|
149
|
+
def num_classes(self):
|
|
150
|
+
return np.max(self.label) + 1
|
|
151
|
+
|
|
152
|
+
""" for visulalization
|
|
153
|
+
from openpoints.dataset import vis_multi_points
|
|
154
|
+
import copy
|
|
155
|
+
old_points = copy.deepcopy(data['pos'])
|
|
156
|
+
if self.transform is not None:
|
|
157
|
+
data = self.transform(data)
|
|
158
|
+
new_points = copy.deepcopy(data['pos'])
|
|
159
|
+
vis_multi_points([old_points, new_points.numpy()])
|
|
160
|
+
End of visulization """
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .data import *
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
import torch
|
|
3
|
+
from ..dataset_base import DatasetBase
|
|
4
|
+
from ..graph_dataset import GraphDataset
|
|
5
|
+
from ..graph_dataset import SVDEncodingsGraphDataset
|
|
6
|
+
from ..graph_dataset import StructuralDataset
|
|
7
|
+
|
|
8
|
+
class MOLHIVDataset(DatasetBase):
|
|
9
|
+
def __init__(self,
|
|
10
|
+
dataset_path ,
|
|
11
|
+
dataset_name = 'MOLHIV' ,
|
|
12
|
+
**kwargs
|
|
13
|
+
):
|
|
14
|
+
super().__init__(dataset_name = dataset_name,
|
|
15
|
+
**kwargs)
|
|
16
|
+
self.dataset_path = dataset_path
|
|
17
|
+
|
|
18
|
+
@property
|
|
19
|
+
def dataset(self):
|
|
20
|
+
try:
|
|
21
|
+
return self._dataset
|
|
22
|
+
except AttributeError:
|
|
23
|
+
from ogb.graphproppred import GraphPropPredDataset
|
|
24
|
+
self._dataset = GraphPropPredDataset(name='ogbg-molhiv', root=self.dataset_path)
|
|
25
|
+
return self._dataset
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def record_tokens(self):
|
|
29
|
+
try:
|
|
30
|
+
return self._record_tokens
|
|
31
|
+
except AttributeError:
|
|
32
|
+
split = {'training':'train',
|
|
33
|
+
'validation':'valid',
|
|
34
|
+
'test':'test'}[self.split]
|
|
35
|
+
self._record_tokens = self.dataset.get_idx_split()[split]
|
|
36
|
+
return self._record_tokens
|
|
37
|
+
|
|
38
|
+
def read_record(self, token):
|
|
39
|
+
graph, target = self.dataset[token]
|
|
40
|
+
graph['num_nodes'] = np.array(graph['num_nodes'], dtype=np.int16)
|
|
41
|
+
graph['edges'] = graph.pop('edge_index').T.astype(np.int16)
|
|
42
|
+
graph['edge_features'] = graph.pop('edge_feat').astype(np.int16)
|
|
43
|
+
graph['node_features'] = graph.pop('node_feat').astype(np.int16)
|
|
44
|
+
graph['target'] = np.array(target, np.float32)
|
|
45
|
+
return graph
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class MOLHIVGraphDataset(GraphDataset,MOLHIVDataset):
|
|
50
|
+
pass
|
|
51
|
+
|
|
52
|
+
class MOLHIVSVDGraphDataset(SVDEncodingsGraphDataset,MOLHIVDataset):
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
class MOLHIVStructuralGraphDataset(StructuralDataset,MOLHIVGraphDataset):
|
|
56
|
+
pass
|
|
57
|
+
|
|
58
|
+
class MOLHIVStructuralSVDGraphDataset(StructuralDataset,MOLHIVSVDGraphDataset):
|
|
59
|
+
pass
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from .data import *
|