00001
00053 #include <octomap/octomap.h>
00054 #include <octomap/OcTree.h>
00055 #include <iomanip>
00056 #include "MapExtractor.h"
00057
00058 using namespace std;
00059 using namespace roboearth;
00060
00061 MapExtractor::MapExtractor(const std::string& filename) :
00062 m_gridmap(NULL), m_octoMap(NULL), m_res(0.025), m_treeDepth(0) {
00063
00064 cout << "Loading 3d octomap '" << filename.c_str() << "':" << endl << " ";
00065 cout << setprecision(3);
00066
00067 m_octoMap = new octomap::OcTree(m_res);
00068 if (m_octoMap->readBinary(filename)) {
00069
00070 m_treeDepth = m_octoMap->getTreeDepth();
00071 m_res = m_octoMap->getResolution();
00072 m_gridmap = new OccupancyGrid;
00073 m_gridmap->resolution = m_res;
00074
00075 } else {
00076 cout << endl;
00077 exit(-1);
00078 }
00079
00080 }
00081
00082 MapExtractor::~MapExtractor() {
00083
00084 delete m_octoMap;
00085 delete m_gridmap;
00086
00087 }
00088
00089 bool MapExtractor::isSpeckleNode(const octomap::OcTreeKey& nKey) const {
00090 octomap::OcTreeKey key;
00091 bool neighborFound = false;
00092 for (key[2] = nKey[2] - 1; !neighborFound && key[2] <= nKey[2] + 1; ++key[2]) {
00093 for (key[1] = nKey[1] - 1; !neighborFound && key[1] <= nKey[1] + 1; ++key[1]) {
00094 for (key[0] = nKey[0] - 1; !neighborFound && key[0] <= nKey[0] + 1; ++key[0]) {
00095 if (key != nKey) {
00096 octomap::OcTreeNode* node = m_octoMap->search(key);
00097 if (node && m_octoMap->isNodeOccupied(node)) {
00098 neighborFound = true;
00099 }
00100 }
00101 }
00102 }
00103 }
00104
00105 return !neighborFound;
00106 }
00107
00108 bool MapExtractor::calc2dSlice(double occupancyMinZ, double occupancyMaxZ,
00109 bool filterSpeckles, double minSizeX, double minSizeY) {
00110
00111
00112
00113
00114
00115 double minX, minY, minZ, maxX, maxY, maxZ;
00116 m_octoMap->getMetricMin(minX, minY, minZ);
00117 m_octoMap->getMetricMax(maxX, maxY, maxZ);
00118
00119 cout << " min - x: " << minX << " y: " << minY << " z: " << minZ << endl;
00120 cout << " max - x: " << maxX << " y: " << maxY << " z: " << maxZ << endl;
00121
00122 octomap::point3d minPt(minX, minY, minZ);
00123 octomap::point3d maxPt(maxX, maxY, maxZ);
00124 octomap::OcTreeKey minKey, maxKey, curKey;
00125
00126 if (!m_octoMap->genKey(minPt, minKey)) {
00127 cout << " Creating min octree key (x: " << minPt.x() << ", y: "
00128 << minPt.y() << ", z: " << minPt.z() << ") failed." << endl;
00129 return false;
00130 }
00131 if (!m_octoMap->genKey(maxPt, maxKey)) {
00132 cout << " Creating max octree key (x: " << maxPt.x() << ", y: "
00133 << maxPt.y() << ", z: " << maxPt.z() << ") failed." << endl;
00134 return false;
00135 }
00136
00137 cout << " min key - x: " << minKey[0] << " y: " << minKey[1] << " z: "
00138 << minKey[2] << endl;
00139 cout << " max key - x: " << maxKey[0] << " y: " << maxKey[1] << " z: "
00140 << maxKey[2] << endl;
00141
00142
00143 double halfPaddedX = 0.5 * minSizeX;
00144 double halfPaddedY = 0.5 * minSizeY;
00145 minX = std::min(minX, -halfPaddedX);
00146 maxX = std::max(maxX, halfPaddedX);
00147 minY = std::min(minY, -halfPaddedY);
00148 maxY = std::max(maxY, halfPaddedY);
00149 minPt = octomap::point3d(minX, minY, minZ);
00150 maxPt = octomap::point3d(maxX, maxY, maxZ);
00151 octomap::OcTreeKey paddedMinKey, paddedMaxKey;
00152
00153 if (!m_octoMap->genKey(minPt, paddedMinKey)) {
00154 cout << " Creating padded min octree key (x: " << minPt.x() << ", y: "
00155 << minPt.y() << ", z: " << minPt.z() << ") failed." << endl;
00156 return false;
00157 }
00158 if (!m_octoMap->genKey(maxPt, paddedMaxKey)) {
00159 cout << " Creating padded max octree key (x: " << maxPt.x() << ", y: "
00160 << maxPt.y() << ", z: " << maxPt.z() << ") failed." << endl;
00161 return false;
00162 }
00163
00164 if (paddedMinKey[0] != minKey[0] || paddedMinKey[1] != minKey[1]) {
00165 cout << " padded min key - x: " << paddedMinKey[0] << " y: "
00166 << paddedMinKey[1] << " z: " << paddedMinKey[2] << endl;
00167 cout << " padded max key - x: " << paddedMaxKey[0] << " y: "
00168 << paddedMaxKey[1] << " z: " << paddedMaxKey[2] << endl;
00169
00170 assert(paddedMaxKey[0] >= maxKey[0] && paddedMaxKey[1] >= maxKey[1]);
00171 }
00172
00173 m_gridmap->width = paddedMaxKey[0] - paddedMinKey[0] + 1;
00174 m_gridmap->height = paddedMaxKey[1] - paddedMinKey[1] + 1;
00175 int mapOriginX = minKey[0] - paddedMinKey[0];
00176 int mapOriginY = minKey[1] - paddedMinKey[1];
00177
00178 octomap::point3d origin;
00179 m_octoMap->genCoords(paddedMinKey, m_treeDepth, origin);
00180 m_gridmap->orientation.x = origin.x() - m_res * 0.5;
00181 m_gridmap->orientation.y = origin.y() - m_res * 0.5;
00182 m_gridmap->orientation.yaw = 0;
00183
00184
00185 m_gridmap->data.resize(m_gridmap->width * m_gridmap->height, -1);
00186
00187
00188 for (octomap::OcTree::leaf_iterator it = m_octoMap->begin(), end =
00189 m_octoMap->end(); it != end; ++it) {
00190
00191 if (m_octoMap->isNodeOccupied(*it)) {
00192
00193 double z = it.getZ();
00194 if (z > occupancyMinZ && z < occupancyMaxZ) {
00195
00196 double size = it.getSize();
00197 double x = it.getX();
00198 double y = it.getY();
00199 octomap::OcTreeKey nKey = it.getKey();
00200
00201
00202 if (filterSpeckles && (it.getDepth() == m_treeDepth + 1)
00203 && isSpeckleNode(nKey)) {
00204 cout << "Ignoring single occupied node - x: " << x
00205 << " y: " << y << " z: " << z << endl;
00206 continue;
00207 }
00208
00209 if (it.getDepth() == m_treeDepth) {
00210 octomap::OcTreeKey nKey = it.getKey();
00211 int i = nKey[0] - paddedMinKey[0];
00212 int j = nKey[1] - paddedMinKey[1];
00213 m_gridmap->data[m_gridmap->width * j + i] = 100;
00214 } else {
00215 int intSize = 1 << (m_treeDepth - it.getDepth());
00216 octomap::OcTreeKey minKey = it.getIndexKey();
00217 for (int dx = 0; dx < intSize; dx++) {
00218 int i = minKey[0] + dx - paddedMinKey[0];
00219 for (int dy = 0; dy < intSize; dy++) {
00220 int j = minKey[1] + dy - paddedMinKey[1];
00221 m_gridmap->data[m_gridmap->width * j + i] = 100;
00222 }
00223 }
00224 }
00225
00226 }
00227
00228 } else {
00229
00230 if (it.getDepth() == m_treeDepth) {
00231
00232 octomap::OcTreeKey nKey = it.getKey();
00233 int i = nKey[0] - paddedMinKey[0];
00234 int j = nKey[1] - paddedMinKey[1];
00235 if (m_gridmap->data[m_gridmap->width * j + i] == -1) {
00236 m_gridmap->data[m_gridmap->width * j + i] = 0;
00237 }
00238
00239 } else {
00240
00241 int intSize = 1 << (m_treeDepth - it.getDepth());
00242 octomap::OcTreeKey minKey = it.getIndexKey();
00243 for (int dx = 0; dx < intSize; dx++) {
00244 int i = minKey[0] + dx - paddedMinKey[0];
00245 for (int dy = 0; dy < intSize; dy++) {
00246 int j = minKey[1] + dy - paddedMinKey[1];
00247 if (m_gridmap->data[m_gridmap->width * j + i] == -1) {
00248 m_gridmap->data[m_gridmap->width * j + i] = 0;
00249 }
00250 }
00251 }
00252
00253 }
00254
00255 }
00256
00257 }
00258
00259 return true;
00260
00261 }
00262
00263 bool MapExtractor::save2dMap(const std::string& mapName, double z,
00264 bool filterSpeckles, double minSizeX, double minSizeY) {
00265
00266 return save2dMap(mapName, z - m_res, z + m_res, filterSpeckles, minSizeX,
00267 minSizeY);
00268
00269 }
00270
00271 bool MapExtractor::save2dMap(const std::string& mapName, double minZ,
00272 double maxZ, bool filterSpeckles, double minSizeX, double minSizeY) {
00273
00274 if (!calc2dSlice(minZ, maxZ, filterSpeckles, minSizeX, minSizeY)) {
00275 return false;
00276 }
00277
00278 cout << " size: " << m_gridmap->width << " x " << m_gridmap->height
00279 << ", resolution: " << m_gridmap->resolution << " m/pixel" << endl;
00280
00281 string mapFilename = mapName + ".pgm";
00282 FILE* outMap = fopen(mapFilename.c_str(), "w");
00283 if (!outMap) {
00284 cout << "couldn't save map to '" << mapFilename.c_str() << "'" << endl;
00285 return false;
00286 }
00287
00288 fprintf(outMap, "P5\n# CREATOR: MapExtractor.cpp %.3f m/pix\n%d %d\n255\n",
00289 m_gridmap->resolution, m_gridmap->width, m_gridmap->height);
00290
00291 for (unsigned int y = 0; y < m_gridmap->height; y++) {
00292 for (unsigned int x = 0; x < m_gridmap->width; x++) {
00293 unsigned int i = x + (m_gridmap->height - y - 1) * m_gridmap->width;
00294 if (m_gridmap->data[i] == 0) {
00295 fputc(254, outMap);
00296 } else if (m_gridmap->data[i] == +100) {
00297 fputc(000, outMap);
00298 } else {
00299 fputc(205, outMap);
00300 }
00301 }
00302 }
00303
00304 fclose(outMap);
00305
00306 string metaFilename = mapName + ".yaml";
00307 FILE* outMeta = fopen(metaFilename.c_str(), "w");
00308 if (!outMeta) {
00309 cout << "couldn't save meta data to '" << metaFilename.c_str() << "'"
00310 << endl;
00311 return false;
00312 }
00313
00314 std::string::size_type filename_begin = mapFilename.find_last_of('/');
00315 if (filename_begin == std::string::npos) {
00316 filename_begin = 0;
00317 } else {
00318 filename_begin++;
00319 }
00320 std::string::size_type filename_length = mapFilename.length() - filename_begin;
00321 mapFilename = mapFilename.substr(filename_begin, filename_length);
00322
00323 fprintf(
00324 outMeta,
00325 "image: %s\nresolution: %f\norigin: [%f, %f, %f]\nnegate: 0\noccupied_thresh: 0.65\nfree_thresh: 0.196\n\n",
00326 mapFilename.c_str(), m_gridmap->resolution,
00327 m_gridmap->orientation.x, m_gridmap->orientation.y,
00328 m_gridmap->orientation.yaw);
00329
00330 fclose(outMeta);
00331
00332 return true;
00333
00334 }