00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "cartographer/mapping/2d/tsdf_range_data_inserter_2d.h"
00018
00019 #include "cartographer/mapping/internal/2d/normal_estimation_2d.h"
00020 #include "cartographer/mapping/internal/2d/ray_to_pixel_mask.h"
00021
00022 namespace cartographer {
00023 namespace mapping {
00024 namespace {
00025
00026
00027 constexpr int kSubpixelScale = 1000;
00028
00029
00030 constexpr float kMinRangeMeters = 1e-6f;
00031 const float kSqrtTwoPi = std::sqrt(2.0 * M_PI);
00032
00033 void GrowAsNeeded(const sensor::RangeData& range_data,
00034 const float truncation_distance, TSDF2D* const tsdf) {
00035 Eigen::AlignedBox2f bounding_box(range_data.origin.head<2>());
00036 for (const sensor::RangefinderPoint& hit : range_data.returns) {
00037 const Eigen::Vector3f direction =
00038 (hit.position - range_data.origin).normalized();
00039 const Eigen::Vector3f end_position =
00040 hit.position + truncation_distance * direction;
00041 bounding_box.extend(end_position.head<2>());
00042 }
00043
00044 constexpr float kPadding = 1e-6f;
00045 tsdf->GrowLimits(bounding_box.min() - kPadding * Eigen::Vector2f::Ones());
00046 tsdf->GrowLimits(bounding_box.max() + kPadding * Eigen::Vector2f::Ones());
00047 }
00048
00049 float GaussianKernel(const float x, const float sigma) {
00050 return 1.0 / (kSqrtTwoPi * sigma) * std::exp(-0.5 * x * x / (sigma * sigma));
00051 }
00052
00053 std::pair<Eigen::Array2i, Eigen::Array2i> SuperscaleRay(
00054 const Eigen::Vector2f& begin, const Eigen::Vector2f& end,
00055 TSDF2D* const tsdf) {
00056 const MapLimits& limits = tsdf->limits();
00057 const double superscaled_resolution = limits.resolution() / kSubpixelScale;
00058 const MapLimits superscaled_limits(
00059 superscaled_resolution, limits.max(),
00060 CellLimits(limits.cell_limits().num_x_cells * kSubpixelScale,
00061 limits.cell_limits().num_y_cells * kSubpixelScale));
00062
00063 const Eigen::Array2i superscaled_begin =
00064 superscaled_limits.GetCellIndex(begin);
00065 const Eigen::Array2i superscaled_end = superscaled_limits.GetCellIndex(end);
00066 return std::make_pair(superscaled_begin, superscaled_end);
00067 }
00068
00069 struct RangeDataSorter {
00070 RangeDataSorter(Eigen::Vector3f origin) { origin_ = origin.head<2>(); }
00071 bool operator()(const sensor::RangefinderPoint& lhs,
00072 const sensor::RangefinderPoint& rhs) {
00073 const Eigen::Vector2f delta_lhs =
00074 (lhs.position.head<2>() - origin_).normalized();
00075 const Eigen::Vector2f delta_rhs =
00076 (lhs.position.head<2>() - origin_).normalized();
00077 if ((delta_lhs[1] < 0.f) != (delta_rhs[1] < 0.f)) {
00078 return delta_lhs[1] < 0.f;
00079 } else if (delta_lhs[1] < 0.f) {
00080 return delta_lhs[0] < delta_rhs[0];
00081 } else {
00082 return delta_lhs[0] > delta_rhs[0];
00083 }
00084 }
00085
00086 private:
00087 Eigen::Vector2f origin_;
00088 };
00089
00090 float ComputeRangeWeightFactor(float range, int exponent) {
00091 float weight = 0.f;
00092 if (std::abs(range) > kMinRangeMeters) {
00093 weight = 1.f / (std::pow(range, exponent));
00094 }
00095 return weight;
00096 }
00097 }
00098
00099 proto::TSDFRangeDataInserterOptions2D CreateTSDFRangeDataInserterOptions2D(
00100 common::LuaParameterDictionary* parameter_dictionary) {
00101 proto::TSDFRangeDataInserterOptions2D options;
00102 options.set_truncation_distance(
00103 parameter_dictionary->GetDouble("truncation_distance"));
00104 options.set_maximum_weight(parameter_dictionary->GetDouble("maximum_weight"));
00105 options.set_update_free_space(
00106 parameter_dictionary->GetBool("update_free_space"));
00107 *options
00108 .mutable_normal_estimation_options() = CreateNormalEstimationOptions2D(
00109 parameter_dictionary->GetDictionary("normal_estimation_options").get());
00110 options.set_project_sdf_distance_to_scan_normal(
00111 parameter_dictionary->GetBool("project_sdf_distance_to_scan_normal"));
00112 options.set_update_weight_range_exponent(
00113 parameter_dictionary->GetInt("update_weight_range_exponent"));
00114 options.set_update_weight_angle_scan_normal_to_ray_kernel_bandwidth(
00115 parameter_dictionary->GetDouble(
00116 "update_weight_angle_scan_normal_to_ray_kernel_bandwidth"));
00117 options.set_update_weight_distance_cell_to_hit_kernel_bandwidth(
00118 parameter_dictionary->GetDouble(
00119 "update_weight_distance_cell_to_hit_kernel_bandwidth"));
00120 return options;
00121 }
00122
00123 TSDFRangeDataInserter2D::TSDFRangeDataInserter2D(
00124 const proto::TSDFRangeDataInserterOptions2D& options)
00125 : options_(options) {}
00126
00127
00128
00129
00130
00131 void TSDFRangeDataInserter2D::Insert(const sensor::RangeData& range_data,
00132 GridInterface* grid) const {
00133 const float truncation_distance =
00134 static_cast<float>(options_.truncation_distance());
00135 TSDF2D* tsdf = static_cast<TSDF2D*>(grid);
00136 GrowAsNeeded(range_data, truncation_distance, tsdf);
00137
00138
00139 bool scale_update_weight_angle_scan_normal_to_ray =
00140 options_.update_weight_angle_scan_normal_to_ray_kernel_bandwidth() != 0.f;
00141 sensor::RangeData sorted_range_data = range_data;
00142 std::vector<float> normals;
00143 if (options_.project_sdf_distance_to_scan_normal() ||
00144 scale_update_weight_angle_scan_normal_to_ray) {
00145 std::sort(sorted_range_data.returns.begin(),
00146 sorted_range_data.returns.end(),
00147 RangeDataSorter(sorted_range_data.origin));
00148 normals = EstimateNormals(sorted_range_data,
00149 options_.normal_estimation_options());
00150 }
00151
00152 const Eigen::Vector2f origin = sorted_range_data.origin.head<2>();
00153 for (size_t hit_index = 0; hit_index < sorted_range_data.returns.size();
00154 ++hit_index) {
00155 const Eigen::Vector2f hit =
00156 sorted_range_data.returns[hit_index].position.head<2>();
00157 const float normal = normals.empty()
00158 ? std::numeric_limits<float>::quiet_NaN()
00159 : normals[hit_index];
00160 InsertHit(options_, hit, origin, normal, tsdf);
00161 }
00162 tsdf->FinishUpdate();
00163 }
00164
00165 void TSDFRangeDataInserter2D::InsertHit(
00166 const proto::TSDFRangeDataInserterOptions2D& options,
00167 const Eigen::Vector2f& hit, const Eigen::Vector2f& origin, float normal,
00168 TSDF2D* tsdf) const {
00169 const Eigen::Vector2f ray = hit - origin;
00170 const float range = ray.norm();
00171 const float truncation_distance =
00172 static_cast<float>(options_.truncation_distance());
00173 if (range < truncation_distance) return;
00174 const float truncation_ratio = truncation_distance / range;
00175 const Eigen::Vector2f ray_begin =
00176 options_.update_free_space() ? origin
00177 : origin + (1.0f - truncation_ratio) * ray;
00178 const Eigen::Vector2f ray_end = origin + (1.0f + truncation_ratio) * ray;
00179 std::pair<Eigen::Array2i, Eigen::Array2i> superscaled_ray =
00180 SuperscaleRay(ray_begin, ray_end, tsdf);
00181 std::vector<Eigen::Array2i> ray_mask = RayToPixelMask(
00182 superscaled_ray.first, superscaled_ray.second, kSubpixelScale);
00183
00184
00185 float weight_factor_angle_ray_normal = 1.f;
00186 if (options_.update_weight_angle_scan_normal_to_ray_kernel_bandwidth() !=
00187 0.f) {
00188 const Eigen::Vector2f negative_ray = -ray;
00189 float angle_ray_normal =
00190 common::NormalizeAngleDifference(normal - common::atan2(negative_ray));
00191 weight_factor_angle_ray_normal = GaussianKernel(
00192 angle_ray_normal,
00193 options_.update_weight_angle_scan_normal_to_ray_kernel_bandwidth());
00194 }
00195 float weight_factor_range = 1.f;
00196 if (options_.update_weight_range_exponent() != 0) {
00197 weight_factor_range = ComputeRangeWeightFactor(
00198 range, options_.update_weight_range_exponent());
00199 }
00200
00201
00202 for (const Eigen::Array2i& cell_index : ray_mask) {
00203 if (tsdf->CellIsUpdated(cell_index)) continue;
00204 Eigen::Vector2f cell_center = tsdf->limits().GetCellCenter(cell_index);
00205 float distance_cell_to_origin = (cell_center - origin).norm();
00206 float update_tsd = range - distance_cell_to_origin;
00207 if (options_.project_sdf_distance_to_scan_normal()) {
00208 float normal_orientation = normal;
00209 update_tsd = (cell_center - hit)
00210 .dot(Eigen::Vector2f{std::cos(normal_orientation),
00211 std::sin(normal_orientation)});
00212 }
00213 update_tsd =
00214 common::Clamp(update_tsd, -truncation_distance, truncation_distance);
00215 float update_weight = weight_factor_range * weight_factor_angle_ray_normal;
00216 if (options_.update_weight_distance_cell_to_hit_kernel_bandwidth() != 0.f) {
00217 update_weight *= GaussianKernel(
00218 update_tsd,
00219 options_.update_weight_distance_cell_to_hit_kernel_bandwidth());
00220 }
00221 UpdateCell(cell_index, update_tsd, update_weight, tsdf);
00222 }
00223 }
00224
00225 void TSDFRangeDataInserter2D::UpdateCell(const Eigen::Array2i& cell,
00226 float update_sdf, float update_weight,
00227 TSDF2D* tsdf) const {
00228 if (update_weight == 0.f) return;
00229 const std::pair<float, float> tsd_and_weight = tsdf->GetTSDAndWeight(cell);
00230 float updated_weight = tsd_and_weight.second + update_weight;
00231 float updated_sdf = (tsd_and_weight.first * tsd_and_weight.second +
00232 update_sdf * update_weight) /
00233 updated_weight;
00234 updated_weight =
00235 std::min(updated_weight, static_cast<float>(options_.maximum_weight()));
00236 tsdf->SetCell(cell, updated_sdf, updated_weight);
00237 }
00238
00239 }
00240 }