MRXT: The Multi-Robot eXploration Tool
Multi-Robot autonomous exploration and mapping simulator.
|
00001 /* 00002 * 00003 * Author: Miguel Julia <mjulia@umh.es> 00004 * 00005 * Date: 2008 00006 * 00007 * Class binMap 00008 * 00009 * Implements a binary gridmap 00010 * 00011 */ 00012 #include "binMap.h" 00013 00014 using namespace std; 00015 00016 // Constructors 00017 00018 // Default constructor 00019 binMap::binMap(): 00020 width(0), 00021 height(0), 00022 totalsize(0), 00023 xorigin(0), 00024 yorigin(0), 00025 resolution(1), 00026 roi(0,0,0,0), 00027 cells(0) 00028 { 00029 00030 } 00031 // Builds a binary grid map of size w x h 00032 binMap::binMap(int w, int h): 00033 width(w), 00034 height(h), 00035 totalsize((width*height)/32 + 1), 00036 xorigin(0), 00037 yorigin(0), 00038 resolution(1), 00039 roi(0,0,w,h) 00040 { 00041 cells.resize(totalsize); 00042 clear(); 00043 }; 00044 // Builds a binary grid map of size w x h with origin in real coordinates (x,y) and resolution res 00045 binMap::binMap(int w, int h, float res, float x, float y): 00046 width(w), 00047 height(h), 00048 totalsize((width*height)/32 + 1), 00049 xorigin(x), 00050 yorigin(y), 00051 resolution(res), 00052 roi(RoI(0,0,w,h)) 00053 { 00054 cells.resize(totalsize); 00055 clear(); 00056 }; 00057 // Builds a binary grid map of size w x h (in meters) with origin in real coordinates (x,y) and resolution res 00058 binMap::binMap(float w, float h, float res, float x, float y): 00059 width((int)floor(w/res+0.5)), 00060 height((int)floor(h/res+0.5)), 00061 totalsize((width*height)/32 + 1), 00062 xorigin(x), 00063 yorigin(y), 00064 resolution(res), 00065 roi(RoI(0,0,width,height)) 00066 { 00067 cells.resize(totalsize); 00068 clear(); 00069 }; 00070 // Copy contructor 00071 binMap::binMap(const binMap &map): 00072 width(map.width), 00073 height(map.height), 00074 totalsize(map.totalsize), 00075 xorigin(map.xorigin), 00076 yorigin(map.yorigin), 00077 resolution(map.resolution), 00078 roi(map.roi), 00079 cells(map.cells) 00080 { 00081 00082 }; 00083 // Destructor 00084 binMap::~binMap(){ 00085 00086 } 00087 // Initializers 00088 void binMap::initialize(int w, int h){ 00089 initialize(w,h,0,0,0); 00090 }; 00091 void binMap::initialize(int w, int h, float res, float x, float y){ 00092 width = w; 00093 height = h; 00094 totalsize = (width*height)/32 + 1; 00095 xorigin = x; 00096 yorigin = y; 00097 resolution = res; 00098 cells.resize(totalsize); 00099 roi.x = 0; 00100 roi.y = 0; 00101 roi.width = width; 00102 roi.height = height; 00103 clear(); 00104 }; 00105 void binMap::initialize(float w, float h, float res, float x, float y){ 00106 int wd = (int)floor(w/res+0.5); 00107 int ht = (int)floor(h/res+0.5); 00108 initialize(wd, ht, res, x, y); 00109 }; 00110 binMap& binMap::operator=(const binMap& map){ 00111 width = map.width; 00112 height = map.height; 00113 totalsize = map.totalsize; 00114 xorigin = map.xorigin; 00115 yorigin = map.yorigin; 00116 resolution = map.resolution; 00117 roi = map.roi; 00118 cells = map.cells; 00119 return *this; 00120 } 00121 00122 00123 // Data operations 00124 00125 bool binMap::isInside(int x, int y, int size) const{ 00126 for (int i = x-size; i<= x+size; i++) 00127 for (int j = y-size; j<= y+size; j++) 00128 if (!get(i,j)) 00129 return false; 00130 return true; 00131 } 00132 00133 bool binMap::isInsideD(int x, int y) const { 00134 int i,j; 00135 i = x; j = y; 00136 if (!get(i,j)) 00137 return false; 00138 i = x+1; j = y; 00139 if (!get(i,j)) 00140 return false; 00141 i = x-1; j = y; 00142 if (!get(i,j)) 00143 return false; 00144 i = x; j = y+1; 00145 if (!get(i,j)) 00146 return false; 00147 i = x; j = y-1; 00148 if (!get(i,j)) 00149 return false; 00150 return true; 00151 } 00152 00153 bool binMap::isOver(int x, int y, int size) const { 00154 for (int i = x-size; i<= x+size; i++) 00155 for (int j = y-size; j<= y+size; j++) 00156 if (get(i,j)){ 00157 return true; 00158 } 00159 return false; 00160 } 00161 00162 // Full map operations 00163 void binMap::sub(const binMap& map){ 00164 for (int i = 0; i< (int)cells.size(); i++){ 00165 cells[i] &= (~map.cells[i]); 00166 } 00167 } 00168 void binMap::times(const binMap& map){ 00169 for (int i = 0; i< (int)cells.size(); i++){ 00170 cells[i] &= map.cells[i]; 00171 } 00172 } 00173 void binMap::invert(){ 00174 for (int i = 0; i< (int)cells.size(); i++){ 00175 cells[i].flip(); 00176 } 00177 } 00178 00179 void binMap::add(const binMap& map){ 00180 for (int i = 0; i< (int)cells.size(); i++){ 00181 cells[i] |= map.cells[i]; 00182 } 00183 if (roi.x > map.roi.x){ 00184 roi.width += roi.x-map.roi.x; 00185 roi.x = map.roi.x; 00186 } 00187 if (roi.y > map.roi.y){ 00188 roi.height += roi.y-map.roi.y; 00189 roi.y = map.roi.y; 00190 } 00191 if (roi.x + roi.width <= map.roi.x + map.roi.width){ 00192 roi.width += (map.roi.x + map.roi.width) - (roi.x + roi.width); 00193 } 00194 if (roi.y + roi.height <= map.roi.y + map.roi.height){ 00195 roi.height += (map.roi.y + map.roi.height) - (roi.y + roi.height); 00196 } 00197 } 00198 void binMap::clear(){ 00199 for (int i = 0; i< (int)cells.size(); i++){ 00200 cells[i].reset(); 00201 } 00202 } 00203 void binMap::closing(int rad){ 00204 dilate(rad); 00205 erode(rad); 00206 } 00207 void binMap::opening(int rad){ 00208 erode(rad); 00209 dilate(rad); 00210 } 00211 void binMap::dilate(int rad){ 00212 int i,j; 00213 binMap prevData(*this); 00214 roi.x -= rad; 00215 roi.y -= rad; 00216 roi.width += 2*rad; 00217 roi.height += 2*rad; 00218 if (roi.x < 0){ roi.width += roi.x; roi.x = 0; } 00219 if (roi.y < 0){ roi.height += roi.y; roi.y = 0; } 00220 if (roi.x + roi.width > width) {roi.width = width - roi.x;} 00221 if (roi.y + roi.height > height) {roi.height = height - roi.y;} 00222 for (i = roi.x ; i < roi.x + roi.width ; i++){ 00223 for (j = roi.y ; j < roi.y + roi.height ; j++){ // for each cell 00224 if(prevData.isOver(i,j,rad)){ 00225 set(i,j,true); 00226 } 00227 else{ 00228 set(i,j,false); 00229 } 00230 } 00231 } 00232 } 00233 void binMap::erode(int rad){ 00234 int i,j; 00235 binMap prevData(*this); 00236 roi.x += rad; 00237 roi.y += rad; 00238 roi.width -= 2*rad; 00239 roi.height -= 2*rad; 00240 for (i = roi.x ; i < roi.x + roi.width ; i++){ 00241 for (j = roi.y ; j < roi.y + roi.height ; j++){ // for each cell 00242 if(prevData.isInside(i,j,rad)){ 00243 set(i,j,true); 00244 } 00245 else{ 00246 set(i,j,false); 00247 } 00248 } 00249 } 00250 } 00251 00252 void binMap::remUnconnectRec(int x, int y, const binMap& prevData){ 00253 for (int i = x-1 ; i <= x+1; i++){ 00254 for (int j = y-1 ; j <= y+1 ; j++){ // for each cell 00255 if(prevData.get(i,j) && !get(i,j)) { 00256 set(i,j,true); 00257 remUnconnectRec(i,j,prevData); 00258 } 00259 } 00260 } 00261 } 00262 00263 void binMap::removeUnconnected(int x, int y){ 00264 binMap prevData(*this); 00265 clear(); 00266 set(x,y,true); 00267 remUnconnectRec(x,y,prevData); 00268 } 00269 00270 00271 // Drawing Functions 00272 void binMap::line(int x1, int y1, int x2, int y2){ 00273 int i,j ; 00274 float incx, incy, auxx, auxy; 00275 auxx = fabs((float)(x1-x2)); 00276 auxy = fabs((float)(y1-y2)); 00277 incx = auxx/auxy; 00278 incy = auxy/auxx; 00279 00280 int count = 0; 00281 00282 if (incx > incy){ 00283 j = y1; 00284 00285 count=1; 00286 if (x1 < x2){ 00287 for(i = x1; i <= x2; i++){ 00288 if (fabs((float)(i-x1))>=count*incx) { 00289 count++; 00290 if (y1<y2) 00291 j++; 00292 else 00293 j--; 00294 } 00295 set(i,j,true); 00296 } 00297 } 00298 else{ 00299 for(i = x1; i >= x2; i--){ 00300 if (fabs((float)(x1-i))>=count*incx) { 00301 count++; 00302 if (y1<y2) 00303 j++; 00304 else 00305 j--; 00306 } 00307 set(i,j,true); 00308 } 00309 } 00310 } 00311 00312 else{ 00313 j = x1; 00314 00315 count=1; 00316 if (y1 < y2){ 00317 for(i = y1; i <= y2; i++){ 00318 if (fabs((float)(i-y1))>=count*incy) { 00319 count++; 00320 if (x1<x2) 00321 j++; 00322 else 00323 j--; 00324 } 00325 set(j,i,true); 00326 } 00327 } 00328 else{ 00329 for(i = y1; i >= y2; i--){ 00330 if (fabs((float)(y1-i))>=count*incy) { 00331 count++; 00332 if (x1<x2) 00333 j++; 00334 else 00335 j--; 00336 } 00337 set(j,i,true); 00338 } 00339 } 00340 } 00341 } 00342 00343 void binMap::saveMapAsImage(const char* file) const{ 00344 00345 IplImage* img = getMapAsImage(); 00346 cvSaveImage(file, img); 00347 cvReleaseImage(&img); 00348 } 00349 00350 void binMap::showMap(const char* windowname)const{ 00351 IplImage* img = getMapAsImage(); 00352 cvNamedWindow(windowname, 0); 00353 cvShowImage(windowname,img); 00354 cvReleaseImage(&img); 00355 00356 } 00357 00358 IplImage* binMap::getMapAsImage() const { 00359 IplImage* img = cvCreateImage(cvSize(width,height), IPL_DEPTH_8U, 3); 00360 00361 for (int i = 0; i< width; i++) 00362 for(int j = 0; j< height; j++){ 00363 uchar greyvalue = (uchar) (255.0f*get(i,j)); 00364 ((uchar*)(img->imageData + img->widthStep*(height-1-j)))[3*i] = greyvalue; 00365 ((uchar*)(img->imageData + img->widthStep*(height-1-j)))[3*i+1] = greyvalue; 00366 ((uchar*)(img->imageData + img->widthStep*(height-1-j)))[3*i+2] = greyvalue; 00367 } 00368 return img; 00369 } 00370 00371 int binMap::getPositives(vector<point>& positives) const{ 00372 int idx = 0; 00373 int count=0; 00374 positives.reserve(width*height); 00375 for (int j = 0; j< height; j++){ 00376 for (int i = 0; i< width; i++){ 00377 if (cells[idx/32][idx%32]){ 00378 positives.push_back(point(i,j)); 00379 count++; 00380 } 00381 idx++; 00382 } 00383 } 00384 return count; 00385 } 00386 00387 int binMap::cluster(vector<clusterCell>& clusterList, int minSize) const{ 00388 00389 //mapa en blanco de celdas analizadas 00390 binMap aux(getWidth(), getHeight(), getResolution(), getXOrigin(), getYOrigin()); 00391 00392 clusterCell cl; 00393 int count = 0; // numero de clusters encontrado 00394 00395 for (int i = getRoi().x ; i < getRoi().x + getRoi().width ; i++){ 00396 for (int j = getRoi().y ; j < getRoi().y + getRoi().height ; j++){ // for each cell 00397 00398 std::list<point> seq; 00399 clustering(i,j,aux,cl,seq,true); 00400 00401 if (cl.scale >= minSize){ // cluster de al menos 3 celdas 00402 00403 // nos quedamos con la celda central del cluster 00404 std::list<point>::iterator it; 00405 int k; 00406 for( k = 0, it = seq.begin(); it != seq.end() && k <= cl.scale/2; it++ , k++); 00407 it--; 00408 k--; 00409 cl.x = it->x; 00410 cl.y = it->y; 00411 00412 count++; 00413 00414 clusterList.push_back(cl); 00415 } 00416 cl.x=0; 00417 cl.y=0; 00418 cl.scale=0; 00419 } 00420 } 00421 00422 return count; 00423 } 00424 00425 bool binMap::clustering(const int &i, const int &j, binMap& aux, clusterCell& cl, std::list<point> &seq, bool backfront) const{ 00426 00427 if(!aux.get(i,j) && get(i,j) ){ // if ipoint or door 00428 point p(i,j); 00429 if (backfront) seq.push_back(p); 00430 else seq.push_front(p); 00431 00432 cl.x += i; 00433 cl.y += j; 00434 cl.scale++; 00435 aux.set(i,j,true); 00436 00437 int x, y; 00438 for (x = i-1; x<=i+1; x++){ 00439 for (y = j-1; y<=j+1; y++){ 00440 if (clustering(x,y,aux,cl,seq,backfront)){ 00441 backfront = !backfront; 00442 } 00443 } 00444 } 00445 return true; 00446 } 00447 else{ 00448 aux.set(i,j,true); 00449 return false; 00450 } 00451 } 00452 00453 void binMap::set(const vector<clusterCell>& cl){ 00454 clear(); 00455 vector<clusterCell>::const_iterator clit; 00456 for(clit = cl.begin(); clit != cl.end(); clit++) 00457 set(clit->x, clit->y, true); 00458 } 00459 00460 int binMap::count() const{ 00461 int count=0; 00462 for (int i = getRoi().x ; i < getRoi().x + getRoi().width ; i++) 00463 for (int j = getRoi().y ; j < getRoi().y + getRoi().height ; j++) // for each cell 00464 if (get(i,j)) count++; 00465 return count; 00466 } 00467