-
Notifications
You must be signed in to change notification settings - Fork 14
/
Copy pathpoisson_sampling.cc
293 lines (253 loc) · 13.7 KB
/
poisson_sampling.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
/////////////////////////////////////////////////////////////////////////////
/// \file poisson_sampling.cc
///
/// \brief C++ operations definition to perform a poisson disk
/// sampling on a batch of point clouds (O(n)), to obtain the
/// associated features to the selected points, and to propagate the
/// feature gradients.
///
/// \copyright Copyright (c) 2018 Visual Computing group of Ulm University,
/// Germany. See the LICENSE file at the top-level directory of
/// this distribution.
///
/// \author pedro hermosilla ([email protected])
/////////////////////////////////////////////////////////////////////////////
#include "tensorflow/core/framework/op.h"
#include "tensorflow/core/framework/op_kernel.h"
#include "tensorflow/core/framework/shape_inference.h"
#include "tensorflow/core/framework/common_shape_fns.h"
#include <cuda_runtime.h>
#include "cuda_kernel_utils.h"
using namespace tensorflow;
REGISTER_OP("PoissonSampling")
.Attr("radius: float")
.Attr("batch_size: int")
.Attr("scale_inv: bool")
.Input("points: float32")
.Input("batch_ids: int32")
.Input("cell_indexs: int32")
.Input("aabb_min: float32")
.Input("aabb_max: float32")
.Output("out_pts: float32")
.Output("out_batchs: int32")
.Output("out_indexs: int32")
.SetShapeFn([](::tensorflow::shape_inference::InferenceContext* c) {
shape_inference::ShapeHandle outputDims = c->MakeShape({-1, 3});
c->set_output(0, outputDims);
shape_inference::ShapeHandle outputDims2 = c->MakeShape({-1, 1});
c->set_output(1, outputDims2);
c->set_output(2, outputDims2);
return Status::OK();
});
REGISTER_OP("GetSampledFeatures")
.Input("pts_indexs: int32")
.Input("features: float32")
.Output("out_features: float32")
.SetShapeFn([](::tensorflow::shape_inference::InferenceContext* c) {
shape_inference::ShapeHandle outputDims = c->MakeShape({c->Dim(c->input(0), 0), c->Dim(c->input(1), 1)});
c->set_output(0, outputDims);
return Status::OK();
});
REGISTER_OP("GetSampledFeaturesGrad")
.Input("pts_indexs: int32")
.Input("in_features: float32")
.Input("sampled_features_gradients: float32")
.Output("in_gradients: float32")
.SetShapeFn([](::tensorflow::shape_inference::InferenceContext* c) {
shape_inference::ShapeHandle outputDims = c->MakeShape({c->Dim(c->input(1), 0), c->Dim(c->input(1), 1)});
c->set_output(0, outputDims);
return Status::OK();
});
int samplePointCloud(
const bool scaleInv,
const float pRadius,
const int pNumPoints,
const int pBatchSize,
const int pNumCells,
const float* pAABBMin,
const float* pAABBMax,
const float* pPoints,
const int* pBatchIds,
const int* pCellIndexs,
float* pSelectedPts,
int* pSelectedBatchIds,
int* pSelectedIndexs,
bool* pAuxBoolBuffer);
void copyPoints(
float* pSelectedPts,
int* pSelectedBatchIds,
int* pSelectedIndexs,
const int pNumPts,
float* pDestPts,
int* pDestBatchIds,
int* pDestIndexs);
void getFeaturesSampledPoints(
int pNumPoints,
int pNumFeatures,
int pNumSampledPoints,
const int* pInPointsIndexs,
const float* pInFeature,
float* pOutSelFeatures);
void getFeaturesSampledPointsGradients(
int pNumPoints,
int pNumFeatures,
int pNumSampledPoints,
const int* pInPointsIndexs,
const float* pInOutFeatureGrad,
float* pOutInFeaturesGradients);
class PoissonSamplingOp : public OpKernel {
public:
explicit PoissonSamplingOp(OpKernelConstruction* context) : OpKernel(context)
{
OP_REQUIRES_OK(context, context->GetAttr("radius", &radius_));
OP_REQUIRES(context, radius_ > 0.0, errors::InvalidArgument("PoissonSamplingOp expects a positive radius"));
OP_REQUIRES_OK(context, context->GetAttr("batch_size", &batchSize_));
OP_REQUIRES(context, batchSize_ > 0, errors::InvalidArgument("PoissonSamplingOp expects a positive batch size"));
OP_REQUIRES_OK(context, context->GetAttr("scale_inv", &scaleInv_));
}
void Compute(OpKernelContext* context) override {
//Process input points.
const Tensor& inPointsTensor = context->input(0);
OP_REQUIRES(context, inPointsTensor.dims() == 2, errors::InvalidArgument
("PoissonSamplingOp expects points with the following dimensions (batchSize, pointComponents)"));
OP_REQUIRES(context, inPointsTensor.shape().dim_size(1) == 3, errors::InvalidArgument
("PoissonSamplingOp expects points with three components"));
int numPoints = inPointsTensor.shape().dim_size(0);
auto inPointsFlat = inPointsTensor.flat<float>();
const float* inPointsPtr = &(inPointsFlat(0));
const Tensor& inBatchTensor=context->input(1);
OP_REQUIRES(context, inBatchTensor.dims() == 2 &&
inBatchTensor.shape().dim_size(0) == inPointsTensor.shape().dim_size(0) &&
inBatchTensor.shape().dim_size(1) == 1, errors::InvalidArgument
("PoissonSamplingOp expects as batch ids input the following dimensions (numPoints)"));
auto inBatchFlat = inBatchTensor.flat<int>();
const int* inBatchPtr = &(inBatchFlat(0));
//Process input cell ids.
const Tensor& inCellIdsTensor = context->input(2);
OP_REQUIRES(context, inCellIdsTensor.dims() == 5 &&
inCellIdsTensor.shape().dim_size(0) == batchSize_, errors::InvalidArgument
("PoissonSamplingOp expects a four dimension tensor for the cell indices"));
int numCells = inCellIdsTensor.shape().dim_size(1);
auto inCellIdsFlat = inCellIdsTensor.flat<int>();
const int* inCellIdsPtr = &(inCellIdsFlat(0));
//Process input bounding box.
const Tensor& inAABBMinTensor = context->input(3);
OP_REQUIRES(context, inAABBMinTensor.dims() == 2
&& inAABBMinTensor.shape().dim_size(0) == batchSize_ && inAABBMinTensor.shape().dim_size(1) == 3, errors::InvalidArgument
("PoissonSamplingOp expects a minimum point of the bounding box with 3 components"));
auto inAABBMinFlat = inAABBMinTensor.flat<float>();
const float* inAABBMinPtr = &(inAABBMinFlat(0));
const Tensor& inAABBMaxTensor = context->input(4);
OP_REQUIRES(context, inAABBMaxTensor.dims() == 2
&& inAABBMaxTensor.shape().dim_size(0) == batchSize_ && inAABBMaxTensor.shape().dim_size(1) == 3, errors::InvalidArgument
("PoissonSamplingOp expects a maximum point of the bounding box with 3 components"));
auto inAABBMaxFlat = inAABBMaxTensor.flat<float>();
const float* inAABBMaxPtr = &(inAABBMaxFlat(0));
//Create the temp tensors
Tensor tmpPts;
OP_REQUIRES_OK(context,context->allocate_temp(DataTypeToEnum<float>::value,TensorShape{numPoints,3}, &tmpPts));
auto tmpPtsFlat = tmpPts.flat<float>();
float* tmpPtsPtr = &(tmpPtsFlat(0));
Tensor tmpBatchs;
OP_REQUIRES_OK(context,context->allocate_temp(DataTypeToEnum<int>::value,TensorShape{numPoints,1}, &tmpBatchs));
auto tmpBatchsFlat = tmpBatchs.flat<int>();
int* tmpBatchsPtr = &(tmpBatchsFlat(0));
Tensor tmpIndexs;
OP_REQUIRES_OK(context,context->allocate_temp(DataTypeToEnum<int>::value,TensorShape{numPoints,1}, &tmpIndexs));
auto tmpIndexsFlat = tmpIndexs.flat<int>();
int* tmpIndexsPtr = &(tmpIndexsFlat(0));
Tensor tmpUsedBool;
OP_REQUIRES_OK(context,context->allocate_temp(DataTypeToEnum<bool>::value,TensorShape{numPoints,1}, &tmpUsedBool));
auto tmpUsedBoolFlat = tmpUsedBool.flat<bool>();
bool* tmpUsedBoolPtr = &(tmpUsedBoolFlat(0));
//Sample the point cloud
int numSelSamples = samplePointCloud(scaleInv_, radius_, numPoints, batchSize_, numCells, inAABBMinPtr, inAABBMaxPtr,
inPointsPtr, inBatchPtr, inCellIdsPtr, tmpPtsPtr, tmpBatchsPtr, tmpIndexsPtr, tmpUsedBoolPtr);
//Create the output tensors.
Tensor* outSelPts = nullptr;
Tensor* outSelBatchIds = nullptr;
Tensor* outSelIndexs = nullptr;
OP_REQUIRES_OK(context,context->allocate_output(0, TensorShape{numSelSamples, 3}, &outSelPts));
OP_REQUIRES_OK(context,context->allocate_output(1, TensorShape{numSelSamples, 1}, &outSelBatchIds));
OP_REQUIRES_OK(context,context->allocate_output(2, TensorShape{numSelSamples}, &outSelIndexs));
auto outSelPtsFlat = outSelPts->flat<float>();
auto outSelBatchIdsFlat = outSelBatchIds->flat<int>();
auto outSelIndexsFlat = outSelIndexs->flat<int>();
float* outSelPtsPtr = &(outSelPtsFlat(0));
int* outSelBatchIdsPtr = &(outSelBatchIdsFlat(0));
int* outSelIndexsPtr = &(outSelIndexsFlat(0));
//Copy the points.
copyPoints(tmpPtsPtr, tmpBatchsPtr, tmpIndexsPtr, numSelSamples, outSelPtsPtr, outSelBatchIdsPtr, outSelIndexsPtr);
}
private:
float radius_;
int batchSize_;
bool scaleInv_;
};
class GetSampledFeaturesOp : public OpKernel {
public:
explicit GetSampledFeaturesOp(OpKernelConstruction* context) : OpKernel(context) {}
void Compute(OpKernelContext* context) override {
//Process input point indexs.
const Tensor& inPointsIndexsTensor = context->input(0);
OP_REQUIRES(context, inPointsIndexsTensor.dims() == 1, errors::InvalidArgument
("GetSampledFeaturesOp expects point indexs with the following dimensions (numpoints)"));
int numSampledPoints = inPointsIndexsTensor.shape().dim_size(0);
auto inPointsIndexsFlat = inPointsIndexsTensor.flat<int>();
const int* inPointsIndexsPtr = &(inPointsIndexsFlat(0));
//Process input features.
const Tensor& inFeatureTensor=context->input(1);
OP_REQUIRES(context, inFeatureTensor.dims() == 2, errors::InvalidArgument
("GetSampledFeaturesOp features in the right format"));
int numPoints = inFeatureTensor.shape().dim_size(0);
int numFeatures = inFeatureTensor.shape().dim_size(1);
auto inFeatureFlat = inFeatureTensor.flat<float>();
const float* inFeaturePtr = &(inFeatureFlat(0));
//Create the output tensors.
Tensor* outSelFeatures = nullptr;
OP_REQUIRES_OK(context,context->allocate_output(0, TensorShape{numSampledPoints, numFeatures}, &outSelFeatures));
auto outSelFeaturesFlat = outSelFeatures->flat<float>();
float* outSelFeaturesPtr = &(outSelFeaturesFlat(0));
//Get features.
getFeaturesSampledPoints(numPoints, numFeatures, numSampledPoints, inPointsIndexsPtr, inFeaturePtr, outSelFeaturesPtr);
}
};
class GetSampledFeaturesGradOp : public OpKernel {
public:
explicit GetSampledFeaturesGradOp(OpKernelConstruction* context) : OpKernel(context) {}
void Compute(OpKernelContext* context) override {
//Process input point indexs.
const Tensor& inPointsIndexsTensor = context->input(0);
OP_REQUIRES(context, inPointsIndexsTensor.dims() == 1, errors::InvalidArgument
("GetSampledFeaturesOp expects point indexs with the following dimensions (numpoints)"));
int numSampledPoints = inPointsIndexsTensor.shape().dim_size(0);
auto inPointsIndexsFlat = inPointsIndexsTensor.flat<int>();
const int* inPointsIndexsPtr = &(inPointsIndexsFlat(0));
//Process input features.
const Tensor& inFeatureTensor=context->input(1);
OP_REQUIRES(context, inFeatureTensor.dims() == 2, errors::InvalidArgument
("GetSampledFeaturesGradOp expects features in the right format"));
int numPoints = inFeatureTensor.shape().dim_size(0);
int numFeatures = inFeatureTensor.shape().dim_size(1);
auto inFeatureFlat = inFeatureTensor.flat<float>();
const float* inFeaturePtr = &(inFeatureFlat(0));
//Process gradients of output features.
const Tensor& inOutFeatureGradTensor=context->input(2);
OP_REQUIRES(context, inOutFeatureGradTensor.dims() == 2 &&
inOutFeatureGradTensor.shape().dim_size(0) == numSampledPoints &&
inOutFeatureGradTensor.shape().dim_size(1) == numFeatures, errors::InvalidArgument
("GetSampledFeaturesGradOp expects gradients in the right format"));
auto inOutFeatureGradFlat = inOutFeatureGradTensor.flat<float>();
const float* inOutFeatureGradPtr = &(inOutFeatureGradFlat(0));
//Create the output tensors.
Tensor* outInFeaturesGradients = nullptr;
OP_REQUIRES_OK(context,context->allocate_output(0, TensorShape{numPoints, numFeatures}, &outInFeaturesGradients));
auto outInFeaturesGradientsFlat = outInFeaturesGradients->flat<float>();
float* outInFeaturesGradientsPtr = &(outInFeaturesGradientsFlat(0));
//Get features.
getFeaturesSampledPointsGradients(numPoints, numFeatures, numSampledPoints, inPointsIndexsPtr, inOutFeatureGradPtr, outInFeaturesGradientsPtr);
}
};
REGISTER_KERNEL_BUILDER(Name("PoissonSampling").Device(DEVICE_GPU), PoissonSamplingOp);
REGISTER_KERNEL_BUILDER(Name("GetSampledFeatures").Device(DEVICE_GPU), GetSampledFeaturesOp);
REGISTER_KERNEL_BUILDER(Name("GetSampledFeaturesGrad").Device(DEVICE_GPU), GetSampledFeaturesGradOp);