grid_conversion.cpp
Go to the documentation of this file.
1#include "grid_conversion.h"
2
3#include <algorithm>
4#include <cstdint>
5
6#include <Eigen/Geometry>
7
8#include <opencv2/core.hpp>
9#include <opencv2/core/mat.hpp>
10#include <opencv2/opencv.hpp>
11
14
15#include <cartographer/mapping/2d/grid_2d.h>
16#include <cartographer/mapping/2d/probability_grid.h>
17#include <cartographer/mapping/2d/submap_2d.h>
18#include <cartographer/mapping/2d/xy_index.h>
19#include <cartographer/mapping/internal/2d/tsdf_2d.h>
20
22{
23 ColoredMeshGrid::ColoredMeshGrid(Eigen::Array2i numCells) :
24 num_cells(numCells),
25 vertices(numCells.x(), std::vector<Position>(numCells.y(), Position::Zero())),
26 colors(numCells.x(), std::vector<Color>(numCells.y(), Color::Zero()))
27 {
28 }
29
30 void
31 ColoredMeshGrid::setColoredVertex(const Eigen::Array2i& idx,
32 const Position& position,
33 const Color& color)
34 {
35 vertices.at(idx.x()).at(idx.y()) = position;
36 colors.at(idx.x()).at(idx.y()) = color;
37 }
38
40 toMeshGrid(const ::cartographer::mapping::ProbabilityGrid& grid)
41 {
42 const auto resolution = static_cast<float>(grid.limits().resolution());
43
44 Eigen::Array2i offset;
45 ::cartographer::mapping::CellLimits mapLimits;
46 grid.ComputeCroppedLimits(&offset, &mapLimits);
47
48 ::cartographer::mapping::XYIndexRangeIterator iter(mapLimits);
49
50 ColoredMeshGrid meshGrid({mapLimits.num_x_cells, mapLimits.num_y_cells});
51
52 constexpr uint8_t transparency{255}; // non transparent
53 const ColoredMeshGrid::Color colorCellUnknown =
54 ColoredMeshGrid::Color::Zero(); // fully transparent
55
56 std::for_each(iter.begin(),
57 iter.end(),
58 [&](const Eigen::Array2i& cellIndexCropped)
59 {
60 const auto cellIndex = cellIndexCropped + offset;
61
62 const float probability = grid.GetProbability(cellIndex);
63 const bool isKnown = grid.IsKnown(cellIndex);
64
65 const ColoredMeshGrid::Color color = [&]() -> ColoredMeshGrid::Color
66 {
67 if (isKnown)
68 {
69 const auto c = static_cast<uint8_t>((1 - probability) * 255);
70 return {c, c, c, transparency};
71 }
72
73 return colorCellUnknown;
74 }();
75
76 ColoredMeshGrid::Position position = ColoredMeshGrid::Position::Zero();
77
78 // x and y are swapped on purpose.
79 position.y() = -cellIndex.x() * resolution;
80 position.x() = -cellIndex.y() * resolution;
81
82 meshGrid.setColoredVertex(cellIndexCropped, position, color);
83 });
84
85 // x and y are swapped on purpose.
86 // see cartographer/mapping/2d/probability_grid.cc
87 const double maxX = grid.limits().max().x();
88 const double maxY = grid.limits().max().y();
89
90 meshGrid.innerSlicePosition = Eigen::Vector3f(maxX, maxY, 0.);
91
92 return meshGrid;
93 }
94
96 toOccupancyGrid(const ::cartographer::mapping::ProbabilityGrid& grid)
97 {
98 const auto resolution = static_cast<float>(grid.limits().resolution());
99
100 Eigen::Array2i offset = Eigen::Array2i::Zero();
101 ::cartographer::mapping::CellLimits mapLimits = grid.limits().cell_limits();
102 grid.ComputeCroppedLimits(&offset, &mapLimits);
103
104 armem::vision::OccupancyGrid::Grid occGrid(mapLimits.num_y_cells, mapLimits.num_x_cells);
105
106 ::cartographer::mapping::XYIndexRangeIterator iter(mapLimits);
107
108 std::for_each(iter.begin(),
109 iter.end(),
110 [&](const Eigen::Array2i& cellIndexCropped)
111 {
112 const auto cellIndex = cellIndexCropped + offset;
113
114 const float probability = grid.GetProbability(cellIndex);
115 const bool isKnown = grid.IsKnown(cellIndex);
116
117 // x and y are mirrored
118 occGrid(mapLimits.num_y_cells - 1 - cellIndexCropped.y(),
119 mapLimits.num_x_cells - 1 - cellIndexCropped.x()) =
120 isKnown ? probability : 0.F;
121 });
122
123 // x and y are swapped on purpose.
124 // see cartographer/mapping/2d/probability_grid.cc
125
126 const int inner_shift_x =
127 grid.limits().cell_limits().num_x_cells - (offset.x() + mapLimits.num_x_cells);
128 const int inner_shift_y =
129 grid.limits().cell_limits().num_y_cells - (offset.y() + mapLimits.num_y_cells);
130
131 const float maxY = resolution - grid.limits().max().y() + resolution * inner_shift_y;
132 const float maxX = resolution - grid.limits().max().x() + resolution * inner_shift_x;
133
135 .resolution = resolution,
136 .frame = MapFrame,
137 // Intentionally, we swap x and y. See comment above.
138 .pose = Eigen::Isometry3f(Eigen::Translation3f(maxY, maxX, 0.F)),
139 .grid = occGrid};
140 }
141
143 toOccupancyGrid(const ::cartographer::mapping::Grid2D& grid)
144 {
145 const auto* probGrid = dynamic_cast<const ::cartographer::mapping::ProbabilityGrid*>(&grid);
146 if (probGrid != nullptr)
147 {
148 auto occ = toOccupancyGrid(*probGrid);
149 return occ;
150 }
151
152 throw InvalidArgumentException();
153 }
154
155 ColoredMeshGrid
156 toMeshGrid(const ::cartographer::mapping::Grid2D& grid)
157 {
158 const auto* probGrid = dynamic_cast<const ::cartographer::mapping::ProbabilityGrid*>(&grid);
159
160 if (probGrid != nullptr)
161 {
162 return toMeshGrid(*probGrid);
163 }
164
165 // const auto* tsdf = dynamic_cast<const cartographer::mapping::TSDF2D*>(&grid);
166 // if (tsdf)
167 // {
168 // ARMARX_INFO << "Processing tsdf grid";
169 // return toMeshGrid(*tsdf, resolution);
170 // }
171
172 throw InvalidArgumentException();
173 }
174
175 cv::Mat2b
176 toImage(const ::cartographer::mapping::ProbabilityGrid& grid)
177 {
178 Eigen::Array2i offset;
179 ::cartographer::mapping::CellLimits mapLimits;
180 grid.ComputeCroppedLimits(&offset, &mapLimits);
181
182 ::cartographer::mapping::XYIndexRangeIterator iter(mapLimits);
183
184 cv::Mat1f outputMap(mapLimits.num_x_cells, mapLimits.num_y_cells);
185 cv::Mat1b outputMapMask(mapLimits.num_x_cells, mapLimits.num_y_cells);
186
187 std::for_each(iter.begin(),
188 iter.end(),
189 [&](const ::Eigen::Array2i& cellIndexCropped)
190 {
191 const auto cellIndex = cellIndexCropped + offset;
192 const cv::Point idx{cellIndexCropped[1], cellIndexCropped[0]};
193
194 outputMap.at<float>(idx) = grid.GetProbability(cellIndex);
195 outputMapMask.at<uint8_t>(idx) =
196 static_cast<uint8_t>(grid.IsKnown(cellIndex));
197 });
198
199 outputMap *= std::numeric_limits<uint8_t>::max(); // Scale [0..1] -> [0..255]
200 outputMapMask *= std::numeric_limits<uint8_t>::max(); // Scale [0..1] -> [0..255]
201
202 cv::Mat1b out;
203 outputMap.convertTo(out, CV_8UC1);
204
205 cv::Mat1b outMask;
206 outputMapMask.convertTo(outMask, CV_8UC1);
207 outputMapMask *= std::numeric_limits<uint8_t>::max(); // Scale {0,1} -> {0,255}
208
209 cv::Mat2b outWithMask;
210 cv::merge(std::vector({out, outMask}), outWithMask);
211
212 return outWithMask;
213 }
214
215 cv::Mat2b
216 toImage(const ::cartographer::mapping::TSDF2D& tsdf)
217 {
218 const ::cartographer::mapping::CellLimits& mapLimits = tsdf.limits().cell_limits();
219
220 ::cartographer::mapping::XYIndexRangeIterator iter(mapLimits);
221
222 cv::Mat1f outputMap(mapLimits.num_x_cells, mapLimits.num_y_cells);
223 cv::Mat1f outputMapMask(mapLimits.num_x_cells, mapLimits.num_y_cells);
224
225 std::for_each(iter.begin(),
226 iter.end(),
227 [&](const ::Eigen::Array2i& cellIndex)
228 {
229 const cv::Point idx{cellIndex[1], cellIndex[0]};
230
231 outputMap.at<float>(idx) = tsdf.GetTSD(cellIndex);
232 outputMapMask.at<bool>(idx) = tsdf.IsKnown(cellIndex);
233 });
234
235 outputMap *= std::numeric_limits<uint8_t>::max(); // Scale [0..1] -> [0..255]
236
237 cv::Mat1b out;
238 outputMap.convertTo(out, CV_8UC1);
239
240 cv::Mat1b outMask;
241 outputMapMask.convertTo(outMask, CV_8UC1);
242 outputMapMask *= std::numeric_limits<uint8_t>::max(); // Scale {0,1} -> {0,255}
243
244 cv::Mat2b outWithMask;
245 cv::merge(std::vector({out, outMask}), outWithMask);
246
247 return outWithMask;
248 }
249
250 cv::Mat2b
251 toImage(const ::cartographer::mapping::Grid2D& grid)
252 {
253 const auto* probGrid = dynamic_cast<const ::cartographer::mapping::ProbabilityGrid*>(&grid);
254
255 if (probGrid != nullptr)
256 {
257 return toImage(*probGrid);
258 }
259
260 const auto* tsdf = dynamic_cast<const ::cartographer::mapping::TSDF2D*>(&grid);
261 if (tsdf != nullptr)
262 {
263 return toImage(*tsdf);
264 }
265
266 return {};
267 }
268
269} // namespace armarx::localization_and_mapping::cartographer_adapter
cv::Mat2b toImage(const ::cartographer::mapping::ProbabilityGrid &grid)
armem::vision::OccupancyGrid toOccupancyGrid(const ::cartographer::mapping::ProbabilityGrid &grid)
ColoredMeshGrid toMeshGrid(const ::cartographer::mapping::ProbabilityGrid &grid)
This file offers overloads of toIce() and fromIce() functions for STL container types.
std::string const MapFrame
Definition FramedPose.h:67
Eigen::Array< CellType, Eigen::Dynamic, Eigen::Dynamic > Grid
Definition types.h:45
void setColoredVertex(const Eigen::Array2i &idx, const Position &position, const Color &color)