00001 
00009 #include <youbot_overhead_vision/image_calibration.h>
00010 #include <sys/time.h>
00011 #include <math.h>
00012 
00013 using namespace std;
00014 using namespace cv;
00015 
00016 imageCalibration::imageCalibration()
00017 {
00018   count = 0;
00019 
00020 
00021   
00022   blurringFactor = 1;
00023   calibAccuracy = 5;
00024 
00025   seq_num = 0;
00026 
00027   
00028   robotMarkersVect = *(new vector<markerPoints>());
00029   robotMarkersVect.push_back(*(new markerPoints()));
00030   robotMarkersVect[0].numPoints = 0;
00031 
00032   ros::NodeHandle nh;
00033 
00034   imgSub1 = nh.subscribe<sensor_msgs::Image>(OVERHEAD_NORTH, 0, &imageCalibration::imageCallback1, this);
00035   imgSub2 = nh.subscribe<sensor_msgs::Image>(OVERHEAD_SOUTH, 0, &imageCalibration::imageCallback2, this);
00036 
00037   pubImgCal = nh.advertise<sensor_msgs::Image>("/image_calibration/image_cal", 1);
00038   pubRobotPosition = nh.advertise<youbot_overhead_vision::PositionFromCamera>("/image_calibration/position_from_camera",
00039                                                                               1);
00040 
00041   
00042 
00043   nh.getParam("/image_calibration/runFromSimulation", useSim);
00044 
00045   nh.getParam("/image_calibration/floor_cal", filenames[FLOOR]);
00046   nh.getParam("/image_calibration/robot_lb_file", filenames[ROBOT_LEFT_BACK]);
00047   nh.getParam("/image_calibration/robot_rb_file", filenames[ROBOT_RIGHT_BACK]);
00048   nh.getParam("/image_calibration/robot_lf_file", filenames[ROBOT_LEFT_FRONT]);
00049   nh.getParam("/image_calibration/robot_rf_file", filenames[ROBOT_RIGHT_FRONT]);
00050   calTree = new calibTree();
00051 
00052   getCalibration(FLOOR, 255, 255, 255);
00053   getCalibration(ROBOT_RIGHT_BACK, 255, 0, 0);
00054   getCalibration(ROBOT_LEFT_BACK, 0, 255, 0);
00055   getCalibration(ROBOT_LEFT_FRONT, 0, 0, 255);
00056   getCalibration(ROBOT_RIGHT_FRONT, 0, 255, 255);
00057 
00058   string roomBoundaryFileName;
00059   nh.getParam("/image_calibration/room_boundary_map", roomBoundaryFileName);
00060   roomBoundary = cv::imread(roomBoundaryFileName);
00061 
00062   
00063   colors[NOT_SET][0] = (uint8_t)0;
00064   colors[NOT_SET][1] = (uint8_t)0;
00065   colors[NOT_SET][2] = (uint8_t)0;
00066 
00067   lastFrameMidpointX = -SIDE_MARKER_DIST;
00068   lastFrameMidpointY = -SIDE_MARKER_DIST;
00069 
00070   if (useSim)
00071     pastObstImg = *(new cv::Mat(600 - SIM_OVERLAP, 400, CV_8UC3));
00072   else
00073     pastObstImg = *(new cv::Mat(600 - REAL_OVERLAP, 400, CV_8UC3));
00074 
00075   cv::rectangle(pastObstImg, cv::Point(0, 0), cv::Point(pastObstImg.cols, pastObstImg.rows), CV_RGB(255,255,255),
00076                 CV_FILLED);
00077 }
00078 
00079 imageCalibration::~imageCalibration()
00080 {
00081   freerobotVector();
00082 }
00083 
00084 void imageCalibration::getCalibration(int calibType, int calibR, int calibB, int calibG)
00085 {
00086 
00087   string filename = filenames[calibType];
00088   colors[calibType][0] = calibR;
00089   colors[calibType][1] = calibG;
00090   colors[calibType][2] = calibB;
00091 
00092   ifstream calFile(filename.c_str());
00093   YAML::Parser parser(calFile);
00094   YAML::Node doc;
00095   parser.GetNextDocument(doc);
00096 
00097   if ((doc.size() > 0 && calibType != FLOOR) || doc.size() > 1)
00098   {
00099     int max = doc.size();
00100 
00101     
00102     if (calibType == FLOOR)
00103     {
00104       max -= 2;
00105       try
00106       {
00107         doc["blur"] >> blurringFactor;
00108         doc["calib_accuracy"] >> calibAccuracy;
00109       }
00110       catch (YAML::InvalidScalar &)
00111       {
00112         ROS_WARN("The floor file does not have a blurring or accuracy value.  Values are set to defaults");
00113       }
00114     }
00115     
00116     for (int i = 1; i <= max; i++)
00117     {
00118       string aPoint = "Point " + convertInt(i);
00119 
00120       int red, green, blue, camera;
00121       (*(doc.FindValue(aPoint.c_str()))->FindValue("rgb"))[0] >> red;
00122       (*(doc.FindValue(aPoint.c_str()))->FindValue("rgb"))[1] >> green;
00123       (*(doc.FindValue(aPoint.c_str()))->FindValue("rgb"))[2] >> blue;
00124       (*(doc.FindValue(aPoint.c_str()))->FindValue("camera")) >> camera;
00125       calTree->newCalibPoint((uint8_t)red, (uint8_t)green, (uint8_t)blue, camera, calibType);
00126 
00127     }
00128     calTree->orderCalibsByRed();
00129     calTree->createTree();
00130   }
00131   else if (calibType == FLOOR)
00132     ROS_INFO("Floor file did not have proper format. No blur/calibration variables found.");
00133 
00134 }
00135 
00136 void imageCalibration::processImage()
00137 {
00138 
00139   vector<int> ImageXCoords;
00140   vector<int> ImageYCoords;
00141   resetForNextFrame();
00142   ros::NodeHandle nh;
00143 
00144   
00145   for (int x = 0; x < 4; x++)
00146   {
00147     ImageXCoords.push_back(NOT_SET);
00148     ImageYCoords.push_back(NOT_SET);
00149   }
00150 
00151   
00152 
00153   cv_bridge::CvImagePtr * temp1 = new cv_bridge::CvImagePtr(new cv_bridge::CvImage());
00154   cv_bridge::CvImagePtr * temp2 = new cv_bridge::CvImagePtr(new cv_bridge::CvImage());
00155   output_Img1 = *(temp1);
00156   output_Img2 = *(temp2);
00157 
00158   while (raw_Img1->encoding != ENCODING && raw_Img2->encoding != ENCODING)
00159     cout << "Images Not Loaded" << endl;
00160 
00161   raw_Img1->image.copyTo(output_Img1->image);
00162   raw_Img2->image.copyTo(output_Img2->image);
00163 
00164   
00165   cv::Mat * out1 = (new cv::Mat(output_Img1->image.rows / 2, output_Img1->image.cols / 2, output_Img1->image.type()));
00166   cv::Mat * out2 = (new cv::Mat(output_Img2->image.rows / 2, output_Img2->image.cols / 2, output_Img2->image.type()));
00167 
00168   cv::resize(output_Img1->image, *out1, out1->size(), cv::INTER_NEAREST);
00169   cv::resize(output_Img2->image, *out2, out2->size(), cv::INTER_NEAREST);
00170   output_Img1->image = (output_Img1->image)(cv::Rect(0, 0, out1->cols, out1->rows));
00171   output_Img2->image = (output_Img2->image)(cv::Rect(0, 0, out2->cols, out2->rows));
00172 
00173   cv::Mat * cvImg;
00174   if (useSim)
00175     cvImg = new cv::Mat(out1->rows * 2 - SIM_OVERLAP, out1->cols, out1->type());
00176   else
00177     cvImg = new cv::Mat(out1->rows * 2 - REAL_OVERLAP, out1->cols, out1->type());
00178 
00179   cv::Mat roiCvImgBot, roiCvImgTop, roiOut2;
00180   roiCvImgTop = (*cvImg)(cv::Rect(0, 0, out1->cols, out1->rows));
00181   if (useSim)
00182   {
00183     roiCvImgBot = (*cvImg)(cv::Rect(0, out1->rows - SIM_OVERLAP / 2, out2->cols, out2->rows - SIM_OVERLAP / 2));
00184     roiOut2 = (*out2)(cv::Rect(0, SIM_OVERLAP / 2, out2->cols, out2->rows - SIM_OVERLAP / 2));
00185   }
00186   else
00187   {
00188     roiCvImgBot = (*cvImg)(cv::Rect(0, out1->rows - REAL_OVERLAP / 2, out2->cols, out2->rows - REAL_OVERLAP / 2));
00189     roiOut2 = (*out2)(cv::Rect(0, REAL_OVERLAP / 2, out2->cols, out2->rows - REAL_OVERLAP / 2));
00190   }
00191 
00192   cv::Mat roiOut1 = (*out1)(cv::Rect(0, 0, out1->cols, out1->rows));
00193 
00194   roiOut1.copyTo(roiCvImgTop);
00195   roiOut2.copyTo(roiCvImgBot);
00196 
00197   (*cvImg).copyTo(output_Img1->image);
00198 
00199   output_Img1->encoding = ENCODING;
00200   output_Img1->header.seq = seq_num++;
00201   output_Img1->header.stamp = ros::Time::now();
00202   output_Img1->header.frame_id = FRAME_ID;
00203 
00204   
00205 
00206   applyCalib();
00207 
00208   addClusters(&ImageXCoords, &ImageYCoords);
00209 
00210   
00211   int pointsFound = 0;
00212   for (int i = 0; i < (int)ImageXCoords.size(); i++)
00213   {
00214     if (ImageXCoords[i] != NOT_SET)
00215       pointsFound++;
00216   }
00217 
00218   
00219   if (pointsFound == 2 || pointsFound == 3)
00220     extrapolateMarkers(&ImageXCoords, &ImageYCoords);
00221 
00222   
00223   if (ImageXCoords[0] != NOT_SET && ImageXCoords[1] != NOT_SET && ImageXCoords[2] != NOT_SET
00224       && ImageXCoords[3] != NOT_SET)
00225   {
00226 
00227     double heading = atan2((double)ImageYCoords[ROBOT_LEFT_FRONT] - ImageYCoords[ROBOT_LEFT_BACK],
00228                            ImageXCoords[ROBOT_LEFT_FRONT] - ImageXCoords[ROBOT_LEFT_BACK]);
00229 
00230     youbot_overhead_vision::PositionFromCamera pos;
00231     pos.heading = heading;
00232     pos.midpointX = (ImageXCoords[ROBOT_LEFT_FRONT] + ImageXCoords[ROBOT_RIGHT_BACK]) / 2;
00233     pos.midpointY = (ImageYCoords[ROBOT_LEFT_FRONT] + ImageYCoords[ROBOT_RIGHT_BACK]) / 2;
00234 
00235     
00236     lastFrameMidpointX = pos.midpointX;
00237     lastFrameMidpointY = pos.midpointY;
00238 
00239     
00240     removeRobot(ImageXCoords, ImageYCoords, pos.midpointX, pos.midpointY);
00241 
00242     pos.midpointX *= 2;
00243     pos.midpointY *= 2;
00244     pubRobotPosition.publish(pos);
00245   }
00246 
00247   
00248   cv::resize(output_Img1->image, output_Img1->image,
00249              cv::Size(output_Img1->image.cols / 2.0, output_Img1->image.rows / 2.0));
00250   
00251   cv::bitwise_and(roomBoundary, output_Img1->image, output_Img1->image);
00252   
00253   pubImgCal.publish(output_Img1->toImageMsg());
00254 
00255   delete temp1;
00256   delete temp2;
00257   resetForNextFrame();
00258   delete cvImg;
00259   delete out1;
00260   delete out2;
00261 }
00262 
00263 void imageCalibration::imageCallback1(const sensor_msgs::ImageConstPtr& image_msg)
00264 {
00265   ros::Time time = image_msg->header.stamp;
00266   raw_Img1 = cv_bridge::toCvCopy(image_msg, ENCODING);
00267 
00268   
00269   raw_Img1->encoding = ENCODING;
00270   
00271   raw_Img1->header.seq = seq_num++;
00272   
00273   raw_Img1->header.stamp = ros::Time::now();
00274   
00275   raw_Img1->header.frame_id = FRAME_ID;
00276 }
00277 
00278 void imageCalibration::imageCallback2(const sensor_msgs::ImageConstPtr& image_msg)
00279 {
00280   ros::Time time = image_msg->header.stamp;
00281 
00282   raw_Img2 = cv_bridge::toCvCopy(image_msg, ENCODING);
00283 
00284   
00285   raw_Img2->encoding = ENCODING;
00286   
00287   raw_Img2->header.seq = seq_num++;
00288   
00289   raw_Img2->header.stamp = ros::Time::now();
00290   
00291   raw_Img2->header.frame_id = FRAME_ID;
00292 }
00293 
00294 void imageCalibration::applyCalib()
00295 {
00296   const cv::Mat& image = output_Img1->image;
00297 
00298   cv::Mat roiCvImgBot, roiCvImgTop;
00299   if (useSim)
00300   {
00301     roiCvImgBot = image(
00302         cv::Rect(0, output_Img2->image.rows - SIM_OVERLAP / 2, image.cols, output_Img2->image.rows - SIM_OVERLAP / 2));
00303     roiCvImgTop = image(cv::Rect(0, 0, image.cols, output_Img2->image.rows - SIM_OVERLAP / 2));
00304   }
00305   else
00306   {
00307     roiCvImgBot = image(
00308         cv::Rect(0, output_Img2->image.rows - REAL_OVERLAP / 2, image.cols,
00309                  output_Img2->image.rows - REAL_OVERLAP / 2));
00310     roiCvImgTop = image(cv::Rect(0, 0, image.cols, output_Img2->image.rows - REAL_OVERLAP / 2));
00311   }
00312 
00313   cv::blur(image, image, cv::Size(blurringFactor, blurringFactor), cv::Point(-1, -1), cv::BORDER_DEFAULT);
00314 
00315   cv::Mat * imagePtr;
00316   
00317   for (int camera = 1; camera <= 2; camera++)
00318   {
00319     if (camera == NORTH_CAMERA)
00320       imagePtr = &roiCvImgTop;
00321     else
00322       imagePtr = &roiCvImgBot;
00323 
00324     int numBytes = imagePtr->step * imagePtr->rows;
00325     
00326     for (int pixelItt = 0; pixelItt < numBytes; pixelItt += 3)
00327     {
00328       
00329 
00330       int calibType = calTree->parseCalibTree((int)imagePtr->data[pixelItt], (int)imagePtr->data[pixelItt + 1],
00331                                               (int)imagePtr->data[pixelItt + 2], camera, calibAccuracy);
00332 
00333       imagePtr->data[pixelItt] = (uint8_t)colors[calibType][0];
00334       imagePtr->data[pixelItt + 1] = (uint8_t)colors[calibType][1];
00335       imagePtr->data[pixelItt + 2] = (uint8_t)colors[calibType][2];
00336       
00337       if (calibType < FLOOR)
00338       {
00339         int pointX = pixelItt / (output_Img1->image.step);
00340         int pointY = pixelItt - pointX * (output_Img1->image.step);
00341 
00342         if (camera == SOUTH_CAMERA)
00343         {
00344           pointX += roiCvImgTop.rows;
00345         }
00346 
00347         pointY /= 3;
00348         addMarkerPoint(pointX, pointY, calibType);
00349       }
00350     }
00351   }
00352 
00353   
00354   int erosion_size = 1;
00355   cv::Mat element = getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(2 * erosion_size + 1, 2 * erosion_size + 1),
00356                                           cv::Point(erosion_size, erosion_size));
00357   morphologyEx(image, image, cv::MORPH_CLOSE, element);
00358 }
00359 
00360 void imageCalibration::addMarkerPoint(int pointX, int pointY, int calibType)
00361 {
00362 
00363   for (int markerItt = 0; markerItt < (int)robotMarkersVect.size(); markerItt++)
00364   {
00365     
00366 
00367     
00368     if (robotMarkersVect[markerItt].markerType
00369         == calibType&& abs(pointX - robotMarkersVect[markerItt].avgX) < MARKER_CLUSTER_RADIUS && abs(pointY - robotMarkersVect[markerItt].avgY) < MARKER_CLUSTER_RADIUS){
00370 
00371     
00372 
00373     robotMarkersVect[markerItt].avgX = (robotMarkersVect[markerItt].avgX * robotMarkersVect[markerItt].numPoints + pointX) /(robotMarkersVect[markerItt].numPoints + 1);
00374     robotMarkersVect[markerItt].avgY = (robotMarkersVect[markerItt].avgY * robotMarkersVect[markerItt].numPoints + pointY) /(robotMarkersVect[markerItt].numPoints + 1);
00375 
00376     robotMarkersVect[markerItt].numPoints++;
00377     return;
00378   }
00379   
00380   else if(robotMarkersVect[markerItt].numPoints == 0)
00381   {
00382 
00383     robotMarkersVect[markerItt].numPoints ++;
00384     robotMarkersVect[markerItt].avgX = pointX;
00385     robotMarkersVect[markerItt].avgY = pointY;
00386     robotMarkersVect[markerItt].markerType = calibType;
00387 
00388     
00389     robotMarkersVect.push_back(*(new markerPoints()));
00390     robotMarkersVect[markerItt + 1].numPoints = 0;
00391     robotMarkersVect[markerItt + 1].avgX = (-1 * MARKER_CLUSTER_RADIUS - 1);
00392     robotMarkersVect[markerItt + 1].avgY = (-1 * MARKER_CLUSTER_RADIUS - 1);
00393     robotMarkersVect[markerItt + 1].markerType = NOT_SET;
00394     return;
00395   }
00396 }
00397 }
00398 
00399 void imageCalibration::addClusters(vector<int> *ImageXCoords, vector<int> *ImageYCoords)
00400 {
00401 
00402   
00403   for (int itt = 0; itt < (int)robotMarkersVect.size(); itt++)
00404   {
00405     if (robotMarkersVect[itt].numPoints < MIN_MARKER_PIXELS)
00406     {
00407       robotMarkersVect.erase(robotMarkersVect.begin() + itt);
00408       itt--;
00409     }
00410 
00411   }
00412 
00413   
00414   int highestProb[4][2];
00415   for (int clearItt = 0; clearItt < 4; clearItt++)
00416   {
00417     highestProb[clearItt][0] = -1;
00418     highestProb[clearItt][1] = -1;
00419 
00420   }
00421 
00422   
00423 
00424   for (int markerItt = 0; markerItt < (int)robotMarkersVect.size(); markerItt++)
00425   {
00426     int probCount = 0;
00427     for (int markerColor = 0; markerColor < FLOOR; markerColor++)
00428     {
00429       bool probIncreased = false;
00430 
00431       
00432       for (int comparisonItt = 0; (!probIncreased) && comparisonItt < (int)robotMarkersVect.size(); comparisonItt++)
00433       {
00434         if (robotMarkersVect[comparisonItt].markerType == markerColor)
00435         {
00436           int dist = pow(
00437               pow((double)robotMarkersVect[markerItt].avgX - robotMarkersVect[comparisonItt].avgX, 2)
00438                   + pow((double)robotMarkersVect[markerItt].avgY - robotMarkersVect[comparisonItt].avgY, 2),
00439               .5);
00440 
00441           
00442           if (abs(dist - SIDE_MARKER_DIST) < MARKER_ACCURACY || abs(dist - FRONT_MARKER_DIST) < MARKER_ACCURACY
00443               || abs(dist - DIAG_MARKER_DIST) < MARKER_ACCURACY)
00444           {
00445             probCount++;
00446             probIncreased = true;
00447           }
00448         }
00449       }
00450     }
00451 
00452     
00453     int distToMid = pow(
00454         pow((double)robotMarkersVect[markerItt].avgX - lastFrameMidpointX, 2)
00455             + pow((double)robotMarkersVect[markerItt].avgY - lastFrameMidpointY, 2),
00456         .5);
00457     if (abs(distToMid - DIAG_MARKER_DIST / 2) < MARKER_ACCURACY)
00458     {
00459       probCount = probCount + 2;
00460     }
00461 
00462     
00463     int markerType = robotMarkersVect[markerItt].markerType;
00464 
00465     if (highestProb[markerType][1] < probCount
00466         || (highestProb[markerType][1] == probCount
00467             && robotMarkersVect[highestProb[markerType][0]].numPoints < robotMarkersVect[markerItt].numPoints))
00468     {
00469       highestProb[markerType][0] = markerItt;
00470       highestProb[markerType][1] = probCount;
00471     }
00472   }
00473 
00474   
00475   
00476   bool pointRemoved = false;
00477   for (int i = 0; i < 4 && (!pointRemoved); i++)
00478   {
00479     for (int j = i + 1; j < 4 && (!pointRemoved); j++)
00480     {
00481       if (highestProb[j][1] >= 1 && highestProb[i][1] >= 1)
00482       {
00483         int dist = pow(
00484             pow((double)robotMarkersVect[highestProb[i][0]].avgX - robotMarkersVect[highestProb[j][0]].avgX, 2)
00485                 + pow((double)robotMarkersVect[highestProb[i][0]].avgY - robotMarkersVect[highestProb[j][0]].avgY, 2),
00486             .5);
00487         
00488 
00489         if ((j == (i + 2) % 4 && abs(dist - SIDE_MARKER_DIST) > MARKER_ACCURACY)
00490             || (j == (5 - i) % 4 && abs(dist - FRONT_MARKER_DIST) > MARKER_ACCURACY)
00491             || (j == (3 - i) % 4 && abs(dist - DIAG_MARKER_DIST) > MARKER_ACCURACY))
00492         {
00493           int distiToMid = pow(
00494               pow((double)robotMarkersVect[highestProb[i][0]].avgX - lastFrameMidpointX, 2)
00495                   + pow((double)robotMarkersVect[highestProb[i][0]].avgY - lastFrameMidpointY, 2),
00496               .5);
00497           int distjToMid = pow(
00498               pow((double)robotMarkersVect[highestProb[j][0]].avgX - lastFrameMidpointX, 2)
00499                   + pow((double)robotMarkersVect[highestProb[j][0]].avgY - lastFrameMidpointY, 2),
00500               .5);
00501           
00502           if (abs(distiToMid - DIAG_MARKER_DIST / 2) > abs(distjToMid - DIAG_MARKER_DIST / 2))
00503           {
00504             robotMarkersVect.erase(robotMarkersVect.begin() + highestProb[i][0]);
00505             pointRemoved = true;
00506           }
00507           else
00508           {
00509             robotMarkersVect.erase(robotMarkersVect.begin() + highestProb[j][0]);
00510             pointRemoved = true;
00511           }
00512         }
00513       }
00514     }
00515   }
00516 
00517   
00518   if (pointRemoved)
00519   {
00520     addClusters(ImageXCoords, ImageYCoords);
00521     return;
00522   }
00523   else
00524   {
00525     int threshold = 1;
00526     for (int itt = 0; itt < 4; itt++)
00527     {
00528       if (highestProb[itt][0] > -1 && highestProb[itt][1] >= threshold)
00529       {
00530         (*ImageXCoords)[itt] = robotMarkersVect[highestProb[itt][0]].avgX;
00531         (*ImageYCoords)[itt] = robotMarkersVect[highestProb[itt][0]].avgY;
00532       }
00533       else
00534       {
00535         (*ImageXCoords)[itt] = NOT_SET;
00536         (*ImageYCoords)[itt] = NOT_SET;
00537       }
00538     }
00539 
00540   }
00541 }
00542 
00543 bool imageCalibration::extrapolateMarkers(vector<int> *ImageXCoords, vector<int> *ImageYCoords)
00544 {
00545 
00546   vector<int> * xCoords = ImageXCoords;
00547   vector<int> * yCoords = ImageYCoords;
00548 
00549   double heading;
00550   
00551   if ((*xCoords)[ROBOT_LEFT_FRONT] != NOT_SET && (*xCoords)[ROBOT_RIGHT_FRONT] != NOT_SET)
00552   {
00553     heading = atan2((double)(*yCoords)[ROBOT_LEFT_FRONT] - (*yCoords)[ROBOT_RIGHT_FRONT],
00554                     (*xCoords)[ROBOT_LEFT_FRONT] - (*xCoords)[ROBOT_RIGHT_FRONT]) - PI / 2;
00555 
00556     if ((*xCoords)[ROBOT_LEFT_BACK] == NOT_SET)
00557     {
00558       (*xCoords)[ROBOT_LEFT_BACK] = (*xCoords)[ROBOT_LEFT_FRONT] - SIDE_MARKER_DIST * cos(heading);
00559       (*yCoords)[ROBOT_LEFT_BACK] = (*yCoords)[ROBOT_LEFT_FRONT] - SIDE_MARKER_DIST * sin(heading);
00560     }
00561     if ((*xCoords)[ROBOT_RIGHT_BACK] == NOT_SET)
00562     {
00563       (*xCoords)[ROBOT_RIGHT_BACK] = (*xCoords)[ROBOT_RIGHT_FRONT] - SIDE_MARKER_DIST * cos(heading);
00564       (*yCoords)[ROBOT_RIGHT_BACK] = (*yCoords)[ROBOT_RIGHT_FRONT] - SIDE_MARKER_DIST * sin(heading);
00565     }
00566     return true;
00567   }
00568   
00569   else if ((*xCoords)[ROBOT_LEFT_BACK] != NOT_SET && (*xCoords)[ROBOT_RIGHT_BACK] != NOT_SET)
00570   {
00571     heading = atan2((double)(*yCoords)[ROBOT_LEFT_BACK] - (*yCoords)[ROBOT_RIGHT_BACK],
00572                     (*xCoords)[ROBOT_LEFT_BACK] - (*xCoords)[ROBOT_RIGHT_BACK]) - PI / 2;
00573 
00574     if ((*xCoords)[ROBOT_LEFT_FRONT] == NOT_SET)
00575     {
00576       (*xCoords)[ROBOT_LEFT_FRONT] = (*xCoords)[ROBOT_LEFT_BACK] + SIDE_MARKER_DIST * cos(heading);
00577       (*yCoords)[ROBOT_LEFT_FRONT] = (*yCoords)[ROBOT_LEFT_BACK] + SIDE_MARKER_DIST * sin(heading);
00578     }
00579     if ((*xCoords)[ROBOT_RIGHT_FRONT] == NOT_SET)
00580     {
00581       (*xCoords)[ROBOT_RIGHT_FRONT] = (*xCoords)[ROBOT_RIGHT_BACK] + SIDE_MARKER_DIST * cos(heading);
00582       (*yCoords)[ROBOT_RIGHT_FRONT] = (*yCoords)[ROBOT_RIGHT_BACK] + SIDE_MARKER_DIST * sin(heading);
00583     }
00584     return true;
00585   }
00586   
00587   else if ((*xCoords)[ROBOT_LEFT_FRONT] != NOT_SET && (*xCoords)[ROBOT_LEFT_BACK] != NOT_SET)
00588   {
00589     heading = atan2((double)(*yCoords)[ROBOT_LEFT_FRONT] - (*yCoords)[ROBOT_LEFT_BACK],
00590                     (*xCoords)[ROBOT_LEFT_FRONT] - (*xCoords)[ROBOT_LEFT_BACK]);
00591     if ((*xCoords)[ROBOT_RIGHT_FRONT] == NOT_SET)
00592     {
00593       (*xCoords)[ROBOT_RIGHT_FRONT] = (*xCoords)[ROBOT_LEFT_FRONT] + FRONT_MARKER_DIST * cos(heading - PI / 2);
00594       (*yCoords)[ROBOT_RIGHT_FRONT] = (*yCoords)[ROBOT_LEFT_FRONT] + FRONT_MARKER_DIST * sin(heading - PI / 2);
00595     }
00596     if ((*xCoords)[ROBOT_RIGHT_BACK] == NOT_SET)
00597     {
00598       (*xCoords)[ROBOT_RIGHT_BACK] = (*xCoords)[ROBOT_LEFT_BACK] + FRONT_MARKER_DIST * cos(heading - PI / 2);
00599       (*yCoords)[ROBOT_RIGHT_BACK] = (*yCoords)[ROBOT_LEFT_BACK] + FRONT_MARKER_DIST * sin(heading - PI / 2);
00600     }
00601     return true;
00602   }
00603   
00604   else if ((*xCoords)[ROBOT_RIGHT_FRONT] != NOT_SET && (*xCoords)[ROBOT_RIGHT_BACK] != NOT_SET)
00605   {
00606     heading = atan2((double)(*yCoords)[ROBOT_RIGHT_FRONT] - (*yCoords)[ROBOT_RIGHT_BACK],
00607                     (*xCoords)[ROBOT_RIGHT_FRONT] - (*xCoords)[ROBOT_RIGHT_BACK]);
00608     if ((*xCoords)[ROBOT_LEFT_FRONT] == NOT_SET)
00609     {
00610       (*xCoords)[ROBOT_LEFT_FRONT] = (*xCoords)[ROBOT_RIGHT_FRONT] + FRONT_MARKER_DIST * cos(heading + PI / 2);
00611       (*yCoords)[ROBOT_LEFT_FRONT] = (*yCoords)[ROBOT_RIGHT_FRONT] + FRONT_MARKER_DIST * sin(heading + PI / 2);
00612     }
00613     if ((*xCoords)[ROBOT_LEFT_BACK] == NOT_SET)
00614     {
00615       (*xCoords)[ROBOT_LEFT_BACK] = (*xCoords)[ROBOT_RIGHT_BACK] + FRONT_MARKER_DIST * cos(heading + PI / 2);
00616       (*yCoords)[ROBOT_LEFT_BACK] = (*yCoords)[ROBOT_RIGHT_BACK] + FRONT_MARKER_DIST * sin(heading + PI / 2);
00617     }
00618     return true;
00619   }
00620   
00621   else if ((*xCoords)[ROBOT_LEFT_FRONT] != NOT_SET && (*xCoords)[ROBOT_RIGHT_BACK] != NOT_SET)
00622   {
00623     heading = atan2((double)(*yCoords)[ROBOT_LEFT_FRONT] - (*yCoords)[ROBOT_RIGHT_BACK],
00624                     (*xCoords)[ROBOT_LEFT_FRONT] - (*xCoords)[ROBOT_RIGHT_BACK])
00625         - atan((double)FRONT_MARKER_DIST / (double)SIDE_MARKER_DIST);
00626     if ((*xCoords)[ROBOT_RIGHT_FRONT] == NOT_SET)
00627     {
00628       (*xCoords)[ROBOT_RIGHT_FRONT] = (*xCoords)[ROBOT_RIGHT_BACK] + SIDE_MARKER_DIST * cos(heading);
00629       (*yCoords)[ROBOT_RIGHT_FRONT] = (*yCoords)[ROBOT_RIGHT_BACK] + SIDE_MARKER_DIST * sin(heading);
00630     }
00631     if ((*xCoords)[ROBOT_LEFT_BACK] == NOT_SET)
00632     {
00633       (*xCoords)[ROBOT_LEFT_BACK] = (*xCoords)[ROBOT_LEFT_FRONT] - SIDE_MARKER_DIST * cos(heading);
00634       (*yCoords)[ROBOT_LEFT_BACK] = (*yCoords)[ROBOT_LEFT_FRONT] - SIDE_MARKER_DIST * sin(heading);
00635     }
00636     return true;
00637   }
00638   else if ((*xCoords)[ROBOT_RIGHT_FRONT] != NOT_SET && (*xCoords)[ROBOT_LEFT_BACK] != NOT_SET)
00639   {
00640     heading = atan2((double)((*yCoords)[ROBOT_RIGHT_FRONT] - (*yCoords)[ROBOT_LEFT_BACK]),
00641                     ((*xCoords)[ROBOT_RIGHT_FRONT] - (*xCoords)[ROBOT_LEFT_BACK]))
00642         + atan((double)FRONT_MARKER_DIST / (double)SIDE_MARKER_DIST);
00643 
00644     if ((*xCoords)[ROBOT_LEFT_FRONT] == NOT_SET)
00645     {
00646       (*xCoords)[ROBOT_LEFT_FRONT] = (*xCoords)[ROBOT_LEFT_BACK] + SIDE_MARKER_DIST * cos(heading);
00647       (*yCoords)[ROBOT_LEFT_FRONT] = (*yCoords)[ROBOT_LEFT_BACK] + SIDE_MARKER_DIST * sin(heading);
00648     }
00649     if ((*xCoords)[ROBOT_RIGHT_BACK] == NOT_SET)
00650     {
00651       (*xCoords)[ROBOT_RIGHT_BACK] = (*xCoords)[ROBOT_RIGHT_FRONT] - SIDE_MARKER_DIST * cos(heading);
00652       (*yCoords)[ROBOT_RIGHT_BACK] = (*yCoords)[ROBOT_RIGHT_FRONT] - SIDE_MARKER_DIST * sin(heading);
00653     }
00654     return true;
00655   }
00656   else
00657   {
00658     return false;
00659   }
00660 
00661 }
00662 
00663 void imageCalibration::removeRobot(vector<int> xCoords, vector<int> yCoords, int xpos, int ypos)
00664 {
00665   cv::Mat cvImg = output_Img1->image;
00666   int minDstIndex;
00667 
00668   vector<int> outerxCoords;
00669   vector<int> outeryCoords;
00670 
00671   float heading = atan2((double)yCoords[ROBOT_LEFT_FRONT] - yCoords[ROBOT_LEFT_BACK],
00672                         xCoords[ROBOT_LEFT_FRONT] - xCoords[ROBOT_LEFT_BACK]);
00673   float theta;
00674   float l;
00675 
00676   
00677   theta = heading + atan((float)(LEFT_EXTENDED / 3.0) / (float)(FRONT_EXTENDED / 3.0));
00678   l = sqrt(pow((LEFT_EXTENDED / 3.0), 2) + pow((FRONT_EXTENDED / 3.0), 2));
00679   outerxCoords.push_back((int)(yCoords[ROBOT_LEFT_FRONT] + l * sin(theta)));
00680   outeryCoords.push_back((int)(xCoords[ROBOT_LEFT_FRONT] + l * cos(theta)));
00681 
00682   
00683   theta = heading - atan((float)(RIGHT_EXTENDED / 3.0) / (float)(FRONT_EXTENDED / 3.0));
00684   l = sqrt(pow((RIGHT_EXTENDED / 3.0), 2) + pow((FRONT_EXTENDED / 3.0), 2));
00685   outerxCoords.push_back((int)(yCoords[ROBOT_RIGHT_FRONT] + l * sin(theta)));
00686   outeryCoords.push_back((int)(xCoords[ROBOT_RIGHT_FRONT] + l * cos(theta)));
00687 
00688   
00689   theta = heading + 3.14159 - atan((float)(LEFT_EXTENDED / 3.0) / (float)(BACK_EXTENDED / 3.0));
00690   l = sqrt(pow((LEFT_EXTENDED / 3.0), 2) + pow((BACK_EXTENDED / 3.0), 2));
00691   outerxCoords.push_back((int)(yCoords[ROBOT_LEFT_BACK] + l * sin(theta)));
00692   outeryCoords.push_back((int)(xCoords[ROBOT_LEFT_BACK] + l * cos(theta)));
00693 
00694   
00695   theta = heading + 3.14159 + atan((float)(RIGHT_EXTENDED / 3.0) / (float)(BACK_EXTENDED / 3.0));
00696   l = sqrt(pow((RIGHT_EXTENDED / 3.0), 2) + pow((BACK_EXTENDED / 3.0), 2));
00697   outerxCoords.push_back((int)(yCoords[ROBOT_RIGHT_BACK] + l * sin(theta)));
00698   outeryCoords.push_back((int)(xCoords[ROBOT_RIGHT_BACK] + l * cos(theta)));
00699 
00700   cv::Point points[4];
00701   points[0].x = outerxCoords[0];
00702   points[0].y = outeryCoords[0];
00703   points[1].x = outerxCoords[1];
00704   points[1].y = outeryCoords[1];
00705   points[2].x = outerxCoords[3];
00706   points[2].y = outeryCoords[3];
00707   points[3].x = outerxCoords[2];
00708   points[3].y = outeryCoords[2];
00709 
00710   cv::fillConvexPoly(cvImg, points, 4, cv::Scalar(0, 0, 0));
00711 
00712   
00713   vector<cv::RotatedRect> minRect = findBoundingBox(cvImg, xpos, ypos, &minDstIndex);
00714 
00715   if (minRect.size() > 0)
00716   {
00717     applyBoundingBox(&cvImg, minRect[minDstIndex]);
00718   }
00719   
00720   
00721   else
00722   {
00723     outerxCoords.clear();
00724     outeryCoords.clear();
00725 
00726     
00727     theta = heading + atan((float)LEFT_EXTENDED / (float)FRONT_EXTENDED);
00728     l = sqrt(pow((double)LEFT_EXTENDED, 2) + pow((double)FRONT_EXTENDED, 2));
00729     outerxCoords.push_back((int)(yCoords[ROBOT_LEFT_FRONT] + l * sin(theta)));
00730     outeryCoords.push_back((int)(xCoords[ROBOT_LEFT_FRONT] + l * cos(theta)));
00731 
00732     
00733     theta = heading - atan((float)RIGHT_EXTENDED / (float)FRONT_EXTENDED);
00734     l = sqrt(pow((double)RIGHT_EXTENDED, 2) + pow((double)FRONT_EXTENDED, 2));
00735     outerxCoords.push_back((int)(yCoords[ROBOT_RIGHT_FRONT] + l * sin(theta)));
00736     outeryCoords.push_back((int)(xCoords[ROBOT_RIGHT_FRONT] + l * cos(theta)));
00737 
00738     
00739     theta = heading + 3.14159 - atan((float)LEFT_EXTENDED / (float)BACK_EXTENDED);
00740     l = sqrt(pow((double)LEFT_EXTENDED, 2) + pow((double)BACK_EXTENDED, 2));
00741     outerxCoords.push_back((int)(yCoords[ROBOT_LEFT_BACK] + l * sin(theta)));
00742     outeryCoords.push_back((int)(xCoords[ROBOT_LEFT_BACK] + l * cos(theta)));
00743 
00744     
00745     theta = heading + 3.14159 + atan((float)RIGHT_EXTENDED / (float)BACK_EXTENDED);
00746     l = sqrt(pow((double)RIGHT_EXTENDED, 2) + pow((double)BACK_EXTENDED, 2));
00747     outerxCoords.push_back((int)(yCoords[ROBOT_RIGHT_BACK] + l * sin(theta)));
00748     outeryCoords.push_back((int)(xCoords[ROBOT_RIGHT_BACK] + l * cos(theta)));
00749 
00750     cv::Point points[4];
00751     points[0].x = outerxCoords[0];
00752     points[0].y = outeryCoords[0];
00753     points[1].x = outerxCoords[1];
00754     points[1].y = outeryCoords[1];
00755     points[2].x = outerxCoords[3];
00756     points[2].y = outeryCoords[3];
00757     points[3].x = outerxCoords[2];
00758     points[3].y = outeryCoords[2];
00759 
00760     
00761     cv::fillConvexPoly(cvImg, points, 4, cv::Scalar(251, 144, 2));
00762 
00763     int numBytes = cvImg.step * cvImg.rows;
00764 
00765     
00766     for (int pixelItt = 0; pixelItt < numBytes; pixelItt += 3)
00767     {
00768       if (cvImg.data[pixelItt] != 251 && cvImg.data[pixelItt + 1] != 144 && cvImg.data[pixelItt + 2] != 2)
00769       {
00770         pastObstImg.data[pixelItt] = cvImg.data[pixelItt];
00771         pastObstImg.data[pixelItt + 1] = cvImg.data[pixelItt + 1];
00772         pastObstImg.data[pixelItt + 2] = cvImg.data[pixelItt + 2];
00773       }
00774       else
00775       {
00776         cvImg.data[pixelItt] = pastObstImg.data[pixelItt];
00777         cvImg.data[pixelItt + 1] = pastObstImg.data[pixelItt + 1];
00778         cvImg.data[pixelItt + 2] = pastObstImg.data[pixelItt + 2];
00779       }
00780     }
00781   }
00782 
00783 }
00784 
00785 vector<cv::RotatedRect> imageCalibration::findBoundingBox(cv::Mat image, int xpos, int ypos, int *minDstIndex)
00786 {
00787   cv::Mat imgCopy;
00788 
00789   cv::cvtColor(image, imgCopy, CV_BGR2GRAY);
00790   cv::blur(imgCopy, imgCopy, cv::Size(3, 3));
00791 
00792   vector<vector<cv::Point> > contours;
00793 
00794   
00795   cv::threshold(imgCopy, imgCopy, 60, 255, cv::THRESH_BINARY);
00796 
00797   cv::Mat element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3), cv::Point(1, 1));
00798   cv::morphologyEx(imgCopy, imgCopy, cv::MORPH_CLOSE, element);
00799   element = cv::getStructuringElement(cv::MORPH_RECT, cv::Size(3, 3), cv::Point(1, 1));
00800   cv::morphologyEx(imgCopy, imgCopy, cv::MORPH_OPEN, element);
00801 
00802   
00803   cv::findContours(imgCopy, contours, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, cv::Point(0, 0));
00804 
00805   
00806   vector<cv::RotatedRect> minRect(contours.size());
00807 
00808   for (unsigned int i = 0; i < contours.size(); i++)
00809   {
00810     minRect[i] = cv::minAreaRect(cv::Mat(contours[i]));
00811   }
00812 
00813   
00814   unsigned int i = 0;
00815   float minDst = 999999;
00816   int minIndex = 0;
00817   while (i < minRect.size())
00818   {
00819     float width = minRect[i].size.width;
00820     float length = minRect[i].size.height;
00821 
00822     if (length < width)
00823     {
00824       float temp = width;
00825       width = length;
00826       length = temp;
00827     }
00828 
00829     int xbox = minRect[i].center.y;
00830     int ybox = minRect[i].center.x;
00831 
00832     float dst = sqrt(pow((double)xpos - xbox, 2) + pow((double)ypos - ybox, 2));
00833 
00834     if (!(width > MIN_BOUND_WIDTH && width < MAX_BOUND_WIDTH && length > MIN_BOUND_LENGTH && length < MAX_BOUND_LENGTH)
00835         || dst > DST_BOUND_THRESH)
00836       minRect.erase(minRect.begin() + i);
00837     else
00838     {
00839       if (dst < minDst)
00840       {
00841         minDst = dst;
00842         minIndex = i;
00843       }
00844       i++;
00845     }
00846   }
00847   *minDstIndex = minIndex;
00848 
00849   return minRect;
00850 }
00851 
00852 void imageCalibration::applyBoundingBox(cv::Mat *image, cv::RotatedRect rect)
00853 {
00854   cv::Point2f rectPoints[4];
00855   rect.size.width += 8;
00856   rect.size.height += 8;
00857   rect.points(rectPoints);
00858   cv::Point rectPointsConverted[4];
00859   for (int i = 0; i < 4; i++)
00860   {
00861     rectPointsConverted[i].x = (int)rectPoints[i].x;
00862     rectPointsConverted[i].y = (int)rectPoints[i].y;
00863   }
00864   cv::fillConvexPoly(*image, rectPointsConverted, 4, cv::Scalar(255, 255, 255));
00865 }
00866 
00867 string imageCalibration::convertInt(int number)
00868 {
00869   stringstream ss; 
00870   ss << number; 
00871   return ss.str(); 
00872 }
00873 
00874 void imageCalibration::resetForNextFrame()
00875 {
00876   
00877   freerobotVector();
00878   
00879   robotMarkersVect = *(new vector<markerPoints>());
00880   robotMarkersVect.push_back(*(new markerPoints()));
00881   robotMarkersVect[0].numPoints = 0;
00882 }
00883 
00884 void imageCalibration::freerobotVector()
00885 {
00886   for (int x = 0; x < (int)robotMarkersVect.size(); x++)
00887   {
00888     robotMarkersVect.erase(robotMarkersVect.begin() + x);
00889   }
00890 }
00891 
00892 int main(int argc, char** argv)
00893 {
00894   
00895   ros::init(argc, argv, "image_calibration");
00896 
00897   imageCalibration * dispPtr = new imageCalibration();
00898 
00902   ros::Rate loop_rate(20);
00903   while (ros::ok())
00904   {
00905     if (dispPtr->raw_Img1 != NULL && dispPtr->raw_Img2 != NULL)
00906     {
00907       dispPtr->processImage();
00908     }
00909     ros::spinOnce();
00910     loop_rate.sleep();
00911   }
00912 
00913   return (0);
00914 }