15 #include <geometry_msgs/Point.h> 16 #include <geometry_msgs/Quaternion.h> 26 using namespace Eigen;
30 GridMapRosConverter::GridMapRosConverter()
34 GridMapRosConverter::~GridMapRosConverter()
38 bool GridMapRosConverter::fromMessage(
const grid_map_msgs::GridMap& message,
grid_map::GridMap& gridMap)
40 gridMap.
setTimestamp(message.info.header.stamp.toNSec());
41 gridMap.
setFrameId(message.info.header.frame_id);
42 gridMap.
setGeometry(
Length(message.info.length_x, message.info.length_y), message.info.resolution,
43 Position(message.info.pose.position.x, message.info.pose.position.y));
45 if (message.layers.size() != message.data.size()) {
46 ROS_ERROR(
"Different number of layers and data in grid map message.");
50 for (
unsigned int i = 0; i < message.layers.size(); i++) {
54 gridMap.
add(message.layers[i], data);
62 void GridMapRosConverter::toMessage(
const grid_map::GridMap& gridMap, grid_map_msgs::GridMap& message)
64 toMessage(gridMap, gridMap.
getLayers(), message);
67 void GridMapRosConverter::toMessage(
const grid_map::GridMap& gridMap,
const std::vector<std::string>& layers,
68 grid_map_msgs::GridMap& message)
70 message.info.header.stamp.fromNSec(gridMap.
getTimestamp());
71 message.info.header.frame_id = gridMap.
getFrameId();
73 message.info.length_x = gridMap.
getLength().x();
74 message.info.length_y = gridMap.
getLength().y();
75 message.info.pose.position.x = gridMap.
getPosition().x();
76 message.info.pose.position.y = gridMap.
getPosition().y();
77 message.info.pose.position.z = 0.0;
78 message.info.pose.orientation.x = 0.0;
79 message.info.pose.orientation.y = 0.0;
80 message.info.pose.orientation.z = 0.0;
81 message.info.pose.orientation.w = 1.0;
83 message.layers = layers;
87 for (
const auto& layer : layers) {
88 std_msgs::Float32MultiArray dataArray;
90 message.data.push_back(dataArray);
98 const std::string& pointLayer,
99 sensor_msgs::PointCloud2& pointCloud)
101 toPointCloud(gridMap, gridMap.
getLayers(), pointLayer, pointCloud);
105 const std::vector<std::string>& layers,
106 const std::string& pointLayer,
107 sensor_msgs::PointCloud2& pointCloud)
110 pointCloud.header.frame_id = gridMap.
getFrameId();
111 pointCloud.header.stamp.fromNSec(gridMap.
getTimestamp());
112 pointCloud.is_dense =
false;
115 std::vector <std::string> fieldNames;
117 for (
const auto& layer : layers) {
118 if (layer == pointLayer) {
119 fieldNames.push_back(
"x");
120 fieldNames.push_back(
"y");
121 fieldNames.push_back(
"z");
122 }
else if (layer ==
"color") {
123 fieldNames.push_back(
"rgb");
125 fieldNames.push_back(layer);
129 pointCloud.fields.clear();
130 pointCloud.fields.reserve(fieldNames.size());
133 for (
auto& name : fieldNames) {
134 sensor_msgs::PointField pointField;
135 pointField.name = name;
136 pointField.count = 1;
137 pointField.datatype = sensor_msgs::PointField::FLOAT32;
138 pointField.offset = offset;
139 pointCloud.fields.push_back(pointField);
140 offset = offset + pointField.count * 4;
144 size_t maxNumberOfPoints = gridMap.
getSize().prod();
145 pointCloud.height = 1;
146 pointCloud.width = maxNumberOfPoints;
147 pointCloud.point_step = offset;
148 pointCloud.row_step = pointCloud.width * pointCloud.point_step;
149 pointCloud.data.resize(pointCloud.height * pointCloud.row_step);
152 std::unordered_map<std::string, sensor_msgs::PointCloud2Iterator<float>> fieldIterators;
153 for (
auto& name : fieldNames) {
154 fieldIterators.insert(
162 size_t realNumberOfPoints = 0;
163 for (
size_t i = 0; i < maxNumberOfPoints; ++i) {
164 if (hasBasicLayers) {
165 if (!gridMap.
isValid(*mapIterator)) {
172 if (!gridMap.
getPosition3(pointLayer, *mapIterator, position)) {
177 for (
auto& iterator : fieldIterators) {
178 if (iterator.first ==
"x") {
179 *iterator.second = (float) position.x();
180 }
else if (iterator.first ==
"y") {
181 *iterator.second = (float) position.y();
182 }
else if (iterator.first ==
"z") {
183 *iterator.second = (float) position.z();
184 }
else if (iterator.first ==
"rgb") {
185 *iterator.second = gridMap.
at(
"color", *mapIterator);
187 *iterator.second = gridMap.
at(iterator.first, *mapIterator);
192 for (
auto& iterator : fieldIterators) {
195 ++realNumberOfPoints;
198 if (realNumberOfPoints != maxNumberOfPoints) {
199 pointCloud.width = realNumberOfPoints;
200 pointCloud.row_step = pointCloud.width * pointCloud.point_step;
201 pointCloud.data.resize(pointCloud.height * pointCloud.row_step);
205 bool GridMapRosConverter::fromOccupancyGrid(
const nav_msgs::OccupancyGrid& occupancyGrid,
208 const Size size(occupancyGrid.info.width, occupancyGrid.info.height);
209 const double resolution = occupancyGrid.info.resolution;
211 const string& frameId = occupancyGrid.header.frame_id;
212 Position position(occupancyGrid.info.origin.position.x, occupancyGrid.info.origin.position.y);
214 position += 0.5 * length.matrix();
216 const auto& orientation = occupancyGrid.info.origin.orientation;
217 if (orientation.w != 1.0 && !(orientation.x == 0 && orientation.y == 0
218 && orientation.z == 0 && orientation.w == 0)) {
219 ROS_WARN_STREAM(
"Conversion of occupancy grid: Grid maps do not support orientation.");
220 ROS_INFO_STREAM(
"Orientation of occupancy grid: " << endl << occupancyGrid.info.origin.orientation);
224 if (size.prod() != occupancyGrid.data.size()) {
225 ROS_WARN_STREAM(
"Conversion of occupancy grid: Size of data does not correspond to width * height.");
233 gridMap.
setTimestamp(occupancyGrid.header.stamp.toNSec());
241 for (std::vector<int8_t>::const_reverse_iterator iterator = occupancyGrid.data.rbegin();
242 iterator != occupancyGrid.data.rend(); ++iterator) {
243 size_t i = std::distance(occupancyGrid.data.rbegin(), iterator);
244 data(i) = *iterator != -1 ? *iterator : NAN;
247 gridMap.
add(layer, data);
252 const std::string& layer,
float dataMin,
float dataMax,
253 nav_msgs::OccupancyGrid& occupancyGrid)
255 occupancyGrid.header.frame_id = gridMap.
getFrameId();
256 occupancyGrid.header.stamp.fromNSec(gridMap.
getTimestamp());
257 occupancyGrid.info.map_load_time = occupancyGrid.header.stamp;
259 occupancyGrid.info.width = gridMap.
getSize()(0);
260 occupancyGrid.info.height = gridMap.
getSize()(1);
262 occupancyGrid.info.origin.position.x = position.x();
263 occupancyGrid.info.origin.position.y = position.y();
264 occupancyGrid.info.origin.position.z = 0.0;
265 occupancyGrid.info.origin.orientation.x = 0.0;
266 occupancyGrid.info.origin.orientation.y = 0.0;
267 occupancyGrid.info.origin.orientation.z = 0.0;
268 occupancyGrid.info.origin.orientation.w = 1.0;
269 size_t nCells = gridMap.
getSize().prod();
270 occupancyGrid.data.resize(nCells);
273 const float cellMin = 0;
274 const float cellMax = 100;
275 const float cellRange = cellMax - cellMin;
278 float value = (gridMap.
at(layer, *iterator) - dataMin) / (dataMax - dataMin);
282 value = cellMin +
min(max(0.0
f, value), 1.0
f) * cellRange;
285 occupancyGrid.data[nCells - index - 1] = value;
289 void GridMapRosConverter::toGridCells(
const grid_map::GridMap& gridMap,
const std::string& layer,
290 float lowerThreshold,
float upperThreshold,
291 nav_msgs::GridCells& gridCells)
293 gridCells.header.frame_id = gridMap.
getFrameId();
294 gridCells.header.stamp.fromNSec(gridMap.
getTimestamp());
299 if (!gridMap.
isValid(*iterator, layer))
continue;
300 if (gridMap.
at(layer, *iterator) >= lowerThreshold
301 && gridMap.
at(layer, *iterator) <= upperThreshold) {
304 geometry_msgs::Point point;
305 point.x = position.x();
306 point.y = position.y();
307 gridCells.cells.push_back(point);
312 bool GridMapRosConverter::initializeFromImage(
const sensor_msgs::Image& image,
316 const double lengthX = resolution * image.height;
317 const double lengthY = resolution * image.width;
325 bool GridMapRosConverter::addLayerFromImage(
const sensor_msgs::Image& image,
327 const float lowerValue,
const float upperValue,
328 const double alphaThreshold)
335 ROS_ERROR(
"cv_bridge exception: %s", e.what());
340 switch (cvEncoding) {
342 return GridMapCvConverter::addLayerFromImage<unsigned char, 1>(cvImage->image, layer, gridMap, lowerValue, upperValue, alphaThreshold);
344 return GridMapCvConverter::addLayerFromImage<unsigned char, 3>(cvImage->image, layer, gridMap, lowerValue, upperValue, alphaThreshold);
346 return GridMapCvConverter::addLayerFromImage<unsigned char, 4>(cvImage->image, layer, gridMap, lowerValue, upperValue, alphaThreshold);
348 return GridMapCvConverter::addLayerFromImage<unsigned short, 1>(cvImage->image, layer, gridMap, lowerValue, upperValue, alphaThreshold);
350 return GridMapCvConverter::addLayerFromImage<unsigned short, 3>(cvImage->image, layer, gridMap, lowerValue, upperValue, alphaThreshold);
352 return GridMapCvConverter::addLayerFromImage<unsigned short, 4>(cvImage->image, layer, gridMap, lowerValue, upperValue, alphaThreshold);
354 ROS_ERROR(
"Expected MONO8, MONO16, RGB(A)8, RGB(A)16, BGR(A)8, or BGR(A)16 image encoding.");
359 bool GridMapRosConverter::addColorLayerFromImage(
const sensor_msgs::Image& image,
360 const std::string& layer,
367 ROS_ERROR(
"cv_bridge exception: %s", e.what());
372 switch (cvEncoding) {
374 return GridMapCvConverter::addColorLayerFromImage<unsigned char, 3>(cvImage->image, layer, gridMap);
376 return GridMapCvConverter::addColorLayerFromImage<unsigned char, 4>(cvImage->image, layer, gridMap);
378 return GridMapCvConverter::addColorLayerFromImage<unsigned short, 3>(cvImage->image, layer, gridMap);
380 return GridMapCvConverter::addColorLayerFromImage<unsigned short, 4>(cvImage->image, layer, gridMap);
382 ROS_ERROR(
"Expected RGB(A)8, RGB(A)16, BGR(A)8, or BGR(A)16 image encoding.");
388 const std::string encoding, sensor_msgs::Image& image)
391 if (!toCvImage(gridMap, layer, encoding, cvImage))
return false;
397 const std::string encoding,
const float lowerValue,
398 const float upperValue, sensor_msgs::Image& image)
401 if (!toCvImage(gridMap, layer, encoding, lowerValue, upperValue, cvImage))
return false;
409 const float minValue = gridMap.
get(layer).minCoeffOfFinites();
410 const float maxValue = gridMap.
get(layer).maxCoeffOfFinites();
411 return toCvImage(gridMap, layer, encoding, minValue, maxValue, cvImage);
415 const std::string encoding,
const float lowerValue,
423 switch (cvEncoding) {
425 return GridMapCvConverter::toImage<unsigned char, 1>(gridMap, layer, cvEncoding, lowerValue, upperValue, cvImage.
image);
427 return GridMapCvConverter::toImage<unsigned char, 3>(gridMap, layer, cvEncoding, lowerValue, upperValue, cvImage.
image);
429 return GridMapCvConverter::toImage<unsigned char, 4>(gridMap, layer, cvEncoding, lowerValue, upperValue, cvImage.
image);
431 return GridMapCvConverter::toImage<unsigned short, 1>(gridMap, layer, cvEncoding, lowerValue, upperValue, cvImage.
image);
433 return GridMapCvConverter::toImage<unsigned short, 3>(gridMap, layer, cvEncoding, lowerValue, upperValue, cvImage.
image);
435 return GridMapCvConverter::toImage<unsigned short, 4>(gridMap, layer, cvEncoding, lowerValue, upperValue, cvImage.
image);
437 ROS_ERROR(
"Expected MONO8, MONO16, RGB(A)8, RGB(A)16, BGR(A)8, or BGR(A)16 image encoding.");
442 bool GridMapRosConverter::saveToBag(
const grid_map::GridMap& gridMap,
const std::string& pathToBag,
443 const std::string& topic)
445 grid_map_msgs::GridMap message;
446 toMessage(gridMap, message);
457 bag.
write(topic, time, message);
462 bool GridMapRosConverter::loadFromBag(
const std::string& pathToBag,
const std::string& topic,
469 bool isDataFound =
false;
470 for (
const auto& messageInstance : view) {
471 grid_map_msgs::GridMap::ConstPtr message = messageInstance.instantiate<grid_map_msgs::GridMap>();
472 if (message != NULL) {
473 fromMessage(*message, gridMap);
477 ROS_WARN(
"Unable to load data from ROS bag.");
481 if (!isDataFound)
ROS_WARN_STREAM(
"No data under the topic '" << topic <<
"' was found.");
const Length & getLength() const
void setGeometry(const Length &length, const double resolution, const Position &position=Position::Zero())
Time getTimestamp() const
const Index & getStartIndex() const
void open(std::string const &filename, uint32_t mode=bagmode::Read)
bool getPosition(const Index &index, Position &position) const
Time & fromNSec(uint64_t t)
void setBasicLayers(const std::vector< std::string > &basicLayers)
const std::string & getFrameId() const
bool isValid(const Index &index) const
Eigen::Vector3d Position3
double getResolution() const
const std::vector< std::string > & getLayers() const
bool multiArrayMessageCopyToMatrixEigen(const MultiArrayMessageType_ &m, EigenType_ &e)
const Matrix & get(const std::string &layer) const
void setStartIndex(const Index &startIndex)
CvImagePtr toCvCopy(const sensor_msgs::ImageConstPtr &source, const std::string &encoding=std::string())
bool matrixEigenCopyToMultiArrayMessage(const EigenType_ &e, MultiArrayMessageType_ &m)
#define ROS_WARN_STREAM(args)
float & at(const std::string &layer, const Index &index)
int getCvType(const std::string &encoding)
void add(const std::string &layer, const double value=NAN)
#define ROS_INFO_STREAM(args)
size_t getLinearIndexFromIndex(const Index &index, const Size &bufferSize, const bool rowMajor=false)
TFSIMD_FORCE_INLINE tfScalar length(const Quaternion &q)
void setFrameId(const std::string &frameId)
void setTimestamp(const Time timestamp)
bool getPosition3(const std::string &layer, const Index &index, Position3 &position) const
void write(std::string const &topic, ros::MessageEvent< T > const &event)
sensor_msgs::ImagePtr toImageMsg() const
const std::vector< std::string > & getBasicLayers() const
const Size & getSize() const