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.
Files changed (184) hide show
  1. openpoints/__init__.py +3 -0
  2. openpoints/cpp/__init__.py +6 -0
  3. openpoints/cpp/chamfer_dist/__init__.py +110 -0
  4. openpoints/cpp/chamfer_dist/setup.py +19 -0
  5. openpoints/cpp/chamfer_dist/test.py +34 -0
  6. openpoints/cpp/emd/__init__.py +3 -0
  7. openpoints/cpp/emd/emd.py +88 -0
  8. openpoints/cpp/emd/setup.py +27 -0
  9. openpoints/cpp/emd/test_emd_loss.py +45 -0
  10. openpoints/cpp/pointnet2_batch/__init__.py +24 -0
  11. openpoints/cpp/pointnet2_batch/setup.py +23 -0
  12. openpoints/cpp/pointops/__init__.py +0 -0
  13. openpoints/cpp/pointops/functions/__init__.py +0 -0
  14. openpoints/cpp/pointops/functions/pointops.py +314 -0
  15. openpoints/cpp/pointops/setup.py +37 -0
  16. openpoints/cpp/pointops/src/__init__.py +0 -0
  17. openpoints/dataset/__init__.py +10 -0
  18. openpoints/dataset/atom3d/__init__.py +1 -0
  19. openpoints/dataset/atom3d/psr.py +38 -0
  20. openpoints/dataset/build.py +98 -0
  21. openpoints/dataset/data_util.py +192 -0
  22. openpoints/dataset/datalist.py +67 -0
  23. openpoints/dataset/dataset_base.py +96 -0
  24. openpoints/dataset/graph_dataset/__init__.py +3 -0
  25. openpoints/dataset/graph_dataset/graph_dataset.py +93 -0
  26. openpoints/dataset/graph_dataset/stack_with_pad.py +91 -0
  27. openpoints/dataset/graph_dataset/structural_dataset.py +73 -0
  28. openpoints/dataset/graph_dataset/svd_encodings_dataset.py +110 -0
  29. openpoints/dataset/grid_sample.py +21 -0
  30. openpoints/dataset/matterport3d/__init__.py +1 -0
  31. openpoints/dataset/matterport3d/category_mapping.tsv +1660 -0
  32. openpoints/dataset/matterport3d/matterport3d.py +210 -0
  33. openpoints/dataset/matterport3d/matterport3d_dataprocessing.py +105 -0
  34. openpoints/dataset/modelnet/__init__.py +3 -0
  35. openpoints/dataset/modelnet/modelnet40_normal_resampled_loader.py +124 -0
  36. openpoints/dataset/modelnet/modelnet40_ply_2048_loader.py +160 -0
  37. openpoints/dataset/molhiv/__init__.py +1 -0
  38. openpoints/dataset/molhiv/data.py +59 -0
  39. openpoints/dataset/molpcba/__init__.py +1 -0
  40. openpoints/dataset/molpcba/data.py +59 -0
  41. openpoints/dataset/parsers/__init__.py +1 -0
  42. openpoints/dataset/parsers/class_map.py +19 -0
  43. openpoints/dataset/parsers/constants.py +1 -0
  44. openpoints/dataset/parsers/parser.py +17 -0
  45. openpoints/dataset/parsers/parser_factory.py +29 -0
  46. openpoints/dataset/parsers/parser_image_folder.py +69 -0
  47. openpoints/dataset/parsers/parser_image_in_tar.py +222 -0
  48. openpoints/dataset/parsers/parser_image_tar.py +72 -0
  49. openpoints/dataset/parsers/parser_tfds.py +297 -0
  50. openpoints/dataset/pcqm4m/__init__.py +1 -0
  51. openpoints/dataset/pcqm4m/data.py +62 -0
  52. openpoints/dataset/pcqm4mv2/__init__.py +1 -0
  53. openpoints/dataset/pcqm4mv2/data.py +87 -0
  54. openpoints/dataset/s3dis/__init__.py +2 -0
  55. openpoints/dataset/s3dis/s3dis.py +156 -0
  56. openpoints/dataset/s3dis/s3dis_block.py +96 -0
  57. openpoints/dataset/s3dis/s3dis_sphere.py +349 -0
  58. openpoints/dataset/scannetv2/__init__.py +1 -0
  59. openpoints/dataset/scannetv2/scannet.py +176 -0
  60. openpoints/dataset/scanobjectnn/__init__.py +3 -0
  61. openpoints/dataset/scanobjectnn/scanobjectnn.py +110 -0
  62. openpoints/dataset/semantic_kitti/__init__.py +1 -0
  63. openpoints/dataset/semantic_kitti/helper_tool.py +286 -0
  64. openpoints/dataset/semantic_kitti/label_mapping.yaml +211 -0
  65. openpoints/dataset/semantic_kitti/semantickitti.py +229 -0
  66. openpoints/dataset/semantic_kitti/utils/meta/anno_paths.txt +272 -0
  67. openpoints/dataset/semantic_kitti/utils/meta/class_names.txt +13 -0
  68. openpoints/dataset/semantic_kitti/utils/semantic-kitti.yaml +211 -0
  69. openpoints/dataset/shapenet/__init__.py +1 -0
  70. openpoints/dataset/shapenet/shapenet55.py +76 -0
  71. openpoints/dataset/shapenet/shapenetpart.py +121 -0
  72. openpoints/dataset/shapenetpart/__init__.py +1 -0
  73. openpoints/dataset/shapenetpart/shapenet55.py +75 -0
  74. openpoints/dataset/shapenetpart/shapenetpart.py +388 -0
  75. openpoints/dataset/vis2d.py +17 -0
  76. openpoints/dataset/vis3d.py +153 -0
  77. openpoints/loss/__init__.py +3 -0
  78. openpoints/loss/build.py +281 -0
  79. openpoints/loss/cross_entropy.py +38 -0
  80. openpoints/loss/distill_loss.py +76 -0
  81. openpoints/models/__init__.py +10 -0
  82. openpoints/models/backbone/Stratified_transformer.py +558 -0
  83. openpoints/models/backbone/__init__.py +11 -0
  84. openpoints/models/backbone/baafnet.py +527 -0
  85. openpoints/models/backbone/ball_dgcnn.py +123 -0
  86. openpoints/models/backbone/curvenet.py +793 -0
  87. openpoints/models/backbone/debug_invvit.py +114 -0
  88. openpoints/models/backbone/deepgcn.py +143 -0
  89. openpoints/models/backbone/dgcnn.py +119 -0
  90. openpoints/models/backbone/graphvit3d.py +134 -0
  91. openpoints/models/backbone/grouppointnet.py +100 -0
  92. openpoints/models/backbone/pct.py +163 -0
  93. openpoints/models/backbone/pointmlp.py +417 -0
  94. openpoints/models/backbone/pointnet.py +199 -0
  95. openpoints/models/backbone/pointnetv2.py +511 -0
  96. openpoints/models/backbone/pointnext.py +663 -0
  97. openpoints/models/backbone/pointnextPyG.py +555 -0
  98. openpoints/models/backbone/pointtransformer.py +293 -0
  99. openpoints/models/backbone/pointvector.py +853 -0
  100. openpoints/models/backbone/pointvit.py +392 -0
  101. openpoints/models/backbone/pointvit_inv.py +942 -0
  102. openpoints/models/backbone/pointvit_inv_old.py +784 -0
  103. openpoints/models/backbone/randlenet.py +318 -0
  104. openpoints/models/backbone/resnet.py +342 -0
  105. openpoints/models/backbone/simpleview.py +153 -0
  106. openpoints/models/backbone/simpleview_util.py +292 -0
  107. openpoints/models/build.py +13 -0
  108. openpoints/models/classification/__init__.py +5 -0
  109. openpoints/models/classification/cls_base.py +136 -0
  110. openpoints/models/classification/point_bert.py +154 -0
  111. openpoints/models/layers/__init__.py +14 -0
  112. openpoints/models/layers/activation.py +57 -0
  113. openpoints/models/layers/attention.py +103 -0
  114. openpoints/models/layers/conv.py +167 -0
  115. openpoints/models/layers/drop.py +164 -0
  116. openpoints/models/layers/graph_conv.py +122 -0
  117. openpoints/models/layers/group.py +415 -0
  118. openpoints/models/layers/group_embed.py +286 -0
  119. openpoints/models/layers/helpers.py +43 -0
  120. openpoints/models/layers/kmeans.py +119 -0
  121. openpoints/models/layers/knn.py +110 -0
  122. openpoints/models/layers/local_aggregation.py +286 -0
  123. openpoints/models/layers/mlp.py +129 -0
  124. openpoints/models/layers/norm.py +106 -0
  125. openpoints/models/layers/padding.py +56 -0
  126. openpoints/models/layers/patch_embed.py +37 -0
  127. openpoints/models/layers/registry.py +168 -0
  128. openpoints/models/layers/subsample.py +185 -0
  129. openpoints/models/layers/upsampling.py +106 -0
  130. openpoints/models/layers/weight_init.py +89 -0
  131. openpoints/models/reconstruction/__init__.py +8 -0
  132. openpoints/models/reconstruction/base_recontruct.py +216 -0
  133. openpoints/models/reconstruction/maskedpoint.py +116 -0
  134. openpoints/models/reconstruction/maskedpointgroup.py +168 -0
  135. openpoints/models/reconstruction/maskedpointvit.py +253 -0
  136. openpoints/models/reconstruction/nodeshuffle.py +11 -0
  137. openpoints/models/registry.py +149 -0
  138. openpoints/models/segmentation/__init__.py +6 -0
  139. openpoints/models/segmentation/base_seg.py +278 -0
  140. openpoints/models/segmentation/vit_seg.py +126 -0
  141. openpoints/optim/__init__.py +15 -0
  142. openpoints/optim/adabelief.py +201 -0
  143. openpoints/optim/adafactor.py +167 -0
  144. openpoints/optim/adahessian.py +156 -0
  145. openpoints/optim/adamp.py +105 -0
  146. openpoints/optim/adamw.py +122 -0
  147. openpoints/optim/lamb.py +192 -0
  148. openpoints/optim/lars.py +135 -0
  149. openpoints/optim/lookahead.py +61 -0
  150. openpoints/optim/madgrad.py +184 -0
  151. openpoints/optim/nadam.py +92 -0
  152. openpoints/optim/nvnovograd.py +120 -0
  153. openpoints/optim/optim_factory.py +306 -0
  154. openpoints/optim/radam.py +89 -0
  155. openpoints/optim/rmsprop_tf.py +139 -0
  156. openpoints/optim/sgdp.py +70 -0
  157. openpoints/scheduler/__init__.py +8 -0
  158. openpoints/scheduler/cosine_lr.py +124 -0
  159. openpoints/scheduler/multistep_lr.py +65 -0
  160. openpoints/scheduler/plateau_lr.py +113 -0
  161. openpoints/scheduler/poly_lr.py +116 -0
  162. openpoints/scheduler/scheduler.py +110 -0
  163. openpoints/scheduler/scheduler_factory.py +118 -0
  164. openpoints/scheduler/step_lr.py +65 -0
  165. openpoints/scheduler/tanh_lr.py +117 -0
  166. openpoints/transforms/__init__.py +7 -0
  167. openpoints/transforms/point_transform_cpu.py +332 -0
  168. openpoints/transforms/point_transformer_gpu.py +764 -0
  169. openpoints/transforms/transforms_factory.py +60 -0
  170. openpoints/utils/__init__.py +8 -0
  171. openpoints/utils/ckpt_util.py +438 -0
  172. openpoints/utils/config.py +113 -0
  173. openpoints/utils/dist_utils.py +54 -0
  174. openpoints/utils/logger.py +170 -0
  175. openpoints/utils/metrics.py +311 -0
  176. openpoints/utils/random.py +16 -0
  177. openpoints/utils/registry.py +294 -0
  178. openpoints/utils/str2bool.py +11 -0
  179. openpoints/utils/wandb.py +88 -0
  180. openpoints-0.1.0.dist-info/METADATA +150 -0
  181. openpoints-0.1.0.dist-info/RECORD +184 -0
  182. openpoints-0.1.0.dist-info/WHEEL +5 -0
  183. openpoints-0.1.0.dist-info/licenses/LICENSE +21 -0
  184. 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