util3d_mapping.cpp
Go to the documentation of this file.
00001 /*
00002 Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
00003 All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without
00006 modification, are permitted provided that the following conditions are met:
00007     * Redistributions of source code must retain the above copyright
00008       notice, this list of conditions and the following disclaimer.
00009     * Redistributions in binary form must reproduce the above copyright
00010       notice, this list of conditions and the following disclaimer in the
00011       documentation and/or other materials provided with the distribution.
00012     * Neither the name of the Universite de Sherbrooke nor the
00013       names of its contributors may be used to endorse or promote products
00014       derived from this software without specific prior written permission.
00015 
00016 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00017 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00018 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00019 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
00020 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00021 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00022 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00023 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00024 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00025 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00026 */
00027 
00028 #include "rtabmap/core/util3d_mapping.h"
00029 
00030 #include <rtabmap/core/util3d_transforms.h>
00031 #include <rtabmap/core/util3d_filtering.h>
00032 #include <rtabmap/core/util3d.h>
00033 
00034 #include <rtabmap/utilite/ULogger.h>
00035 #include <rtabmap/utilite/UTimer.h>
00036 #include <rtabmap/utilite/UStl.h>
00037 #include <rtabmap/utilite/UConversion.h>
00038 
00039 #include <pcl/common/common.h>
00040 #include <pcl/common/centroid.h>
00041 #include <pcl/common/io.h>
00042 
00043 namespace rtabmap
00044 {
00045 
00046 namespace util3d
00047 {
00048 void occupancy2DFromLaserScan(
00049                 const cv::Mat & scan,
00050                 cv::Mat & ground,
00051                 cv::Mat & obstacles,
00052                 float cellSize,
00053                 bool unknownSpaceFilled,
00054                 float scanMaxRange)
00055 {
00056         if(scan.empty())
00057         {
00058                 return;
00059         }
00060 
00061         std::map<int, Transform> poses;
00062         poses.insert(std::make_pair(1, Transform::getIdentity()));
00063 
00064         pcl::PointCloud<pcl::PointXYZ>::Ptr obstaclesCloud = util3d::laserScanToPointCloud(scan);
00065         //obstaclesCloud = util3d::voxelize<pcl::PointXYZ>(obstaclesCloud, cellSize);
00066 
00067         std::map<int, pcl::PointCloud<pcl::PointXYZ>::Ptr> scans;
00068         scans.insert(std::make_pair(1, obstaclesCloud));
00069 
00070         float xMin, yMin;
00071         cv::Mat map8S = create2DMap(poses, scans, cellSize, unknownSpaceFilled, xMin, yMin, 0.0f, scanMaxRange);
00072 
00073         // find ground cells
00074         std::list<int> groundIndices;
00075         for(unsigned int i=0; i< map8S.total(); ++i)
00076         {
00077                 if(map8S.data[i] == 0)
00078                 {
00079                         groundIndices.push_back(i);
00080                 }
00081         }
00082 
00083         // Convert to position matrices, get points to each center of the cells
00084         ground = cv::Mat();
00085         if(groundIndices.size())
00086         {
00087                 ground = cv::Mat((int)groundIndices.size(), 1, CV_32FC2);
00088                 int i=0;
00089                 for(std::list<int>::iterator iter=groundIndices.begin();iter!=groundIndices.end(); ++iter)
00090                 {
00091                         int x = *iter / map8S.cols;
00092                         int y = *iter - x*map8S.cols;
00093                         ground.at<cv::Vec2f>(i)[0] = (float(y)+0.5)*cellSize + xMin;
00094                         ground.at<cv::Vec2f>(i)[1] = (float(x)+0.5)*cellSize + yMin;
00095                         ++i;
00096                 }
00097         }
00098 
00099         // copy directly obstacles precise positions
00100         obstacles = cv::Mat();
00101         if(obstaclesCloud->size())
00102         {
00103                 obstacles = cv::Mat((int)obstaclesCloud->size(), 1, CV_32FC2);
00104                 for(unsigned int i=0;i<obstaclesCloud->size(); ++i)
00105                 {
00106                         obstacles.at<cv::Vec2f>(i)[0] = obstaclesCloud->at(i).x;
00107                         obstacles.at<cv::Vec2f>(i)[1] = obstaclesCloud->at(i).y;
00108                 }
00109         }
00110 }
00111 
00125 cv::Mat create2DMapFromOccupancyLocalMaps(
00126                 const std::map<int, Transform> & posesIn,
00127                 const std::map<int, std::pair<cv::Mat, cv::Mat> > & occupancy,
00128                 float cellSize,
00129                 float & xMin,
00130                 float & yMin,
00131                 float minMapSize,
00132                 bool erode)
00133 {
00134         UASSERT(minMapSize >= 0.0f);
00135         UDEBUG("cellSize=%f m, minMapSize=%f m, erode=%d", cellSize, minMapSize, erode?1:0);
00136         UTimer timer;
00137 
00138         std::map<int, cv::Mat> emptyLocalMaps;
00139         std::map<int, cv::Mat> occupiedLocalMaps;
00140 
00141         std::list<std::pair<int, Transform> > poses;
00142         // place negative poses at the end
00143         for(std::map<int, Transform>::const_reverse_iterator iter = posesIn.rbegin(); iter!=posesIn.rend(); ++iter)
00144         {
00145                 if(iter->first>0)
00146                 {
00147                         poses.push_front(*iter);
00148                 }
00149                 else
00150                 {
00151                         poses.push_back(*iter);
00152                 }
00153         }
00154 
00155         float minX=-minMapSize/2.0, minY=-minMapSize/2.0, maxX=minMapSize/2.0, maxY=minMapSize/2.0;
00156         bool undefinedSize = minMapSize == 0.0f;
00157         float x=0.0f,y=0.0f,z=0.0f,roll=0.0f,pitch=0.0f,yaw=0.0f,cosT=0.0f,sinT=0.0f;
00158         cv::Mat affineTransform(2,3,CV_32FC1);
00159         for(std::list<std::pair<int, Transform> >::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
00160         {
00161                 UASSERT(!iter->second.isNull());
00162 
00163                 iter->second.getTranslationAndEulerAngles(x,y,z,roll,pitch,yaw);
00164 
00165                 if(undefinedSize)
00166                 {
00167                         minX = maxX = x;
00168                         minY = maxY = y;
00169                         undefinedSize = false;
00170                 }
00171                 else
00172                 {
00173                         if(minX > x)
00174                                 minX = x;
00175                         else if(maxX < x)
00176                                 maxX = x;
00177 
00178                         if(minY > y)
00179                                 minY = y;
00180                         else if(maxY < y)
00181                                 maxY = y;
00182                 }
00183 
00184                 if(uContains(occupancy, iter->first))
00185                 {
00186                         const std::pair<cv::Mat, cv::Mat> & pair = occupancy.at(iter->first);
00187                         cosT = cos(yaw);
00188                         sinT = sin(yaw);
00189                         affineTransform.at<float>(0,0) = cosT;
00190                         affineTransform.at<float>(0,1) = -sinT;
00191                         affineTransform.at<float>(1,0) = sinT;
00192                         affineTransform.at<float>(1,1) = cosT;
00193                         affineTransform.at<float>(0,2) = x;
00194                         affineTransform.at<float>(1,2) = y;
00195 
00196                         //ground
00197                         if(pair.first.rows)
00198                         {
00199                                 UASSERT(pair.first.type() == CV_32FC2);
00200                                 cv::Mat ground(pair.first.rows, pair.first.cols, pair.first.type());
00201                                 cv::transform(pair.first, ground, affineTransform);
00202                                 for(int i=0; i<ground.rows; ++i)
00203                                 {
00204                                         if(minX > ground.at<float>(i,0))
00205                                                 minX = ground.at<float>(i,0);
00206                                         else if(maxX < ground.at<float>(i,0))
00207                                                 maxX = ground.at<float>(i,0);
00208 
00209                                         if(minY > ground.at<float>(i,1))
00210                                                 minY = ground.at<float>(i,1);
00211                                         else if(maxY < ground.at<float>(i,1))
00212                                                 maxY = ground.at<float>(i,1);
00213                                 }
00214                                 emptyLocalMaps.insert(std::make_pair(iter->first, ground));
00215                         }
00216 
00217                         //obstacles
00218                         if(pair.second.rows)
00219                         {
00220                                 UASSERT(pair.second.type() == CV_32FC2);
00221                                 cv::Mat obstacles(pair.second.rows, pair.second.cols, pair.second.type());
00222                                 cv::transform(pair.second, obstacles, affineTransform);
00223                                 for(int i=0; i<obstacles.rows; ++i)
00224                                 {
00225                                         if(minX > obstacles.at<float>(i,0))
00226                                                 minX = obstacles.at<float>(i,0);
00227                                         else if(maxX < obstacles.at<float>(i,0))
00228                                                 maxX = obstacles.at<float>(i,0);
00229 
00230                                         if(minY > obstacles.at<float>(i,1))
00231                                                 minY = obstacles.at<float>(i,1);
00232                                         else if(maxY < obstacles.at<float>(i,1))
00233                                                 maxY = obstacles.at<float>(i,1);
00234                                 }
00235                                 occupiedLocalMaps.insert(std::make_pair(iter->first, obstacles));
00236                         }
00237                 }
00238         }
00239         UDEBUG("timer=%fs", timer.ticks());
00240 
00241         cv::Mat map;
00242         if(minX != maxX && minY != maxY)
00243         {
00244                 //Get map size
00245                 float margin = cellSize*10.0f;
00246                 xMin = minX-margin;
00247                 yMin = minY-margin;
00248                 float xMax = maxX+margin;
00249                 float yMax = maxY+margin;
00250                 if(fabs((yMax - yMin) / cellSize) > 99999 ||
00251                    fabs((xMax - xMin) / cellSize) > 99999)
00252                 {
00253                         UERROR("Large map size!! map min=(%f, %f) max=(%f,%f). "
00254                                         "There's maybe an error with the poses provided! The map will not be created!",
00255                                         xMin, yMin, xMax, yMax);
00256                 }
00257                 else
00258                 {
00259                         UDEBUG("map min=(%f, %f) max=(%f,%f)", xMin, yMin, xMax, yMax);
00260 
00261 
00262                         map = cv::Mat::ones((yMax - yMin) / cellSize + 0.5f, (xMax - xMin) / cellSize + 0.5f, CV_8S)*-1;
00263                         for(std::list<std::pair<int, Transform> >::const_iterator kter = poses.begin(); kter!=poses.end(); ++kter)
00264                         {
00265                                 std::map<int, cv::Mat >::iterator iter = emptyLocalMaps.find(kter->first);
00266                                 std::map<int, cv::Mat >::iterator jter = occupiedLocalMaps.find(kter->first);
00267                                 if(iter!=emptyLocalMaps.end())
00268                                 {
00269                                         for(int i=0; i<iter->second.rows; ++i)
00270                                         {
00271                                                 cv::Point2i pt((iter->second.at<float>(i,0)-xMin)/cellSize + 0.5f, (iter->second.at<float>(i,1)-yMin)/cellSize + 0.5f);
00272                                                 map.at<char>(pt.y, pt.x) = 0; // free space
00273                                         }
00274                                 }
00275                                 if(jter!=occupiedLocalMaps.end())
00276                                 {
00277                                         for(int i=0; i<jter->second.rows; ++i)
00278                                         {
00279                                                 cv::Point2i pt((jter->second.at<float>(i,0)-xMin)/cellSize + 0.5f, (jter->second.at<float>(i,1)-yMin)/cellSize + 0.5f);
00280                                                 map.at<char>(pt.y, pt.x) = 100; // obstacles
00281                                         }
00282                                 }
00283 
00284                                 //UDEBUG("empty=%d occupied=%d", empty, occupied);
00285                         }
00286 
00287                         // fill holes and remove empty from obstacle borders
00288                         cv::Mat updatedMap = map.clone();
00289                         std::list<std::pair<int, int> > obstacleIndices;
00290                         for(int i=2; i<map.rows-2; ++i)
00291                         {
00292                                 for(int j=2; j<map.cols-2; ++j)
00293                                 {
00294                                         if(map.at<char>(i, j) == -1 &&
00295                                                 map.at<char>(i+1, j) != -1 &&
00296                                                 map.at<char>(i-1, j) != -1 &&
00297                                                 map.at<char>(i, j+1) != -1 &&
00298                                                 map.at<char>(i, j-1) != -1)
00299                                         {
00300                                                 updatedMap.at<char>(i, j) = 0;
00301                                         }
00302                                         else if(map.at<char>(i, j) == 100)
00303                                         {
00304                                                 // obstacle/empty/unknown -> remove empty
00305                                                 // unknown/empty/obstacle -> remove empty
00306                                                 if(map.at<char>(i-1, j) == 0 &&
00307                                                         map.at<char>(i-2, j) == -1)
00308                                                 {
00309                                                         updatedMap.at<char>(i-1, j) = -1;
00310                                                 }
00311                                                 else if(map.at<char>(i+1, j) == 0 &&
00312                                                                 map.at<char>(i+2, j) == -1)
00313                                                 {
00314                                                         updatedMap.at<char>(i+1, j) = -1;
00315                                                 }
00316                                                 if(map.at<char>(i, j-1) == 0 &&
00317                                                         map.at<char>(i, j-2) == -1)
00318                                                 {
00319                                                         updatedMap.at<char>(i, j-1) = -1;
00320                                                 }
00321                                                 else if(map.at<char>(i, j+1) == 0 &&
00322                                                                 map.at<char>(i, j+2) == -1)
00323                                                 {
00324                                                         updatedMap.at<char>(i, j+1) = -1;
00325                                                 }
00326 
00327                                                 if(erode)
00328                                                 {
00329                                                         obstacleIndices.push_back(std::make_pair(i, j));
00330                                                 }
00331                                         }
00332                                         else if(map.at<char>(i, j) == 0)
00333                                         {
00334                                                 // obstacle/empty/obstacle -> remove empty
00335                                                 if(map.at<char>(i-1, j) == 100 &&
00336                                                         map.at<char>(i+1, j) == 100)
00337                                                 {
00338                                                         updatedMap.at<char>(i, j) = -1;
00339                                                 }
00340                                                 else if(map.at<char>(i, j-1) == 100 &&
00341                                                         map.at<char>(i, j+1) == 100)
00342                                                 {
00343                                                         updatedMap.at<char>(i, j) = -1;
00344                                                 }
00345                                         }
00346 
00347                                 }
00348                         }
00349                         map = updatedMap;
00350 
00351                         if(erode)
00352                         {
00353                                 // remove obstacles which touch at least 3 empty cells but not unknown cells
00354                                 cv::Mat erodedMap = map.clone();
00355                                 for(std::list<std::pair<int,int> >::iterator iter = obstacleIndices.begin();
00356                                         iter!= obstacleIndices.end();
00357                                         ++iter)
00358                                 {
00359                                         int i = iter->first;
00360                                         int j = iter->second;
00361                                         int touchEmpty = (map.at<char>(i+1, j) == 0?1:0) +
00362                                                 (map.at<char>(i-1, j) == 0?1:0) +
00363                                                 (map.at<char>(i, j+1) == 0?1:0) +
00364                                                 (map.at<char>(i, j-1) == 0?1:0);
00365                                         if(touchEmpty>=3 && map.at<char>(i+1, j) != -1 &&
00366                                                 map.at<char>(i-1, j) != -1 &&
00367                                                 map.at<char>(i, j+1) != -1 &&
00368                                                 map.at<char>(i, j-1) != -1)
00369                                         {
00370                                                 erodedMap.at<char>(i, j) = 0; // empty
00371                                         }
00372                                 }
00373                                 map = erodedMap;
00374                         }
00375                 }
00376         }
00377         UDEBUG("timer=%fs", timer.ticks());
00378         return map;
00379 }
00380 
00395 cv::Mat create2DMap(const std::map<int, Transform> & poses,
00396                 const std::map<int, pcl::PointCloud<pcl::PointXYZ>::Ptr > & scans,
00397                 float cellSize,
00398                 bool unknownSpaceFilled,
00399                 float & xMin,
00400                 float & yMin,
00401                 float minMapSize,
00402                 float scanMaxRange)
00403 {
00404         UDEBUG("poses=%d, scans = %d scanMaxRange=%f", poses.size(), scans.size(), scanMaxRange);
00405         std::map<int, pcl::PointCloud<pcl::PointXYZ>::Ptr > localScans;
00406 
00407         pcl::PointCloud<pcl::PointXYZ> minMax;
00408         if(minMapSize > 0.0f)
00409         {
00410                 minMax.push_back(pcl::PointXYZ(-minMapSize/2.0, -minMapSize/2.0, 0));
00411                 minMax.push_back(pcl::PointXYZ(minMapSize/2.0, minMapSize/2.0, 0));
00412         }
00413         for(std::map<int, Transform>::const_iterator iter = poses.begin(); iter!=poses.end(); ++iter)
00414         {
00415                 if(uContains(scans, iter->first) && scans.at(iter->first)->size())
00416                 {
00417                         UASSERT(!iter->second.isNull());
00418                         pcl::PointCloud<pcl::PointXYZ>::Ptr cloud = util3d::transformPointCloud(scans.at(iter->first), iter->second);
00419                         pcl::PointXYZ min, max;
00420                         pcl::getMinMax3D(*cloud, min, max);
00421                         minMax.push_back(min);
00422                         minMax.push_back(max);
00423                         minMax.push_back(pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z()));
00424                         localScans.insert(std::make_pair(iter->first, cloud));
00425                 }
00426         }
00427 
00428         cv::Mat map;
00429         if(minMax.size())
00430         {
00431                 //Get map size
00432                 pcl::PointXYZ min, max;
00433                 pcl::getMinMax3D(minMax, min, max);
00434 
00435                 // Added margin to make sure that all points are inside the map (when rounded to integer)
00436                 float margin = cellSize*10.0f;
00437                 xMin = (unknownSpaceFilled && scanMaxRange > 0 && -scanMaxRange < min.x?-scanMaxRange:min.x) - margin;
00438                 yMin = (unknownSpaceFilled && scanMaxRange > 0 && -scanMaxRange < min.y?-scanMaxRange:min.y) - margin;
00439                 float xMax = (unknownSpaceFilled && scanMaxRange > 0 && scanMaxRange > max.x?scanMaxRange:max.x) + margin;
00440                 float yMax = (unknownSpaceFilled && scanMaxRange > 0 && scanMaxRange > max.y?scanMaxRange:max.y) + margin;
00441 
00442                 //UWARN("map min=(%fm, %fm) max=(%fm,%fm) (margin=%fm, cellSize=%fm, scan range=%f, min=[%fm,%fm] max=[%fm,%fm])",
00443                 //              xMin, yMin, xMax, yMax, margin, cellSize, scanMaxRange, min.x, min.y, max.x, max.y);
00444 
00445                 UTimer timer;
00446 
00447                 map = cv::Mat::ones((yMax - yMin) / cellSize + 0.5f, (xMax - xMin) / cellSize + 0.5f, CV_8S)*-1;
00448                 int j=0;
00449                 for(std::map<int, pcl::PointCloud<pcl::PointXYZ>::Ptr >::iterator iter = localScans.begin(); iter!=localScans.end(); ++iter)
00450                 {
00451                         const Transform & pose = poses.at(iter->first);
00452                         cv::Point2i start((pose.x()-xMin)/cellSize + 0.5f, (pose.y()-yMin)/cellSize + 0.5f);
00453                         for(unsigned int i=0; i<iter->second->size(); ++i)
00454                         {
00455                                 cv::Point2i end((iter->second->points[i].x-xMin)/cellSize, (iter->second->points[i].y-yMin)/cellSize);
00456                                 if(end!=start)
00457                                 {
00458                                         rayTrace(start, end, map, true); // trace free space
00459                                         map.at<char>(end.y, end.x) = 100; // obstacle
00460                                 }
00461                         }
00462                         ++j;
00463                 }
00464                 UDEBUG("Ray trace known space=%fs", timer.ticks());
00465 
00466                 // now fill unknown spaces
00467                 if(unknownSpaceFilled && scanMaxRange > 0)
00468                 {
00469                         j=0;
00470                         float a = CV_PI/256.0f; // angle increment
00471                         for(std::map<int, pcl::PointCloud<pcl::PointXYZ>::Ptr >::iterator iter = localScans.begin(); iter!=localScans.end(); ++iter)
00472                         {
00473                                 if(iter->second->size() > 1)
00474                                 {
00475                                         if(scanMaxRange > cellSize)
00476                                         {
00477                                                 const Transform & pose = poses.at(iter->first);
00478                                                 cv::Point2i start((pose.x()-xMin)/cellSize + 0.5f, (pose.y()-yMin)/cellSize + 0.5f);
00479 
00480                                                 //UWARN("maxLength = %f", maxLength);
00481                                                 //rotate counterclockwise from the first point until we pass the last point
00482                                                 // Note: assuming that first laser scan is negative y
00483                                                 cv::Mat rotation = (cv::Mat_<float>(2,2) << cos(a), -sin(a),
00484                                                                                                                                          sin(a), cos(a));
00485                                                 cv::Mat origin(2,1,CV_32F), endFirst(2,1,CV_32F), endLast(2,1,CV_32F);
00486                                                 origin.at<float>(0) = pose.x();
00487                                                 origin.at<float>(1) = pose.y();
00488                                                 pcl::PointXYZ ptFirst = iter->second->points[0];
00489                                                 pcl::PointXYZ ptLast = iter->second->points[iter->second->points.size()-1];
00490                                                 //if(ptFirst.y > ptLast.y)
00491                                                 //{
00492                                                         // swap to iterate counterclockwise
00493                                                 //      pcl::PointXYZ tmp = ptLast;
00494                                                 //      ptLast = ptFirst;
00495                                                 //      ptFirst = tmp;
00496                                                 //}
00497                                                 endFirst.at<float>(0) = ptFirst.x;
00498                                                 endFirst.at<float>(1) = ptFirst.y;
00499                                                 endLast.at<float>(0) = ptLast.x;
00500                                                 endLast.at<float>(1) = ptLast.y;
00501                                                 //UWARN("origin = %f %f", origin.at<float>(0), origin.at<float>(1));
00502                                                 //UWARN("endFirst = %f %f", endFirst.at<float>(0), endFirst.at<float>(1));
00503                                                 //UWARN("endLast = %f %f", endLast.at<float>(0), endLast.at<float>(1));
00504                                                 cv::Mat tmp = (endFirst - origin);
00505                                                 cv::Mat endRotated = rotation*((tmp/cv::norm(tmp))*scanMaxRange) + origin;
00506                                                 cv::Mat endLastVector(3,1,CV_32F), endRotatedVector(3,1,CV_32F);
00507                                                 endLastVector.at<float>(0) = endLast.at<float>(0) - origin.at<float>(0);
00508                                                 endLastVector.at<float>(1) = endLast.at<float>(1) - origin.at<float>(1);
00509                                                 endLastVector.at<float>(2) = 0.0f;
00510                                                 endRotatedVector.at<float>(0) = endRotated.at<float>(0) - origin.at<float>(0);
00511                                                 endRotatedVector.at<float>(1) = endRotated.at<float>(1) - origin.at<float>(1);
00512                                                 endRotatedVector.at<float>(2) = 0.0f;
00513                                                 //UWARN("endRotated = %f %f", endRotated.at<float>(0), endRotated.at<float>(1));
00514                                                 float normEndRotatedVector = cv::norm(endRotatedVector);
00515                                                 endLastVector = endLastVector / cv::norm(endLastVector);
00516                                                 float angle = (endRotatedVector/normEndRotatedVector).dot(endLastVector);
00517                                                 angle = angle<-1.0f?-1.0f:angle>1.0f?1.0f:angle;
00518                                                 while(acos(angle) > M_PI_4 || endRotatedVector.cross(endLastVector).at<float>(2) > 0.0f)
00519                                                 {
00520                                                         cv::Point2i end((endRotated.at<float>(0)-xMin)/cellSize + 0.5f, (endRotated.at<float>(1)-yMin)/cellSize + 0.5f);
00521                                                         //end must be inside the grid
00522                                                         end.x = end.x < 0?0:end.x;
00523                                                         end.x = end.x >= map.cols?map.cols-1:end.x;
00524                                                         end.y = end.y < 0?0:end.y;
00525                                                         end.y = end.y >= map.rows?map.rows-1:end.y;
00526                                                         rayTrace(start, end, map, true); // trace free space
00527                                                         // next point
00528                                                         endRotated = rotation*(endRotated - origin) + origin;
00529                                                         endRotatedVector.at<float>(0) = endRotated.at<float>(0) - origin.at<float>(0);
00530                                                         endRotatedVector.at<float>(1) = endRotated.at<float>(1) - origin.at<float>(1);
00531                                                         angle = (endRotatedVector/normEndRotatedVector).dot(endLastVector);
00532                                                         angle = angle<-1.0f?-1.0f:angle>1.0f?1.0f:angle;
00533 
00534                                                         //UWARN("endRotated = %f %f (%f %f %f)",
00535                                                         //              endRotated.at<float>(0), endRotated.at<float>(1),
00536                                                         //              acos(angle),
00537                                                         //              angle,
00538                                                         //              endRotatedVector.cross(endLastVector).at<float>(2));
00539                                                 }
00540                                         }
00541                                 }
00542                                 ++j;
00543                         }
00544                         UDEBUG("Fill empty space=%fs", timer.ticks());
00545                         //cv::imwrite("map.png", util3d::convertMap2Image8U(map));
00546                         //UWARN("saved map.png");
00547                 }
00548         }
00549         return map;
00550 }
00551 
00552 void rayTrace(const cv::Point2i & start, const cv::Point2i & end, cv::Mat & grid, bool stopOnObstacle)
00553 {
00554         UASSERT_MSG(start.x >= 0 && start.x < grid.cols, uFormat("start.x=%d grid.cols=%d", start.x, grid.cols).c_str());
00555         UASSERT_MSG(start.y >= 0 && start.y < grid.rows, uFormat("start.y=%d grid.rows=%d", start.y, grid.rows).c_str());
00556         UASSERT_MSG(end.x >= 0 && end.x < grid.cols, uFormat("end.x=%d grid.cols=%d", end.x, grid.cols).c_str());
00557         UASSERT_MSG(end.y >= 0 && end.y < grid.rows, uFormat("end.x=%d grid.cols=%d", end.y, grid.rows).c_str());
00558 
00559         cv::Point2i ptA, ptB;
00560         ptA = start;
00561         ptB = end;
00562 
00563         float slope = float(ptB.y - ptA.y)/float(ptB.x - ptA.x);
00564 
00565         bool swapped = false;
00566         if(slope<-1.0f || slope>1.0f)
00567         {
00568                 // swap x and y
00569                 slope = 1.0f/slope;
00570 
00571                 int tmp = ptA.x;
00572                 ptA.x = ptA.y;
00573                 ptA.y = tmp;
00574 
00575                 tmp = ptB.x;
00576                 ptB.x = ptB.y;
00577                 ptB.y = tmp;
00578 
00579                 swapped = true;
00580         }
00581 
00582         float b = ptA.y - slope*ptA.x;
00583         for(int x=ptA.x; ptA.x<ptB.x?x<ptB.x:x>ptB.x; ptA.x<ptB.x?++x:--x)
00584         {
00585                 int upperbound = float(x)*slope + b;
00586                 int lowerbound = upperbound;
00587                 if(x != ptA.x)
00588                 {
00589                         lowerbound = (ptA.x<ptB.x?x+1:x-1)*slope + b;
00590                 }
00591 
00592                 if(lowerbound > upperbound)
00593                 {
00594                         int tmp = upperbound;
00595                         upperbound = lowerbound;
00596                         lowerbound = tmp;
00597                 }
00598 
00599                 if(!swapped)
00600                 {
00601                         UASSERT_MSG(lowerbound >= 0 && lowerbound < grid.rows, uFormat("lowerbound=%f grid.rows=%d x=%d slope=%f b=%f x=%f", lowerbound, grid.rows, x, slope, b, x).c_str());
00602                         UASSERT_MSG(upperbound >= 0 && upperbound < grid.rows, uFormat("upperbound=%f grid.rows=%d x+1=%d slope=%f b=%f x=%f", upperbound, grid.rows, x+1, slope, b, x).c_str());
00603                 }
00604                 else
00605                 {
00606                         UASSERT_MSG(lowerbound >= 0 && lowerbound < grid.cols, uFormat("lowerbound=%f grid.cols=%d x=%d slope=%f b=%f x=%f", lowerbound, grid.cols, x, slope, b, x).c_str());
00607                         UASSERT_MSG(upperbound >= 0 && upperbound < grid.cols, uFormat("upperbound=%f grid.cols=%d x+1=%d slope=%f b=%f x=%f", upperbound, grid.cols, x+1, slope, b, x).c_str());
00608                 }
00609 
00610                 for(int y = lowerbound; y<=(int)upperbound; ++y)
00611                 {
00612                         char * v;
00613                         if(swapped)
00614                         {
00615                                 v = &grid.at<char>(x, y);
00616                         }
00617                         else
00618                         {
00619                                 v = &grid.at<char>(y, x);
00620                         }
00621                         if(*v == 100 && stopOnObstacle)
00622                         {
00623                                 return;
00624                         }
00625                         else
00626                         {
00627                                 *v = 0; // free space
00628                         }
00629                 }
00630         }
00631 }
00632 
00633 //convert to gray scaled map
00634 cv::Mat convertMap2Image8U(const cv::Mat & map8S)
00635 {
00636         UASSERT(map8S.channels() == 1 && map8S.type() == CV_8S);
00637         cv::Mat map8U = cv::Mat(map8S.rows, map8S.cols, CV_8U);
00638         for (int i = 0; i < map8S.rows; ++i)
00639         {
00640                 for (int j = 0; j < map8S.cols; ++j)
00641                 {
00642                         char v = map8S.at<char>(i, j);
00643                         unsigned char gray;
00644                         if(v == 0)
00645                         {
00646                                 gray = 178;
00647                         }
00648                         else if(v == 100)
00649                         {
00650                                 gray = 0;
00651                         }
00652                         else // -1
00653                         {
00654                                 gray = 89;
00655                         }
00656                         map8U.at<unsigned char>(i, j) = gray;
00657                 }
00658         }
00659         return map8U;
00660 }
00661 
00662 }
00663 
00664 }


rtabmap
Author(s): Mathieu Labbe
autogenerated on Sat Jul 23 2016 11:44:28