00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
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
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
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
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
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
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
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
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
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;
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;
00281 }
00282 }
00283
00284
00285 }
00286
00287
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
00305
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
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
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;
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
00432 pcl::PointXYZ min, max;
00433 pcl::getMinMax3D(minMax, min, max);
00434
00435
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
00443
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);
00459 map.at<char>(end.y, end.x) = 100;
00460 }
00461 }
00462 ++j;
00463 }
00464 UDEBUG("Ray trace known space=%fs", timer.ticks());
00465
00466
00467 if(unknownSpaceFilled && scanMaxRange > 0)
00468 {
00469 j=0;
00470 float a = CV_PI/256.0f;
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
00481
00482
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
00491
00492
00493
00494
00495
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
00502
00503
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
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
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);
00527
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
00535
00536
00537
00538
00539 }
00540 }
00541 }
00542 ++j;
00543 }
00544 UDEBUG("Fill empty space=%fs", timer.ticks());
00545
00546
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
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;
00628 }
00629 }
00630 }
00631 }
00632
00633
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
00653 {
00654 gray = 89;
00655 }
00656 map8U.at<unsigned char>(i, j) = gray;
00657 }
00658 }
00659 return map8U;
00660 }
00661
00662 }
00663
00664 }