Program Listing for File vdb_likelihood_field_model.hpp
↰ Return to documentation for file (include/beluga_vdb/sensor/vdb_likelihood_field_model.hpp
)
// Copyright 2024 Ekumen, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef BELUGA_VDB_SENSOR_VDB_LIKELIHOOD_FIELD_MODEL_HPP
#define BELUGA_VDB_SENSOR_VDB_LIKELIHOOD_FIELD_MODEL_HPP
#include <algorithm>
#include <cmath>
#include <random>
#include <vector>
#include <openvdb/openvdb.h>
#include <beluga/3d_embedding.hpp>
#include <Eigen/Core>
#include <range/v3/numeric/accumulate.hpp>
#include <range/v3/range/conversion.hpp>
#include <range/v3/view/all.hpp>
#include <range/v3/view/transform.hpp>
#include <sophus/se2.hpp>
#include <sophus/se3.hpp>
#include <sophus/so2.hpp>
#include <sophus/so3.hpp>
namespace beluga_vdb {
struct VDBLikelihoodFieldModelParam {
double max_obstacle_distance = 100.0;
double max_laser_distance = 2.0;
double z_hit = 0.5;
double z_random = 0.5;
double sigma_hit = 0.2;
};
template <typename GridT, typename PointCloud, class StateType = Sophus::SE3d>
class VDBLikelihoodFieldModel {
static_assert(
std::is_same_v<StateType, Sophus::SE2d> or std::is_same_v<StateType, Sophus::SE3d>,
"VDB likelihood field sensor model only supports SE2 and SE3 state types.");
public:
using state_type = StateType;
using weight_type = double;
using measurement_type = PointCloud;
using map_type = GridT;
using param_type = VDBLikelihoodFieldModelParam;
explicit VDBLikelihoodFieldModel(const param_type& params, const map_type& grid)
: params_{params},
grid_{openvdb::gridPtrCast<map_type>(grid.deepCopyGrid())},
accessor_{grid_->getConstAccessor()},
transform_{grid_->transform()},
background_{grid_->background()},
two_squared_sigma_{2 * params.sigma_hit * params.sigma_hit},
amplitude_{params.z_hit / (params.sigma_hit * std::sqrt(2 * Sophus::Constants<double>::pi()))},
offset_{params.z_random / params.max_laser_distance} {
openvdb::initialize();
assert(two_squared_sigma_ > 0.0);
assert(amplitude_ > 0.0);
}
[[nodiscard]] auto operator()(measurement_type&& measurement) const {
// Transform each point from the sensor frame to the origin frame
auto transformed_points = measurement.points() | ranges::views::transform([&](const auto& point) {
return measurement.origin() * point.template cast<double>();
}) |
ranges::to<std::vector>();
return [this, points = std::move(transformed_points)](const state_type& state) -> weight_type {
return ranges::accumulate(
points | //
ranges::views::transform([this, state = beluga::To3d(state)](const auto& point) {
const Eigen::Vector3d point_in_state_frame = state * point;
const openvdb::math::Coord ijk = transform_.worldToIndexCellCentered(
openvdb::math::Vec3d(point_in_state_frame.x(), point_in_state_frame.y(), point_in_state_frame.z()));
const auto distance = accessor_.isValueOn(ijk) ? accessor_.getValue(ijk) : background_;
return amplitude_ * std::exp(-(distance * distance) / two_squared_sigma_) + offset_;
}),
1.0, std::plus{});
};
}
private:
param_type params_;
const typename map_type::Ptr grid_;
const typename map_type::ConstAccessor accessor_;
const openvdb::math::Transform transform_;
const typename map_type::ValueType background_;
double two_squared_sigma_;
double amplitude_;
double offset_;
};
template <typename GridT, typename PointCloud>
using VDBLikelihoodFieldModel2 = VDBLikelihoodFieldModel<GridT, PointCloud, Sophus::SE2d>;
template <typename GridT, typename PointCloud>
using VDBLikelihoodFieldModel3 = VDBLikelihoodFieldModel<GridT, PointCloud, Sophus::SE3d>;
} // namespace beluga_vdb
#endif