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 }