353 lines
14 KiB
C++
Executable File
353 lines
14 KiB
C++
Executable File
/*
|
||
* Copyright 2016 The Cartographer Authors
|
||
*
|
||
* 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.
|
||
*/
|
||
#include "cartographer/mapping/2d/probability_grid.h"
|
||
|
||
#include <limits>
|
||
#include <iostream>
|
||
#include "absl/memory/memory.h"
|
||
#include "cartographer/mapping/probability_values.h"
|
||
#include "cartographer/mapping/submaps.h"
|
||
#include <queue>
|
||
|
||
namespace cartographer {
|
||
namespace mapping {
|
||
|
||
/**
|
||
* @brief ProbabilityGrid的构造函数
|
||
*
|
||
* @param[in] limits 地图坐标信息
|
||
* @param[in] conversion_tables 转换表
|
||
*/
|
||
ProbabilityGrid::ProbabilityGrid(const MapLimits& limits,
|
||
ValueConversionTables* conversion_tables)
|
||
: Grid2D(limits, kMinCorrespondenceCost, kMaxCorrespondenceCost,
|
||
conversion_tables),
|
||
conversion_tables_(conversion_tables) {
|
||
}
|
||
|
||
ProbabilityGrid::ProbabilityGrid(const proto::Grid2D& proto,
|
||
ValueConversionTables* conversion_tables)
|
||
: Grid2D(proto, conversion_tables), conversion_tables_(conversion_tables) {
|
||
CHECK(proto.has_probability_grid_2d());
|
||
|
||
}
|
||
|
||
// Sets the probability of the cell at 'cell_index' to the given
|
||
// 'probability'. Only allowed if the cell was unknown before.
|
||
// 将 索引 处单元格的概率设置为给定的概率, 仅当单元格之前处于未知状态时才允许
|
||
void ProbabilityGrid::SetProbability(const Eigen::Array2i& cell_index,
|
||
const float probability) {
|
||
// 获取对应栅格的引用
|
||
uint16& cell =
|
||
(*mutable_correspondence_cost_cells())[ToFlatIndex(cell_index)];
|
||
CHECK_EQ(cell, kUnknownProbabilityValue);
|
||
// 为栅格赋值 value
|
||
cell =
|
||
CorrespondenceCostToValue(ProbabilityToCorrespondenceCost(probability));
|
||
// 更新bounding_box
|
||
mutable_known_cells_box()->extend(cell_index.matrix());
|
||
}
|
||
|
||
// Applies the 'odds' specified when calling ComputeLookupTableToApplyOdds()
|
||
// to the probability of the cell at 'cell_index' if the cell has not already
|
||
// been updated. Multiple updates of the same cell will be ignored until
|
||
// FinishUpdate() is called. Returns true if the cell was updated.
|
||
// 如果单元格尚未更新,则将调用 ComputeLookupTableToApplyOdds() 时指定的 'odds' 应用于单元格在 'cell_index' 处的概率
|
||
// 在调用 FinishUpdate() 之前,将忽略同一单元格的多次更新。如果单元格已更新,则返回 true
|
||
//
|
||
// If this is the first call to ApplyOdds() for the specified cell, its value
|
||
// will be set to probability corresponding to 'odds'.
|
||
// 如果这是对指定单元格第一次调用 ApplyOdds(),则其值将设置为与 'odds' 对应的概率
|
||
|
||
// 使用查找表对指定栅格进行栅格值的更新
|
||
|
||
//。。新增函数
|
||
bool ProbabilityGrid::ApplyLookupTableHit(const Eigen::Array2i& cell_index,
|
||
const std::vector<uint16>& table,
|
||
const uint8 intensity) {
|
||
DCHECK_EQ(table.size(), kUpdateMarker);
|
||
const int flat_index = ToFlatIndex(cell_index);
|
||
// 获取对应栅格的指针
|
||
uint16* cell = &(*mutable_correspondence_cost_cells())[flat_index];
|
||
// 对处于更新状态的栅格, 不再进行更新了
|
||
if (*cell >= kUpdateMarker) {
|
||
return false;
|
||
}
|
||
// 标记这个索引的栅格已经被更新过
|
||
mutable_update_indices()->push_back(flat_index);
|
||
|
||
if(((*mutable_correspondence_cost_cells2()).size())<flat_index) (*mutable_correspondence_cost_cells2()).resize((*mutable_correspondence_cost_cells()).size());
|
||
//if(intensities!=0)
|
||
((*mutable_correspondence_cost_cells2())[flat_index]).push_back(intensity);
|
||
|
||
// 更新栅格值
|
||
*cell = table[*cell];
|
||
DCHECK_GE(*cell, kUpdateMarker);
|
||
// 更新bounding_box
|
||
mutable_known_cells_box()->extend(cell_index.matrix());
|
||
// jzq
|
||
mutable_semantics_observer()->at(flat_index) = 1;
|
||
ApplyLookupTableSemHit(intensity, flat_index);
|
||
return true;
|
||
}
|
||
|
||
// jzq 每一个栅格使用一个vector来记录语义,固定其大小为7来保持语义的动态性
|
||
void ProbabilityGrid::ApplyLookupTableSemHit(const uint8 intensity, const int flat_index) {
|
||
// 非视野内、已更新过语义 则不再更新语义
|
||
if(intensity == 0 || mutable_semantics_update_indices()->at(flat_index))
|
||
return ;
|
||
|
||
std::vector<uint16>* counter = &(mutable_semantics_counter()->at(flat_index));
|
||
counter->push_back(intensity);
|
||
while(counter->size() > 7)
|
||
counter->erase(counter->begin());
|
||
|
||
std::map<int, int> tempCounter{};
|
||
for (uint16 x : *counter)
|
||
{
|
||
if (tempCounter.find(x) == tempCounter.end())
|
||
tempCounter[x] = 1;
|
||
else
|
||
tempCounter[x] += 1;
|
||
if (tempCounter[x] > 3) {
|
||
// 如果是新的语义,则直接更新
|
||
if(x > 2) {
|
||
mutable_semantics()->at(flat_index) = x;
|
||
mutable_semantics_update_indices()->at(flat_index) = 1;
|
||
return ;
|
||
}
|
||
// 如果是没有语义,则对于小物体允许更新语义,大物体则需要counter中全为1才允许更新
|
||
// if(smallObjects.find(mutable_semantics()->at(flat_index)) != smallObjects.end()) {
|
||
// mutable_semantics()->at(flat_index) = x;
|
||
// mutable_semantics_update_indices()->at(flat_index) = 1;
|
||
// }
|
||
// 要求语义vector中是7个1才允许语义消失
|
||
else if(tempCounter[x] > 6) {
|
||
mutable_semantics()->at(flat_index) = x;
|
||
mutable_semantics_update_indices()->at(flat_index) = 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// jzq miss语义更新策略
|
||
void ProbabilityGrid::ApplyLookupTableSemMiss(const uint8 intensity, const int flat_index) {
|
||
// jzq intensity>0表示摄像头视域,为0则表示其他角度雷达返回的点
|
||
// 非摄像头视域,已更新过语义则不再更新
|
||
if(intensity == 0 || mutable_semantics_update_indices()->at(flat_index))
|
||
return ;
|
||
// 测距范围外的小物体语义不更新
|
||
if((smallObjects.find(semantics().at(flat_index)) != smallObjects.end()) && (!scanSemantics().at(flat_index)))
|
||
return ;
|
||
|
||
std::vector<uint16>* counter = &(mutable_semantics_counter()->at(flat_index));
|
||
counter->push_back(1);
|
||
|
||
while(counter->size() > 7)
|
||
counter->erase(counter->begin());
|
||
|
||
std::map<int, int> tempCounter{};
|
||
for (uint16 x : *counter)
|
||
{
|
||
if (tempCounter.find(x) == tempCounter.end())
|
||
tempCounter[x] = 1;
|
||
else
|
||
tempCounter[x] += 1;
|
||
if (tempCounter[x] > 3) {
|
||
if(x > 2) {
|
||
mutable_semantics()->at(flat_index) = x;
|
||
mutable_semantics_update_indices()->at(flat_index) = 1;
|
||
return ;
|
||
}
|
||
// if(smallObjects.find(mutable_semantics()->at(flat_index)) != smallObjects.end()) {
|
||
// mutable_semantics()->at(flat_index) = x;
|
||
// mutable_semantics_update_indices()->at(flat_index) = 1;
|
||
// }
|
||
// 要求语义vector中是7个1才允许语义消失
|
||
else if(tempCounter[x] > 6) {
|
||
mutable_semantics()->at(flat_index) = x;
|
||
mutable_semantics_update_indices()->at(flat_index) = 1;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
bool ProbabilityGrid::ApplyLookupTableMiss(const Eigen::Array2i& cell_index,
|
||
const std::vector<uint16>& table,
|
||
const uint8 intensity) {
|
||
DCHECK_EQ(table.size(), kUpdateMarker);
|
||
const int flat_index = ToFlatIndex(cell_index);
|
||
// 获取对应栅格的指针
|
||
uint16* cell = &(*mutable_correspondence_cost_cells())[flat_index];
|
||
// 对处于更新状态的栅格, 不再进行更新了
|
||
if (*cell >= kUpdateMarker) {
|
||
return false;
|
||
}
|
||
// 标记这个索引的栅格已经被更新过
|
||
mutable_update_indices()->push_back(flat_index);
|
||
// 更新栅格值
|
||
//。。。cell2_>append(range.hit.color)
|
||
//*cell2 = table[*cell];
|
||
*cell = table[*cell];
|
||
DCHECK_GE(*cell, kUpdateMarker);
|
||
// 更新bounding_box
|
||
mutable_known_cells_box()->extend(cell_index.matrix());
|
||
// jzq
|
||
ApplyLookupTableSemMiss(intensity, flat_index);
|
||
return true;
|
||
}
|
||
|
||
bool ProbabilityGrid::ApplyLookupTable(const Eigen::Array2i& cell_index,
|
||
const std::vector<uint16>& table) {
|
||
DCHECK_EQ(table.size(), kUpdateMarker);
|
||
const int flat_index = ToFlatIndex(cell_index);
|
||
// 获取对应栅格的指针
|
||
uint16* cell = &(*mutable_correspondence_cost_cells())[flat_index];
|
||
// 对处于更新状态的栅格, 不再进行更新了
|
||
if (*cell >= kUpdateMarker) {
|
||
return false;
|
||
}
|
||
// 标记这个索引的栅格已经被更新过
|
||
mutable_update_indices()->push_back(flat_index);
|
||
// 更新栅格值
|
||
*cell = table[*cell];
|
||
DCHECK_GE(*cell, kUpdateMarker);
|
||
// 更新bounding_box
|
||
mutable_known_cells_box()->extend(cell_index.matrix());
|
||
return true;
|
||
}
|
||
|
||
GridType ProbabilityGrid::GetGridType() const {
|
||
return GridType::PROBABILITY_GRID;
|
||
}
|
||
|
||
// Returns the probability of the cell with 'cell_index'.
|
||
// 获取 索引 处单元格的占用概率
|
||
float ProbabilityGrid::GetProbability(const Eigen::Array2i& cell_index) const {
|
||
if (!limits().Contains(cell_index)) return kMinProbability;
|
||
return CorrespondenceCostToProbability(ValueToCorrespondenceCost(
|
||
correspondence_cost_cells()[ToFlatIndex(cell_index)]));
|
||
}
|
||
//int ColorGrid::GetColor(const Eigen::Array2i& cell_index) const 取出改结构第二维的众数 记得声明
|
||
//。。。新增函数getcolor
|
||
float ProbabilityGrid::GetColor(const Eigen::Array2i& cell_index) const {
|
||
if (!limits().Contains(cell_index)) return 0; //???
|
||
// jzq 返回最近时刻赋给栅格的语义
|
||
return semantics().at(ToFlatIndex(cell_index));
|
||
}
|
||
|
||
uint8 ProbabilityGrid::GetSemantics_observer(const Eigen::Array2i& cell_index) const {
|
||
if (!limits().Contains(cell_index)) return 0; //???
|
||
// jzq 返回子图被摄像头观测过的区域
|
||
// 本来想返回scanSemantics_observer_对应的值,但其视野范围太窄,更新好像有问题
|
||
// 可考虑同时结合scanSemantics_observer_的信息解决子图融合时的小物体语义问题
|
||
// return scanSemantics().at(ToFlatIndex(cell_index));
|
||
return semantics_counter().at(ToFlatIndex(cell_index)).size();
|
||
}
|
||
|
||
proto::Grid2D ProbabilityGrid::ToProto() const {
|
||
proto::Grid2D result;
|
||
result = Grid2D::ToProto();
|
||
result.mutable_probability_grid_2d();
|
||
return result;
|
||
}
|
||
|
||
// 根据bounding_box对栅格地图进行裁剪到正好包含点云
|
||
std::unique_ptr<Grid2D> ProbabilityGrid::ComputeCroppedGrid() const {
|
||
Eigen::Array2i offset;
|
||
CellLimits cell_limits;
|
||
// 根据bounding_box对栅格地图进行裁剪
|
||
ComputeCroppedLimits(&offset, &cell_limits);
|
||
const double resolution = limits().resolution();
|
||
// 重新计算最大值坐标
|
||
const Eigen::Vector2d max =
|
||
limits().max() - resolution * Eigen::Vector2d(offset.y(), offset.x());
|
||
// 重新定义概率栅格地图的大小
|
||
std::unique_ptr<ProbabilityGrid> cropped_grid =
|
||
absl::make_unique<ProbabilityGrid>(
|
||
MapLimits(resolution, max, cell_limits), conversion_tables_);
|
||
// 给新栅格地图赋值
|
||
for (const Eigen::Array2i& xy_index : XYIndexRangeIterator(cell_limits)) {
|
||
if (!IsKnown(xy_index + offset)) continue;
|
||
cropped_grid->SetProbability(xy_index, GetProbability(xy_index + offset));
|
||
}
|
||
|
||
// 返回新地图的指针
|
||
return std::unique_ptr<Grid2D>(cropped_grid.release());
|
||
}
|
||
|
||
// 获取压缩后的地图栅格数据
|
||
bool ProbabilityGrid::DrawToSubmapTexture(
|
||
proto::SubmapQuery::Response::SubmapTexture* const texture,
|
||
transform::Rigid3d local_pose) const {
|
||
Eigen::Array2i offset;
|
||
CellLimits cell_limits;
|
||
// 根据bounding_box对栅格地图进行裁剪
|
||
ComputeCroppedLimits(&offset, &cell_limits);
|
||
|
||
std::string cells;
|
||
// 遍历地图, 将栅格数据存入cells
|
||
for (const Eigen::Array2i& xy_index : XYIndexRangeIterator(cell_limits)) {
|
||
if (!IsKnown(xy_index + offset)) {
|
||
cells.push_back(0 /* unknown log odds value */);
|
||
cells.push_back(0 /* alpha */);
|
||
cells.push_back(0);
|
||
continue;
|
||
}
|
||
// We would like to add 'delta' but this is not possible using a value and
|
||
// alpha. We use premultiplied alpha, so when 'delta' is positive we can
|
||
// add it by setting 'alpha' to zero. If it is negative, we set 'value' to
|
||
// zero, and use 'alpha' to subtract. This is only correct when the pixel
|
||
// is currently white, so walls will look too gray. This should be hard to
|
||
// detect visually for the user, though.
|
||
// 我们想添加 'delta',但使用值和 alpha 是不可能的
|
||
// 我们使用预乘 alpha,因此当 'delta' 为正时,我们可以通过将 'alpha' 设置为零来添加它。
|
||
// 如果它是负数,我们将 'value' 设置为零,并使用 'alpha' 进行减法。 这仅在像素当前为白色时才正确,因此墙壁看起来太灰。
|
||
// 但是,这对于用户来说应该很难在视觉上检测到。
|
||
|
||
// delta处于[-127, 127]
|
||
const int8 delta =
|
||
128 - ProbabilityToLogOddsInteger(GetProbability(xy_index + offset));
|
||
//。。。写一个函数 输入索引 输出颜色值const color=GetColor(xy_index + offset)
|
||
const uint8 color = uint8(GetColor(xy_index + offset));
|
||
// 存数据时存了2个值, 一个是栅格值value, 另一个是alpha透明度
|
||
//。。。将颜色值存入cell
|
||
cells.push_back(delta);
|
||
cells.push_back(color);
|
||
cells.push_back(GetSemantics_observer(xy_index + offset));
|
||
}
|
||
|
||
// 保存地图栅格数据时进行压缩
|
||
common::FastGzipString(cells, texture->mutable_cells());
|
||
|
||
// 填充地图描述信息
|
||
texture->set_width(cell_limits.num_x_cells);
|
||
texture->set_height(cell_limits.num_y_cells);
|
||
const double resolution = limits().resolution();
|
||
texture->set_resolution(resolution);
|
||
const double max_x = limits().max().x() - resolution * offset.y();
|
||
const double max_y = limits().max().y() - resolution * offset.x();
|
||
*texture->mutable_slice_pose() = transform::ToProto(
|
||
local_pose.inverse() *
|
||
transform::Rigid3d::Translation(Eigen::Vector3d(max_x, max_y, 0.)));
|
||
|
||
return true;
|
||
}
|
||
|
||
} // namespace mapping
|
||
} // namespace cartographer
|
||
|