00001
00002 #include <ros/ros.h>
00003 #include <image_transport/image_transport.h>
00004 #include <opencv/cv.h>
00005 #include <opencv/highgui.h>
00006 #include <cv_bridge/CvBridge.h>
00007
00008 #include <ar_recog/Tag.h>
00009 #include <ar_recog/Tags.h>
00010 #include <ar_recog/CalibrateDistance.h>
00011
00012 #include <math.h>
00013
00014 #include <AR/ar.h>
00015 #include <AR/video.h>
00016 #include <AR/matrix.h>
00017
00018
00019 extern "C" {
00020 #include "object.h"
00021 }
00022
00023 #include <iostream>
00024
00025 #define THRESH 100
00026 #define THRESH_VARIATION 5
00027 #define THRESH_RANGE_LIMIT 40
00028
00029 char cparam_name[65536];
00030 ARParam cparam;
00031
00032 char model_name[65536];
00033 ObjectData_T *object;
00034 int objectnum;
00035 double patt_trans[3][4];
00036
00037 bool using_rectified_images;
00038
00039
00040 int thresh = THRESH;
00041 int threshVariation = THRESH_VARIATION;
00042 int kThresh = 1;
00043 int sign = 1;
00044
00045 void init(int width, int height) {
00046 ARParam wparam;
00047 if (arParamLoad(cparam_name, 1, &wparam) < 0) {
00048 std::cerr << "Problem loading AR camera parameters." << std::endl;
00049 exit(-1);
00050 }
00051
00052
00053
00054
00055
00056
00057
00058 arParamChangeSize(&wparam, width, height, &cparam);
00059 arInitCparam(&cparam);
00060
00061 if ((object = read_ObjData(model_name, &objectnum)) == NULL) {
00062 std::cerr << "Problem reading patterns." << std::endl;
00063 exit(-1);
00064 }
00065 }
00066
00067
00068 IplImage * drawHistogram(IplImage *img)
00069 {
00070 int numBins = 256;
00071 float range[] = {0, 255};
00072 float *ranges[] = { range };
00073 float scaleX = 2, scaleY = 2;
00074 const int width = 3;
00075
00076 CvHistogram *hist = cvCreateHist(1, &numBins, CV_HIST_ARRAY, ranges, 1);
00077 cvClearHist(hist);
00078
00079 IplImage *im_gray = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
00080 cvCvtColor(img, im_gray, CV_RGB2GRAY);
00081
00082 cvCalcHist(&im_gray, hist, 0, 0);
00083 IplImage *imgHistGray = cvCreateImage(cvSize(256*scaleX, 64*scaleY), 8, 3);
00084 cvZero(imgHistGray);
00085
00086 float histMax = 0;
00087 cvGetMinMaxHistValue(hist, 0, &histMax, 0, 0);
00088
00089 for(int i=0;i<255;i++)
00090 {
00091 float histValue = cvQueryHistValue_1D(hist, i);
00092 float nextValue = cvQueryHistValue_1D(hist, i+1);
00093
00094 CvPoint pt1 = cvPoint(i*scaleX, 64*scaleY);
00095 CvPoint pt2 = cvPoint(i*scaleX+scaleX, 64*scaleY);
00096 CvPoint pt3 = cvPoint(i*scaleX+scaleX, (64-nextValue*64/histMax)*scaleY);
00097 CvPoint pt4 = cvPoint(i*scaleX, (64-histValue*64/histMax)*scaleY);
00098
00099 int numPts = 5;
00100 CvPoint pts[] = {pt1, pt2, pt3, pt4, pt1};
00101
00102 cvFillConvexPoly(imgHistGray, pts, numPts, CV_RGB(255,255,255));
00103 }
00104
00105 cvLine(imgHistGray,cvPoint(thresh*scaleX, 0),
00106 cvPoint(thresh*scaleX, 64*scaleY),
00107 CV_RGB(255,0,0),width);
00108
00109
00110 cvReleaseImage(&im_gray);
00111 cvReleaseHist(&hist);
00112
00113 return imgHistGray;
00114 }
00115
00116
00117 double haov, vaov;
00118 bool ar_smooth = true;
00119 ros::Publisher tags_pub;
00120 image_transport::Publisher ar_img;
00121 image_transport::Publisher ar_hist;
00122 int last_reported_distance;
00123
00124 void handleImage(const sensor_msgs::ImageConstPtr& in, const sensor_msgs::CameraInfoConstPtr& camera_info) {
00125 sensor_msgs::CvBridge bridge;
00126 double icpara[3][4], trans[3][4];
00127 IplImage* img = bridge.imgMsgToCv(in, "rgb8");
00128
00129 if (img->width != arImXsize || img->height != arImYsize) init(img->width, img->height);
00130 IplImage *hist = drawHistogram(img);
00131
00132 ARUint8 *data = (ARUint8*) malloc(sizeof(ARUint8)*img->width*img->height*3);
00133 int i = 0;
00134 for (int y = 0; y < img->height; y++) {
00135 for (int x = 0; x < img->width; x++) {
00136 for (int j = 0; j < 3; j++) {
00137 data[i++] = img->imageData[y*(img->widthStep/sizeof(uchar))+x*3+j];
00138 }
00139 }
00140 }
00141
00142
00143 cvSetImageROI(img, cvRect(img->width - hist->width, img->height - hist->height,
00144 img->width, img->height));
00145 cvCopy(hist, img);
00146 cvResetImageROI(img);
00147
00148
00149 ARMarkerInfo *marker_info;
00150 int marker_num;
00151 if(arDetectMarker(data, thresh, &marker_info, &marker_num) < 0) {
00152 std::cerr << "Problem running detect marker." << std::endl;
00153 exit(-1);
00154 }
00155
00156 if( arParamDecompMat(cparam.mat, icpara, trans) < 0 ) {
00157 printf("gConvGLcpara: Parameter error!!\n");
00158 exit(0);
00159 }
00160
00161
00162 for( int i = 0; i < 3; i++ ) {
00163 for( int j = 0; j < 3; j++ ) {
00164 icpara[i][j] = icpara[i][j] / icpara[2][2];
00165 printf("%.3f ", icpara[i][j]);
00166 }
00167 printf("\n");
00168 }
00169
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184
00185
00186
00187 if (using_rectified_images) {
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198 double y_foc = camera_info->P[5];
00199 double y_princ = camera_info->P[6];
00200 double x_foc = camera_info->P[0];
00201 double x_princ = camera_info->P[2];
00202
00203
00204 haov = 2.0 * atan(x_princ / x_foc);
00205 vaov = 2.0 * atan(y_princ / y_foc);
00206
00207 ROS_INFO("entrando por using_rectified_images");
00208 }
00209 else {
00210 vaov = haov * ((double)img->height / (double)img->width);
00211 ROS_INFO("no entrando por using_rectified_images");
00212 }
00213
00214 ar_recog::Tags tags;
00215 tags.image_width = img->width;
00216 tags.image_height = img->height;
00217 tags.angle_of_view = haov;
00218
00219
00220 tags.header.stamp = ros::Time::now();
00221
00222 for( int i = 0; i < objectnum; i++ ) {
00223 int k = -1;
00224 for( int j = 0; j < marker_num; j++ ) {
00225
00226 if( object[i].id == marker_info[j].id) {
00227
00228
00229
00230
00231
00232
00233
00234
00235 k=j;
00236
00237
00238
00239 if( k == -1 ) {
00240 object[i].visible = 0;
00241 continue;
00242 }
00243
00244
00245 if( (!ar_smooth) || (object[i].visible == 0) ) {
00246 arGetTransMat(&marker_info[k],
00247 object[i].marker_center,
00248 object[i].marker_width,
00249 object[i].trans);
00250 } else {
00251 arGetTransMatCont(&marker_info[k],
00252 object[i].trans,
00253 object[i].marker_center,
00254 object[i].marker_width,
00255 object[i].trans);
00256 }
00257
00258 object[i].visible = 1;
00259
00260
00261
00262
00263 const int width = 3;
00264 cvLine(img,cvPoint(marker_info[k].vertex[0][0],marker_info[k].vertex[0][1]),
00265 cvPoint(marker_info[k].vertex[1][0],marker_info[k].vertex[1][1])
00266 ,CV_RGB(0,255,0),width);
00267 cvLine(img,cvPoint(marker_info[k].vertex[1][0],marker_info[k].vertex[1][1]),
00268 cvPoint(marker_info[k].vertex[2][0],marker_info[k].vertex[2][1])
00269 ,CV_RGB(0,255,0),width);
00270 cvLine(img,cvPoint(marker_info[k].vertex[2][0],marker_info[k].vertex[2][1]),
00271 cvPoint(marker_info[k].vertex[3][0],marker_info[k].vertex[3][1])
00272 ,CV_RGB(0,255,0),width);
00273 cvLine(img,cvPoint(marker_info[k].vertex[3][0],marker_info[k].vertex[3][1]),
00274 cvPoint(marker_info[k].vertex[0][0],marker_info[k].vertex[0][1])
00275 ,CV_RGB(0,255,0),width);
00276
00277 ARMat cameraMatrix, cubeMatrix, proyMatrix, kMatrix, pMatrix;
00278 double cube[4][4] = { {0, 10, 0, 0}, {0, 0, 10, 0}, {0, 0, 0, 10}, {1, 1, 1, 1}};
00279 double proy[3][4];
00280 double cam[3][4];
00281 double km[3][3];
00282
00283 pMatrix.m = &cam[0][0];
00284 pMatrix.row = 3;
00285 pMatrix.clm = 4;
00286
00287 cameraMatrix.m = &object[i].trans[0][0];
00288 cameraMatrix.row = 3;
00289 cameraMatrix.clm = 4;
00290
00291 kMatrix.m = &km[0][0];
00292 kMatrix.row = 3;
00293 kMatrix.clm = 3;
00294
00295 cubeMatrix.m = &cube[0][0];
00296 cubeMatrix.row = 4;
00297 cubeMatrix.clm = 4;
00298
00299 proyMatrix.m = &proy[0][0];
00300 proyMatrix.row = 3;
00301 proyMatrix.clm = 4;
00302
00303 for (int k = 0 ; k < 3; k++) {
00304 for (int l = 0; l < 3; l++)
00305 kMatrix.m[k*3+l] = icpara[k][l];
00306 }
00307 arMatrixMul(&pMatrix, &kMatrix, &cameraMatrix);
00308 arMatrixMul(&proyMatrix, &pMatrix, &cubeMatrix);
00309
00310
00311
00312
00313
00314 cvLine(img, cvPoint(proyMatrix.m[0]/proyMatrix.m[8], proyMatrix.m[4]/proyMatrix.m[8]),
00315 cvPoint(proyMatrix.m[1]/proyMatrix.m[9], proyMatrix.m[5]/proyMatrix.m[9]),
00316 CV_RGB(0,0,255), width);
00317
00318 cvLine(img, cvPoint(proyMatrix.m[0]/proyMatrix.m[8], proyMatrix.m[4]/proyMatrix.m[8]),
00319 cvPoint(proyMatrix.m[2]/proyMatrix.m[10], proyMatrix.m[6]/proyMatrix.m[10]),
00320 CV_RGB(255,0,0), width);
00321
00322 cvLine(img, cvPoint(proyMatrix.m[0]/proyMatrix.m[8], proyMatrix.m[4]/proyMatrix.m[8]),
00323 cvPoint(proyMatrix.m[3]/proyMatrix.m[11], proyMatrix.m[7]/proyMatrix.m[11]),
00324 CV_RGB(127,0,127), width);
00325
00326 CvFont font;
00327 cvInitFont(&font, CV_FONT_HERSHEY_SIMPLEX, 0.5, 0.5, 0, 2, CV_AA);
00328 char posZ[16];
00329 sprintf(posZ, "%.1f", object[i].trans[2][3]/20);
00330 cvPutText(img, posZ, cvPoint(marker_info[k].pos[0], marker_info[k].pos[1]+32),
00331 &font, cvScalar(255,145,0, 0));
00332
00333
00334
00335 printf("origen x = %.2f\n", marker_info[k].vertex[0][0]);
00336 printf("origen y = %.2f\n", marker_info[k].vertex[0][1]);
00337
00338 for (int k = 0; k < 3; k++) {
00339 for (int l = 0; l < 4; l++) {
00340 printf("%.2f ", pMatrix.m[k*4+l]);
00341 }
00342 printf("\n");
00343 }
00344
00345
00346 printf("---------------\n");
00347
00348 for (int k = 0; k < 3; k++) {
00349 for (int l = 0; l < 3; l++) {
00350 printf("%.2f ", kMatrix.m[k*3+l]);
00351 }
00352 printf("\n");
00353 }
00354
00355
00356 printf("---------------\n");
00357
00358 for (int k = 0; k < 3; k++) {
00359 for (int l = 0; l < 4; l++) {
00360 printf("%.2f ", icpara[k][l]);
00361 }
00362 printf("\n");
00363 }
00364
00365
00366 printf("---------------\n");
00367 for (int k = 0; k < 2; k++) {
00368 for (int l = 0; l < 4; l++) {
00369
00370 printf("%.2f ", proyMatrix.m[k*4+l]/proyMatrix.m[2*4+l]);
00371 }
00372 printf("\n");
00373 }
00374
00375
00376 int x, y;
00377 double diameter;
00378 double xRot, yRot, zRot;
00379 double xMetric, yMetric, zMetric;
00380
00381 x = marker_info[k].pos[0];
00382 y = marker_info[k].pos[1];
00383
00384
00385
00386
00387 xRot = -asin(-object[i].trans[1][2]);
00388 yRot = -atan2(object[i].trans[0][2],-object[i].trans[2][2]);
00389 zRot = atan2(object[i].trans[1][0],-object[i].trans[1][1]);
00390
00391
00392
00393
00394
00395
00396 double x_delta = (double)(2*x-img->width)/(double)img->width;
00397 double y_delta = (double)(2*y-img->height)/(double)img->height;
00398 double rel_theta = x_delta * haov / 2.0;
00399 double rel_phi = y_delta * vaov / 2.0;
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412 double x1 = marker_info[k].vertex[0][0] - marker_info[k].vertex[2][0];
00413 double y1 = marker_info[k].vertex[0][1] - marker_info[k].vertex[2][1];
00414 double x2 = marker_info[k].vertex[1][0] - marker_info[k].vertex[3][0];
00415 double y2 = marker_info[k].vertex[1][1] - marker_info[k].vertex[3][1];
00416 double area = 0.5 * fabs(x1*y2 - x2*y1);
00417 double unrotated_area = area / (cos(xRot)*cos(yRot));
00418 diameter = sqrt(unrotated_area);
00419
00420 double theta_object = haov * (diameter / (double)img->width);
00421
00422
00423
00424
00425 int dist = object[i].marker_width / tan(theta_object);
00426
00427 xMetric = dist * cos(rel_theta) / 1000.0;
00428 yMetric = -dist * sin(rel_theta) * cos(rel_phi) / 1000.0;
00429 zMetric = -dist * cos(rel_theta) * sin(rel_phi) / 1000.0;
00430
00431 ar_recog::Tag tag;
00432 tag.id = i;
00433 tag.cf = marker_info[k].cf;
00434 tag.x = x;
00435 tag.y = y;
00436 tag.diameter = diameter;
00437 tag.distance = dist/1000.0;
00438 tag.xRot = xRot;
00439 tag.yRot = yRot;
00440 tag.zRot = zRot;
00441 tag.xMetric = xMetric;
00442 tag.yMetric = yMetric;
00443 tag.zMetric = zMetric;
00444 int b = marker_info[k].dir;
00445 int idx[4];
00446
00447 switch (b) {
00448 case 0:
00449 idx[0] = 0;
00450 idx[1] = 1;
00451 idx[2] = 2;
00452 idx[3] = 3;
00453 break;
00454 case 3:
00455 idx[0] = 1;
00456 idx[1] = 2;
00457 idx[2] = 3;
00458 idx[3] = 0;
00459 break;
00460 case 2:
00461 idx[0] = 2;
00462 idx[1] = 3;
00463 idx[2] = 0;
00464 idx[3] = 1;
00465 break;
00466 default:
00467 idx[0] = 3;
00468 idx[1] = 0;
00469 idx[2] = 1;
00470 idx[3] = 2;
00471 break;
00472 }
00473
00474 tag.cwCorners[0] = marker_info[k].vertex[idx[0]][0];
00475 tag.cwCorners[1] = marker_info[k].vertex[idx[0]][1];
00476 tag.cwCorners[2] = marker_info[k].vertex[idx[1]][0];
00477 tag.cwCorners[3] = marker_info[k].vertex[idx[1]][1];
00478 tag.cwCorners[4] = marker_info[k].vertex[idx[2]][0];
00479 tag.cwCorners[5] = marker_info[k].vertex[idx[2]][1];
00480 tag.cwCorners[6] = marker_info[k].vertex[idx[3]][0];
00481 tag.cwCorners[7] = marker_info[k].vertex[idx[3]][1];
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501 tags.tags.push_back(tag);
00502
00503 last_reported_distance = dist;
00504
00505
00506 }
00507 }
00508 }
00509
00510 ROS_INFO("markernum=%d", marker_num);
00511 if (marker_num == 0) {
00512 thresh += sign * kThresh * threshVariation;
00513 kThresh = kThresh + 1;
00514 sign = -sign;
00515
00516 if (abs(thresh - THRESH) > THRESH_RANGE_LIMIT) {
00517 thresh = THRESH;
00518 kThresh = 1;
00519 sign = 1;
00520 }
00521 }
00522
00523 ROS_INFO("THRESH=%d\n", thresh);
00524
00525 tags.tag_count = tags.tags.size();
00526
00527 sensor_msgs::ImagePtr out = sensor_msgs::CvBridge::cvToImgMsg(img, "bgr8");
00528 sensor_msgs::ImagePtr outhist = sensor_msgs::CvBridge::cvToImgMsg(hist, "passthrough");
00529 ar_img.publish(out);
00530 ar_hist.publish(outhist);
00531
00532 tags_pub.publish(tags);
00533
00534 free(data);
00535 }
00536
00537 void handleRawImage(const sensor_msgs::ImageConstPtr& in) {
00538 if (using_rectified_images) return;
00539 const sensor_msgs::CameraInfoConstPtr ign;
00540 handleImage(in,ign);
00541 }
00542
00543 bool calibrateDistance(ar_recog::CalibrateDistance::Request &req,
00544 ar_recog::CalibrateDistance::Response &resp) {
00545
00546 using_rectified_images = false;
00547 haov = haov*((double)last_reported_distance / (double)req.dist);
00548 resp.aov = haov;
00549 return true;
00550 }
00551
00552 int main(int argc, char **argv) {
00553 ros::init(argc, argv, "image_listener");
00554 ros::NodeHandle nh;
00555
00556 std::string tmp;
00557 nh.param<std::string>("camera_para", tmp, "camera_para.dat");
00558 strcpy(cparam_name, tmp.c_str());
00559 nh.param<std::string>("model_name", tmp, "object_data");
00560 strcpy(model_name, tmp.c_str());
00561
00562 if (nh.getParam("aov", haov)) {
00563 using_rectified_images = false;
00564
00565 std::cout << "aov-: " << haov << std::endl;
00566 }
00567 else {
00568 using_rectified_images = true;
00569 }
00570
00571 if (nh.getParam("ar_smooth", ar_smooth)) {
00572 std::cout << "ar_smooth: " << ar_smooth << std::endl;
00573 } else {
00574 std::cout << "ar_smooth parameter missing, will implement smoothing" << std::endl;
00575 }
00576
00577 tags_pub = nh.advertise<ar_recog::Tags>("tags",1);
00578
00579 ros::ServiceServer calibrate_distance = nh.advertiseService("ar/calibrate_distance", calibrateDistance);
00580
00581 image_transport::ImageTransport it(nh);
00582 ar_img = it.advertise("ar/image", 1);
00583 ar_hist = it.advertise("ar/hist", 1);
00584
00585 arImXsize = arImYsize = 0;
00586
00587
00588 image_transport::CameraSubscriber sub = it.subscribeCamera("image", 1, handleImage);
00589 image_transport::Subscriber subRaw = it.subscribe("image", 1, handleRawImage);
00590 ros::spin();
00591 }