topological_mapper.cpp
Go to the documentation of this file.
00001 
00038 #include <bwi_mapper/topological_mapper.h>
00039 #include <bwi_mapper/connected_components.h>
00040 #include <bwi_mapper/map_utils.h>
00041 #include <bwi_mapper/point_utils.h>
00042 
00043 #include <boost/foreach.hpp>
00044 
00045 #include <opencv/highgui.h>
00046 
00047 namespace bwi_mapper {
00048 
00059   void TopologicalMapper::computeTopologicalGraph(double threshold, 
00060       double critical_epsilon, double merge_threshold) {
00061 
00062     std::cout << "computeTopologicalGraph(): find voronoi points" << std::endl;
00063     findVoronoiPoints(threshold);
00064     std::cout << "computeTopologicalGraph(): compute critical regions" << std::endl;
00065     computeCriticalRegions(critical_epsilon);
00066     std::cout << "computeTopologicalGraph(): compute ze graph" << std::endl;
00067     computeGraph(merge_threshold);
00068   }
00069 
00074   void TopologicalMapper::drawCriticalPoints(cv::Mat &image, 
00075       uint32_t orig_x, uint32_t orig_y) {
00076 
00077     for (size_t i = 0; i < critical_points_.size(); ++i) {
00078       VoronoiPoint &vp = critical_points_[i];
00079       cv::circle(image, 
00080           cv::Point(vp.x + orig_x, vp.y + orig_y), 8, cv::Scalar(0,0,255), -1);
00081     }
00082 
00083     drawCriticalLines(image, orig_x, orig_y, false, true);
00084   }
00085 
00090   void TopologicalMapper::drawConnectedComponents(cv::Mat &image,
00091       uint32_t orig_x, uint32_t orig_y) {
00092 
00093     // Figure out different colors - 1st color should always be black
00094     size_t num_colors = num_components_;
00095     component_colors_.resize(num_colors);
00096     for (size_t i = 0; i < num_colors; ++i) {
00097       component_colors_[i] = 
00098         cv::Vec3b(160 + rand() % 64, 160 + rand() % 64, 160 + rand() % 64);
00099     }
00100 
00101     // component 0 is obstacles + background. don't draw?
00102 
00103     // Now paint!
00104     for (uint32_t j = 1; j < map_resp_.map.info.height; ++j) {
00105       cv::Vec3b* image_row_j = image.ptr<cv::Vec3b>(j + orig_y);
00106       for (uint32_t i = 0; i < map_resp_.map.info.width; ++i) {
00107         size_t map_idx = MAP_IDX(map_resp_.map.info.width, i, j);
00108         if (component_map_[map_idx] == -1)
00109           continue;
00110         cv::Vec3b& pixel = image_row_j[i + orig_x];
00111         pixel[0] = component_colors_[component_map_[map_idx]][0];
00112         pixel[1] = component_colors_[component_map_[map_idx]][1];
00113         pixel[2] = component_colors_[component_map_[map_idx]][2];
00114 
00115       }
00116     }
00117   }
00118 
00119 
00120   void TopologicalMapper::drawRegionGraph(cv::Mat &image,
00121       uint32_t orig_x, uint32_t orig_y) {
00122     drawGraph(image, region_graph_, orig_x, orig_y);
00123   }
00124 
00125   void TopologicalMapper::drawPointGraph(cv::Mat &image,
00126       uint32_t orig_x, uint32_t orig_y) {
00127     drawGraph(image, point_graph_, orig_x, orig_y);
00128   }
00129 
00130   void TopologicalMapper::writeRegionGraphToFile(std::string &filename) {
00131     writeGraphToFile(filename, region_graph_, map_resp_.map.info);
00132   }
00133 
00134   void TopologicalMapper::writePointGraphToFile(std::string &filename) {
00135     writeGraphToFile(filename, point_graph_, map_resp_.map.info);
00136   }
00137 
00142   void TopologicalMapper::printCriticalPoints() {
00143     for (size_t i = 0; i < critical_points_.size(); ++i) {
00144       VoronoiPoint &vp = critical_points_[i];
00145       std::cout << " (" << vp.x << "," << vp.y << "): ";
00146       for (size_t j = 0; j < vp.basis_points.size(); ++j) {
00147         std::cout << " (" << vp.basis_points[j].x << "," 
00148                   << vp.basis_points[j].y << "," 
00149                   << vp.basis_points[j].distance_from_ref << "), ";
00150       }
00151       std::cout << std::endl;
00152     }
00153   }
00154 
00161   void TopologicalMapper::drawOutput(cv::Mat &image) {
00162     VoronoiApproximator::drawOutput(image);
00163     drawMap(image, 2 * map_resp_.map.info.width);
00164     drawConnectedComponents(image, 2 * map_resp_.map.info.width);
00165     drawCriticalPoints(image, 2 * map_resp_.map.info.width);
00166     drawMap(image, 3 * map_resp_.map.info.width);
00167     drawRegionGraph(image, 3 * map_resp_.map.info.width);
00168     drawMap(image, 4 * map_resp_.map.info.width);
00169     drawPointGraph(image, 4 * map_resp_.map.info.width);
00170   }
00171 
00172   void TopologicalMapper::saveOutput() {
00173     cv::Mat image;
00174     drawMap(image);
00175     drawVoronoiPoints(image);
00176     cv::imwrite("graphvoronoi.png", image);
00177     drawMap(image);
00178     drawConnectedComponents(image);
00179     drawCriticalPoints(image);
00180     cv::imwrite("graphcritical.png", image);
00181     drawMap(image);
00182     drawGraph(image, region_graph_);
00183     cv::imwrite("graphoriginal.png", image);
00184     drawMap(image);
00185     drawGraph(image, pass_1_graph_);
00186     cv::imwrite("graphpass1.png", image);
00187     drawMap(image);
00188     drawGraph(image, pass_2_graph_);
00189     cv::imwrite("graphpass2.png", image);
00190     drawMap(image);
00191     drawGraph(image, pass_3_graph_);
00192     cv::imwrite("graphpass3.png", image);
00193     drawMap(image);
00194     drawGraph(image, pass_4_graph_);
00195     cv::imwrite("graphpass4.png", image);
00196     drawMap(image);
00197     drawGraph(image, point_graph_);
00198     cv::imwrite("graphfinal.png", image);
00199   }
00200 
00206   void TopologicalMapper::computeCriticalRegions (double critical_epsilon) {
00207 
00208     // Compute critical points
00209     size_t pixel_critical_epsilon = 
00210       critical_epsilon / map_resp_.map.info.resolution;
00211 
00212     for (size_t i = 0; i < voronoi_points_.size(); ++i) {
00213       VoronoiPoint &vpi = voronoi_points_[i];
00214       float average_neighbourhood_clearance = 0;
00215       size_t neighbour_count = 0;
00216       bool is_clearance_minima = true;
00217       // Get all voronoi points in a region around this voronoi point
00218       for (size_t j = 0; j < voronoi_points_.size(); ++j) {
00219         // Don't check if it is the same point
00220         if (j == i) {
00221           continue;
00222         }
00223 
00224         // Compute distance of jth point to ith point - 
00225         // don't compare if too far away
00226         VoronoiPoint &vpj = voronoi_points_[j];
00227         float distance = bwi_mapper::getMagnitude(vpj - vpi); 
00228         if (distance > pixel_critical_epsilon) {
00229           continue;
00230         }
00231 
00232         average_neighbourhood_clearance += vpj.average_clearance;
00233         ++neighbour_count;
00234 
00235         // See if the jth point has lower clearance than the ith
00236         if (vpj.average_clearance < vpi.average_clearance) {
00237           is_clearance_minima = false;
00238           break;
00239         }
00240       }
00241 
00242       // If no neighbours, then this cannot be a critical point
00243       if (neighbour_count == 0) {
00244         continue;
00245       }
00246 
00247       // Check if the point is indeed better than the neighbourhood
00248       // This can happen is any 2 walls of the map are too straight
00249       average_neighbourhood_clearance /= neighbour_count;
00250       if (vpi.average_clearance >= 0.999 * average_neighbourhood_clearance) {
00251         continue;
00252       }
00253 
00254       /* std::cout << "Check1: VP at " << vpi << " with clearance " << vpi.average_clearance << " and avg neighbourhood clearance " << average_neighbourhood_clearance << std::endl; */
00255 
00256       vpi.critical_clearance_diff = 
00257         average_neighbourhood_clearance - vpi.average_clearance;
00258 
00259       std::vector<size_t> mark_for_removal;
00260       // This removal is not perfect, but ensures you don't have critical 
00261       // points too close.
00262       for (size_t j = 0; j < critical_points_.size(); ++j) {
00263 
00264         // Check if in same neighbourhood
00265         VoronoiPoint &vpj = critical_points_[j];
00266         float distance = norm(vpj - vpi); 
00267         if (distance > pixel_critical_epsilon) {
00268           continue;
00269         }
00270 
00271         // If in same neighbourhood, retain better point
00272         if (vpj.critical_clearance_diff >= vpi.critical_clearance_diff) {
00273           is_clearance_minima = false;
00274           break;
00275         } else {
00276           mark_for_removal.push_back(j);
00277         }
00278       }
00279 
00280       if (is_clearance_minima) {
00281         // Let's remove any points marked for removal
00282         for (size_t j = mark_for_removal.size() - 1; 
00283             j < mark_for_removal.size(); --j) { //unsigned
00284           critical_points_.erase(
00285               critical_points_.begin() + mark_for_removal[j]);
00286         }
00287 
00288         // And then add this critical point
00289         critical_points_.push_back(vpi);
00290       }
00291     }
00292 
00293     // Remove any critical points where the point itself does not lie on the line
00294     std::vector<size_t> mark_for_removal;
00295     for (size_t i = 0; i < critical_points_.size(); ++i) {
00296       VoronoiPoint &cp = critical_points_[i];
00297       float theta0 = 
00298         atan2((cp.basis_points[0] - cp).y,
00299               (cp.basis_points[0] - cp).x);
00300       float theta1 = 
00301         atan2((cp.basis_points[1] - cp).y,
00302               (cp.basis_points[1] - cp).x);
00303       float thetadiff = fabs(theta1 - theta0);
00304 
00305       // We don't need to worry about wrapping here due known range of atan2
00306       if (thetadiff > M_PI + M_PI/12 || thetadiff < M_PI - M_PI/12) {
00307         mark_for_removal.push_back(i);
00308       }
00309     }
00310 
00311     // Remove bad critical points
00312     for (size_t j = mark_for_removal.size() - 1; 
00313         j < mark_for_removal.size(); --j) { //unsigned
00314       critical_points_.erase(
00315           critical_points_.begin() + mark_for_removal[j]);
00316     }
00317 
00318     // Once you have critical lines, produce connected regions (4-connected)
00319     // draw the critical lines on to a copy of the map so that we can find
00320     // connected regions
00321     cv::Mat component_map_color;
00322     drawMap(component_map_color, inflated_map_);
00323     cvtColor(component_map_color, component_image_, CV_RGB2GRAY);
00324     drawCriticalLines(component_image_);
00325 
00326     component_map_.resize(
00327         component_image_.rows * component_image_.cols);
00328     ConnectedComponents cc(component_image_, component_map_);
00329     num_components_ = cc.getNumberComponents();
00330 
00331   }
00332 
00333   void TopologicalMapper::computeGraph(double merge_threshold) {
00334 
00335     // First for each critical point, find out the neigbouring regions
00336     std::vector<std::set<uint32_t> > point_neighbour_sets;
00337     point_neighbour_sets.resize(critical_points_.size());
00338 
00339     // Draw the critical lines as their indexes on the map
00340     cv::Mat lines(map_resp_.map.info.height, map_resp_.map.info.width, CV_16UC1,
00341         cv::Scalar((uint16_t)-1));
00342     drawCriticalLines(lines, 0, 0, true);
00343 
00344     // Go over all the pixels in the lines image and find neighbouring critical
00345     // regions
00346     for (int j = 0; j < lines.rows; ++j) {
00347       uint16_t* image_row_j = lines.ptr<uint16_t>(j);
00348       for (int i = 0; i < lines.cols; ++i) {
00349         uint16_t pixel = image_row_j[i];
00350         if (pixel == (uint16_t)-1) {
00351           continue;
00352         }
00353         int x_offset[] = {0, -1, 1, 0};
00354         int y_offset[] = {-1, 0, 0, 1};
00355         size_t num_neighbours = 4;
00356         for (size_t count = 0; count < num_neighbours; ++count) {
00357           uint32_t x_n = i + x_offset[count];
00358           uint32_t y_n = j + y_offset[count];
00359           if (x_n >= (uint16_t) lines.cols || y_n >= (uint16_t) lines.rows) {
00360             continue;
00361           }
00362           size_t map_idx = MAP_IDX(lines.cols, x_n, y_n);
00363           if (component_map_[map_idx] >= 0 && 
00364               component_map_[map_idx] < (int32_t) num_components_) {
00365             point_neighbour_sets[pixel].insert(component_map_[map_idx]);
00366           }
00367         }
00368       }
00369     }
00370 
00371     // Throw out any critical points that do not have 2 adjoining regions.
00372     // This can happen if the regions are too small
00373     std::vector<std::vector<uint32_t> > point_neighbours;
00374     point_neighbours.resize(critical_points_.size());
00375     std::vector<int> remove_crit_points;
00376     for (size_t i = 0; i < critical_points_.size(); ++i) {
00377       if (point_neighbour_sets[i].size() == 2) {
00378         point_neighbours[i] = 
00379           std::vector<uint32_t>(point_neighbour_sets[i].begin(),
00380               point_neighbour_sets[i].end());
00381       } else {
00382         remove_crit_points.push_back(i);
00383       }
00384     }
00385 
00386     for (int i = remove_crit_points.size() - 1; i >=0 ; --i) {
00387       critical_points_.erase(critical_points_.begin() + i);
00388       point_neighbour_sets.erase(point_neighbour_sets.begin() + i);
00389       point_neighbours.erase(point_neighbours.begin() + i);
00390     }
00391 
00392     // Find connectivity to remove any isolated sub-graphs
00393     std::vector<bool> checked_region(critical_points_.size(), false);
00394     std::vector<std::set<int> > graph_sets;
00395     for (size_t i = 0; i < num_components_; ++i) {
00396       if (checked_region[i]) {
00397         continue;
00398       }
00399       std::set<int> open_set, closed_set;
00400       open_set.insert(i);
00401       while (open_set.size() != 0) {
00402         int current_region = *(open_set.begin());
00403         open_set.erase(open_set.begin());
00404         closed_set.insert(current_region);
00405         checked_region[current_region] = true;
00406         for (int j = 0; j < critical_points_.size(); ++j) {
00407           for (int k = 0; k < 2; ++k) {
00408             if (point_neighbours[j][k] == current_region && 
00409                 std::find(closed_set.begin(), closed_set.end(), 
00410                   point_neighbours[j][1-k]) == 
00411                 closed_set.end()) {
00412               open_set.insert(point_neighbours[j][1-k]);
00413             }
00414           }
00415         }
00416       }
00417       graph_sets.push_back(closed_set);
00418     }
00419 
00420     std::set<int> master_region_set;
00421     if (graph_sets.size() != 1) {
00422       std::cout << "WARNING: Master graph is fragmented into " <<
00423         graph_sets.size() << " sub-graphs!!!" << std::endl;
00424       int max_idx = 0;
00425       int max_size = graph_sets[0].size();
00426       for (size_t i = 1; i < graph_sets.size(); ++i) {
00427         if (graph_sets[i].size() > max_size) {
00428           max_idx = i;
00429           max_size = graph_sets[i].size();
00430         }
00431       }
00432       master_region_set = graph_sets[max_idx];
00433     } else {
00434       master_region_set = graph_sets[0];
00435     }
00436     
00437     // Create the region graph next
00438     std::map<int, int> region_to_vertex_map;
00439     int vertex_count = 0;
00440     for (size_t r = 0; r < num_components_; ++r) { 
00441       if (std::find(master_region_set.begin(), master_region_set.end(), r) ==
00442           master_region_set.end()) {
00443         region_to_vertex_map[r] = -1;
00444         continue;
00445       }
00446 
00447       Graph::vertex_descriptor vi = boost::add_vertex(region_graph_);
00448 
00449       // Calculate the centroid
00450       uint32_t avg_i = 0, avg_j = 0, pixel_count = 0;
00451       for (size_t j = 0; j < map_resp_.map.info.height; ++j) {
00452         for (size_t i = 0; i < map_resp_.map.info.width; ++i) {
00453           size_t map_idx = MAP_IDX(map_resp_.map.info.width, i, j);
00454           if (component_map_[map_idx] == (int)r) {
00455             avg_j += j;
00456             avg_i += i;
00457             pixel_count++;
00458           }
00459         }
00460       }
00461 
00462       region_graph_[vi].location.x = ((float) avg_i) / pixel_count;
00463       region_graph_[vi].location.y = ((float) avg_j) / pixel_count;
00464       region_graph_[vi].pixels = floor(sqrt(pixel_count));
00465 
00466       // This map is only required till the point we form edges on this graph 
00467       region_to_vertex_map[r] = vertex_count;
00468 
00469       ++vertex_count;
00470     }
00471 
00472     // Now that region_to_vertex_map is complete, 
00473     // forward critical points to next graph
00474     std::map<int, std::map<int, VoronoiPoint> > 
00475       region_vertex_crit_points;
00476     for (size_t r = 0; r < num_components_; ++r) { 
00477       if (std::find(master_region_set.begin(), master_region_set.end(), r) ==
00478           master_region_set.end()) {
00479         region_to_vertex_map[r] = -1;
00480         continue;
00481       }
00482       // Store the critical points corresponding to this vertex
00483       for (int j = 0; j < critical_points_.size(); ++j) {
00484         for (int k = 0; k < 2; ++k) {
00485           if (point_neighbours[j][k] == r) {
00486             int region_vertex = region_to_vertex_map[r];
00487             int other_region_vertex = region_to_vertex_map[point_neighbours[j][1-k]];
00488             if (region_vertex == 192 && other_region_vertex == 202) {
00489               std::cout << "192-202: " << r << " " << point_neighbours[j][1-k] << " " << critical_points_[j] << std::endl;
00490             }
00491             if (region_vertex == 202 && other_region_vertex == 192) {
00492               std::cout << "192-202: " << r << " " << point_neighbours[j][1-k] << " " << critical_points_[j] << std::endl;
00493             }
00494             region_vertex_crit_points[region_vertex]
00495               [region_to_vertex_map[point_neighbours[j][1-k]]] =  
00496                 critical_points_[j];
00497           }
00498         }
00499       }
00500     }
00501 
00502     // Create 1 edge per critical point
00503     for (size_t i = 0; i < critical_points_.size(); ++i) {
00504       int region1 = region_to_vertex_map[point_neighbours[i][0]];
00505       int region2 = region_to_vertex_map[point_neighbours[i][1]];
00506       if (region1 == -1) {
00507         // part of one of the sub-graphs that was discarded
00508         continue;
00509       }
00510       int count = 0;
00511       Graph::vertex_descriptor vi,vj;
00512       vi = boost::vertex(region1, region_graph_);
00513       vj = boost::vertex(region2, region_graph_);
00514       Graph::edge_descriptor e; bool b;
00515       boost::tie(e,b) = boost::edge(vi, vj, region_graph_);
00516       if (!b) {
00517         boost::tie(e,b) = boost::add_edge(vi, vj, region_graph_);
00518       }
00519       /* boost::tie(e,b) = boost::add_edge(vi, vj, region_graph_); */
00520       // region_graph_[e].weight = bwi_mapper::getMagnitude(
00521       //     region_graph_[vi].location - region_graph_[vj].location);
00522     }
00523 
00524     // Refine the region graph into the point graph:
00525     int pixel_threshold = merge_threshold / map_resp_.map.info.resolution;
00526 
00527     enum {
00528       PRESENT = 0,
00529       REMOVED_REGION_VERTEX = 1,
00530       CONVERT_TO_CRITICAL_POINT = 2,
00531       MERGE_VERTEX = 3
00532     };
00533     Graph::vertex_iterator vi, vend;
00534 
00535     // PASS 1 - resolve all vertices that are too big and have more than 2 
00536     // critical points to their underlying critical points
00537     std::cout << std::endl << "==============================" << std::endl;
00538     std::cout << "PASS 1" << std::endl;
00539     std::cout << "==============================" << std::endl << std::endl;
00540     Graph pass_0_graph = region_graph_;
00541     Graph pass_1_graph;
00542     int pass_0_count = 0;
00543     int pass_1_count = 0;
00544     std::vector<int> pass_0_vertex_status(
00545         boost::num_vertices(pass_0_graph), PRESENT);
00546     std::map<int, int> pass_0_vertex_to_pass_1_map;
00547     for (boost::tie(vi, vend) = boost::vertices(pass_0_graph); vi != vend;
00548         ++vi, ++pass_0_count) {
00549 
00550       std::cout << "Analyzing pass 0 graph vertex: " << pass_0_count << std::endl;
00551 
00552       std::vector<size_t> adj_vertices;
00553       getAdjacentNodes(pass_0_count, pass_0_graph, adj_vertices);
00554       // See if the area of this region is too big to be directly pushed into 
00555       // the pass 3 graph
00556       if (pass_0_graph[*vi].pixels >= pixel_threshold &&
00557           adj_vertices.size() > 2) {
00558         pass_0_vertex_status[pass_0_count] = CONVERT_TO_CRITICAL_POINT;
00559         std::cout << " - throwing it out (needs to be resolved to CPs)" <<
00560           std::endl;
00561         continue;
00562       }
00563 
00564       // Otherwise insert this as is into the point graph
00565       Graph::vertex_descriptor point_vi = boost::add_vertex(pass_1_graph);
00566       pass_1_graph[point_vi] = pass_0_graph[*vi];
00567       pass_0_vertex_to_pass_1_map[pass_0_count] = pass_1_count;
00568 
00569       ++pass_1_count;
00570     }
00571 
00572     // Now for each vertex that needs to be resolved into critical points, 
00573     // check neighbours recursively to convert these vertices into critical
00574     // points
00575     std::map<int, std::map<int, int> > pass_0_vertex_to_cp_map;
00576     pass_0_count = 0;
00577     for (boost::tie(vi, vend) = boost::vertices(pass_0_graph); vi != vend;
00578         ++vi, ++pass_0_count) {
00579 
00580       if (pass_0_vertex_status[pass_0_count] != CONVERT_TO_CRITICAL_POINT) {
00581         continue;
00582       }
00583       std::cout << "Converting pass1 vtx to CPs: " << pass_0_count << std::endl;
00584 
00585       std::vector<size_t> adj_vertices;
00586       getAdjacentNodes(pass_0_count, pass_0_graph, adj_vertices);
00587       std::vector<int> connect_edges;
00588       BOOST_FOREACH(size_t vtx, adj_vertices) {
00589         if (pass_0_vertex_status[vtx] == PRESENT) {
00590           Graph::vertex_descriptor point_vi = boost::add_vertex(pass_1_graph);
00591           pass_1_graph[point_vi].location =
00592             region_vertex_crit_points[pass_0_count][vtx];
00593           std::cout << " - added vtx at " << pass_1_graph[point_vi].location 
00594             << std::endl;
00595           int pass_1_vertex = pass_0_vertex_to_pass_1_map[vtx];
00596           std::cout << " - connecting vtx to pass_1_vertex: " << pass_1_vertex
00597             << " (pass0 = " << vtx << ")" << std::endl;
00598           Graph::vertex_descriptor vj;
00599           vj = boost::vertex(pass_1_vertex, pass_1_graph);
00600           Graph::edge_descriptor e; bool b;
00601           boost::tie(e,b) = boost::add_edge(point_vi, vj, pass_1_graph);
00602           connect_edges.push_back(pass_1_count);
00603           ++pass_1_count;
00604         } else if (vtx > pass_0_count) {
00605           // The CP is shared, but has not been added
00606           Graph::vertex_descriptor point_vi = boost::add_vertex(pass_1_graph);
00607           pass_1_graph[point_vi].location =
00608             region_vertex_crit_points[pass_0_count][vtx];
00609           std::cout << " - added shared cp with " << vtx << " at " 
00610             << pass_1_graph[point_vi].location << std::endl;
00611           pass_0_vertex_to_cp_map[pass_0_count][vtx] = pass_1_count;
00612           connect_edges.push_back(pass_1_count);
00613           ++pass_1_count;
00614         } else {
00615           // Retrieve existing CP
00616           int cp_vtx = pass_0_vertex_to_cp_map[vtx][pass_0_count];
00617           connect_edges.push_back(cp_vtx);
00618         }
00619       }
00620 
00621       /* Connect all the edges */
00622       for (int i = 0; i < connect_edges.size(); ++i) {
00623         for (int j = 0; j < i; ++j) {
00624           Graph::vertex_descriptor vi, vj;
00625           vi = boost::vertex(connect_edges[i], pass_1_graph);
00626           vj = boost::vertex(connect_edges[j], pass_1_graph);
00627           Graph::edge_descriptor e; bool b;
00628           boost::tie(e,b) = boost::add_edge(vi, vj, pass_1_graph);
00629         }
00630       }
00631 
00632     }
00633 
00634     // Connect all the edges as is from pass 1
00635     pass_0_count = 0;
00636     for (boost::tie(vi, vend) = boost::vertices(pass_0_graph); vi != vend;
00637         ++vi, ++pass_0_count) {
00638 
00639       if (pass_0_vertex_status[pass_0_count] != PRESENT) {
00640         continue;
00641       }
00642       std::cout << "Adding pass 1 edges for: " << pass_0_count << std::endl;
00643 
00644       std::vector<size_t> adj_vertices;
00645       getAdjacentNodes(pass_0_count, pass_0_graph, adj_vertices);
00646       BOOST_FOREACH(size_t vtx, adj_vertices) {
00647         if (pass_0_vertex_status[vtx] == PRESENT && vtx < pass_0_count) {
00648           Graph::vertex_descriptor vi, vj;
00649           vi = boost::vertex(
00650               pass_0_vertex_to_pass_1_map[pass_0_count], pass_1_graph);
00651           vj = boost::vertex(
00652               pass_0_vertex_to_pass_1_map[vtx], pass_1_graph);
00653           Graph::edge_descriptor e; bool b;
00654           boost::tie(e,b) = boost::add_edge(vi, vj, pass_1_graph);
00655         }
00656       }
00657     }
00658 
00659     pass_1_graph_ = pass_1_graph;
00660 
00661     // PASS 2 - remove any vertices that are adjacent to only 2 other vertices,
00662     // where both those vertices are visible to each other
00663     std::cout << std::endl << "==============================" << std::endl;
00664     std::cout << "PASS 2" << std::endl;
00665     std::cout << "==============================" << std::endl << std::endl;
00666 
00667     Graph pass_2_graph;
00668 
00669     std::vector<int> pass_1_vertex_status(boost::num_vertices(pass_1_graph), PRESENT);
00670     std::map<int, int> pass_1_vertex_to_pass_2_vertex_map;
00671     std::vector<std::pair<int, int> > rr_extra_edges;
00672     std::map<int, std::pair<int, int> > removed_vertex_map;
00673 
00674     pass_1_count = 0;
00675     int pass_2_count = 0;
00676     for (boost::tie(vi, vend) = boost::vertices(pass_1_graph); vi != vend;
00677         ++vi, ++pass_1_count) {
00678 
00679       std::cout << "Analyzing pass_1 graph vertex: " << pass_1_count << std::endl;
00680 
00681       if (pass_1_vertex_status[pass_1_count] != PRESENT) {
00682         std::cout << " - the vertex has been thrown out already " << std::endl;
00683         continue;
00684       }
00685       
00686       // See if this only has 2 neighbours, and the 2 neighbours are visible to
00687       // each other
00688       std::vector<size_t> open_vertices;
00689       int current_vertex = pass_1_count;
00690       getAdjacentNodes(current_vertex, pass_1_graph, open_vertices);
00691       std::vector<int> removed_vertices;
00692       std::pair<int, int> edge;
00693       if (open_vertices.size() == 2 &&
00694           pass_1_vertex_status[open_vertices[0]] == PRESENT &&
00695           pass_1_vertex_status[open_vertices[1]] == PRESENT) {
00696         while(true) {
00697           std::cout << " - has 2 adjacent vertices " << open_vertices[0] << ", " 
00698             << open_vertices[1] << std::endl;
00699           // Check if the 2 adjacent vertices are visible
00700           Point2f location1 = 
00701             getLocationFromGraphId(open_vertices[0], pass_1_graph);
00702           Point2f location2 = 
00703             getLocationFromGraphId(open_vertices[1], pass_1_graph);
00704           bool locations_visible = 
00705             locationsInDirectLineOfSight(location1, location2, map_resp_.map);
00706           if (locations_visible) {
00707             std::cout << " - the 2 adjacent vertices are visible " 
00708               << "- removing vertex." << std::endl; 
00709             pass_1_vertex_status[current_vertex] = REMOVED_REGION_VERTEX;
00710             removed_vertices.push_back(current_vertex);
00711             edge = std::make_pair(open_vertices[0], open_vertices[1]);
00712             bool replacement_found = false;
00713             for (int i = 0; i < 2; ++i) {
00714               std::vector<size_t> adj_vertices;
00715               getAdjacentNodes(open_vertices[i], pass_1_graph, 
00716                   adj_vertices);
00717               if (adj_vertices.size() == 2) {
00718                 size_t new_vertex = (adj_vertices[0] == current_vertex) ? 
00719                   adj_vertices[1] : adj_vertices[0];
00720                 if (pass_1_vertex_status[new_vertex] == PRESENT) {
00721                   current_vertex = open_vertices[i];
00722                   std::cout << " - neighbours may suffer from the same problem"
00723                     << ". checking vertex " << current_vertex << std::endl;
00724                   open_vertices[i] = new_vertex;
00725                   replacement_found = true;
00726                   break;
00727                 }
00728               }
00729             }
00730             if (!replacement_found) {
00731               // Both neighbours on either side had 1 or more than 2 adjacent 
00732               // vertices
00733               break;
00734             }
00735           } else {
00736             // left and right vertices not visible
00737             break;
00738           }
00739         }
00740       }
00741 
00742       BOOST_FOREACH(int removed_vertex, removed_vertices) {
00743         removed_vertex_map[removed_vertex] = edge;
00744       }
00745 
00746       if (removed_vertices.size() != 0) {
00747         // Add the extra edge
00748         std::cout << " - adding extra edge between " << edge.first <<
00749           " " << edge.second << std::endl;
00750         rr_extra_edges.push_back(edge);
00751         continue;
00752       }
00753 
00754       // Otherwise insert this as is into the point graph
00755       Graph::vertex_descriptor point_vi = boost::add_vertex(pass_2_graph);
00756       pass_2_graph[point_vi] = pass_1_graph[*vi];
00757       pass_1_vertex_to_pass_2_vertex_map[pass_1_count] = 
00758         pass_2_count;
00759 
00760       ++pass_2_count;
00761     }
00762 
00763     // Insert all edges that can be inserted
00764     
00765     // Add edges from the pass_1 graph that can be placed as is
00766     pass_1_count = 0;
00767     for (boost::tie(vi, vend) = boost::vertices(pass_1_graph); vi != vend;
00768         ++vi, ++pass_1_count) {
00769       if (pass_1_vertex_status[pass_1_count] == PRESENT) {
00770         std::vector<size_t> adj_vertices;
00771         getAdjacentNodes(pass_1_count, pass_1_graph, adj_vertices);
00772         BOOST_FOREACH(size_t adj_vertex, adj_vertices) {
00773           if (pass_1_vertex_status[adj_vertex] == PRESENT &&
00774               adj_vertex > pass_1_count) {
00775             Graph::vertex_descriptor vi,vj;
00776             int vertex1 = 
00777               pass_1_vertex_to_pass_2_vertex_map[pass_1_count];
00778             int vertex2 = pass_1_vertex_to_pass_2_vertex_map[adj_vertex];
00779             vi = boost::vertex(vertex1, pass_2_graph);
00780             vj = boost::vertex(vertex2, pass_2_graph);
00781             Graph::edge_descriptor e; bool b;
00782             boost::tie(e,b) = boost::add_edge(vi, vj, pass_2_graph);
00783           }
00784         }
00785       }
00786     }
00787 
00788     // Add all the extra edges
00789     typedef std::pair<int, int> int2pair;
00790     BOOST_FOREACH(const int2pair& edge, rr_extra_edges) {
00791       Graph::vertex_descriptor vi,vj;
00792       int vertex1 = 
00793         pass_1_vertex_to_pass_2_vertex_map[edge.first];
00794       int vertex2 = pass_1_vertex_to_pass_2_vertex_map[edge.second];
00795       vi = boost::vertex(vertex1, pass_2_graph);
00796       vj = boost::vertex(vertex2, pass_2_graph);
00797       Graph::edge_descriptor e; bool b;
00798       boost::tie(e,b) = boost::add_edge(vi, vj, pass_2_graph);
00799     }
00800 
00801     pass_2_graph_ = pass_2_graph;
00802 
00803     // Pass 3 - Merge all close vertices and remove any edges that can be
00804     // replaced by 2 edges of marginally longer length
00805     int vertex_merge_threshold = 2.0f / map_resp_.map.info.resolution;
00806     std::cout << std::endl << "==============================" << std::endl;
00807     std::cout << "PASS 3" << std::endl;
00808     std::cout << "==============================" << std::endl << std::endl;
00809     Graph pass_3_graph;
00810     pass_2_count = 0;
00811     int pass_3_count = 0;
00812     std::map<int, int> pass_2_vertex_to_pass_3_vertex_map;
00813     std::vector<int> pass_2_vertex_status(
00814         boost::num_vertices(pass_2_graph), PRESENT);
00815     for (boost::tie(vi, vend) = boost::vertices(pass_2_graph); vi != vend;
00816         ++vi, ++pass_2_count) {
00817 
00818       std::cout << "Analyzing pass 2 graph vtx: " << pass_2_count << std::endl;
00819       if (pass_2_vertex_status[pass_2_count] != PRESENT) {
00820         std::cout << " - vtx already thrown out " << std::endl;
00821         continue;
00822       }
00823 
00824       std::set<int> open_set;
00825       std::set<int> closed_set;
00826       open_set.insert(pass_2_count);
00827       while(open_set.size() != 0) {
00828         int current_vertex = *open_set.begin();
00829         open_set.erase(open_set.begin());
00830         closed_set.insert(current_vertex);
00831         std::vector<size_t> adj_vertices;
00832         getAdjacentNodes(current_vertex, pass_2_graph, adj_vertices);
00833         BOOST_FOREACH(size_t vtx, adj_vertices) {
00834           if (closed_set.count(vtx) || open_set.count(vtx)) {
00835             continue;
00836           }
00837           std::cout << " - checking " << current_vertex << ", " << vtx;
00838           Point2f l1 = getLocationFromGraphId(current_vertex, pass_2_graph);
00839           Point2f l2 = getLocationFromGraphId(vtx, pass_2_graph);
00840           float distance = getMagnitude(l1-l2);
00841           std::cout << " - " << distance;
00842           if (distance < vertex_merge_threshold) {
00843             open_set.insert(vtx);
00844             std::cout << " - WILL MERGE";
00845           }
00846           std::cout << std::endl;
00847         }
00848       }
00849 
00850       Point2f vertex_location = pass_2_graph[*vi].location;
00851       if (closed_set.size() != 1) {
00852         Point2f sum(0,0);
00853         BOOST_FOREACH(int vtx, closed_set) {
00854           pass_2_vertex_status[vtx] = MERGE_VERTEX;
00855           pass_2_vertex_to_pass_3_vertex_map[vtx] = pass_3_count;
00856           sum += getLocationFromGraphId(vtx, pass_2_graph); 
00857         }
00858         vertex_location = (1.0f / closed_set.size()) * sum;
00859       } else {
00860         pass_2_vertex_to_pass_3_vertex_map[pass_2_count] = pass_3_count;
00861       }
00862         
00863       Graph::vertex_descriptor point_vi = boost::add_vertex(pass_3_graph);
00864       pass_3_graph[point_vi].location = vertex_location;
00865       ++pass_3_count;
00866     }
00867 
00868     // Add edges from the pass_1 graph that can be placed as is
00869     pass_2_count = 0;
00870     for (boost::tie(vi, vend) = boost::vertices(pass_2_graph); vi != vend;
00871         ++vi, ++pass_2_count) {
00872       std::cout << "Gen edges pass 2 graph vtx: " << pass_2_count << std::endl;
00873       std::vector<size_t> adj_vertices;
00874       getAdjacentNodes(pass_2_count, pass_2_graph, adj_vertices);
00875       BOOST_FOREACH(size_t adj_vertex, adj_vertices) {
00876         if (adj_vertex > pass_2_count) {
00877           Graph::vertex_descriptor vi,vj;
00878           int vertex1 = pass_2_vertex_to_pass_3_vertex_map[pass_2_count];
00879           int vertex2 = pass_2_vertex_to_pass_3_vertex_map[adj_vertex];
00880           if (vertex1 != vertex2) {
00881             vi = boost::vertex(vertex1, pass_3_graph);
00882             vj = boost::vertex(vertex2, pass_3_graph);
00883             Graph::edge_descriptor e; bool b;
00884             boost::tie(e,b) = boost::edge(vi, vj, pass_3_graph);
00885             if (!b) {
00886               boost::tie(e,b) = boost::add_edge(vi, vj, pass_3_graph);
00887               pass_3_graph[e].weight = getMagnitude(
00888                   getLocationFromGraphId(vertex1, pass_3_graph) - 
00889                   getLocationFromGraphId(vertex2, pass_3_graph));
00890               std::cout << " - gen edge " << vertex1 << " " << vertex2 << std::endl;
00891             }
00892           }
00893         }
00894       }
00895     }
00896 
00897     pass_3_graph_ = pass_3_graph;
00898 
00899     // Now, nudge all vertices to see if you can increase visibility.
00900     pass_3_count = 0;
00901     int neighbourhood = 0.5 / map_resp_.map.info.resolution;
00902     int num_vertices_pass_3 = boost::num_vertices(pass_3_graph);
00903     for (boost::tie(vi, vend) = boost::vertices(pass_3_graph); vi != vend;
00904         ++vi, ++pass_3_count) {
00905       std::cout << "Attempting nudge on vtx: " << pass_3_count << std::endl;
00906       Point2f vtx_loc = getLocationFromGraphId(pass_3_count, pass_3_graph);
00907       int max_visibility = 0, best_i = vtx_loc.x, best_j = vtx_loc.y; 
00908       for (int k = 0; k < num_vertices_pass_3; ++k) {
00909         Point2f k_loc = getLocationFromGraphId(k, pass_3_graph);
00910         if (locationsInDirectLineOfSight(vtx_loc, k_loc, map_resp_.map)) {
00911           ++max_visibility;
00912         }
00913       }
00914       for (int j = vtx_loc.y - neighbourhood / 2; 
00915           j <= vtx_loc.y + neighbourhood / 2; ++j) {
00916         for (int i = vtx_loc.x - neighbourhood / 2; 
00917             i <= vtx_loc.x + neighbourhood / 2; ++i) {
00918           Point2f point_loc(i, j); 
00919           int visibility = 0;
00920           for (int k = 0; k < num_vertices_pass_3; ++k) {
00921             Point2f k_loc = getLocationFromGraphId(k, pass_3_graph);
00922             if (locationsInDirectLineOfSight(point_loc, k_loc, map_resp_.map)) {
00923               ++visibility;
00924             }
00925           }
00926           if (visibility > max_visibility) {
00927             max_visibility = visibility;
00928             best_i = i;
00929             best_j = j;
00930           }
00931         }
00932       }
00933       pass_3_graph[*vi].location = Point2f(best_i, best_j);
00934     }
00935 
00936     // Recompute edge weights
00937     pass_3_count = 0;
00938     for (boost::tie(vi, vend) = boost::vertices(pass_3_graph); vi != vend;
00939         ++vi, ++pass_3_count) {
00940       Point2f vtx1 = getLocationFromGraphId(pass_3_count, pass_3_graph);
00941       std::vector<size_t> adj_vertices;
00942       getAdjacentNodes(pass_3_count, pass_3_graph, adj_vertices);
00943       BOOST_FOREACH(size_t adj_vertex, adj_vertices) {
00944         if (adj_vertex > pass_3_count) {
00945           Point2f vtx2 = getLocationFromGraphId(adj_vertex, pass_3_graph);
00946           Graph::vertex_descriptor vi,vj;
00947           vi = boost::vertex(pass_3_count, pass_3_graph);
00948           vj = boost::vertex(adj_vertex, pass_3_graph);
00949           Graph::edge_descriptor e; bool b;
00950           boost::tie(e,b) = boost::edge(vi, vj, pass_3_graph);
00951           if (b) {
00952             pass_3_graph[e].weight = getMagnitude(vtx1 - vtx2);
00953           }
00954         }
00955       }
00956     }
00957 
00958     pass_4_graph_ = pass_3_graph;
00959 
00960     // Once all the edges have been added, remove edges that fail triangle inequality
00961     pass_3_count = 0;
00962     for (boost::tie(vi, vend) = boost::vertices(pass_3_graph); vi != vend;
00963         ++vi, ++pass_3_count) {
00964       std::cout << "Analyzing edges on vtx " << pass_3_count << std::endl;
00965       std::vector<size_t> adj_vertices;
00966       getAdjacentNodes(pass_3_count, pass_3_graph, adj_vertices);
00967       Point2f vtx1 = getLocationFromGraphId(pass_3_count, pass_3_graph);
00968       BOOST_FOREACH(size_t adj_vertex, adj_vertices) {
00969         if (adj_vertex < pass_3_count)
00970           continue;
00971         std::cout << " - analyzing edge between " << pass_3_count << " and " <<
00972           adj_vertex << std::endl;
00973         Point2f vtx2 = getLocationFromGraphId(adj_vertex, pass_3_graph);
00974         float edge_length = getMagnitude(vtx1 - vtx2);
00975         Graph::vertex_descriptor vi,vj;
00976         vi = boost::vertex(pass_3_count, pass_3_graph);
00977         vj = boost::vertex(adj_vertex, pass_3_graph);
00978         boost::remove_edge(vi, vj, pass_3_graph);
00979         std::vector<size_t> replacement_path;
00980         float path_cost = 
00981           getShortestPathWithDistance(pass_3_count, adj_vertex, replacement_path, pass_3_graph);
00982         if (replacement_path.size() >= 2) {
00983           std::cout << " - fount alternate path cost: " << path_cost << std::endl;
00984         }
00985         if (replacement_path.size() < 2 || path_cost  > 1.05 * edge_length) {
00986           // re-add edge to graph
00987           Graph::edge_descriptor e; bool b;
00988           boost::tie(e,b) = boost::add_edge(vi, vj, pass_3_graph);
00989           pass_3_graph[e].weight = getMagnitude(
00990               getLocationFromGraphId(pass_3_count, pass_3_graph) - 
00991               getLocationFromGraphId(adj_vertex, pass_3_graph));
00992         } else {
00993           std::cout << " - removing edge between " << pass_3_count << " and " <<
00994             adj_vertex << std::endl;
00995         }
00996       }
00997     }
00998 
00999     point_graph_ = pass_3_graph;
01000     
01001   }
01002 
01007   void TopologicalMapper::drawCriticalLines(cv::Mat &image, 
01008       uint32_t orig_x, uint32_t orig_y, bool draw_idx, 
01009       bool visualization_image) {
01010 
01011     for (size_t i = 0; i < critical_points_.size(); ++i) {
01012       cv::Scalar color = cv::Scalar(0);
01013       if (draw_idx) {
01014         color = cv::Scalar((uint16_t)i);
01015       }
01016       VoronoiPoint &vp = critical_points_[i];
01017       if (vp.basis_points.size() != 2) {
01018         std::cerr << "ERROR: Found a critical point with more than 2 basis" 
01019           << "points. This should not have happened" << std::endl;
01020       } else {
01021         Point2d &p1(vp.basis_points[0]);
01022         Point2d &p2(vp.basis_points[1]);
01023         if (!visualization_image) {
01024           cv::line(image, 
01025               cv::Point(orig_x + p1.x, orig_y + p1.y),
01026               cv::Point(orig_x + p2.x, orig_y + p2.y), 
01027               color,
01028               1, 4); // draw a 4 connected line
01029         } else {
01030           color = cv::Scalar(0, 0, 255);
01031           cv::line(image, 
01032               cv::Point(orig_x + p1.x, orig_y + p1.y),
01033               cv::Point(orig_x + p2.x, orig_y + p2.y), 
01034               color,
01035               2, CV_AA); // draw a 4 connected line
01036         }
01037       }
01038     }
01039   }
01040 
01041 } /* bwi_mapper */
01042 


bwi_mapper
Author(s): Piyush Khandelwal
autogenerated on Fri Aug 28 2015 10:14:35