ellipses_representation.cpp
Go to the documentation of this file.
00001 #include "ellipses_representation.h"
00002 
00003 using namespace cv;
00004 using namespace std;
00005 
00006 
00007 EllipsesRepresentation::EllipsesRepresentation(void)
00008 {
00009         // arbitrarial intial position
00010         currentArmPosition.x = 0;
00011         currentArmPosition.y = 0;
00012 }
00013 
00014 EllipsesRepresentation::~EllipsesRepresentation(void)
00015 {
00016 }
00017 
00018 void EllipsesRepresentation::config_update(Config& new_cfg, uint32_t level)
00019 {
00020   this->lock();
00021 
00022   this->minFillThreshold     = new_cfg.minFillThreshold;
00023   this->minAreaThreshold     = new_cfg.minAreaThreshold;
00024   this->board_plan           = new_cfg.board_plan;
00025   this->max_number_ellipses  = new_cfg.max_number_ellipses;
00026   this->small_objects_join_distance = new_cfg.small_objects_join_distance;
00027   this->initial_state_idx    = new_cfg.initial_state_idx;
00028   
00029   // Rules generation
00030   // Erase a board
00031   this->min_width_threshold = new_cfg.min_width_threshold;
00032   this->max_width_threshold = new_cfg.max_width_threshold;
00033   
00034   // Small objects
00035   this->small_area_threshold = new_cfg.small_area_threshold;
00036   this->medium_area_threshold = new_cfg.medium_area_threshold;
00037   this->near_distance_threshold = new_cfg.near_distance_threshold;
00038   
00039   this->is_planning = ((!new_cfg.no_perceptions) && (!new_cfg.no_planning));
00040   
00041   this->is_learning = new_cfg.is_learning;
00042   
00043   // save the current configuration
00044   this->config_=new_cfg;
00045   
00046   this->unlock();
00047 }
00048 
00049 
00050 void EllipsesRepresentation::createNewState(cv::Mat image)
00051 {
00052         std::vector<estirabot_msgs::DirtyArea> previousDirtyAreas = this->dirtyAreas_;
00053         clearLastEllipses();
00054         setSourceImage(image);
00055         computeBoundingEllipses(image);
00056         this->dirtyAreas_ = orderDirtyAreas(calculateRosDirtyAreas(imageEllipses), previousDirtyAreas);
00057 }
00058 
00059 void EllipsesRepresentation::setSourceImage(cv::Mat image)
00060 {
00061         // save bgr image for displaying plan
00062         cv::cvtColor(image, this->show_image, CV_GRAY2BGR);
00063         
00064         // get binarized image
00065         threshold(image, this->state_image, 10, 255, cv::THRESH_BINARY );
00066 }
00067 
00068 
00069 // divides image in two halfs, one containing half a ellipse
00070 // then gets ellipses in each half calling recursively getBoundingEllipses
00071 // returns false if couldn't divide ellipses
00072 bool EllipsesRepresentation::divideBigEllipse(cv::Mat image, cv::Mat ellipseMask, RotatedRect currentEllipse)
00073 {
00074         Mat rectangleMask, finalMask;
00075         Mat firstEllipsePart, secondEllipsePart;
00076         Point2i rectanglePoint;
00077         
00078         ROS_DEBUG("Recursive ellipse");
00079         
00080         float angle = currentEllipse.angle;
00081         // we want angle in [0..90]
00082         if (angle > 180)
00083                 angle -=180;
00084         if (angle > 90)
00085                 angle = 180 - angle;
00086         
00087         //float angle = (ellipse.angle / 180) * M_PI;
00088         
00089         if (currentEllipse.size.width > currentEllipse.size.height) {
00090                 if (angle < 45)
00091                         rectanglePoint = Point2i(currentEllipse.center.x, image.size().height); // divide width
00092                 else
00093                         rectanglePoint = Point2i(image.size().width, currentEllipse.center.y); // divide height
00094         }
00095         else {
00096                 if (angle < 45)
00097                         rectanglePoint = Point2i(image.size().width, currentEllipse.center.y); // divide height
00098                 else
00099                         rectanglePoint = Point2i(currentEllipse.center.x, image.size().height); // divide width
00100         }
00101         
00102         rectangleMask = Mat::zeros(image.size(),CV_8UC1);
00103         rectangle(rectangleMask, Point2i(0,0), rectanglePoint, 255, CV_FILLED);
00104         
00105         // First half
00106         bitwise_and(ellipseMask, rectangleMask, finalMask); // mask = rectangle and ellipse
00107         bitwise_and(finalMask, image, firstEllipsePart); // image and mask
00108         
00109         // Second half
00110         bitwise_not(rectangleMask, rectangleMask); // invert rectangle (the other half image)
00111         bitwise_and(ellipseMask, rectangleMask, finalMask); // mask = rectangle and ellipse
00112         bitwise_and(finalMask, image, secondEllipsePart); // image and mask
00113         
00114         // check for infinite loops -> one half gets all the ellipse
00115         int sumFirstHalf, sumSecondHalf;
00116         sumFirstHalf = countNonZero(firstEllipsePart);
00117         sumSecondHalf = countNonZero(secondEllipsePart);
00118         
00119         // if a new ellipse has too few points -> cancel division (if not, we may enter a infinite loop)
00120         if ((sumFirstHalf < 150) || (sumSecondHalf < 150)) {
00121                 ROS_INFO("EllipsesRepresentation: Couldn't divide ellipses");
00122                 
00123                 return false;
00124         }
00125         else{
00126                 computeBoundingEllipses(firstEllipsePart); //recursive
00127                 computeBoundingEllipses(secondEllipsePart); //recursive
00128                 
00129                 return true;
00130         }
00131 }
00132 
00133 
00134 // EllipsesRepresentation Public API
00135 void EllipsesRepresentation::computeBoundingEllipses(cv::Mat image)
00136 {
00137         double filledArea, totalArea;
00138         bool sparse;
00139         std::vector<std::vector<cv::Point> > contours;
00140         std::vector<Vec4i> hierarchy;
00141         
00142         ROS_DEBUG("Compute ellipses");
00143         
00144         // extract contours
00145         if (this->board_plan)
00146                 findContours( image, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
00147         else {
00148                 cv::Mat image_closed;
00149                 cv::Mat element = cv::getStructuringElement(MORPH_ELLIPSE, cv::Size(small_objects_join_distance, small_objects_join_distance));
00150                 cv::morphologyEx(image, image_closed, cv::MORPH_CLOSE, element);
00151                 findContours( image_closed, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
00152         }
00153         
00154         ROS_DEBUG("Extracted contours");
00155         // get ellipse for each contour
00156         RotatedRect currentEllipse;
00157         for( size_t i = 0; i < contours.size(); i++ ) {
00158                 if( contours[i].size() > 5 ) { 
00159                         ROS_DEBUG("A ellipse");
00160                         currentEllipse = fitEllipse( Mat(contours[i]) );
00161                         
00162                         // Sometimes fitEllipse returns ellipses bigger than the image. Check for it
00163                         if ((currentEllipse.size.width > 500) || (currentEllipse.size.height > 500)) {
00164                                 ROS_ERROR("Detected ellipse with a dimension bigger than 500. Ignoring it...");
00165                                 return;
00166                         }
00167                         
00168                         // get real filled area
00169                         Mat region = Mat::zeros(image.rows, image.cols, CV_8UC1);
00170                         drawContours(region, contours, i, Scalar(255), CV_FILLED );
00171                         bitwise_and(region, image, region);
00172                         filledArea = countNonZero(region);
00173                         //filledArea = contourArea(contours[i]);
00174                         totalArea = currentEllipse.size.width * currentEllipse.size.height;
00175                         sparse = (filledArea/totalArea) < minFillThreshold;
00176                         ROS_DEBUG_STREAM("filledArea: "<<filledArea);
00177                         ROS_DEBUG_STREAM("totalArea: "<< totalArea);
00178                         
00179                         // Check if ellipse is big and too sparse
00180                         // only divide ellipses for board plans
00181                         bool divide_ellipse = (totalArea > minAreaThreshold) and (sparse);// and this->board_plan;
00182                         
00183                         if (divide_ellipse) {
00184                                 Mat ellipseMask = Mat::zeros(image.size(),CV_8UC1);
00185                                 drawContours(ellipseMask, contours, i, 255, CV_FILLED);
00186                                 
00187                                 //recursive algorithm for dividing ellipses
00188                                 divide_ellipse = divideBigEllipse(image, ellipseMask, currentEllipse); 
00189                         }
00190                         
00191                         // it isn't else because it can change in the previous if()
00192                         if (not divide_ellipse) {
00193                                 this->imageEllipses.push_back(currentEllipse);
00194                                 this->ellipsesMaxWidths.push_back(currentEllipse.size.height);
00195                                 this->ellipsesMinWidths.push_back(currentEllipse.size.width);
00196                                 this->ellipsesArea.push_back(totalArea);
00197                                 this->ellipsesSparse.push_back(sparse);
00198                                 
00199                                 // save visual image for publishing and debugging
00200                                 ellipse(show_image, currentEllipse, Scalar(0,0,255), 2, CV_AA);
00201                         }
00202                 }
00203         }
00204         
00205         // Truncate number of ellipses to improve plan quality
00206         if (this->is_planning)
00207                 truncateEllipsesNumber();
00208 }
00209 
00210 
00211 void EllipsesRepresentation::clearLastEllipses()
00212 {
00213         this->imageEllipses.clear();
00214         this->ellipsesMinWidths.clear();
00215         this->ellipsesMaxWidths.clear();
00216         this->ellipsesArea.clear();
00217         this->ellipsesSparse.clear();
00218 }
00219 
00220 
00221 void EllipsesRepresentation::truncateEllipsesNumber()
00222 {
00223         if (imageEllipses.size() <= this->max_number_ellipses) // check if we already have few ellipses
00224                 return;
00225         
00226         Point origPoint = Point(0,0);
00227         std::set<size_t> availableEllipses;
00228         std::vector<size_t> selectedEllipses;
00229         
00230         for (size_t i = 0; i < this->imageEllipses.size(); i++)
00231                 availableEllipses.insert(i);
00232         
00233         size_t nearestEllipse;
00234         double distance, minDist;
00235         
00236         for (size_t i = 0; i < this->max_number_ellipses; i++) {
00237                 minDist = 2000;
00238                 for (size_t j = 0; j < this->imageEllipses.size(); j++) {
00239                         if (availableEllipses.find(j) != availableEllipses.end()) { //
00240                                 distance = getDistance(origPoint, imageEllipses[j].center);
00241                                 if (distance < minDist) {
00242                                         minDist = distance;
00243                                         nearestEllipse = j;
00244                                 }
00245                         }
00246                 }
00247                 selectedEllipses.push_back(nearestEllipse);
00248                 availableEllipses.erase(nearestEllipse);
00249         }
00250         
00251         std::vector<cv::RotatedRect> newImageEllipses;
00252         std::vector<double> newEllipsesMinWidths;
00253         std::vector<double> newEllipsesMaxWidths;
00254         std::vector<double> newEllipsesArea;
00255         std::vector<uint8_t> newEllipsesSparse;
00256         
00257         for (size_t i = 0; i < selectedEllipses.size(); i++) {
00258                 newImageEllipses.push_back(this->imageEllipses[ selectedEllipses[i] ]);
00259                 newEllipsesMinWidths.push_back(this->ellipsesMinWidths[ selectedEllipses[i] ]);
00260                 newEllipsesMaxWidths.push_back(this->ellipsesMaxWidths[ selectedEllipses[i] ]);
00261                 newEllipsesArea.push_back(this->ellipsesArea[ selectedEllipses[i] ]);
00262                 newEllipsesSparse.push_back(this->ellipsesSparse[ selectedEllipses[i] ]);
00263         }
00264         
00265         this->imageEllipses = newImageEllipses;
00266         this->ellipsesMinWidths = newEllipsesMinWidths;
00267         this->ellipsesMaxWidths = newEllipsesMaxWidths;
00268         this->ellipsesArea = newEllipsesArea;
00269         this->ellipsesSparse = newEllipsesSparse;
00270 }
00271 
00272 
00273 std::vector< estirabot_msgs::PointsDistanceMsg > EllipsesRepresentation::distancesBetweenEllipses(std::vector<estirabot_msgs::DirtyArea> dirty_areas)
00274 {
00275     std::vector< estirabot_msgs::PointsDistanceMsg > result;
00276     
00277     for(size_t i=0; i < dirty_areas.size(); i++) {
00278         for(size_t j=i+1; j < dirty_areas.size(); j++) {
00279             estirabot_msgs::PointsDistanceMsg distanceMsg;
00280             distanceMsg.origIdx = dirty_areas[i].id;
00281             distanceMsg.dstIdx  = dirty_areas[j].id;
00282             distanceMsg.distance = getDistance(dirty_areas[i].ellipse.center, dirty_areas[j].ellipse.center);
00283             
00284             result.push_back(distanceMsg);
00285         }
00286     }
00287     
00288     return result;
00289 }
00290 
00291 // ugly conversions
00292 bool EllipsesRepresentation::pointIsBetween(iri_perception_msgs::ImagePoint new_p1, iri_perception_msgs::ImagePoint new_p2, iri_perception_msgs::ImagePoint new_point)
00293 {
00294     cv::Point2f p2;
00295     p2.x = new_p2.x;
00296     p2.y = new_p2.y;
00297     return pointIsBetween(new_p1, p2, new_point);
00298 }
00299 
00300 bool EllipsesRepresentation::pointIsBetween(iri_perception_msgs::ImagePoint new_p1, cv::Point2f p2, iri_perception_msgs::ImagePoint new_point)
00301 {
00302     cv::Point2f p1, point;
00303     p1.x = new_p1.x;
00304     p1.y = new_p1.y;
00305     point.x = new_point.x;
00306     point.y = new_point.y;
00307     return pointIsBetween(p1, p2, point);
00308 }
00309 
00310 bool EllipsesRepresentation::pointIsBetween(cv::Point2f p1, cv::Point2f p2, cv::Point2f point)
00311 {
00312         float distance, crossproduct, dotproduct, squaredlengthba;
00313         float epsilon = 12;
00314         
00315         /*
00316         * http://stackoverflow.com/questions/328107/how-can-you-determine-a-point-is-between-two-other-points-on-a-line-segment
00317         * 
00318         * Check if the cross product of (b-a) and (c-a) is 0, as tells Darius Bacon, tells 
00319         * you if the points a, b and c are aligned.
00320         * 
00321         * But, as you want to know if c is between a and b, you also have to check that the
00322         * dot product of (b-a) and (c-a) is positive and is less than the square of the 
00323         * distance between a and b.
00324         */
00325         
00326         distance = sqrt( pow(p1.x - p2.x, 2) + pow(p1.y - p2.y, 2) );
00327         
00328         crossproduct = (point.y - p1.y) * (p2.x - p1.x) - (point.x - p1.x) * (p2.y - p1.y);
00329         
00330         if (abs(crossproduct) > (epsilon * distance))
00331                 return false;   // (or != 0 if using integers)
00332         
00333         dotproduct = (point.x - p1.x) * (p2.x - p1.x) + (point.y - p1.y)*(p2.y - p1.y);
00334         if (dotproduct < 0)
00335                 return false;
00336         
00337         squaredlengthba = (p2.x - p1.x)*(p2.x - p1.x) + (p2.y - p1.y)*(p2.y - p1.y);
00338         if (dotproduct > squaredlengthba)
00339                 return false;
00340         
00341         return true;
00342 }
00343 
00344 std::vector< estirabot_msgs::TraversedEllipses > EllipsesRepresentation::getTraversedEllipses(std::vector<estirabot_msgs::DirtyArea> dirty_areas)
00345 {
00346     std::vector< estirabot_msgs::TraversedEllipses > result;
00347     
00348     for(size_t i=0; i < dirty_areas.size(); i++) {
00349         // traversals from ellipse i to other ellipses
00350         if (!this->is_learning) {
00351                 for(size_t j=i+1; j < dirty_areas.size(); j++) {
00352                 estirabot_msgs::TraversedEllipses traversedEllipsesMsg;
00353                 traversedEllipsesMsg.idx1 = dirty_areas[i].id;
00354                 traversedEllipsesMsg.idx2 = dirty_areas[j].id;
00355                 
00356                 for (size_t k=0; k < dirty_areas.size(); k++) {
00357                         if ((k != i) && (k != j) && (pointIsBetween(dirty_areas[i].ellipse.center, dirty_areas[j].ellipse.center, dirty_areas[k].ellipse.center)))
00358                         traversedEllipsesMsg.traversedIdxs.push_back(dirty_areas[k].id);
00359                 }
00360                 result.push_back(traversedEllipsesMsg);
00361                 }
00362         }
00363         
00364         // traversals from ellipse i to edge
00365         cv::Point2f edge_point;
00366         int edge_idx;
00367         edge_idx = -1;
00368         edge_point.y = dirty_areas[i].ellipse.center.y;
00369         edge_point.x = IMAGE_WIDTH;
00370         for (size_t k=0; k < dirty_areas.size(); k++) {
00371             estirabot_msgs::TraversedEllipses traversedEllipsesMsg;
00372             traversedEllipsesMsg.idx1 = dirty_areas[i].id;
00373             traversedEllipsesMsg.idx2 = edge_idx;
00374             
00375             if ( (k != i) && pointIsBetween(dirty_areas[i].ellipse.center, edge_point, dirty_areas[k].ellipse.center) ) {
00376                 traversedEllipsesMsg.traversedIdxs.push_back(dirty_areas[k].id);
00377             }
00378             result.push_back(traversedEllipsesMsg);
00379         }
00380     }
00381     
00382     return result;
00383 }
00384 
00385 
00386 int32_t EllipsesRepresentation::getNearestEllipse()
00387 {
00388         double min = 10000;
00389         int32_t min_idx = -1;
00390         
00391         for(size_t i=0; i < imageEllipses.size(); i++) {
00392                 double dist = getDistance(currentArmPosition, imageEllipses[i].center);
00393                 if (dist < min) {
00394                         min = dist;
00395                         min_idx = i;
00396                 }
00397         }
00398         
00399         ROS_DEBUG_STREAM("Minimun distance is: " << min);
00400         
00401         return min_idx;
00402 }
00403 
00404 
00405 void EllipsesRepresentation::drawPoints(std::vector< Point2f > img_coords_orig)
00406 {
00408         std::vector< Point2f > img_coords = img_coords_orig;
00409         img_coords.pop_back();
00410         
00411         // both straight and circular cleans
00412         if (img_coords.size() > 0) {
00413                 circle(show_image, img_coords[0], 5, Scalar(255, 0, 0), -1);
00414         }
00415         if (img_coords.size() > 1) {
00416                 circle(show_image, img_coords[1], 5, Scalar(0, 255, 0), -1);
00417                 line(show_image, img_coords[0], img_coords[1], Scalar(0, 255, 0));
00418         }
00419         if (img_coords.size() > 2) {
00420                 circle(show_image, img_coords[2], 5, Scalar(255, 0, 255), -1);
00421                 line(show_image, img_coords[1], img_coords[2], Scalar(255, 0, 255));
00422         }
00423         if (img_coords.size() > 3) {
00424                 circle(show_image, img_coords[3], 5, Scalar(0, 255, 255), -1);
00425                 line(show_image, img_coords[2], img_coords[3], Scalar(0, 255, 255));
00426         }
00427         if (img_coords.size() > 4) {
00428                 circle(show_image, img_coords[4], 5, Scalar(125, 125, 0), -1);
00429                 line(show_image, img_coords[3], img_coords[4], Scalar(125, 125, 0));
00430         }
00431         if (img_coords.size() > 5) {
00432                 circle(show_image, img_coords[5], 5, Scalar(0, 125, 125), -1);
00433                 line(show_image, img_coords[4], img_coords[5], Scalar(0, 125, 125));
00434         }
00435         if (img_coords.size() > 6)  {
00436                 circle(show_image, img_coords[6], 5, Scalar(125, 0, 125), -1);
00437                 line(show_image, img_coords[5], img_coords[6], Scalar(125, 0, 125));
00438         }
00439         if (img_coords.size() > 7) {
00440                 circle(show_image, img_coords[7], 5, Scalar(100, 255, 100), -1);
00441                 line(show_image, img_coords[6], img_coords[7], Scalar(100, 255, 100));
00442         }
00443 }
00444 
00445 
00446 std::vector< size_t > EllipsesRepresentation::getGoodPathThroughAllEllipses(size_t init_ellipse)
00447 {
00448         std::vector< size_t > result;
00449         
00450         std::set<size_t> visited;
00451         
00452         int min_dist, distance;
00453         size_t min_idx, last_idx;
00454         
00455         result.push_back(init_ellipse);
00456         visited.insert(init_ellipse);
00457         last_idx = init_ellipse;
00458         
00459         for(size_t i=1; i < imageEllipses.size(); i++) { // add imageEllipses.size() - 1 ellipses
00460                 ROS_DEBUG_STREAM("Nearest ellipse for " << last_idx);
00461                 min_dist = 10000;
00462                 for(size_t j=0; j < imageEllipses.size(); j++) {
00463                         ROS_DEBUG_STREAM("New j is " << j);
00464                         if (visited.find(j) == visited.end()) { // if it isn't on the result yet
00465                                 distance = getDistance(imageEllipses[last_idx].center, imageEllipses[j].center);
00466                                 ROS_DEBUG_STREAM("Distance " << distance);
00467                                 if (distance < min_dist) {
00468                                         min_dist = distance;
00469                                         min_idx = j;
00470                                 }
00471                         }
00472                 }
00473                 
00474                 result.push_back(min_idx);
00475                 visited.insert(min_idx);
00476                 last_idx = min_idx;
00477                 ROS_DEBUG_STREAM("Nearest ellipse was " << last_idx);
00478         }
00479         
00480         return result;
00481 }
00482 
00483 
00484 std::vector< size_t > EllipsesRepresentation::getGoodPathThroughAllDirtyAreas(std::vector< estirabot_msgs::DirtyArea > dirty_areas)
00485 {
00486     std::vector< size_t > result;
00487     
00488     std::set<size_t> visited;
00489     
00490     int min_dist, distance;
00491     size_t min_idx, last_idx;
00492     
00493     result.push_back(dirty_areas[0].id);
00494     visited.insert(0);
00495     last_idx = 0;
00496     
00497     for(size_t i=1; i < dirty_areas.size(); i++) { // add imageEllipses.size() - 1 ellipses
00498         ROS_DEBUG_STREAM("Nearest ellipse for " << last_idx);
00499         min_dist = 10000;
00500         for(size_t j=0; j < dirty_areas.size(); j++) {
00501             ROS_DEBUG_STREAM("New j is " << j);
00502             if (visited.find(j) == visited.end()) { // if it isn't on the result yet
00503                 distance = getDistance( rosEllipseToRotatedRect(dirty_areas[last_idx].ellipse).center, rosEllipseToRotatedRect(dirty_areas[j].ellipse).center);
00504                 ROS_DEBUG_STREAM("Distance " << distance);
00505                 if (distance < min_dist) {
00506                     min_dist = distance;
00507                     min_idx = j;
00508                 }
00509             }
00510         }
00511         
00512         result.push_back(dirty_areas[min_idx].id);
00513         visited.insert(min_idx);
00514         last_idx = min_idx;
00515         ROS_DEBUG_STREAM("Nearest ellipse was " << last_idx);
00516     }
00517     
00518     return result;
00519 }
00520 
00521 
00522 std::vector< cv::RotatedRect> EllipsesRepresentation::loadEllipsesFromRosMsg(vector< estirabot_msgs::Ellipse > ellipses_msg)
00523 {
00524         vector< RotatedRect > ellipses;
00525         
00526         for(vector<estirabot_msgs::Ellipse>::iterator j=ellipses_msg.begin(); j!=ellipses_msg.end(); ++j) {
00527                 ellipses.push_back(rosEllipseToRotatedRect(*j));
00528         }
00529         
00530         return ellipses;
00531 }
00532 
00533 std::vector< cv::RotatedRect > EllipsesRepresentation::loadEllipsesFromRosMsg(std::vector< estirabot_msgs::DirtyArea > dirty_areas_msg)
00534 {
00535         vector< RotatedRect > ellipses;
00536         
00537         for(vector<estirabot_msgs::DirtyArea>::iterator j=dirty_areas_msg.begin(); j!=dirty_areas_msg.end(); ++j) {
00538                 ellipses.push_back(rosEllipseToRotatedRect(j->ellipse));
00539         }
00540         
00541         return ellipses;
00542 }
00543 
00544 
00545 cv::RotatedRect EllipsesRepresentation::getEllipseFromRosDirtyAreas(std::vector< estirabot_msgs::DirtyArea > dirty_areas, int idx)
00546 {
00547     cv::RotatedRect result;
00548     ROS_DEBUG_STREAM("Looking for " << idx);
00549     for(std::vector<estirabot_msgs::DirtyArea>::iterator dirty_area=dirty_areas.begin(); dirty_area!=dirty_areas.end(); ++dirty_area) {
00550         ROS_DEBUG_STREAM("Dirty area is " << *dirty_area);
00551         if (dirty_area->id == idx) {
00552             result = rosEllipseToRotatedRect(dirty_area->ellipse);
00553             ROS_DEBUG_STREAM("Found!");
00554         }
00555     }
00556     return result;
00557 }
00558 
00559 
00560 std::vector<estirabot_msgs::DirtyArea> EllipsesRepresentation::getRosDirtyAreas()
00561 {
00562     return this->dirtyAreas_;
00563 }
00564 
00565 std::vector<estirabot_msgs::DirtyArea> EllipsesRepresentation::calculateRosDirtyAreas(std::vector< cv::RotatedRect > ellipses)
00566 {
00567         std::vector<estirabot_msgs::DirtyArea> dirty_areas;
00568         estirabot_msgs::DirtyArea dirty_area;
00569         double area, min_width, max_width;
00570         
00571         for (size_t i = 0; i < ellipses.size(); i++) {
00572         dirty_area.id = i;
00573                 dirty_area.ellipse = rotatedRectToRosEllipse(ellipses[i]);
00574                 dirty_area.sparse = ellipsesSparse[i];
00575                 
00576                 area = ellipsesArea[i];
00577                 if (area < small_area_threshold)
00578                         dirty_area.area = 0;
00579                 else if (area < medium_area_threshold)
00580                         dirty_area.area = 1;
00581                 else
00582                         dirty_area.area = 2;
00583                 
00584                 min_width = ellipsesMinWidths[i];
00585                 max_width = ellipsesMaxWidths[i];
00586                 if (max_width < this->max_width_threshold)
00587                         dirty_area.shape = 0;
00588                 else if (min_width < this->min_width_threshold)
00589                         dirty_area.shape = 1;
00590                 else
00591                         dirty_area.shape = 2;
00592                 
00593                 dirty_areas.push_back(dirty_area);
00594         }
00595         
00596         return dirty_areas;
00597 }
00598 
00599 
00600 void EllipsesRepresentation::writeStateToFile(std::string path, 
00601                                               std::vector<estirabot_msgs::DirtyArea> dirty_areas)
00602 {
00603         std::ofstream state_file(path.c_str());
00604         if (state_file.is_open())
00605         {
00606                 state_file << getStateString(dirty_areas);
00607         }
00608         state_file.close();
00609 }
00610 
00611 
00612 std::string EllipsesRepresentation::dirtyAreaToString(estirabot_msgs::DirtyArea dirty_area, int idx)
00613 {
00614         std::stringstream ss;
00615         
00616         ss << "-clean(" << idx << "),";
00617         
00618         if (dirty_area.sparse)
00619                 ss << "sparse(" << idx << "),";
00620         else
00621                 ss << "-sparse(" << idx << "),";
00622         
00623         if (dirty_area.area == 0)
00624                 ss << "smallArea(" << idx << ")";
00625         else if (dirty_area.area == 1)
00626                 ss << "mediumArea(" << idx << ")";
00627         else if (dirty_area.area == 2)
00628                 ss << "bigArea(" << idx << ")";
00629         
00630         // TODO erase a board
00631         /*if (dirty_area.shape == 0)
00632                 ss << "smallDirt(" << idx << "),";
00633         else if (dirty_area.shape == 1)
00634                 ss << "narrowDirt(" << idx << "),";
00635         else (dirty_area.shape == 2)
00636                 ss << "bigDirt(" << idx << "),";
00637         */
00638         
00639         return ss.str();
00640 }
00641 
00642 
00643 std::string EllipsesRepresentation::traversedEllipsesToString(std::vector<estirabot_msgs::TraversedEllipses> traversed_ellipses)
00644 {
00645         std::stringstream ss;
00646         for (size_t i = 0; i < traversed_ellipses.size(); i++) {
00647                 for (size_t j = 0; j < traversed_ellipses[i].traversedIdxs.size(); j++) {
00648                         if (traversed_ellipses[i].idx1 >= 0) {
00649                                 if (this->is_learning) {
00650                                         ss << ", traversed2(" << traversed_ellipses[i].idx1 + this->initial_state_idx << "," << traversed_ellipses[i].traversedIdxs[j] + this->initial_state_idx << ")";
00651                                 }
00652                                 else { 
00653                                         ss << ", traversed(" << traversed_ellipses[i].idx1 + this->initial_state_idx << "," << traversed_ellipses[i].idx2 + this->initial_state_idx << "," << traversed_ellipses[i].traversedIdxs[j] + this->initial_state_idx << ")";
00654                                         // inverse order: traversed(idx2, idx1, traversed)
00655                                         ss << ", traversed(" << traversed_ellipses[i].idx2 + this->initial_state_idx << "," << traversed_ellipses[i].idx1 + this->initial_state_idx << "," << traversed_ellipses[i].traversedIdxs[j] + this->initial_state_idx << ")";
00656                                 }
00657                         }
00658                 }
00659         }
00660         
00661         return ss.str();
00662 }
00663 
00664 
00665 std::string EllipsesRepresentation::dirtyAreasDistancesToString(std::vector< estirabot_msgs::PointsDistanceMsg> distances)
00666 {
00667         std::stringstream ss;
00668         for (size_t i = 0; i < distances.size(); i++) {
00669                 ROS_DEBUG_STREAM("Distance is " << distances[i].distance);
00670                 if (distances[i].distance < near_distance_threshold) {
00671                         ss << ",near(" << distances[i].origIdx + this->initial_state_idx << "," << distances[i].dstIdx + this->initial_state_idx << ")";
00672                         ss << ",near(" << distances[i].dstIdx + this->initial_state_idx << "," << distances[i].origIdx + this->initial_state_idx << ")";
00673                 }
00674         }
00675         return ss.str();
00676 }
00677 
00678 
00679 std::string EllipsesRepresentation::getStateStringOrdered(const std::vector<estirabot_msgs::DirtyArea> dirty_areas)
00680 {
00681     std::stringstream ss;
00682     
00683     std::vector<estirabot_msgs::TraversedEllipses> traversed_ellipses = getTraversedEllipses(dirty_areas);
00684     std::vector< estirabot_msgs::PointsDistanceMsg> distances = distancesBetweenEllipses(dirty_areas);
00685     
00686     if (!this->is_learning) {
00687         ss << "edge(" << this->initial_state_idx - 1 <<  "),";
00688     }
00689     for (size_t i = 0; i < dirty_areas.size(); i++) {
00690         ss << dirtyAreaToString(dirty_areas[i], dirty_areas[i].id + this->initial_state_idx);
00691         if (i + 1 < dirty_areas.size())
00692             ss << ",";
00693     }
00694 
00695     ss << dirtyAreasDistancesToString(distances);
00696 //     if (!this->is_learning) {
00697         ss << traversedEllipsesToString(traversed_ellipses);
00698 //     }
00699     return ss.str();
00700 }
00701 
00702 std::string EllipsesRepresentation::getStateString(const std::vector<estirabot_msgs::DirtyArea> dirty_areas)
00703 {
00704     return getStateStringOrdered(dirty_areas);
00705 }
00706 
00707 
00708 std::vector<estirabot_msgs::DirtyArea> EllipsesRepresentation::orderDirtyAreas(const std::vector<estirabot_msgs::DirtyArea> current, const std::vector<estirabot_msgs::DirtyArea> previous)
00709 {
00710     std::vector<estirabot_msgs::DirtyArea> prev_copy(previous), current_copy(current);
00711     std::vector< estirabot_msgs::DirtyArea > current_with_ids, current_ordered;
00712     int max_id = -1;
00713     
00714 //     for(size_t i = 0; i<previous.size();i++)
00715 //         ROS_INFO_STREAM("Previous " << previous[i]);
00716 //     for(size_t i = 0; i<current.size();i++)
00717 //         ROS_INFO_STREAM("Current " << current[i]);
00718     
00719     while ((prev_copy.size() > 0) && (current_copy.size() > 0)) {
00720         double min_distance = 10000;
00721         std::vector<estirabot_msgs::DirtyArea>::iterator it_previous, it_current, it_previous_max, it_current_max;
00722         for ( it_previous=prev_copy.begin() ; it_previous < prev_copy.end(); it_previous++ ) {
00723             for ( it_current=current_copy.begin() ; it_current < current_copy.end(); it_current++ ) {
00724                 // euclidean distance
00725                 int x_inc = it_previous->ellipse.center.x - it_current->ellipse.center.x;
00726                 int y_inc = it_previous->ellipse.center.y - it_current->ellipse.center.y;
00727                 double distance = sqrt( (x_inc*x_inc) + (y_inc*y_inc) );
00728                 ROS_DEBUG_STREAM("New distance is " << distance << "\nx " << x_inc << "\ny " << y_inc);
00729                 if (distance < min_distance) {
00730                     min_distance = distance;
00731                     it_previous_max = it_previous;
00732                     it_current_max = it_current;
00733                 }
00734             }
00735         }
00736         // Use nearest ellipse id
00737         if (it_previous_max->id > max_id) {
00738             max_id = it_previous_max->id;
00739         }
00740         it_current_max->id = it_previous_max->id;
00741         
00742         // push_back to ordered list, remove from original lists
00743         current_with_ids.push_back(estirabot_msgs::DirtyArea(*it_current_max));
00744         prev_copy.erase(it_previous_max);
00745         current_copy.erase(it_current_max);
00746     }
00747     
00748 //     for(size_t i = 0; i<current_with_ids.size();i++)
00749 //         ROS_INFO_STREAM("Current with ids " << current_with_ids[i]);
00750     // add remaining dirty areas (if any)
00751     if (current_copy.size() > 0) {
00752         for (std::vector<estirabot_msgs::DirtyArea>::iterator it=current_copy.begin() ; it < current_copy.end(); it++ ) {
00753             max_id++;
00754             it->id = max_id;
00755             current_with_ids.push_back(estirabot_msgs::DirtyArea(*it));
00756         }
00757     }
00758     
00759 //     for(size_t i = 0; i<current_with_ids.size();i++)
00760 //         ROS_INFO_STREAM("Current with ids2 " << current_with_ids[i]);
00761     // order dirty areas based on their symbol
00762     while (current_with_ids.size() > 0) {
00763         int min_id = 1000;
00764         std::vector<estirabot_msgs::DirtyArea>::iterator min_it;
00765         for (std::vector<estirabot_msgs::DirtyArea>::iterator it=current_with_ids.begin() ; it < current_with_ids.end(); it++ ) {
00766             if (it->id < min_id) {
00767                 min_id = it->id;
00768                 min_it = it;
00769             }
00770         }
00771                 current_ordered.push_back(estirabot_msgs::DirtyArea(*min_it));
00772         current_with_ids.erase(min_it);
00773     }
00774 //     for(size_t i = 0; i<current_ordered.size();i++)
00775 //         ROS_INFO_STREAM("Current with ordered " << current_ordered[i]);
00776     
00777     return current_ordered;
00778 }
00779 


iri_clean_board
Author(s): David Martinez
autogenerated on Fri Dec 6 2013 23:52:37