Sematic-Cartographer/cartographer-master/cartographer/mapping/2d/probability_grid.cc

353 lines
14 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* 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