00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028 #include <srs_env_model_percp/bb_estimator/funcs.h>
00029 #include <srs_env_model_percp/services_list.h>
00030 #include <srs_env_model_percp/topics_list.h>
00031
00032 #include <algorithm>
00033
00034 #include <message_filters/sync_policies/approximate_time.h>
00035 #include <message_filters/cache.h>
00036
00037 #include <tf/transform_listener.h>
00038
00039 using namespace cv;
00040 using namespace sensor_msgs;
00041 using namespace message_filters;
00042
00043
00044 namespace srs_env_model_percp
00045 {
00046
00047
00048
00049
00050
00051 extern message_filters::Cache<Image> depthCache;
00052 extern message_filters::Cache<PointCloud2> pointCloudCache;
00053 extern message_filters::Cache<CameraInfo> camInfoCache;
00054
00055
00056 extern std::string camFrameId;
00057 extern std::string sceneFrameId;
00058
00059
00060 extern int subVariant;
00061
00062
00063 extern tf::TransformListener *tfListener;
00064
00065
00066
00067 extern int outliersPercent;
00068
00069
00070 extern int samplingPercent;
00071
00072
00073
00074 extern double sidesRatio;
00075
00076
00077 extern int estimationMode;
00078
00079
00080
00081
00082
00083
00084 Point3f backProject(Point2i p, float z, float fx, float fy)
00085 {
00086 return Point3f((p.x * z) / fx, (p.y * z) / fy, z);
00087 }
00088
00089
00090
00091
00092
00093
00094 Point2i fwdProject(Point3f p, float fx, float fy, float cx, float cy)
00095 {
00096 return Point2i(int(p.x * fx / p.z + cx + 0.5), int(p.y * fy / p.z + cy + 0.5));
00097 }
00098
00099
00100
00101
00102
00103
00104 bool calcStats(Mat &m, float *mean, float *stdDev)
00105 {
00106
00107
00108
00109 Mat negMask = m <= 0;
00110 Mat infMask = m > 20;
00111 Mat knownMask = ((negMask + infMask) == 0);
00112
00113
00114
00115
00116 int rowSamples = knownMask.rows * (samplingPercent / 100.0);
00117 int columnSamples = knownMask.cols * (samplingPercent / 100.0);
00118 int samplingStepY = max(rowSamples, 1);
00119 int samplingStepX = max(columnSamples, 1);
00120
00121
00122 for(int y = 0; y < knownMask.rows; y++) {
00123 if(y % samplingStepY != 0) {
00124 for(int x = 0; x < knownMask.cols; x++) {
00125 if(x % samplingStepX != 0) {
00126 knownMask.at<uchar>(y, x) = 0;
00127 }
00128 }
00129 }
00130 }
00131
00132
00133 Scalar meanS, stdDevS;
00134 float meanValue, stdDevValue;
00135 meanStdDev(m, meanS, stdDevS, knownMask);
00136 meanValue = meanS[0];
00137 stdDevValue = stdDevS[0];
00138
00139
00140
00141 if(meanValue == 0 && stdDevValue == 0) {
00142 ROS_WARN("No depth information available in the region of interest");
00143 return false;
00144 }
00145
00146
00147 int knownCount = sum(knownMask * (1.0/255.0))[0];
00148 int outliersCount = (knownCount * outliersPercent) / 100;
00149
00150
00151
00152 if((knownCount - outliersCount) > 0) {
00153
00154
00155 Mat mMeanRel = abs(m - meanValue);
00156
00157
00158
00159
00160 vector<Point3f> outliers;
00161
00162
00163 float currMin = 0;
00164 int currMinIndex = 0;
00165
00166
00167
00168 for(int y = 0; y < mMeanRel.rows; y++) {
00169 for(int x = 0; x < mMeanRel.cols; x++) {
00170 if(knownMask.at<uchar>(y, x)
00171 && (mMeanRel.at<float>(y, x) > currMin || (int)outliers.size() < outliersCount)) {
00172
00173 Point3f outlier(x, y, mMeanRel.at<float>(y, x));
00174
00175
00176 if((int)outliers.size() < outliersCount) {
00177 outliers.push_back(outlier);
00178 }
00179
00180
00181 else {
00182 outliers.erase(outliers.begin() + currMinIndex);
00183 outliers.insert(outliers.begin() + currMinIndex, outlier);
00184 }
00185
00186
00187 float min = 100;
00188 int minIndex = 0;
00189 for(unsigned int i = 0; i < outliers.size(); i++) {
00190 if(outliers[i].z < min) {
00191 min = outliers[i].z;
00192 minIndex = i;
00193 }
00194 }
00195 currMin = min;
00196 currMinIndex = minIndex;
00197 }
00198 }
00199 }
00200
00201
00202 for(unsigned int i = 0; i < outliers.size(); i++) {
00203 knownMask.at<uchar>(outliers[i].y, outliers[i].x) = 0;
00204 }
00205
00206
00207 meanStdDev(m, meanS, stdDevS, knownMask);
00208 meanValue = meanS[0];
00209 stdDevValue = stdDevS[0];
00210 }
00211
00212 *mean = meanValue;
00213 *stdDev = stdDevValue;
00214
00215
00216 if(DEBUG) {
00217
00218 double min, max;
00219 minMaxLoc(m, &min, &max, 0, 0, knownMask);
00220
00221
00222 std::cout << "DEPTH STATISTICS "
00223 << "- Mean: " << *mean << ", StdDev: " << *stdDev
00224 << ", Min: " << min << ", Max: " << max << std::endl;
00225 }
00226
00227 return true;
00228 }
00229
00230
00231
00232
00233
00234
00235 bool calcNearAndFarFaceDistance(Mat &m, float fx, float fy, Point2i roiLB,
00236 Point2i roiRT, float *d1, float *d2)
00237 {
00238
00239 float mean, stdDev;
00240 if(!calcStats(m, &mean, &stdDev)) {
00241 return false;
00242 }
00243
00244
00245 *d1 = mean - stdDev;
00246 *d2 = mean + stdDev;
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280 return true;
00281 }
00282
00283
00284
00285
00286
00287
00288 bool calcNearAndFarFaceDepth(Mat &m, float f, float *z1, float *z2)
00289 {
00290
00291 float mean, stdDev;
00292 if(!calcStats(m, &mean, &stdDev)) {
00293 return false;
00294 }
00295
00296
00297
00298 *z1 = mean - stdDev;
00299 *z2 = mean + stdDev;
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310 return true;
00311 }
00312
00313
00314
00315
00316
00317
00318 bool estimateBB(const ros::Time& stamp,
00319 const point2_t& p1, const point2_t& p2, int mode,
00320 Point3f& bbLBF, Point3f& bbRBF,
00321 Point3f& bbRTF, Point3f& bbLTF,
00322 Point3f& bbLBB, Point3f& bbRBB,
00323 Point3f& bbRTB, Point3f& bbLTB
00324 )
00325 {
00326
00327
00328 estimationMode = mode;
00329 if(estimationMode <= 0 || estimationMode > 3) {
00330 estimationMode = 1;
00331 }
00332
00333 Mat depthMap;
00334
00335
00336
00337 sensor_msgs::CameraInfoConstPtr camInfo = camInfoCache.getElemBeforeTime(stamp);
00338 if(camInfo == 0) {
00339 ROS_ERROR("Cannot calculate the bounding box. "
00340 "No frames were obtained before the request time.");
00341 return false;
00342 }
00343
00344
00345
00346 if(subVariant == SV_1) {
00347 sensor_msgs::ImageConstPtr depth = depthCache.getElemBeforeTime(stamp);
00348
00349
00350 try {
00351 cv_bridge::CvImagePtr cvDepth;
00352 cvDepth = cv_bridge::toCvCopy(depth);
00353 cvDepth->image.convertTo(depthMap, CV_32F);
00354 }
00355 catch (cv_bridge::Exception& e) {
00356 ROS_ERROR("cv_bridge exception: %s", e.what());
00357 return false;
00358 }
00359
00360
00361 depthMap *= 1.0/1000.0;
00362 }
00363
00364
00365
00366 else if(subVariant == SV_2) {
00367 sensor_msgs::PointCloud2ConstPtr pointCloud = pointCloudCache.getElemBeforeTime(stamp);
00368
00369
00370
00371 pcl::PointCloud<pcl::PointXYZ> cloud;
00372 pcl::fromROSMsg (*pointCloud, cloud);
00373
00374 depthMap = Mat(cloud.height, cloud.width, CV_32F);
00375
00376 for(int y = 0; y < (int)cloud.height; y++) {
00377 for(int x = 0; x < (int)cloud.width; x++) {
00378 float z = cloud.points[y * cloud.width + x].z;
00379 if(cvIsNaN(z)) z = 0;
00380 depthMap.at<float>(y, x) = z;
00381 }
00382 }
00383 }
00384 else {
00385 ROS_ERROR("Unknown subscription variant!");
00386 return false;
00387 }
00388
00389
00390
00391 tf::StampedTransform sensorToWorldTf;
00392 camFrameId = camInfo->header.frame_id;
00393 try {
00394 tfListener->waitForTransform(camFrameId, sceneFrameId,
00395 camInfo->header.stamp, ros::Duration(2.0));
00396
00397 tfListener->lookupTransform(camFrameId, sceneFrameId,
00398 camInfo->header.stamp, sensorToWorldTf);
00399 }
00400 catch(tf::TransformException& ex) {
00401 string errorMsg = String("Transform error: ") + ex.what();
00402 ROS_ERROR("%s", errorMsg.c_str());
00403 return false;
00404 }
00405
00406
00407 int width = depthMap.cols;
00408 int height = depthMap.rows;
00409
00410
00411
00412
00413
00414 Point2i roiLBi;
00415 Point2i roiRTi;
00416
00417 if(p1[0] < p2[0]) {roiLBi.x = p1[0]; roiRTi.x = p2[0];}
00418 else {roiLBi.x = p2[0]; roiRTi.x = p1[0];}
00419
00420 if(p1[1] < p2[1]) {roiRTi.y = p1[1]; roiLBi.y = p2[1];}
00421 else {roiRTi.y = p2[1]; roiLBi.y = p1[1];}
00422
00423
00424 roiLBi.x = min(max(roiLBi.x, 0), width);
00425 roiLBi.y = min(max(roiLBi.y, 0), height);
00426 roiRTi.x = min(max(roiRTi.x, 0), width);
00427 roiRTi.y = min(max(roiRTi.y, 0), height);
00428
00429
00430 Mat roi = Mat(depthMap, Rect(roiLBi.x, roiRTi.y,
00431 roiRTi.x - roiLBi.x, roiLBi.y - roiRTi.y));
00432
00433
00434
00435 Mat K = Mat(3, 3, CV_64F, (double *)camInfo->K.data());
00436 float cx = (float)K.at<double>(0, 2);
00437 float cy = (float)K.at<double>(1, 2);
00438 float fx = (float)K.at<double>(0, 0);
00439 float fy = (float)K.at<double>(1, 1);
00440 float f = (fx + fy) / 2.0;
00441
00442 if(fx == 0 || fy == 0 || cx == 0 || cy == 0) {
00443 ROS_ERROR("Intrinsic camera parameters are undefined.");
00444 }
00445
00446
00447
00448
00449
00450 Point2i roiLB(roiLBi.x - cx, roiLBi.y - cy);
00451 Point2i roiRT(roiRTi.x - cx, roiRTi.y - cy);
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461 vector<Point3f *> bbVertices(8);
00462 bbVertices[0] = &bbLBF;
00463 bbVertices[1] = &bbRBF;
00464 bbVertices[2] = &bbRTF;
00465 bbVertices[3] = &bbLTF;
00466 bbVertices[4] = &bbLBB;
00467 bbVertices[5] = &bbRBB;
00468 bbVertices[6] = &bbRTB;
00469 bbVertices[7] = &bbLTB;
00470
00471
00473 if(estimationMode == MODE1) {
00474
00475
00476 Mat roiD(roi.size(), CV_32F);
00477 for(int i = 0; i < roi.rows; i++) {
00478 for(int j = 0; j < roi.cols; j++) {
00479 float z = roi.at<float>(i, j);
00480 Point3f P = backProject(Point2i(roiLB.x + j, roiRT.y + i), z, fx, fy);
00481
00482
00483 roiD.at<float>(i, j) = norm(P);
00484 }
00485 }
00486
00487
00488 float d1, d2;
00489 if(!calcNearAndFarFaceDistance(roiD, fx, fy, roiLB, roiRT, &d1, &d2)) {
00490 return false;
00491 }
00492
00493
00494
00495
00496
00497 Point3f vecLBF = backProject(roiLB, 1, fx, fy);
00498 bbLBF = vecLBF * (d1 / (float)norm(vecLBF));
00499
00500 Point3f vecRBF = backProject(Point2i(roiRT.x, roiLB.y), 1, fx, fy);
00501 bbRBF = vecRBF * (d1 / (float)norm(vecRBF));
00502
00503 Point3f vecRTF = backProject(roiRT, 1, fx, fy);
00504 bbRTF = vecRTF * (d1 / (float)norm(vecRTF));
00505
00506 Point3f vecLTF = backProject(Point2i(roiLB.x, roiRT.y), 1, fx, fy);
00507 bbLTF = vecLTF * (d1 / (float)norm(vecLTF));
00508
00509
00510
00511
00512
00513
00514
00515
00516 Point3f vecMid = bbLBF + bbRBF + bbRTF + bbLTF;
00517 vecMid *= 1.0 / (float)norm(vecMid);
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532 float b = 2.0*(bbLBF.x*vecMid.x + bbLBF.y*vecMid.y + bbLBF.z*vecMid.z);
00533 float c = d1*d1 - d2*d2;
00534 float D = b*b - 4.0*c;
00535 float k = (-b + sqrt(D)) / 2.0;
00536 Point3f vecFFtoBF = k * vecMid;
00537
00538
00539 bbLBB = bbLBF + vecFFtoBF;
00540 bbRBB = bbRBF + vecFFtoBF;
00541 bbRTB = bbRTF + vecFFtoBF;
00542 bbLTB = bbLTF + vecFFtoBF;
00543 }
00544
00545
00547
00548
00549
00550 else if(estimationMode == MODE2) {
00551
00552
00553 float z1, z2;
00554 if(!calcNearAndFarFaceDepth(roi, f, &z1, &z2)) {
00555 return false;
00556 }
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577 Point2i roiLBm = roiLB;
00578 Point2i roiRTm = roiRT;
00579
00580 bool flippedX = false;
00581 bool flippedY = false;
00582
00583
00584 if(roiLBm.x > 0) {
00585 roiLBm.x = -roiRT.x;
00586 roiRTm.x = -roiLB.x;
00587 flippedX = true;
00588 }
00589
00590
00591 if(roiLBm.y < 0) {
00592 roiLBm.y = -roiRT.y;
00593 roiRTm.y = -roiLB.y;
00594 flippedY = true;
00595 }
00596
00597
00598
00599 if(roiLBm.x <= 0 && roiRTm.x >= 0) {
00600 bbLBF.x = (roiLBm.x * z1) / fx;
00601 bbRTB.x = (roiRTm.x * z1) / fx;
00602 }
00603 else {
00604 bbLBF.x = (roiLBm.x * z1) / fx;
00605 bbRTB.x = (roiRTm.x * z2) / fx;
00606
00607
00608
00609
00610 if(bbLBF.x > bbRTB.x) {
00611 float midX = (bbLBF.x + bbRTB.x) / 2.0;
00612 bbLBF.x = midX;
00613 bbRTB.x = midX;
00614 z1 = (midX * fx) / roiLBm.x;
00615 z2 = (midX * fx) / roiRTm.x;
00616 }
00617 }
00618
00619
00620
00621 if(roiLBm.y >= 0 && roiRTm.y <= 0) {
00622 bbLBF.y = (roiLBm.y * z1) / fy;
00623 bbRTB.y = (roiRTm.y * z1) / fy;
00624 }
00625 else {
00626 bbLBF.y = (roiLBm.y * z1) / fy;
00627 bbRTB.y = (roiRTm.y * z2) / fy;
00628
00629
00630
00631
00632 if(bbLBF.y < bbRTB.y) {
00633 float midY = (bbLBF.y + bbRTB.y) / 2.0;
00634 bbLBF.y = midY;
00635 bbRTB.y = midY;
00636 z1 = (midY * fy) / roiLBm.y;
00637 z2 = (midY * fy) / roiRTm.y;
00638
00639
00640 if(roiLBm.x <= 0 && roiRTm.x >= 0) {
00641 bbLBF.x = (roiLBm.x * z1) / fx;
00642 bbRTB.x = (roiRTm.x * z1) / fx;
00643 }
00644 else {
00645 bbLBF.x = (roiLBm.x * z1) / fx;
00646 bbRTB.x = (roiRTm.x * z2) / fx;
00647 }
00648 }
00649 }
00650
00651
00652
00653 bbLBF.z = z1;
00654 bbRTB.z = z2;
00655
00656
00657 if(flippedX) {
00658 float bbLBFx = bbLBF.x;
00659 bbLBF.x = -bbRTB.x;
00660 bbRTB.x = -bbLBFx;
00661 }
00662 if(flippedY) {
00663 float bbLBFy = bbLBF.y;
00664 bbLBF.y = -bbRTB.y;
00665 bbRTB.y = -bbLBFy;
00666 }
00667
00668
00669
00670
00671 bbRBF = Point3f(bbRTB.x, bbLBF.y, bbLBF.z);
00672 bbRTF = Point3f(bbRTB.x, bbRTB.y, bbLBF.z);
00673 bbLTF = Point3f(bbLBF.x, bbRTB.y, bbLBF.z);
00674 bbLBB = Point3f(bbLBF.x, bbLBF.y, bbRTB.z);
00675 bbRBB = Point3f(bbRTB.x, bbLBF.y, bbRTB.z);
00676 bbLTB = Point3f(bbLBF.x, bbRTB.y, bbRTB.z);
00677 }
00678
00679
00681
00682
00683
00684 else if(estimationMode == MODE3) {
00685
00686
00687 float z1, z2;
00688 if(!calcNearAndFarFaceDepth(roi, f, &z1, &z2)) {
00689 return false;
00690 }
00691
00692
00693 bbLBF = Point3f((roiLB.x * z1) / fx, (roiLB.y * z1) / fy, z1);
00694
00695
00696
00697
00698
00699 bbRTB = Point3f((roiRT.x * z1) / fx, (roiRT.y * z1) / fy, z2);
00700
00701
00702
00703
00704 bbRBF = Point3f(bbRTB.x, bbLBF.y, bbLBF.z);
00705 bbRTF = Point3f(bbRTB.x, bbRTB.y, bbLBF.z);
00706 bbLTF = Point3f(bbLBF.x, bbRTB.y, bbLBF.z);
00707 bbLBB = Point3f(bbLBF.x, bbLBF.y, bbRTB.z);
00708 bbRBB = Point3f(bbRTB.x, bbLBF.y, bbRTB.z);
00709 bbLTB = Point3f(bbLBF.x, bbRTB.y, bbRTB.z);
00710 }
00711
00712
00713
00714 tf::Transformer t;
00715 t.setTransform(sensorToWorldTf);
00716
00717 for(int i = 0; i < (int)bbVertices.size(); i++) {
00718 tf::Stamped<tf::Point> vertex;
00719 vertex.frame_id_ = camFrameId;
00720
00721 vertex.setX(bbVertices[i]->x);
00722 vertex.setY(bbVertices[i]->y);
00723 vertex.setZ(bbVertices[i]->z);
00724 t.transformPoint(sceneFrameId, vertex, vertex);
00725 bbVertices[i]->x = vertex.getX();
00726 bbVertices[i]->y = vertex.getY();
00727 bbVertices[i]->z = vertex.getZ();
00728 }
00729
00730
00731
00732
00733
00734
00735 Point3f lowestCorner(0, 0, 0);
00736 Point3f vec(0, 0, 0);
00737 bool feasible = true;
00738 bool isSensorFlipped = false;
00739
00740
00741
00742
00743 if(bbLBF.z < lowestCorner.z) {
00744 if(bbLTF.z <= 0) feasible = false;
00745 vec = bbLTF - bbLBF;
00746 lowestCorner = bbLBF;
00747 }
00748 if(bbRBF.z < lowestCorner.z && feasible) {
00749 if(bbRTF.z <= 0) feasible = false;
00750 vec = bbRTF - bbRBF;
00751 lowestCorner = bbRBF;
00752 }
00753 if(bbLBB.z < lowestCorner.z && feasible) {
00754 if(bbLTB.z <= 0) feasible = false;
00755 vec = bbLTB - bbLBB;
00756 lowestCorner = bbLBB;
00757 }
00758 if(bbRBB.z < lowestCorner.z && feasible) {
00759 if(bbRTB.z <= 0) feasible = false;
00760 vec = bbRTB - bbRBB;
00761 lowestCorner = bbRBB;
00762 }
00763
00764
00765
00766 if(bbLTF.z < lowestCorner.z) {
00767 if(bbLBF.z <= 0) feasible = false;
00768 isSensorFlipped = true;
00769 vec = bbLBF - bbLTF;
00770 lowestCorner = bbLTF;
00771 }
00772 if(bbRTF.z < lowestCorner.z && feasible) {
00773 if(bbRBF.z <= 0) feasible = false;
00774 isSensorFlipped = true;
00775 vec = bbRBF - bbRTF;
00776 lowestCorner = bbRTF;
00777 }
00778 if(bbLTB.z < lowestCorner.z && feasible) {
00779 if(bbLBB.z <= 0) feasible = false;
00780 isSensorFlipped = true;
00781 vec = bbLBB - bbLTB;
00782 lowestCorner = bbLTB;
00783 }
00784 if(bbRTB.z < lowestCorner.z && feasible) {
00785 if(bbRBB.z <= 0) feasible = false;
00786 isSensorFlipped = true;
00787 vec = bbRBB - bbRTB;
00788 lowestCorner = bbRTB;
00789 }
00790
00791 if(lowestCorner.z < 0) {
00792 if(!feasible) {
00793 return false;
00794 }
00795 else {
00796
00797
00798 float scale = (-lowestCorner.z) / vec.z;
00799 vec = vec * scale;
00800
00801
00802 if(!isSensorFlipped) {
00803 bbLBF += vec;
00804 bbRBF += vec;
00805 bbLBB += vec;
00806 bbRBB += vec;
00807 }
00808 else {
00809 bbLTF += vec;
00810 bbRTF += vec;
00811 bbLTB += vec;
00812 bbRTB += vec;
00813 }
00814 }
00815 }
00816
00817
00818 return true;
00819 }
00820
00821
00822
00823
00824
00825
00826 bool estimateBBPose(const Point3f& bbLBF, const Point3f& bbRBF,
00827 const Point3f& bbRTF, const Point3f& bbLTF,
00828 const Point3f& bbLBB, const Point3f& bbRBB,
00829 const Point3f& bbRTB, const Point3f& bbLTB,
00830 Point3f& position,
00831 tf::Quaternion& orientation,
00832 Point3f& scale
00833 )
00834 {
00835
00836
00837
00838
00839
00840
00841
00842
00843
00844
00845 vector<Point3f> edges(3), edgesNorm(3);
00846 edges[0] = bbRBF - bbLBF;
00847 edges[1] = bbLTF - bbLBF;
00848 edges[2] = bbLBB - bbLBF;
00849
00850
00851 for(int i = 0; i < 3; i++) edgesNorm[i] = edges[i] * (1.0 / norm(edges[i]));
00852
00853 Point3f rotBest;
00854 float anglesMinSum = -1;
00855 Point3f bbSize;
00856
00857
00858
00859
00860
00861
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871
00872
00873
00874
00875
00876
00877
00878
00879
00880
00881 for(int xi = 0; xi < 3; xi++) {
00882 for(int yi = 0; yi < 3; yi++) {
00883 if(xi == yi) continue;
00884 for(int zi = 0; zi < 3; zi++) {
00885 if(xi == zi || yi == zi) continue;
00886
00887 Point3f rot;
00888 vector<Point3f> edgesTmp = edgesNorm;
00889
00890
00891
00892
00893 Point3f edgeYyz(0, edgesTmp[yi].y, edgesTmp[yi].z);
00894 Point3f edgeZyz(0, edgesTmp[zi].y, edgesTmp[zi].z);
00895 edgeYyz *= (1.0 / norm(edgeYyz));
00896 edgeZyz *= (1.0 / norm(edgeZyz));
00897
00898 float rollY = acos(edgeYyz.y);
00899 float rollZ = acos(edgeZyz.z);
00900
00901 if(rollY > PI/2.0) rollY = -PI + rollY;
00902 if(rollZ > PI/2.0) rollZ = -PI + rollZ;
00903
00904 if(edgeYyz.z < 0) rollY = -rollY;
00905 if(edgeZyz.y > 0) rollZ = -rollZ;
00906
00907 rot.x = (fabs(rollY) < fabs(rollZ)) ? -rollY : -rollZ;
00908
00909
00910 for(int m = 0; m < 3; m++) {
00911 edgesTmp[m] = Point3f(
00912 edgesTmp[m].x,
00913 cos(rot.x)*edgesTmp[m].y - sin(rot.x)*edgesTmp[m].z,
00914 sin(rot.x)*edgesTmp[m].y + cos(rot.x)*edgesTmp[m].z);
00915 }
00916
00917
00918
00919
00920
00921 Point3f edgeXxz(edgesTmp[xi].x, 0, edgesTmp[xi].z);
00922 Point3f edgeZxz(edgesTmp[zi].x, 0, edgesTmp[zi].z);
00923 edgeXxz *= (1.0 / norm(edgeXxz));
00924 edgeZxz *= (1.0 / norm(edgeZxz));
00925
00926 float pitchX = acos(edgeXxz.x);
00927 float pitchZ = acos(edgeZxz.z);
00928
00929 if(pitchX > PI/2.0) pitchX = -PI + pitchX;
00930 if(pitchZ > PI/2.0) pitchZ = -PI + pitchZ;
00931
00932 if(edgeXxz.z > 0) pitchX = -pitchX;
00933 if(edgeZxz.x < 0) pitchZ = -pitchZ;
00934
00935 rot.y = (fabs(pitchX) < fabs(pitchZ)) ? -pitchX : -pitchZ;
00936
00937
00938 for(int m = 0; m < 3; m++) {
00939 edgesTmp[m] = Point3f(
00940 cos(rot.y)*edgesTmp[m].x + sin(rot.y)*edgesTmp[m].z,
00941 edgesTmp[m].y,
00942 -sin(rot.y)*edgesTmp[m].x + cos(rot.y)*edgesTmp[m].z);
00943 }
00944
00945
00946
00947
00948
00949 Point3f edgeXxy(edgesTmp[xi].x, edgesTmp[xi].y, 0);
00950 Point3f edgeYxy(edgesTmp[yi].x, edgesTmp[yi].y, 0);
00951 edgeXxy *= (1.0 / norm(edgeXxy));
00952 edgeYxy *= (1.0 / norm(edgeYxy));
00953
00954 float yawX = acos(edgeXxy.x);
00955 float yawY = acos(edgeYxy.y);
00956
00957 if(yawX > PI/2.0) yawX = -PI + yawX;
00958 if(yawY > PI/2.0) yawY = -PI + yawY;
00959
00960 if(edgeXxy.y < 0) yawX = -yawX;
00961 if(edgeYxy.x > 0) yawY = -yawY;
00962
00963 rot.z = (fabs(yawX) < fabs(yawY)) ? -yawX : -yawY;
00964
00965
00966
00967 float actualSum = fabs(rot.x) + fabs(rot.y) + fabs(rot.z);
00968 if(anglesMinSum == -1 || anglesMinSum > actualSum) {
00969 anglesMinSum = actualSum;
00970 rotBest = rot;
00971
00972
00973
00974 bbSize.x = norm(edges[xi]);
00975 bbSize.y = norm(edges[yi]);
00976 bbSize.z = norm(edges[zi]);
00977 }
00978 }
00979 }
00980 }
00981
00982
00983
00984 orientation = tf::createQuaternionFromRPY(-rotBest.x, -rotBest.y, -rotBest.z);
00985
00986
00987
00988
00989
00990
00991
00992 position = bbLBF;
00993 position += bbRBF;
00994 position += bbRTF;
00995 position += bbLTF;
00996 position += bbLBB;
00997 position += bbRBB;
00998 position += bbRTB;
00999 position += bbLTB;
01000 position *= 1.0/8.0;
01001
01002
01003
01004 scale.x = bbSize.x;
01005 scale.y = bbSize.y;
01006 scale.z = bbSize.z;
01007
01008 return true;
01009 }
01010
01011
01012
01013
01014
01015
01016 bool estimateRect(const ros::Time& stamp,
01017 const Point3f& bbLBF, const Point3f& bbRBF,
01018 const Point3f& bbRTF, const Point3f& bbLTF,
01019 const Point3f& bbLBB, const Point3f& bbRBB,
01020 const Point3f& bbRTB, const Point3f& bbLTB,
01021 point2_t& p1, point2_t& p2
01022 )
01023 {
01024
01025
01026 sensor_msgs::CameraInfoConstPtr camInfo = camInfoCache.getElemBeforeTime(stamp);
01027 if(camInfo == 0) {
01028 ROS_ERROR("Cannot calculate the image rectangle. "
01029 "No camera info was obtained before the request time.");
01030 return false;
01031 }
01032
01033
01034
01035 tf::StampedTransform worldToSensorTf;
01036 camFrameId = camInfo->header.frame_id;
01037 try {
01038 tfListener->waitForTransform(sceneFrameId, camFrameId,
01039 camInfo->header.stamp, ros::Duration(2.0));
01040
01041 tfListener->lookupTransform(sceneFrameId, camFrameId,
01042 camInfo->header.stamp, worldToSensorTf);
01043 }
01044 catch(tf::TransformException& ex) {
01045 string errorMsg = String("Transform error: ") + ex.what();
01046 ROS_ERROR("%s", errorMsg.c_str());
01047 return false;
01048 }
01049
01050
01051 int width = camInfo->width;
01052 int height = camInfo->height;
01053
01054
01055
01056 Mat K = Mat(3, 3, CV_64F, (double *)camInfo->K.data());
01057 float cx = (float)K.at<double>(0, 2);
01058 float cy = (float)K.at<double>(1, 2);
01059 float fx = (float)K.at<double>(0, 0);
01060 float fy = (float)K.at<double>(1, 1);
01061
01062
01063 if(fx == 0 || fy == 0 || cx == 0 || cy == 0) {
01064 ROS_ERROR("Intrinsic camera parameters are undefined.");
01065 }
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075 vector<const Point3f *> bbVertices(8);
01076 bbVertices[0] = &bbLBF;
01077 bbVertices[1] = &bbRBF;
01078 bbVertices[2] = &bbRTF;
01079 bbVertices[3] = &bbLTF;
01080 bbVertices[4] = &bbLBB;
01081 bbVertices[5] = &bbRBB;
01082 bbVertices[6] = &bbRTB;
01083 bbVertices[7] = &bbLTB;
01084
01085
01086 vector<Point2i> trVertices(8);
01087
01088
01089
01090 tf::Transformer t;
01091 t.setTransform(worldToSensorTf);
01092
01093 for( int i = 0; i < (int)bbVertices.size(); i++ )
01094 {
01095
01096 tf::Stamped<tf::Point> vertex;
01097 vertex.frame_id_ = sceneFrameId;
01098 vertex.setX(bbVertices[i]->x);
01099 vertex.setY(bbVertices[i]->y);
01100 vertex.setZ(bbVertices[i]->z);
01101 t.transformPoint(camFrameId, vertex, vertex);
01102
01103
01104 trVertices[i] = fwdProject(Point3f(vertex.getX(), vertex.getY(), vertex.getZ()), fx, fy, cx, cy);
01105 }
01106
01107
01108
01109
01110
01111
01112 Point2i ap1(trVertices[0].x, trVertices[0].y);
01113 Point2i ap2(trVertices[0].x, trVertices[0].y);
01114 for( int i = 1; i < (int)bbVertices.size(); i++ )
01115 {
01116 ap1.x = min(trVertices[i].x, ap1.x);
01117 ap1.y = min(trVertices[i].y, ap1.y);
01118 ap2.x = max(trVertices[i].x, ap2.x);
01119 ap2.y = max(trVertices[i].y, ap2.y);
01120 }
01121
01122
01123 p1[0] = min(max(ap1.x, 0), width);
01124 p1[1] = min(max(ap1.y, 0), height);
01125 p2[0] = min(max(ap2.x, 0), width);
01126 p2[1] = min(max(ap2.y, 0), height);
01127
01128 return true;
01129 }
01130
01131
01132
01133
01134
01135 bool estimate2DConvexHull(const ros::Time& stamp,
01136 const std::vector<cv::Point3f> points,
01137 std::vector<cv::Point2i> &convexHull
01138 )
01139 {
01140
01141
01142 sensor_msgs::CameraInfoConstPtr camInfo = camInfoCache.getElemBeforeTime(stamp);
01143 if(camInfo == 0) {
01144 ROS_ERROR("Cannot calculate the image rectangle. "
01145 "No camera info was obtained before the request time.");
01146 return false;
01147 }
01148
01149
01150
01151 tf::StampedTransform worldToSensorTf;
01152 camFrameId = camInfo->header.frame_id;
01153 try {
01154 tfListener->waitForTransform(sceneFrameId, camFrameId,
01155 camInfo->header.stamp, ros::Duration(2.0));
01156
01157 tfListener->lookupTransform(sceneFrameId, camFrameId,
01158 camInfo->header.stamp, worldToSensorTf);
01159 }
01160 catch(tf::TransformException& ex) {
01161 string errorMsg = String("Transform error: ") + ex.what();
01162 ROS_ERROR("%s", errorMsg.c_str());
01163 return false;
01164 }
01165
01166
01167
01168 Mat K = Mat(3, 3, CV_64F, (double *)camInfo->K.data());
01169 float cx = (float)K.at<double>(0, 2);
01170 float cy = (float)K.at<double>(1, 2);
01171 float fx = (float)K.at<double>(0, 0);
01172 float fy = (float)K.at<double>(1, 1);
01173
01174
01175 if(fx == 0 || fy == 0 || cx == 0 || cy == 0) {
01176 ROS_ERROR("Intrinsic camera parameters are undefined.");
01177 }
01178
01179
01180
01181 tf::Transformer t;
01182 t.setTransform(worldToSensorTf);
01183
01184
01185 vector<Point2i> trPoints(points.size());
01186
01187 for( int i = 0; i < (int)points.size(); i++ )
01188 {
01189
01190 tf::Stamped<tf::Point> vertex;
01191 vertex.frame_id_ = sceneFrameId;
01192 vertex.setX(points[i].x);
01193 vertex.setY(points[i].y);
01194 vertex.setZ(points[i].z);
01195 t.transformPoint(camFrameId, vertex, vertex);
01196
01197
01198 trPoints[i] = fwdProject(Point3f(vertex.getX(), vertex.getY(), vertex.getZ()), fx, fy, cx, cy);
01199 }
01200
01201
01202 cv::convexHull(trPoints, convexHull);
01203
01204 return true;
01205 }
01206
01207 }