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,764 @@
|
|
|
1
|
+
# Copyright (c) Chris Choy (chrischoy@ai.stanford.edu). All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Please cite "4D Spatio-Temporal ConvNets: Minkowski Convolutional Neural
|
|
4
|
+
# Networks", CVPR'19 (https://arxiv.org/abs/1904.08755) if you use any part of
|
|
5
|
+
# the code.
|
|
6
|
+
import random, logging
|
|
7
|
+
import numpy as np
|
|
8
|
+
import torch
|
|
9
|
+
import collections
|
|
10
|
+
from .transforms_factory import DataTransforms
|
|
11
|
+
#
|
|
12
|
+
# import scipy
|
|
13
|
+
# import scipy.ndimage
|
|
14
|
+
# import scipy.interpolate
|
|
15
|
+
from scipy.linalg import expm, norm
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@DataTransforms.register_module()
|
|
19
|
+
class PointCloudToTensor(object):
|
|
20
|
+
def __init__(self, **kwargs):
|
|
21
|
+
pass
|
|
22
|
+
|
|
23
|
+
def __call__(self, data):
|
|
24
|
+
pts = data['pos']
|
|
25
|
+
normals = data['normals'] if 'normals' in data.keys() else None
|
|
26
|
+
colors = data['colors'] if 'colors' in data.keys() else None
|
|
27
|
+
data['pos'] = torch.from_numpy(pts).float()
|
|
28
|
+
if normals is not None:
|
|
29
|
+
data['normals'] = torch.from_numpy(normals).float().transpose(0, 1)
|
|
30
|
+
if colors is not None:
|
|
31
|
+
data['colors'] = torch.from_numpy(colors).transpose(0, 1).float()
|
|
32
|
+
return data
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@DataTransforms.register_module()
|
|
36
|
+
class PointCloudCenterAndNormalize(object):
|
|
37
|
+
def __init__(self, centering=True,
|
|
38
|
+
normalize=True,
|
|
39
|
+
gravity_dim=2,
|
|
40
|
+
append_xyz=False,
|
|
41
|
+
**kwargs):
|
|
42
|
+
self.centering = centering
|
|
43
|
+
self.normalize = normalize
|
|
44
|
+
self.gravity_dim = gravity_dim
|
|
45
|
+
self.append_xyz = append_xyz
|
|
46
|
+
|
|
47
|
+
def __call__(self, data):
|
|
48
|
+
if hasattr(data, 'keys'):
|
|
49
|
+
if self.append_xyz:
|
|
50
|
+
data['heights'] = data['pos'] - torch.min(data['pos'])
|
|
51
|
+
else:
|
|
52
|
+
height = data['pos'][:, self.gravity_dim:self.gravity_dim + 1]
|
|
53
|
+
data['heights'] = height - torch.min(height)
|
|
54
|
+
|
|
55
|
+
if self.centering:
|
|
56
|
+
data['pos'] = data['pos'] - torch.mean(data['pos'], axis=0, keepdims=True)
|
|
57
|
+
|
|
58
|
+
if self.normalize:
|
|
59
|
+
m = torch.max(torch.sqrt(torch.sum(data['pos'] ** 2, axis=-1, keepdims=True)), axis=0, keepdims=True)[0]
|
|
60
|
+
data['pos'] = data['pos'] / m
|
|
61
|
+
else:
|
|
62
|
+
if self.centering:
|
|
63
|
+
data = data - torch.mean(data, axis=-1, keepdims=True)
|
|
64
|
+
if self.normalize:
|
|
65
|
+
m = torch.max(torch.sqrt(torch.sum(data ** 2, axis=-1, keepdims=True)), axis=0, keepdims=True)[0]
|
|
66
|
+
data = data / m
|
|
67
|
+
return data
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
@DataTransforms.register_module()
|
|
71
|
+
class PointCloudXYZAlign(object):
|
|
72
|
+
"""Centering the point cloud in the xy plane
|
|
73
|
+
Args:
|
|
74
|
+
object (_type_): _description_
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
def __init__(self,
|
|
78
|
+
gravity_dim=2,
|
|
79
|
+
**kwargs):
|
|
80
|
+
self.gravity_dim = gravity_dim
|
|
81
|
+
|
|
82
|
+
def __call__(self, data):
|
|
83
|
+
if hasattr(data, 'keys'):
|
|
84
|
+
data['pos'] -= torch.mean(data['pos'], axis=0, keepdims=True)
|
|
85
|
+
data['pos'][:, self.gravity_dim] -= torch.min(data['pos'][:, self.gravity_dim])
|
|
86
|
+
else:
|
|
87
|
+
data -= torch.mean(data, axis=0, keepdims=True)
|
|
88
|
+
data[:, self.gravity_dim] -= torch.min(data[:, self.gravity_dim])
|
|
89
|
+
return data
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@DataTransforms.register_module()
|
|
93
|
+
class RandomDropout(object):
|
|
94
|
+
def __init__(self, dropout_ratio=0.2, dropout_application_ratio=0.2, **kwargs):
|
|
95
|
+
"""
|
|
96
|
+
upright_axis: axis index among x,y,z, i.e. 2 for z
|
|
97
|
+
"""
|
|
98
|
+
self.dropout_ratio = dropout_ratio
|
|
99
|
+
self.dropout_application_ratio = dropout_application_ratio
|
|
100
|
+
|
|
101
|
+
def __call__(self, data):
|
|
102
|
+
if random.random() < self.dropout_application_ratio:
|
|
103
|
+
N = len(data['pos'])
|
|
104
|
+
inds = torch.randperm(N)[:int(N * (1 - self.dropout_ratio))]
|
|
105
|
+
for k, v in data.items():
|
|
106
|
+
if isinstance(v, torch.Tensor):
|
|
107
|
+
data[k] = v[inds]
|
|
108
|
+
return data
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
@DataTransforms.register_module()
|
|
112
|
+
class RandomHorizontalFlip(object):
|
|
113
|
+
def __init__(self, upright_axis, aug_prob=0.95, **kwargs):
|
|
114
|
+
"""
|
|
115
|
+
upright_axis: axis index among x,y,z, i.e. 2 for z
|
|
116
|
+
"""
|
|
117
|
+
self.D = 3
|
|
118
|
+
self.upright_axis = {'x': 0, 'y': 1, 'z': 2}[upright_axis.lower()]
|
|
119
|
+
# Use the rest of axes for flipping.
|
|
120
|
+
self.horz_axes = set(range(self.D)) - set([self.upright_axis])
|
|
121
|
+
self.aug_prob = aug_prob
|
|
122
|
+
|
|
123
|
+
def __call__(self, data):
|
|
124
|
+
if random.random() < self.aug_prob:
|
|
125
|
+
for curr_ax in self.horz_axes:
|
|
126
|
+
if random.random() < 0.5:
|
|
127
|
+
coord_max = torch.max(data['pos'])
|
|
128
|
+
data['pos'][:, curr_ax] = coord_max - data['pos'][:, curr_ax]
|
|
129
|
+
if 'normals' in data:
|
|
130
|
+
data['normals'][:, curr_ax] = -data['normals'][:, curr_ax]
|
|
131
|
+
|
|
132
|
+
return data
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
@DataTransforms.register_module()
|
|
136
|
+
class PointCloudScaling(object):
|
|
137
|
+
def __init__(self,
|
|
138
|
+
scale=[2. / 3, 3. / 2],
|
|
139
|
+
anisotropic=True,
|
|
140
|
+
scale_xyz=[True, True, True],
|
|
141
|
+
mirror=[0, 0, 0], # the possibility of mirroring. set to a negative value to not mirror
|
|
142
|
+
**kwargs):
|
|
143
|
+
self.scale_min, self.scale_max = np.array(scale).astype(np.float32)
|
|
144
|
+
self.anisotropic = anisotropic
|
|
145
|
+
self.scale_xyz = scale_xyz
|
|
146
|
+
self.mirror = torch.from_numpy(np.array(mirror))
|
|
147
|
+
self.use_mirroring = torch.sum(torch.tensor(self.mirror)>0) != 0
|
|
148
|
+
|
|
149
|
+
def __call__(self, data):
|
|
150
|
+
device = data['pos'].device if hasattr(data, 'keys') else data.device
|
|
151
|
+
scale = torch.rand(3 if self.anisotropic else 1, dtype=torch.float32, device=device) * (
|
|
152
|
+
self.scale_max - self.scale_min) + self.scale_min
|
|
153
|
+
if self.use_mirroring:
|
|
154
|
+
assert self.anisotropic==True
|
|
155
|
+
self.mirror = self.mirror.to(device)
|
|
156
|
+
mirror = (torch.rand(3, device=device) > self.mirror).to(torch.float32) * 2 - 1
|
|
157
|
+
scale *= mirror
|
|
158
|
+
for i, s in enumerate(self.scale_xyz):
|
|
159
|
+
if not s: scale[i] = 1
|
|
160
|
+
if hasattr(data, 'keys'):
|
|
161
|
+
data['pos'] *= scale
|
|
162
|
+
else:
|
|
163
|
+
data *= scale
|
|
164
|
+
return data
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
@DataTransforms.register_module()
|
|
168
|
+
class PointCloudTranslation(object):
|
|
169
|
+
def __init__(self, shift=[0.2, 0.2, 0.], **kwargs):
|
|
170
|
+
self.shift = torch.from_numpy(np.array(shift)).to(torch.float32)
|
|
171
|
+
|
|
172
|
+
def __call__(self, data):
|
|
173
|
+
device = data['pos'].device if hasattr(data, 'keys') else data.device
|
|
174
|
+
translation = torch.rand(3, dtype=torch.float32, device=device) * self.shift.to(device)
|
|
175
|
+
if hasattr(data, 'keys'):
|
|
176
|
+
data['pos'] += translation
|
|
177
|
+
else:
|
|
178
|
+
data += translation
|
|
179
|
+
return data
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
@DataTransforms.register_module()
|
|
183
|
+
class PointCloudScaleAndTranslate(object):
|
|
184
|
+
def __init__(self, scale=[2. / 3, 3. / 2], scale_xyz=[True, True, True], # ratio for xyz dimenions
|
|
185
|
+
anisotropic=True,
|
|
186
|
+
shift=[0.2, 0.2, 0.2],
|
|
187
|
+
mirror=[0, 0, 0], # the possibility of mirroring. set to a negative value to not mirror
|
|
188
|
+
**kwargs):
|
|
189
|
+
self.scale_min, self.scale_max = np.array(scale).astype(np.float32)
|
|
190
|
+
self.shift = torch.from_numpy(np.array(shift)).to(torch.float32)
|
|
191
|
+
self.scale_xyz = scale_xyz
|
|
192
|
+
self.anisotropic = anisotropic
|
|
193
|
+
self.mirror = torch.from_numpy(np.array(mirror))
|
|
194
|
+
self.use_mirroring = torch.sum(self.mirror>0) != 0
|
|
195
|
+
|
|
196
|
+
def __call__(self, data):
|
|
197
|
+
device = data['pos'].device if hasattr(data, 'keys') else data.device
|
|
198
|
+
scale = torch.rand(3 if self.anisotropic else 1, dtype=torch.float32, device=device) * (
|
|
199
|
+
self.scale_max - self.scale_min) + self.scale_min
|
|
200
|
+
# * note : scale_xyz has higher priority than mirror
|
|
201
|
+
if self.use_mirroring:
|
|
202
|
+
assert self.anisotropic==True
|
|
203
|
+
self.mirror = self.mirror.to(device)
|
|
204
|
+
mirror = (torch.rand(3, device=device) > self.mirror).to(torch.float32) * 2 - 1
|
|
205
|
+
scale *= mirror
|
|
206
|
+
for i, s in enumerate(self.scale_xyz):
|
|
207
|
+
if not s: scale[i] = 1
|
|
208
|
+
translation = (torch.rand(3, dtype=torch.float32, device=device) - 0.5) * 2 * self.shift.to(device)
|
|
209
|
+
if hasattr(data, 'keys'):
|
|
210
|
+
data['pos'] = torch.mul(data['pos'], scale) + translation
|
|
211
|
+
else:
|
|
212
|
+
data = torch.mul(data, scale) + translation
|
|
213
|
+
return data
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
@DataTransforms.register_module()
|
|
217
|
+
class PointCloudJitter(object):
|
|
218
|
+
def __init__(self, jitter_sigma=0.01, jitter_clip=0.05, **kwargs):
|
|
219
|
+
self.noise_std = jitter_sigma
|
|
220
|
+
self.noise_clip = jitter_clip
|
|
221
|
+
|
|
222
|
+
def __call__(self, data):
|
|
223
|
+
if hasattr(data, 'keys'):
|
|
224
|
+
noise = torch.randn_like(data['pos']) * self.noise_std
|
|
225
|
+
data['pos'] += noise.clamp_(-self.noise_clip, self.noise_clip)
|
|
226
|
+
else:
|
|
227
|
+
noise = torch.randn_like(data) * self.noise_std
|
|
228
|
+
data += noise.clamp_(-self.noise_clip, self.noise_clip)
|
|
229
|
+
return data
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
@DataTransforms.register_module()
|
|
233
|
+
class PointCloudScaleAndJitter(object):
|
|
234
|
+
def __init__(self,
|
|
235
|
+
scale=[2. / 3, 3. / 2],
|
|
236
|
+
scale_xyz=[True, True, True], # ratio for xyz dimenions
|
|
237
|
+
anisotropic=True, # scaling in different ratios for x, y, z
|
|
238
|
+
jitter_sigma=0.01, jitter_clip=0.05,
|
|
239
|
+
mirror=[0, 0, 0], # mirror scaling, x --> -x
|
|
240
|
+
**kwargs):
|
|
241
|
+
self.scale_min, self.scale_max = np.array(scale).astype(np.float32)
|
|
242
|
+
self.scale_xyz = scale_xyz
|
|
243
|
+
self.noise_std = jitter_sigma
|
|
244
|
+
self.noise_clip = jitter_clip
|
|
245
|
+
self.anisotropic = anisotropic
|
|
246
|
+
self.mirror = torch.from_numpy(np.array(mirror))
|
|
247
|
+
|
|
248
|
+
def __call__(self, data):
|
|
249
|
+
device = data['pos'].device if hasattr(data, 'keys') else data.device
|
|
250
|
+
scale = torch.rand(3 if self.anisotropic else 1, dtype=torch.float32, device=device) * (
|
|
251
|
+
self.scale_max - self.scale_min) + self.scale_min
|
|
252
|
+
mirror = torch.round(torch.rand(3, device=device)) * 2 - 1
|
|
253
|
+
self.mirror = self.mirror.to(device)
|
|
254
|
+
mirror = mirror * self.mirror + (1 - self.mirror)
|
|
255
|
+
scale *= mirror
|
|
256
|
+
for i, s in enumerate(self.scale_xyz):
|
|
257
|
+
if not s: scale[i] = 1
|
|
258
|
+
if hasattr(data, 'keys'):
|
|
259
|
+
noise = (torch.randn_like(data['pos']) * self.noise_std).clamp_(-self.noise_clip, self.noise_clip)
|
|
260
|
+
data['pos'] = torch.mul(data['pos'], scale) + noise
|
|
261
|
+
else:
|
|
262
|
+
noise = (torch.randn_like(data) * self.noise_std).clamp_(-self.noise_clip, self.noise_clip)
|
|
263
|
+
data = torch.mul(data, scale) + noise
|
|
264
|
+
return data
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
@DataTransforms.register_module()
|
|
268
|
+
class PointCloudRotation(object):
|
|
269
|
+
def __init__(self, angle=[0, 0, 0], **kwargs):
|
|
270
|
+
self.angle = np.array(angle) * np.pi
|
|
271
|
+
|
|
272
|
+
@staticmethod
|
|
273
|
+
def M(axis, theta):
|
|
274
|
+
return expm(np.cross(np.eye(3), axis / norm(axis) * theta))
|
|
275
|
+
|
|
276
|
+
def __call__(self, data):
|
|
277
|
+
if hasattr(data, 'keys'):
|
|
278
|
+
device = data['pos'].device
|
|
279
|
+
else:
|
|
280
|
+
device = data.device
|
|
281
|
+
|
|
282
|
+
if isinstance(self.angle, collections.Iterable):
|
|
283
|
+
rot_mats = []
|
|
284
|
+
for axis_ind, rot_bound in enumerate(self.angle):
|
|
285
|
+
theta = 0
|
|
286
|
+
axis = np.zeros(3)
|
|
287
|
+
axis[axis_ind] = 1
|
|
288
|
+
if rot_bound is not None:
|
|
289
|
+
theta = np.random.uniform(-rot_bound, rot_bound)
|
|
290
|
+
rot_mats.append(self.M(axis, theta))
|
|
291
|
+
# Use random order
|
|
292
|
+
np.random.shuffle(rot_mats)
|
|
293
|
+
rot_mat = torch.tensor(rot_mats[0] @ rot_mats[1] @ rot_mats[2], dtype=torch.float32, device=device)
|
|
294
|
+
else:
|
|
295
|
+
raise ValueError()
|
|
296
|
+
|
|
297
|
+
""" DEBUG
|
|
298
|
+
from openpoints.dataset import vis_multi_points
|
|
299
|
+
old_points = data.cpu().numpy()
|
|
300
|
+
# old_points = data['pos'].numpy()
|
|
301
|
+
# new_points = (data['pos'] @ rot_mat.T).numpy()
|
|
302
|
+
new_points = (data @ rot_mat.T).cpu().numpy()
|
|
303
|
+
vis_multi_points([old_points, new_points])
|
|
304
|
+
End of DEBUG"""
|
|
305
|
+
|
|
306
|
+
if hasattr(data, 'keys'):
|
|
307
|
+
data['pos'] = data['pos'] @ rot_mat.T
|
|
308
|
+
if 'normals' in data:
|
|
309
|
+
data['normals'] = data['normals'] @ rot_mat.T
|
|
310
|
+
else:
|
|
311
|
+
data = data @ rot_mat.T
|
|
312
|
+
return data
|
|
313
|
+
|
|
314
|
+
|
|
315
|
+
# @DataTransforms.register_module()
|
|
316
|
+
# class ChromaticTranslation(object):
|
|
317
|
+
# """Add random color to the image, input must be an array in [0,255] or a PIL image"""
|
|
318
|
+
#
|
|
319
|
+
# def __init__(self, trans_range_ratio=1e-1, aug_prob=0.95, **kwargs):
|
|
320
|
+
# """
|
|
321
|
+
# trans_range_ratio: ratio of translation i.e. 255 * 2 * ratio * rand(-0.5, 0.5)
|
|
322
|
+
# """
|
|
323
|
+
# self.trans_range_ratio = trans_range_ratio
|
|
324
|
+
# self.aug_prob = aug_prob
|
|
325
|
+
#
|
|
326
|
+
# def __call__(self, data):
|
|
327
|
+
# if 'colors' in data:
|
|
328
|
+
# if random.random() < self.aug_prob:
|
|
329
|
+
# tr = (torch.rand(1, 3, device=data['colors'].device) - 0.5) * 255 * 2 * self.trans_range_ratio
|
|
330
|
+
# data['colors'] = torch.clamp(tr + data['colors'], 0, 255)
|
|
331
|
+
# return data
|
|
332
|
+
#
|
|
333
|
+
|
|
334
|
+
#
|
|
335
|
+
# @DataTransforms.register_module()
|
|
336
|
+
# class PointCloudRandomScale(object):#
|
|
337
|
+
# # @DataTransforms.register_module()
|
|
338
|
+
# # class ChromaticAutoContrast(object):
|
|
339
|
+
# # def __init__(self, randomize_blend_factor=True, blend_factor=0.5, **kwargs):
|
|
340
|
+
# # self.randomize_blend_factor = randomize_blend_factor
|
|
341
|
+
# # self.blend_factor = blend_factor
|
|
342
|
+
# #
|
|
343
|
+
# # def __call__(self, data, **kwargs):
|
|
344
|
+
# # if 'colors' in data:
|
|
345
|
+
# # if random.random() < 0.2:
|
|
346
|
+
# # # to avoid chromatic drop problems
|
|
347
|
+
# # if data['colors'].mean() <= 0.1:
|
|
348
|
+
# # return data
|
|
349
|
+
# # lo = data['colors'].min(1, keepdims=True)[0]
|
|
350
|
+
# # hi = data['colors'].max(1, keepdims=True)[0]
|
|
351
|
+
# # scale = 255 / (hi - lo)
|
|
352
|
+
# # contrast_feats = (data['colors'] - lo) * scale
|
|
353
|
+
# # blend_factor = random.random() if self.randomize_blend_factor else self.blend_factor
|
|
354
|
+
# # data['colors'] = (1 - blend_factor) * data['colors'] + blend_factor * contrast_feats
|
|
355
|
+
# # return data
|
|
356
|
+
# #
|
|
357
|
+
# #
|
|
358
|
+
# # @DataTransforms.register_module()
|
|
359
|
+
# # class ChromaticJitter(object):
|
|
360
|
+
# #
|
|
361
|
+
# # def __init__(self, std=0.01, **kwargs):
|
|
362
|
+
# # self.std = std
|
|
363
|
+
# #
|
|
364
|
+
# # def __call__(self, data):
|
|
365
|
+
# # if 'colors' in data:
|
|
366
|
+
# # if random.random() < 0.95:
|
|
367
|
+
# # noise = torch.randn_like(data['colors'])
|
|
368
|
+
# # noise *= self.std * 255
|
|
369
|
+
# # data['colors'] = torch.clamp(noise + data['colors'], 0, 255)
|
|
370
|
+
# # return data
|
|
371
|
+
|
|
372
|
+
|
|
373
|
+
@DataTransforms.register_module()
|
|
374
|
+
class ChromaticDropGPU(object):
|
|
375
|
+
def __init__(self, color_drop=0.2, **kwargs):
|
|
376
|
+
self.color_drop = color_drop
|
|
377
|
+
|
|
378
|
+
def __call__(self, data):
|
|
379
|
+
if torch.rand(1) < self.color_drop:
|
|
380
|
+
data['x'][:, :3] = 0
|
|
381
|
+
return data
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
@DataTransforms.register_module()
|
|
385
|
+
class ChromaticPerDropGPU(object):
|
|
386
|
+
def __init__(self, color_drop=0.2, **kwargs):
|
|
387
|
+
self.color_drop = color_drop
|
|
388
|
+
|
|
389
|
+
def __call__(self, data):
|
|
390
|
+
colors_drop = (torch.rand((data['x'].shape[0], 1)) > self.color_drop).to(torch.float32)
|
|
391
|
+
data['x'][:, :3] *= colors_drop
|
|
392
|
+
return data
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
@DataTransforms.register_module()
|
|
396
|
+
class ChromaticNormalize(object):
|
|
397
|
+
def __init__(self,
|
|
398
|
+
color_mean=[0.5136457, 0.49523646, 0.44921124],
|
|
399
|
+
color_std=[0.18308958, 0.18415008, 0.19252081],
|
|
400
|
+
**kwargs):
|
|
401
|
+
self.color_mean = torch.from_numpy(np.array(color_mean)).to(torch.float32)
|
|
402
|
+
self.color_std = torch.from_numpy(np.array(color_std)).to(torch.float32)
|
|
403
|
+
|
|
404
|
+
def __call__(self, data):
|
|
405
|
+
device = data['x'].device
|
|
406
|
+
if data['x'][:, :3].max() > 1:
|
|
407
|
+
data['x'][:, :3] /= 255.
|
|
408
|
+
data['x'][:, :3] = (data['x'][:, :3] - self.color_mean.to(device)) / self.color_std.to(device)
|
|
409
|
+
return data
|
|
410
|
+
|
|
411
|
+
|
|
412
|
+
def one_hot(x, num_classes, on_value=1., off_value=0., device='cuda'):
|
|
413
|
+
x = x.long().view(-1, 1)
|
|
414
|
+
return torch.full((x.size()[0], num_classes), off_value, device=device).scatter_(1, x, on_value)
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
def mixup_target(target, num_classes, lam=1., smoothing=0.0, device='cuda'):
|
|
418
|
+
off_value = smoothing / num_classes
|
|
419
|
+
on_value = 1. - smoothing + off_value
|
|
420
|
+
y1 = one_hot(target, num_classes, on_value=on_value, off_value=off_value, device=device)
|
|
421
|
+
y2 = one_hot(target.flip(0), num_classes, on_value=on_value, off_value=off_value, device=device)
|
|
422
|
+
return y1 * lam + y2 * (1. - lam)
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
class Cutmix:
|
|
426
|
+
""" Cutmix that applies different params to each element or whole batch
|
|
427
|
+
Update: 1. random cutmix does not work on classification (ScanObjectNN, PointNext), April 7, 2022
|
|
428
|
+
Args:
|
|
429
|
+
cutmix_alpha (float): cutmix alpha value, cutmix is active if > 0.
|
|
430
|
+
prob (float): probability of applying mixup or cutmix per batch or element
|
|
431
|
+
label_smoothing (float): apply label smoothing to the mixed target tensor
|
|
432
|
+
num_classes (int): number of classes for target
|
|
433
|
+
"""
|
|
434
|
+
|
|
435
|
+
def __init__(self, cutmix_alpha=0.3, prob=1.0,
|
|
436
|
+
label_smoothing=0.1, num_classes=1000):
|
|
437
|
+
self.cutmix_alpha = cutmix_alpha
|
|
438
|
+
self.mix_prob = prob
|
|
439
|
+
self.label_smoothing = label_smoothing
|
|
440
|
+
self.num_classes = num_classes
|
|
441
|
+
|
|
442
|
+
def _mix_batch(self, data):
|
|
443
|
+
lam = np.random.beta(self.cutmix_alpha, self.cutmix_alpha)
|
|
444
|
+
# the trianing batches should have same size.
|
|
445
|
+
if hasattr(data, 'keys'): # data is a dict
|
|
446
|
+
# pos, feat?
|
|
447
|
+
N = data['pos'].shape[1]
|
|
448
|
+
n_mix = int(N * lam)
|
|
449
|
+
data['pos'][:, -n_mix:] = data['pos'].flip(0)[:, -n_mix:]
|
|
450
|
+
|
|
451
|
+
if 'x' in data.keys():
|
|
452
|
+
data['x'][:, :, -n_mix:] = data['x'].flip(0)[:, :, -n_mix:]
|
|
453
|
+
else:
|
|
454
|
+
data[:, -n_mix:] = data.flip(0)[:, -n_mix:]
|
|
455
|
+
return lam
|
|
456
|
+
|
|
457
|
+
def __call__(self, data, target):
|
|
458
|
+
device = data['pos'].device if hasattr(data, 'keys') else data.device
|
|
459
|
+
lam = self._mix_batch(data)
|
|
460
|
+
target = mixup_target(target, self.num_classes, lam, self.label_smoothing, device)
|
|
461
|
+
return data, target
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
# from roi_align import CropAndResize # crop_and_resize module
|
|
465
|
+
# from math import sqrt
|
|
466
|
+
#
|
|
467
|
+
#
|
|
468
|
+
# @DataTransforms.register_module()
|
|
469
|
+
# class Zoom(object):
|
|
470
|
+
# def __init__(self, ratio=0.35, IMG_MEAN=0.044471418750000005, IMG_VAR=0.061778141, resolution=128, views=6,
|
|
471
|
+
# **kwargs): # simple view hyper params
|
|
472
|
+
# # super().__init__()
|
|
473
|
+
# self.ratio = ratio
|
|
474
|
+
# self.extrapolation_value = ((0 - IMG_MEAN) / sqrt(IMG_VAR))
|
|
475
|
+
# self.resolution = resolution
|
|
476
|
+
# self.CropAndResize = CropAndResize(resolution, resolution, self.extrapolation_value)
|
|
477
|
+
# # self.batch = resolution * views
|
|
478
|
+
#
|
|
479
|
+
# def __call__(self, data, batch):
|
|
480
|
+
# if self.extrapolation_value == 0:
|
|
481
|
+
# print("WARNING: using 0 for the extrapolated value")
|
|
482
|
+
# boxes = torch.cat((torch.zeros((batch, 2), device=data.device, dtype=torch.float32),
|
|
483
|
+
# torch.ones((batch, 2), device=data.device, dtype=torch.float32)), dim=1)
|
|
484
|
+
# ind = torch.arange(batch, device=data.device, dtype=torch.int)
|
|
485
|
+
# num = (torch.rand((batch, 4), device=data.device) - 0.5) * 2 * self.ratio
|
|
486
|
+
# boxes = torch.add(boxes, num)
|
|
487
|
+
# return self.CropAndResize(
|
|
488
|
+
# data, boxes=boxes, box_ind=ind
|
|
489
|
+
# )
|
|
490
|
+
|
|
491
|
+
|
|
492
|
+
# # # Numpy Operation
|
|
493
|
+
# # @DataTransforms.register_module()
|
|
494
|
+
# # class RGBtoHSV(object):
|
|
495
|
+
# #
|
|
496
|
+
# # def __init__(self, **kwargs):
|
|
497
|
+
# # pass
|
|
498
|
+
# #
|
|
499
|
+
# # def __call__(self, data):
|
|
500
|
+
# # if 'colors' in data:
|
|
501
|
+
# # # print("hsv")
|
|
502
|
+
# # # Translated from source of colorsys.rgb_to_hsv
|
|
503
|
+
# # # r,g,b should be a numpy arrays with values between 0 and 255
|
|
504
|
+
# # # rgb_to_hsv returns an array of floats between 0.0 and 1.0.
|
|
505
|
+
# # rgb = data['colors'].cpu().float().numpy()
|
|
506
|
+
# # hsv = np.zeros_like(rgb)
|
|
507
|
+
# #
|
|
508
|
+
# # r, g, b = rgb[..., 0], rgb[..., 1], rgb[..., 2]
|
|
509
|
+
# # maxc = np.max(rgb[..., :3], axis=-1)
|
|
510
|
+
# # minc = np.min(rgb[..., :3], axis=-1)
|
|
511
|
+
# # hsv[..., 2] = maxc
|
|
512
|
+
# # mask = maxc != minc
|
|
513
|
+
# # hsv[mask, 1] = (maxc - minc)[mask] / maxc[mask]
|
|
514
|
+
# # rc = np.zeros_like(r)
|
|
515
|
+
# # gc = np.zeros_like(g)
|
|
516
|
+
# # bc = np.zeros_like(b)
|
|
517
|
+
# # rc[mask] = (maxc - r)[mask] / (maxc - minc)[mask]
|
|
518
|
+
# # gc[mask] = (maxc - g)[mask] / (maxc - minc)[mask]
|
|
519
|
+
# # bc[mask] = (maxc - b)[mask] / (maxc - minc)[mask]
|
|
520
|
+
# # hsv[..., 0] = np.select([r == maxc, g == maxc], [bc - gc, 2.0 + rc - bc], default=4.0 + gc - rc)
|
|
521
|
+
# # hsv[..., 0] = (hsv[..., 0] / 6.0) % 1.0
|
|
522
|
+
# # data['colors'] = torch.from_numpy(hsv).to(data['colors'].device)
|
|
523
|
+
# # return data
|
|
524
|
+
# #
|
|
525
|
+
# #
|
|
526
|
+
# # # Numpy Operation
|
|
527
|
+
# # @DataTransforms.register_module()
|
|
528
|
+
# # class HSVtoRGB(object):
|
|
529
|
+
# # def __init__(self, **kwargs):
|
|
530
|
+
# # pass
|
|
531
|
+
# # # Translated from source of colorsys.hsv_to_rgb
|
|
532
|
+
# # # h,s should be a numpy arrays with values between 0.0 and 1.0
|
|
533
|
+
# # # v should be a numpy array with values between 0.0 and 255.0
|
|
534
|
+
# # # hsv_to_rgb returns an array of uints between 0 and 255.
|
|
535
|
+
# #
|
|
536
|
+
# # def __call__(self, data):
|
|
537
|
+
# # if 'colors' in data:
|
|
538
|
+
# # hsv = data['colors'].cpu().float().numpy()
|
|
539
|
+
# # rgb = np.empty_like(hsv)
|
|
540
|
+
# # rgb[..., 3:] = hsv[..., 3:]
|
|
541
|
+
# # h, s, v = hsv[..., 0], hsv[..., 1], hsv[..., 2]
|
|
542
|
+
# # i = (h * 6.0).astype('uint8')
|
|
543
|
+
# # f = (h * 6.0) - i
|
|
544
|
+
# # p = v * (1.0 - s)
|
|
545
|
+
# # q = v * (1.0 - s * f)
|
|
546
|
+
# # t = v * (1.0 - s * (1.0 - f))
|
|
547
|
+
# # i = i % 6
|
|
548
|
+
# # conditions = [s == 0.0, i == 1, i == 2, i == 3, i == 4, i == 5]
|
|
549
|
+
# # rgb[..., 0] = np.select(conditions, [v, q, p, p, t, v], default=v)
|
|
550
|
+
# # rgb[..., 1] = np.select(conditions, [v, v, v, q, p, p], default=t)
|
|
551
|
+
# # rgb[..., 2] = np.select(conditions, [v, p, t, v, v, q], default=p)
|
|
552
|
+
# # rgb = rgb.astype('uint8')
|
|
553
|
+
# # data['colors'] = torch.from_numpy(rgb).to(data['colors'].device)
|
|
554
|
+
# # return rgb
|
|
555
|
+
# #
|
|
556
|
+
# #
|
|
557
|
+
# # # POINT TRANSFORMER CHROMATIC JITTER
|
|
558
|
+
# # @DataTransforms.register_module()
|
|
559
|
+
# # class ChromaticJitters(object):
|
|
560
|
+
# # def __init__(self, p=0.95, std=0.005, **kwargs):
|
|
561
|
+
# # self.p = p
|
|
562
|
+
# # self.std = std
|
|
563
|
+
# #
|
|
564
|
+
# # def __call__(self, data):
|
|
565
|
+
# # if np.random.rand() < self.p:
|
|
566
|
+
# # noise = np.random.randn(data['colors'].shape[0], 3)
|
|
567
|
+
# # noise *= self.std * 255
|
|
568
|
+
# # data['colors'][:, :3] = torch.clamp(noise + data['colors'][:, :3], 0, 255)
|
|
569
|
+
# # return data
|
|
570
|
+
# #
|
|
571
|
+
# #
|
|
572
|
+
# # @DataTransforms.register_module()
|
|
573
|
+
# # class HueSaturationTranslation(object):
|
|
574
|
+
# # # @staticmethod
|
|
575
|
+
# # def rgb_to_hsv(rgb):
|
|
576
|
+
# # # Translated from source of colorsys.rgb_to_hsv
|
|
577
|
+
# # # r,g,b should be a numpy arrays with values between 0 and 255
|
|
578
|
+
# # # rgb_to_hsv returns an array of floats between 0.0 and 1.0.
|
|
579
|
+
# # # rgb = rgb.astype('float')
|
|
580
|
+
# # hsv = torch.zeros_like(rgb)
|
|
581
|
+
# # # in case an RGBA array was passed, just copy the A channel
|
|
582
|
+
# # hsv[..., 3:] = rgb[..., 3:]
|
|
583
|
+
# # r, g, b = rgb[..., 0], rgb[..., 1], rgb[..., 2]
|
|
584
|
+
# # maxc = torch.max(rgb[..., :3], axis=-1)[0]
|
|
585
|
+
# # minc = torch.min(rgb[..., :3], axis=-1)[0]
|
|
586
|
+
# # hsv[..., 2] = maxc
|
|
587
|
+
# # mask = maxc != minc
|
|
588
|
+
# # hsv[mask, 1] = (maxc - minc)[mask] / maxc[mask]
|
|
589
|
+
# # rc = torch.zeros_like(r)
|
|
590
|
+
# # gc = torch.zeros_like(g)
|
|
591
|
+
# # bc = torch.zeros_like(b)
|
|
592
|
+
# # rc[mask] = (maxc - r)[mask] / (maxc - minc)[mask]
|
|
593
|
+
# # gc[mask] = (maxc - g)[mask] / (maxc - minc)[mask]
|
|
594
|
+
# # bc[mask] = (maxc - b)[mask] / (maxc - minc)[mask]
|
|
595
|
+
# # hsv[..., 0] = torch.where(r == maxc, bc - gc, (torch.where(g == maxc, 2.0 + rc - bc, 4.0 + gc)))
|
|
596
|
+
# # # hsv[..., 0] = np.select([r == maxc, g == maxc], [bc - gc, 2.0 + rc - bc], default=4.0 + gc - rc)
|
|
597
|
+
# # hsv[..., 0] = (hsv[..., 0] / 6.0) % 1.0
|
|
598
|
+
# # return hsv
|
|
599
|
+
# #
|
|
600
|
+
# # # @staticmethod
|
|
601
|
+
# # def hsv_to_rgb(hsv):
|
|
602
|
+
# # # Translated from source of colorsys.hsv_to_rgb
|
|
603
|
+
# # # h,s should be a numpy arrays with values between 0.0 and 1.0
|
|
604
|
+
# # # v should be a numpy array with values between 0.0 and 255.0
|
|
605
|
+
# # # hsv_to_rgb returns an array of uints between 0 and 255.
|
|
606
|
+
# # rgb = torch.empty_like(hsv)
|
|
607
|
+
# # rgb[..., 3:] = hsv[..., 3:]
|
|
608
|
+
# # h, s, v = hsv[..., 0], hsv[..., 1], hsv[..., 2]
|
|
609
|
+
# # i = (h * 6.0).type(torch.cuda.ByteTensor)
|
|
610
|
+
# # f = (h * 6.0) - i
|
|
611
|
+
# # p = v * (1.0 - s)
|
|
612
|
+
# # q = v * (1.0 - s * f)
|
|
613
|
+
# # t = v * (1.0 - s * (1.0 - f))
|
|
614
|
+
# # i = i % 6
|
|
615
|
+
# # conditions = [s == 0.0, i == 1, i == 2, i == 3, i == 4, i == 5]
|
|
616
|
+
# #
|
|
617
|
+
# # rgb[..., 0] = torch.where((conditions[0]) | (conditions[5]), v, torch.where(conditions[1], q, torch.where(
|
|
618
|
+
# # (conditions[2]) | (conditions[3]), p, torch.where(conditions[4], t, v))))
|
|
619
|
+
# # rgb[..., 1] = torch.where((conditions[0]) | (conditions[1]) | (conditions[2]), v,
|
|
620
|
+
# # torch.where(conditions[3], q, torch.where((conditions[4]) | (conditions[5]), p, t)))
|
|
621
|
+
# # rgb[..., 2] = torch.where((conditions[0]) | (conditions[3]) | (conditions[4]), v,
|
|
622
|
+
# # torch.where(conditions[1], p, torch.where(
|
|
623
|
+
# # conditions[2], t, torch.where(conditions[5], q, p))))
|
|
624
|
+
# # # rgb[..., 0] = np.select(conditions, [v, q, p, p, t, v], default=v)
|
|
625
|
+
# # # rgb[..., 1] = np.select(conditions, [v, v, v, q, p, p], default=t)
|
|
626
|
+
# # # rgb[..., 2] = np.select(conditions, [v, p, t, v, v, q], default=p)
|
|
627
|
+
# # return rgb.type(torch.cuda.ByteTensor)
|
|
628
|
+
# #
|
|
629
|
+
# # def __init__(self, hue_max=0.5, saturation_max=0.2, **kwargs):
|
|
630
|
+
# # self.hue_max = hue_max
|
|
631
|
+
# # self.saturation_max = saturation_max
|
|
632
|
+
# #
|
|
633
|
+
# # def __call__(self, data):
|
|
634
|
+
# # # Assume feat[:, :3] is rgb
|
|
635
|
+
# # if 'colors' in data:
|
|
636
|
+
# # rgb = data['colors']
|
|
637
|
+
# # hsv = HueSaturationTranslation.rgb_to_hsv(rgb[:, :3])
|
|
638
|
+
# # hue_val = (np.random.rand() - 0.5) * 2 * self.hue_max
|
|
639
|
+
# # sat_ratio = 1 + (np.random.rand() - 0.5) * 2 * self.saturation_max
|
|
640
|
+
# # hsv[..., 0] = torch.remainder(hue_val + hsv[..., 0] + 1, 1)
|
|
641
|
+
# # hsv[..., 1] = torch.clamp(sat_ratio * hsv[..., 1], 0, 1)
|
|
642
|
+
# # data['colors'][:, :3] = torch.clamp(HueSaturationTranslation.hsv_to_rgb(hsv), 0, 255)
|
|
643
|
+
# # return data
|
|
644
|
+
# def __init__(self, scale=[0.9, 1.1], anisotropic=False, **kwargs):
|
|
645
|
+
# self.scale = scale
|
|
646
|
+
# self.anisotropic = anisotropic
|
|
647
|
+
#
|
|
648
|
+
# def __call__(self, data):
|
|
649
|
+
# if hasattr(data, 'keys'):
|
|
650
|
+
# scale = torch.distributions.Uniform(self.scale[0], self.scale[1]).sample((3 if self.anisotropic else 1,)
|
|
651
|
+
# ).to(data['pos'].device)
|
|
652
|
+
# data['pos'] *= scale
|
|
653
|
+
# else:
|
|
654
|
+
# scale = torch.distributions.Uniform(self.scale[0], self.scale[1]).sample((3 if self.anisotropic else 1,)
|
|
655
|
+
# ).to(data.device)
|
|
656
|
+
# data *= scale
|
|
657
|
+
# return data
|
|
658
|
+
#
|
|
659
|
+
#
|
|
660
|
+
# @DataTransforms.register_module()
|
|
661
|
+
# class PointCloudRandomShift(object):
|
|
662
|
+
# def __init__(self, shift=[0.2, 0.2, 0], **kwargs):
|
|
663
|
+
# self.shift = shift
|
|
664
|
+
#
|
|
665
|
+
# def __call__(self, data):
|
|
666
|
+
# if hasattr(data, 'keys'):
|
|
667
|
+
# shift_x = torch.distributions.Uniform(-self.shift[0], self.shift[0]).sample((1,)).to(data['pos'].device)
|
|
668
|
+
# shift_y = torch.distributions.Uniform(-self.shift[1], self.shift[1]).sample((1,)).to(data['pos'].device)
|
|
669
|
+
# shift_z = torch.distributions.Uniform(-self.shift[1], self.shift[1]).sample((1,)).to(data['pos'].device)
|
|
670
|
+
# data['pos'] += [shift_x, shift_y, shift_z]
|
|
671
|
+
# else:
|
|
672
|
+
# shift_x = torch.distributions.Uniform(-self.shift[0], self.shift[0]).sample((1,)).to(data.device)
|
|
673
|
+
# shift_y = torch.distributions.Uniform(-self.shift[1], self.shift[1]).sample((1,)).to(data.device)
|
|
674
|
+
# shift_z = torch.distributions.Uniform(-self.shift[1], self.shift[1]).sample((1,)).to(data.device)
|
|
675
|
+
# data += [shift_x, shift_y, shift_z]
|
|
676
|
+
# return data
|
|
677
|
+
#
|
|
678
|
+
#
|
|
679
|
+
# @DataTransforms.register_module()
|
|
680
|
+
# class RandomFlip(object):
|
|
681
|
+
# def __init__(self, p=0.5, **kwargs):
|
|
682
|
+
# self.p = p
|
|
683
|
+
#
|
|
684
|
+
# def __call__(self, data):
|
|
685
|
+
# if hasattr(data, 'keys'):
|
|
686
|
+
# if np.random.rand() < self.p:
|
|
687
|
+
# data['pos'][:, 0] = -data['pos'][:, 0]
|
|
688
|
+
# if np.random.rand() < self.p:
|
|
689
|
+
# data['pos'][:, 1] = -data['pos'][:, 1]
|
|
690
|
+
# else:
|
|
691
|
+
# if np.random.rand() < self.p:
|
|
692
|
+
# data[:, 0] = -data[:, 0]
|
|
693
|
+
# if np.random.rand() < self.p:
|
|
694
|
+
# data[:, 1] = -data[:, 1]
|
|
695
|
+
# return data
|
|
696
|
+
#
|
|
697
|
+
#
|
|
698
|
+
# @DataTransforms.register_module()
|
|
699
|
+
# class RandomJitter(object):
|
|
700
|
+
# def __init__(self, sigma=0.01, clip=0.05, **kwargs):
|
|
701
|
+
# self.sigma = sigma
|
|
702
|
+
# self.clip = clip
|
|
703
|
+
#
|
|
704
|
+
# def __call__(self, data):
|
|
705
|
+
# assert (self.clip > 0)
|
|
706
|
+
# if hasattr(data, 'keys'):
|
|
707
|
+
# jitter = torch.clamp(self.sigma * torch.randn(data['pos'].shape[0], 3), -1 * self.clip, self.clip)
|
|
708
|
+
# data['pos'] += jitter
|
|
709
|
+
# else:
|
|
710
|
+
# jitter = torch.clamp(self.sigma * torch.randn(data.shape[0], 3), -1 * self.clip, self.clip)
|
|
711
|
+
# data += jitter
|
|
712
|
+
# return data
|
|
713
|
+
#
|
|
714
|
+
#
|
|
715
|
+
# @DataTransforms.register_module()
|
|
716
|
+
# class RandomDropColor(object):
|
|
717
|
+
# def __init__(self, p=0.2, **kwargs):
|
|
718
|
+
# self.p = p
|
|
719
|
+
#
|
|
720
|
+
# def __call__(self, data):
|
|
721
|
+
# if 'colors' in data:
|
|
722
|
+
# if np.random.rand() < self.p:
|
|
723
|
+
# data['colors'][:, :3] = 0
|
|
724
|
+
# return data
|
|
725
|
+
|
|
726
|
+
#
|
|
727
|
+
# class ElasticDistortion(object):
|
|
728
|
+
# def __init__(self, granularity=0.2, magnitude=0.4, **kwargs):
|
|
729
|
+
# self.granularity = granularity
|
|
730
|
+
# self.magnitude = magnitude
|
|
731
|
+
#
|
|
732
|
+
# def __call__(self, data):
|
|
733
|
+
# """Apply elastic distortion on sparse coordinate space.
|
|
734
|
+
#
|
|
735
|
+
# pointcloud: numpy array of (number of points, at least 3 spatial dims)
|
|
736
|
+
# granularity: size of the noise grid (in same scale[m/cm] as the voxel grid)
|
|
737
|
+
# magnitude: noise multiplier
|
|
738
|
+
# """
|
|
739
|
+
# if random.random() < 0.95:
|
|
740
|
+
# blurx = torch.ones((3, 1, 1, 1), dtype=torch.float32) / 3
|
|
741
|
+
# blury = torch.ones((1, 3, 1, 1), dtype=torch.float32) / 3
|
|
742
|
+
# blurz = torch.ones((1, 1, 3, 1), dtype=torch.float32) / 3
|
|
743
|
+
# coords = data['pos']
|
|
744
|
+
# coords_min = coords.min(0)[0]
|
|
745
|
+
#
|
|
746
|
+
# # Create Gaussian noise tensor of the size given by granularity.
|
|
747
|
+
# noise_dim = ((coords - coords_min).max(0)[0] // self.granularity).int() + 3
|
|
748
|
+
# noise = torch.randn(*noise_dim, 3, dtype=torch.float32)
|
|
749
|
+
#
|
|
750
|
+
# # Smoothing.
|
|
751
|
+
# for _ in range(2):
|
|
752
|
+
# noise = scipy.ndimage.filters.convolve(noise, blurx, mode='constant', cval=0)
|
|
753
|
+
# noise = scipy.ndimage.filters.convolve(noise, blury, mode='constant', cval=0)
|
|
754
|
+
# noise = scipy.ndimage.filters.convolve(noise, blurz, mode='constant', cval=0)
|
|
755
|
+
#
|
|
756
|
+
# # Trilinear interpolate noise filters for each spatial dimensions.
|
|
757
|
+
# ax = [
|
|
758
|
+
# torch.linspace(d_min, d_max, d)
|
|
759
|
+
# for d_min, d_max, d in zip(coords_min - self.granularity, coords_min + self.granularity *
|
|
760
|
+
# (noise_dim - 2), noise_dim)
|
|
761
|
+
# ]
|
|
762
|
+
# interp = scipy.interpolate.RegularGridInterpolator(ax, noise, bounds_error=0, fill_value=0)
|
|
763
|
+
# data['pos'] = coords + interp(coords) * self.magnitude
|
|
764
|
+
# return data
|