in tensorflow/libs/transform_points_op.cc [63:183]
void Compute(OpKernelContext* context) override {
// input
auto extract_param = [](float* vec, const Tensor& ts) {
for (int i = 0; i < 3 && i < ts.NumElements(); ++i) {
vec[i] = ts.flat<float>()(i);
}
};
const Tensor& data_in = context->input(0);
// float rotate = context->input(1).flat<float>()(0);
float angle[3] = {0};
extract_param(angle, context->input(1));
float scales[3] = {1.0f, 1.0f, 1.0f};
extract_param(scales, context->input(2));
float jitter[3] = {0};
extract_param(jitter, context->input(3));
float radius = context->input(4).flat<float>()(0);
float center[3] = {0};
extract_param(center, context->input(5));
float ratio = context->input(6).flat<float>()(0);
int dim = context->input(7).flat<int>()(0);
float stddev[3] = {0}; // std_points, std_normals, std_features
extract_param(stddev, context->input(8));
// check
CHECK_EQ(data_in.NumElements(), 1);
for (int i = 0; i < 3; ++i) {
CHECK_GE(scales[i], 0.1f) << "The scale should be larger than 0.1";
}
// copy the data out of the input tensor
auto points_array = data_in.flat<string>();
vector<char> points_buf(points_array(0).begin(), points_array(0).end());
// init the points
Points pts;
pts.set(points_buf.data());
// check the points
string msg;
bool succ = pts.info().check_format(msg);
CHECK(succ) << msg;
// centralize
float dis[3] = {-center[0], -center[1], -center[2]};
if (dis[0] != 0.0f || dis[1] != 0.0f || dis[2] != 0.0f) {
pts.translate(dis);
}
// displacement
const float kEPS = 1.0e-10f;
if (offset_ > kEPS) {
// !!! rescale the offset, relative to the octree node size
float offset = offset_ * 2.0f * radius / float(1 << depth_);
pts.displace(offset);
radius += offset;
}
// data augmentation: rotate the point cloud
if (fabs(angle[0]) > kEPS || fabs(angle[1]) > kEPS || fabs(angle[2]) > kEPS) {
if (axis_ == "x") {
angle[1] = angle[2] = 0;
} else if (axis_ == "y") {
angle[0] = angle[2] = 0;
} else if (axis_ == "z") {
angle[0] = angle[1] = 0;
} else {
}
pts.rotate(angle);
}
// jitter
float max_jitter = -1.0;
for (int i = 0; i < 3; i++) {
// !!! rescale the jitter, relative to the radius
jitter[i] *= 2.0 * radius;
if (max_jitter < fabs(jitter[i])) {
max_jitter = fabs(jitter[i]);
}
}
if (fabs(max_jitter) > kEPS) {
pts.translate(jitter);
// radius += max_jitter;
}
// scale to [-1, 1]^3
if (radius == 0) radius = kEPS;
for (int i = 0; i < 3; ++i) { scales[i] /= radius; }
if (scales[0] != 1.0f || scales[1] != 1.0f || scales[2] != 1.0f) {
pts.scale(scales);
}
// add noise
if (stddev[0] > 0 || stddev[1] > 0 || stddev[2] > 0) {
pts.add_noise(stddev[0], stddev[1]);
}
// clip the points to the box[-1, 1] ^ 3,
const float bbmin[] = {-1.0f, -1.0f, -1.0f};
const float bbmax[] = {1.0f, 1.0f, 1.0f};
pts.clip(bbmin, bbmax);
// float max_scale = -1.0f;
// for (int i = 0; i < 3; ++i) {
// if (max_scale < scales[i]) { max_scale = scales[i]; }
// }
// if (max_scale > 1.0f || max_jitter > kEPS) {
// pts.clip(bbmin, bbmax);
// }
// dropout points
if (dim > 0 && ratio > 0) {
DropPoints drop_points(dim, ratio, bbmin, bbmax);
drop_points.dropout(pts);
}
// output
Tensor* out_data = nullptr;
const TensorShape& shape = data_in.shape();
OP_REQUIRES_OK(context, context->allocate_output(0, shape, &out_data));
string& out_str = out_data->flat<string>()(0);
out_str.assign(points_buf.begin(), points_buf.end());
}