24 #include "glog/logging.h" 41 sensor::RangeData FilterRangeDataByMaxRange(
const sensor::RangeData& range_data,
42 const float max_range) {
43 sensor::RangeData result{range_data.origin, {}, {}};
44 for (
const Eigen::Vector3f& hit : range_data.returns) {
45 if ((hit - range_data.origin).norm() <= max_range) {
46 result.returns.push_back(hit);
52 std::vector<PixelData> AccumulatePixelData(
53 const int width,
const int height,
const Eigen::Array2i& min_index,
54 const Eigen::Array2i& max_index,
55 const std::vector<Eigen::Array4i>& voxel_indices_and_probabilities) {
56 std::vector<PixelData> accumulated_pixel_data(width * height);
57 for (
const Eigen::Array4i& voxel_index_and_probability :
58 voxel_indices_and_probabilities) {
59 const Eigen::Array2i pixel_index = voxel_index_and_probability.head<2>();
60 if ((pixel_index < min_index).any() || (pixel_index > max_index).any()) {
64 const int x = max_index.x() - pixel_index[0];
65 const int y = max_index.y() - pixel_index[1];
66 PixelData& pixel = accumulated_pixel_data[x * width + y];
68 pixel.min_z = std::min(pixel.min_z, voxel_index_and_probability[2]);
69 pixel.max_z = std::max(pixel.max_z, voxel_index_and_probability[2]);
70 const float probability =
72 pixel.probability_sum += probability;
73 pixel.max_probability = std::max(pixel.max_probability, probability);
75 return accumulated_pixel_data;
81 std::vector<Eigen::Array4i> ExtractVoxelData(
83 Eigen::Array2i* min_index, Eigen::Array2i* max_index) {
84 std::vector<Eigen::Array4i> voxel_indices_and_probabilities;
85 const float resolution_inverse = 1.f / hybrid_grid.resolution();
87 constexpr
float kXrayObstructedCellProbabilityLimit = 0.501f;
89 const uint16 probability_value = it.GetValue();
91 if (probability < kXrayObstructedCellProbabilityLimit) {
96 const Eigen::Vector3f cell_center_submap =
97 hybrid_grid.GetCenterOfCell(it.GetCellIndex());
98 const Eigen::Vector3f cell_center_global = transform * cell_center_submap;
99 const Eigen::Array4i voxel_index_and_probability(
105 voxel_indices_and_probabilities.push_back(voxel_index_and_probability);
106 const Eigen::Array2i pixel_index = voxel_index_and_probability.head<2>();
107 *min_index = min_index->cwiseMin(pixel_index);
108 *max_index = max_index->cwiseMax(pixel_index);
110 return voxel_indices_and_probabilities;
115 std::string ComputePixelValues(
116 const std::vector<PixelData>& accumulated_pixel_data) {
117 std::string cell_data;
118 cell_data.reserve(2 * accumulated_pixel_data.size());
119 constexpr
float kMinZDifference = 3.f;
120 constexpr
float kFreeSpaceWeight = 0.15f;
121 for (
const PixelData& pixel : accumulated_pixel_data) {
125 const float z_difference = pixel.count > 0 ? pixel.max_z - pixel.min_z : 0;
126 if (z_difference < kMinZDifference) {
127 cell_data.push_back(0);
128 cell_data.push_back(0);
131 const float free_space = std::max(z_difference - pixel.count, 0.f);
132 const float free_space_weight = kFreeSpaceWeight * free_space;
133 const float total_weight = pixel.count + free_space_weight;
134 const float free_space_probability = 1.f - pixel.max_probability;
136 (pixel.probability_sum + free_space_probability * free_space_weight) /
139 const uint8 alpha = delta > 0 ? 0 : -delta;
140 const uint8 value = delta > 0 ? delta : 0;
141 cell_data.push_back(value);
142 cell_data.push_back((value || alpha) ? alpha : 1);
147 void AddToTextureProto(
149 proto::SubmapQuery::Response::SubmapTexture*
const texture) {
152 const float resolution = hybrid_grid.resolution();
153 texture->set_resolution(resolution);
156 Eigen::Array2i min_index(INT_MAX, INT_MAX);
157 Eigen::Array2i max_index(INT_MIN, INT_MIN);
158 const std::vector<Eigen::Array4i> voxel_indices_and_probabilities =
159 ExtractVoxelData(hybrid_grid, global_submap_pose.cast<
float>(),
160 &min_index, &max_index);
162 const int width = max_index.y() - min_index.y() + 1;
163 const int height = max_index.x() - min_index.x() + 1;
164 texture->set_width(width);
165 texture->set_height(height);
167 const std::vector<PixelData> accumulated_pixel_data = AccumulatePixelData(
168 width, height, min_index, max_index, voxel_indices_and_probabilities);
169 const std::string cell_data = ComputePixelValues(accumulated_pixel_data);
173 global_submap_pose.inverse() *
175 max_index.x() * resolution, max_index.y() * resolution,
176 global_submap_pose.translation().z())));
183 proto::SubmapsOptions3D options;
184 options.set_high_resolution(
185 parameter_dictionary->
GetDouble(
"high_resolution"));
186 options.set_high_resolution_max_range(
187 parameter_dictionary->
GetDouble(
"high_resolution_max_range"));
188 options.set_low_resolution(parameter_dictionary->
GetDouble(
"low_resolution"));
189 options.set_num_range_data(
191 *options.mutable_range_data_inserter_options() =
193 parameter_dictionary->
GetDictionary(
"range_data_inserter").get());
194 CHECK_GT(options.num_range_data(), 0);
200 :
Submap(local_submap_pose),
201 high_resolution_hybrid_grid_(
203 low_resolution_hybrid_grid_(
217 bool include_probability_grid_data)
const {
218 auto*
const submap_3d = proto->mutable_submap_3d();
221 submap_3d->set_finished(
finished());
222 if (include_probability_grid_data) {
223 *submap_3d->mutable_high_resolution_hybrid_grid() =
225 *submap_3d->mutable_low_resolution_hybrid_grid() =
231 CHECK(proto.has_submap_3d());
232 const auto& submap_3d = proto.submap_3d();
235 if (submap_3d.has_high_resolution_hybrid_grid()) {
237 submap_3d.has_high_resolution_hybrid_grid()
238 ? common::make_unique<HybridGrid>(
239 submap_3d.high_resolution_hybrid_grid())
242 if (submap_3d.has_low_resolution_hybrid_grid()) {
244 submap_3d.has_low_resolution_hybrid_grid()
245 ? common::make_unique<HybridGrid>(
246 submap_3d.low_resolution_hybrid_grid())
253 proto::SubmapQuery::Response*
const response)
const {
257 response->add_textures());
259 response->add_textures());
264 const int high_resolution_max_range) {
267 range_data,
local_pose().inverse().cast<float>());
268 range_data_inserter.
Insert(
269 FilterRangeDataByMaxRange(transformed_range_data,
270 high_resolution_max_range),
272 range_data_inserter.
Insert(transformed_range_data,
301 const Eigen::Quaterniond& gravity_alignment) {
304 options_.high_resolution_max_range());
306 if (submaps_.back()->num_range_data() ==
options_.num_range_data()) {
proto::HybridGrid ToProto() const
float ClampProbability(const float probability)
int matching_index() const
proto::RangeDataInserterOptions3D CreateRangeDataInserterOptions3D(common::LuaParameterDictionary *parameter_dictionary)
std::unique_ptr< HybridGrid > high_resolution_hybrid_grid_
void UpdateFromProto(const proto::Submap &proto) override
_Unique_if< T >::_Single_object make_unique(Args &&... args)
const proto::SubmapsOptions3D options_
typename GridBase< uint16 >::Iterator Iterator
const HybridGrid & high_resolution_hybrid_grid() const
int RoundToInt(const float x)
RangeDataInserter3D range_data_inserter_
int matching_submap_index_
void set_num_range_data(const int num_range_data)
int GetNonNegativeInt(const std::string &key)
void set_finished(bool finished)
float ValueToProbability(const uint16 value)
const HybridGrid & low_resolution_hybrid_grid() const
double GetDouble(const std::string &key)
RangeData TransformRangeData(const RangeData &range_data, const transform::Rigid3f &transform)
void Insert(const sensor::RangeData &range_data, HybridGrid *hybrid_grid) const
void ToResponseProto(const transform::Rigid3d &global_submap_pose, proto::SubmapQuery::Response *response) const override
void ToProto(proto::Submap *proto, bool include_probability_grid_data) const override
proto::ProbabilityGridRangeDataInserterOptions2D options_
uint8 ProbabilityToLogOddsInteger(const float probability)
std::unique_ptr< ProbabilityGridRangeDataInserter2D > range_data_inserter_
std::unique_ptr< HybridGrid > low_resolution_hybrid_grid_
std::vector< std::shared_ptr< Submap3D > > submaps() const
void InsertRangeData(const sensor::RangeData &range_data, const RangeDataInserter3D &range_data_inserter, int high_resolution_max_range)
void AddSubmap(const transform::Rigid3d &local_submap_pose)
proto::SubmapsOptions3D CreateSubmapsOptions3D(common::LuaParameterDictionary *parameter_dictionary)
transform::Rigid3d local_pose() const
ActiveSubmaps3D(const proto::SubmapsOptions3D &options)
void FastGzipString(const std::string &uncompressed, std::string *compressed)
std::unique_ptr< LuaParameterDictionary > GetDictionary(const std::string &key)
void InsertRangeData(const sensor::RangeData &range_data, const Eigen::Quaterniond &gravity_alignment)
int num_range_data() const
std::vector< std::shared_ptr< Submap3D > > submaps_
Submap3D(float high_resolution, float low_resolution, const transform::Rigid3d &local_submap_pose)