ar_multi.cpp
Go to the documentation of this file.
00001 /*
00002  *  Multi Marker Pose Estimation using ARToolkit
00003  *  Copyright (C) 2010, CCNY Robotics Lab
00004  *  Ivan Dryanovski <ivan.dryanovski@gmail.com>
00005  *  William Morris <morris@ee.ccny.cuny.edu>
00006  *  Gautier Dumonteil <gautier.dumonteil@gmail.com>
00007  *  http://robotics.ccny.cuny.edu
00008  *
00009  *  This program is free software: you can redistribute it and/or modify
00010  *  it under the terms of the GNU General Public License as published by
00011  *  the Free Software Foundation, either version 3 of the License, or
00012  *  (at your option) any later version.
00013  *
00014  *  This program is distributed in the hope that it will be useful,
00015  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  *  GNU General Public License for more details.
00018  *
00019  *  You should have received a copy of the GNU General Public License
00020  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00021  */
00022 
00023 #include "ar_pose/ar_multi.h"
00024 #include "ar_pose/object.h"
00025 
00026 using namespace cv;
00027 using namespace ar_pose;
00028 
00029 int main (int argc, char **argv)
00030 {
00031   ros::init (argc, argv, "ar_single");
00032   ros::NodeHandle n;
00033   ar_pose::ARSinglePublisher ar_single (n);
00034   
00035   dynamic_reconfigure::Server<ARSinglePublisherConfig> server;
00036   dynamic_reconfigure::Server<ARSinglePublisherConfig>::CallbackType f;
00037 
00038   f = boost::bind(&(ARSinglePublisher::callback), _1, _2);
00039   server.setCallback(f);
00040   
00041   
00042   ros::spin ();
00043   return 0;
00044 }
00045 
00046 namespace ar_pose
00047 {
00048   
00049   int ARSinglePublisher::window_size_ = 80;
00050   double ARSinglePublisher::k_ = 0.06;
00051   bool ARSinglePublisher::enable_thresholded_ = false;
00052   bool ARSinglePublisher::enable_hist_ = false;
00053   int ARSinglePublisher::threshold_ = 100;
00054   bool ARSinglePublisher::enable_local_thresh_=false;
00055   
00056   void ARSinglePublisher::callback(ARSinglePublisherConfig &config, uint32_t level) {
00057   ROS_INFO("Reconfigure Request: %d %d %d %.2f %d", 
00058             config.window_size, 
00059             config.enable_hist, 
00060             config.enable_thresholded, 
00061             config.k,
00062             config.original_thresh,
00063             config.enable_local_thresh);
00064        window_size_ = config.window_size;
00065        enable_hist_ = config.enable_hist; 
00066        enable_thresholded_ = config.enable_thresholded;
00067        k_ = config.k;
00068        threshold_ = config.original_thresh; 
00069        enable_local_thresh_=config.enable_local_thresh;
00070   }
00071   
00072   IplImage * ARSinglePublisher::drawHistogram(IplImage *img)
00073   {
00074     int numBins = 256;
00075     float range[] = {0, 255};
00076     float *ranges[] = { range };
00077     float scaleX = 2, scaleY = 2;
00078     const int width = 3;
00079 
00080     CvHistogram *hist = cvCreateHist(1, &numBins, CV_HIST_ARRAY, ranges, 1);
00081     cvClearHist(hist);
00082 
00083     IplImage *im_gray = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1);
00084     cvCvtColor(img, im_gray, CV_RGB2GRAY);
00085 
00086     cvCalcHist(&im_gray, hist, 0, 0);
00087     IplImage *imgHistGray = cvCreateImage(cvSize(256*scaleX, 64*scaleY), 8, 3);
00088     cvZero(imgHistGray);
00089 
00090     float histMax = 0;
00091     cvGetMinMaxHistValue(hist, 0, &histMax, 0, 0);
00092 
00093     for(int i=0;i<255;i++)
00094     {
00095       float histValue = cvQueryHistValue_1D(hist, i);
00096       float nextValue = cvQueryHistValue_1D(hist, i+1);
00097 
00098       CvPoint pt1 = cvPoint(i*scaleX, 64*scaleY);
00099       CvPoint pt2 = cvPoint(i*scaleX+scaleX, 64*scaleY);
00100       CvPoint pt3 = cvPoint(i*scaleX+scaleX, (64-nextValue*64/histMax)*scaleY);
00101       CvPoint pt4 = cvPoint(i*scaleX, (64-histValue*64/histMax)*scaleY);
00102 
00103       int numPts = 5;
00104       CvPoint pts[] = {pt1, pt2, pt3, pt4, pt1};
00105 
00106       cvFillConvexPoly(imgHistGray, pts, numPts, CV_RGB(255,255,255));
00107     }
00108     /*
00109     cvcv(imgHistGray,cvPoint(thresh*scaleX, 0), 
00110     cvPoint(thresh*scaleX, 64*scaleY),
00111     CV_RGB(255,0,0),width);
00112       */
00113 
00114     cvReleaseImage(&im_gray);
00115     cvReleaseHist(&hist);
00116 
00117     return imgHistGray;
00118   }
00119   
00127   void ARSinglePublisher::localThreshold(Mat& img, Mat& dst, double k, int window)
00128   {
00129     Mat mean(img.size(), CV_32F);
00130     Mat deviation(img.size(), CV_32F);
00131     Mat aux(img.size(), CV_32F);
00132     Mat thresh(img.size(), CV_8U);
00133     boxFilter(img, mean, CV_32F, Size(window, window));
00134     subtract(img, mean, deviation, noArray(), CV_32F);
00135     subtract(Scalar(255), deviation, aux, noArray(), CV_32F);
00136     divide(deviation, aux, aux, 1, CV_32F);
00137     subtract(aux, Scalar(1), aux, noArray(), CV_32F);
00138     multiply(Scalar(k), aux, aux, 1, CV_32F);
00139     add(Scalar(1), aux, aux, noArray(), CV_32F);
00140     multiply(mean, aux, thresh, 1, CV_8U);
00141     dst = img > thresh;
00142   }
00143   
00144   ARSinglePublisher::ARSinglePublisher (ros::NodeHandle & n):n_ (n), it_ (n_)
00145   {
00146     std::string local_path;
00147     std::string package_path = ros::package::getPath (ROS_PACKAGE_NAME);
00148           std::string default_path = "data/object_4x4";
00149     ros::NodeHandle n_param ("~");
00150     XmlRpc::XmlRpcValue xml_marker_center;
00151 
00152     // **** get parameters
00153 
00154     if (!n_param.getParam ("publish_tf", publishTf_))
00155       publishTf_ = true;
00156     ROS_INFO ("\tPublish transforms: %d", publishTf_);
00157 
00158     if (!n_param.getParam ("publish_visual_markers", publishVisualMarkers_))
00159       publishVisualMarkers_ = true;
00160     ROS_INFO ("\tPublish visual markers: %d", publishVisualMarkers_);
00161 
00162     if (!n_param.getParam ("threshold", threshold_))
00163 //      threshold_ = 100;
00164     ROS_INFO ("\tThreshold: %d", threshold_);
00165         
00166         //modifications to allow path list from outside the package
00167         n_param.param ("marker_pattern_list", local_path, default_path);
00168         if (local_path.compare(0,5,"data/") == 0){
00169           //according to previous implementations, check if first 5 chars equal "data/"
00170           sprintf (pattern_filename_, "%s/%s", package_path.c_str (), local_path.c_str ());
00171         }
00172         else{
00173           //for new implementations, can pass a path outside the package_path
00174           sprintf (pattern_filename_, "%s", local_path.c_str ());
00175         }
00176         ROS_INFO ("Marker Pattern Filename: %s", pattern_filename_);
00177         
00178     // **** subscribe
00179 
00180     ROS_INFO ("Subscribing to info topic");
00181     sub_ = n_.subscribe (cameraInfoTopic_, 1, &ARSinglePublisher::camInfoCallback, this);
00182     getCamInfo_ = false;
00183 
00184     // **** advertsie 
00185 
00186     thresholded_ = it_.advertise("thresholded", 1);
00187     histogram_ = it_.advertise("histogram", 1);
00188     arMarkerPub_ = n_.advertise < ar_pose::ARMarkers > ("ar_pose_marker", 0);
00189     if(publishVisualMarkers_)
00190     {
00191                 rvizMarkerPub_ = n_.advertise < visualization_msgs::Marker > ("visualization_marker", 0);
00192          }
00193   }
00194 
00195   ARSinglePublisher::~ARSinglePublisher (void)
00196   {
00197     //cvReleaseImage(&capture_); //Don't know why but crash when release the image
00198     arVideoCapStop ();
00199     arVideoClose ();
00200   }
00201 
00202   void ARSinglePublisher::camInfoCallback (const sensor_msgs::CameraInfoConstPtr & cam_info)
00203   {
00204     if (!getCamInfo_)
00205     {
00206       cam_info_ = (*cam_info);
00207 
00208       cam_param_.xsize = cam_info_.width;
00209       cam_param_.ysize = cam_info_.height;
00210 
00211       cam_param_.mat[0][0] = cam_info_.P[0];
00212       cam_param_.mat[1][0] = cam_info_.P[4];
00213       cam_param_.mat[2][0] = cam_info_.P[8];
00214       cam_param_.mat[0][1] = cam_info_.P[1];
00215       cam_param_.mat[1][1] = cam_info_.P[5];
00216       cam_param_.mat[2][1] = cam_info_.P[9];
00217       cam_param_.mat[0][2] = cam_info_.P[2];
00218       cam_param_.mat[1][2] = cam_info_.P[6];
00219       cam_param_.mat[2][2] = cam_info_.P[10];
00220       cam_param_.mat[0][3] = cam_info_.P[3];
00221       cam_param_.mat[1][3] = cam_info_.P[7];
00222       cam_param_.mat[2][3] = cam_info_.P[11];
00223 
00224       cam_param_.dist_factor[0] = cam_info_.K[2];       // x0 = cX from openCV calibration
00225       cam_param_.dist_factor[1] = cam_info_.K[5];       // y0 = cY from openCV calibration
00226       cam_param_.dist_factor[2] = -100*cam_info_.D[0];  // f = -100*k1 from CV. Note, we had to do mm^2 to m^2, hence 10^8->10^2
00227       cam_param_.dist_factor[3] = 1.0;                  // scale factor, should probably be >1, but who cares...
00228       
00229       arInit ();
00230 
00231       ROS_INFO ("Subscribing to image topic");
00232       cam_sub_ = it_.subscribe (cameraImageTopic_, 1, &ARSinglePublisher::getTransformationCallback, this);
00233       getCamInfo_ = true;
00234     }
00235   }
00236 
00237   void ARSinglePublisher::arInit ()
00238   {
00239     arInitCparam (&cam_param_);
00240     ROS_INFO ("*** Camera Parameter ***");
00241     arParamDisp (&cam_param_);
00242 
00243     // load in the object data - trained markers and associated bitmap files
00244     if ((object = ar_object::read_ObjData (pattern_filename_, &objectnum)) == NULL)
00245       ROS_BREAK ();
00246     ROS_DEBUG ("Objectfile num = %d", objectnum);
00247 
00248     sz_ = cvSize (cam_param_.xsize, cam_param_.ysize);
00249     capture_ = cvCreateImage (sz_, IPL_DEPTH_8U, 4);
00250   }
00251 
00252   void ARSinglePublisher::getTransformationCallback (const sensor_msgs::ImageConstPtr & image_msg)
00253   {
00254     
00255     ARUint8 *dataPtr;
00256     ARMarkerInfo *marker_info;
00257     int marker_num;
00258     int i, k, j, l;
00259 
00260     /* Get the image from ROSTOPIC
00261      * NOTE: the dataPtr format is BGR because the ARToolKit library was
00262      * build with V4L, dataPtr format change according to the 
00263      * ARToolKit configure option (see config.h).*/
00264     try
00265     {
00266       capture_ = bridge_.imgMsgToCv (image_msg, "bgr8");
00267     }
00268     catch (sensor_msgs::CvBridgeException & e)
00269     {
00270       ROS_ERROR ("Could not convert from '%s' to 'bgr8'.", image_msg->encoding.c_str ());
00271     }
00272     
00275 //     ROS_WARN_STREAM("********** trying to compute local threshold\n");
00276     IplImage *hist = NULL;
00277     if (enable_hist_)
00278        hist = drawHistogram(capture_);
00279     IplImage *im_gray = cvCreateImage(cvGetSize(capture_),IPL_DEPTH_8U,1);
00280     cvCvtColor(capture_, im_gray, CV_BGR2GRAY);  
00281     Mat gray(im_gray);
00282     Mat thresholded(gray.size(), CV_8U);
00283     
00284     
00285     if (enable_local_thresh_){
00286     localThreshold(gray, thresholded, k_, 
00287                   (window_size_ % 2 == 0 ? window_size_ + 1: window_size_));
00288     }
00289     else {
00290     threshold(gray, thresholded, threshold_, 255, THRESH_BINARY);
00291     }
00293 //     int erosion_size = 1;   
00294 //     cv::Mat element = cv::getStructuringElement(cv::MORPH_ELLIPSE,
00295 //                       cv::Size(2 * erosion_size + 1, 2 * erosion_size + 1), 
00296 //                       cv::Point(erosion_size, erosion_size) );
00297 //     dilate(thresholded, thresholded, element);
00298 //     erode(thresholded, thresholded, element);
00299     
00300     
00301     
00302 //     ROS_WARN_STREAM("********* successfully computed local threshold\n");
00303     
00304     //cvConvertImage(capture,capture,CV_CVTIMG_FLIP);
00305     //dataPtr = (ARUint8 *) capture_->imageData;
00306     
00307     // copy thresholded image into data
00308     dataPtr = (ARUint8*) malloc(sizeof(ARUint8)*capture_->width*capture_->height*3);
00309     int cnt = 0;
00310     for (int y = 0; y < capture_->height; y++) {
00311       for (int x = 0; x < capture_->width; x++) {
00312         for (int j = 0; j < 3; j++) {
00313           dataPtr[cnt++] = thresholded.at<uchar>(y,x);
00314         }
00315       }
00316     }
00317 
00318     // detect the markers in the video frame
00319     if (arDetectMarker (dataPtr, threshold_, &marker_info, &marker_num) < 0)
00320     {
00321       argCleanup ();
00322       ROS_BREAK ();
00323     }
00324 
00325     arPoseMarkers_.markers.clear ();
00326     // check for known patterns
00327     for (i = 0; i < objectnum; i++)
00328     {
00329       k = -1;
00330       l = -1;
00331       for (j = 0; j < marker_num; j++)
00332       {
00333         if (object[i].id == marker_info[j].id)
00334         {
00335           if (k == -1)
00336             k = j;
00337           else                  // make sure you have the best pattern (highest confidence factor)
00338           if (marker_info[k].cf < marker_info[j].cf) {
00339             l = k;
00340             k = j;
00341           }
00342         }
00343       }
00344       if (k == -1)
00345       {
00346         object[i].visible = 0;
00347         continue;
00348       }
00349       
00350       if (l != -1 && marker_info[k].cf < 2 * marker_info[l].cf)
00351       {
00352         object[i].visible = 0;
00353         continue;
00354       }
00355 
00356       // calculate the transform for each marker
00357       if (object[i].visible == 0)
00358       {
00359         arGetTransMat (&marker_info[k], object[i].marker_center, object[i].marker_width, object[i].trans);
00360       }
00361       else
00362       {
00363         arGetTransMatCont (&marker_info[k], object[i].trans,
00364                            object[i].marker_center, object[i].marker_width, object[i].trans);
00365       }
00366       object[i].visible = 1;
00367       
00368       
00369 
00370       double arQuat[4], arPos[3];
00371 
00372       //arUtilMatInv (object[i].trans, cam_trans);
00373       arUtilMat2QuatPos (object[i].trans, arQuat, arPos);
00374 
00375       // **** convert to ROS frame
00376 
00377       double quat[4], pos[3];
00378 
00379       pos[0] = arPos[0] * AR_TO_ROS;
00380       pos[1] = arPos[1] * AR_TO_ROS;
00381       pos[2] = arPos[2] * AR_TO_ROS;
00382 
00383       quat[0] = -arQuat[0];
00384       quat[1] = -arQuat[1];
00385       quat[2] = -arQuat[2];
00386       quat[3] = arQuat[3];
00387 
00388       ROS_DEBUG (" Object num %i ------------------------------------------------", i);
00389       ROS_DEBUG (" QUAT: Pos x: %3.5f  y: %3.5f  z: %3.5f", pos[0], pos[1], pos[2]);
00390       ROS_DEBUG ("     Quat qx: %3.5f qy: %3.5f qz: %3.5f qw: %3.5f", quat[0], quat[1], quat[2], quat[3]);
00391 
00392       // **** publish the marker
00393 
00394       ar_pose::ARMarker ar_pose_marker;
00395       ar_pose_marker.header.frame_id = image_msg->header.frame_id;
00396       
00397       ar_pose_marker.header.stamp = image_msg->header.stamp;
00398       ar_pose_marker.id = object[i].id;
00399 
00400       ar_pose_marker.pose.pose.position.x = pos[0];
00401       ar_pose_marker.pose.pose.position.y = pos[1];
00402       ar_pose_marker.pose.pose.position.z = pos[2];
00403 
00404       ar_pose_marker.pose.pose.orientation.x = quat[0];
00405       ar_pose_marker.pose.pose.orientation.y = quat[1];
00406       ar_pose_marker.pose.pose.orientation.z = quat[2];
00407       ar_pose_marker.pose.pose.orientation.w = quat[3];
00408 
00409       ar_pose_marker.confidence = round(marker_info->cf * 100);
00410       arPoseMarkers_.markers.push_back (ar_pose_marker);
00411 
00412       // **** publish transform between camera and marker
00413 
00414       btQuaternion rotation (quat[0], quat[1], quat[2], quat[3]);
00415       btVector3 origin (pos[0], pos[1], pos[2]);
00416       btTransform t (rotation, origin);
00417 
00418       if (publishTf_)
00419       {
00420                         tf::StampedTransform camToMarker (t, image_msg->header.stamp, image_msg->header.frame_id, object[i].name);
00421                         broadcaster_.sendTransform(camToMarker);
00422       }
00423 
00424       // **** publish visual marker
00425 
00426       if (publishVisualMarkers_)
00427       {
00428         btVector3 markerOrigin (0, 0, 0.25 * object[i].marker_width * AR_TO_ROS);
00429         btTransform m (btQuaternion::getIdentity (), markerOrigin);
00430         btTransform markerPose = t * m; // marker pose in the camera frame
00431 
00432         tf::poseTFToMsg (markerPose, rvizMarker_.pose);
00433 
00434         rvizMarker_.header.frame_id = image_msg->header.frame_id;
00435         rvizMarker_.header.stamp = image_msg->header.stamp;
00436         rvizMarker_.id = object[i].id;
00437 
00438         rvizMarker_.scale.x = 1.0 * object[i].marker_width * AR_TO_ROS;
00439         rvizMarker_.scale.y = 1.0 * object[i].marker_width * AR_TO_ROS;
00440         rvizMarker_.scale.z = 0.5 * object[i].marker_width * AR_TO_ROS;
00441         rvizMarker_.ns = "basic_shapes";
00442         rvizMarker_.type = visualization_msgs::Marker::CUBE;
00443         rvizMarker_.action = visualization_msgs::Marker::ADD;
00444         switch (i)
00445         {
00446           case 0:
00447             rvizMarker_.color.r = 0.0f;
00448             rvizMarker_.color.g = 0.0f;
00449             rvizMarker_.color.b = 1.0f;
00450             rvizMarker_.color.a = 1.0;
00451             break;
00452           case 1:
00453             rvizMarker_.color.r = 1.0f;
00454             rvizMarker_.color.g = 0.0f;
00455             rvizMarker_.color.b = 0.0f;
00456             rvizMarker_.color.a = 1.0;
00457             break;
00458           default:
00459             rvizMarker_.color.r = 0.0f;
00460             rvizMarker_.color.g = 1.0f;
00461             rvizMarker_.color.b = 0.0f;
00462             rvizMarker_.color.a = 1.0;
00463         }
00464         rvizMarker_.lifetime = ros::Duration (1);
00465 
00466         rvizMarkerPub_.publish (rvizMarker_);
00467         ROS_DEBUG ("Published visual marker");
00468       }
00469     }
00470     
00471  
00472     
00473 //     ROS_WARN_STREAM("************* Trying to convert to bridge\n");
00474     if (enable_thresholded_) {
00475       IplImage threshipl = thresholded;
00476       IplImage* iplThresh = &threshipl; 
00477       IplImage* color = cvCreateImage(thresholded.size(), IPL_DEPTH_8U, 3);
00478       cvCvtColor(iplThresh, color, CV_GRAY2BGR);
00479       
00480       int colorR = 255/(objectnum+1);
00481       for (k = 0; k < marker_num; k++)
00482       {
00483         if (marker_info[k].cf<1 && marker_info[k].cf>0){
00484          const int width = 3;
00485         cvLine(color,cvPoint(marker_info[k].vertex[0][0],marker_info[k].vertex[0][1]),
00486         cvPoint(marker_info[k].vertex[1][0],marker_info[k].vertex[1][1])
00487           ,CV_RGB(colorR*marker_info[k].id, 255-colorR*marker_info[k].id, 50),width);
00488         cvLine(color,cvPoint(marker_info[k].vertex[1][0],marker_info[k].vertex[1][1]),
00489         cvPoint(marker_info[k].vertex[2][0],marker_info[k].vertex[2][1])
00490           ,CV_RGB(colorR*marker_info[k].id, 255-colorR*marker_info[k].id, 50),width);
00491         cvLine(color,cvPoint(marker_info[k].vertex[2][0],marker_info[k].vertex[2][1]),
00492         cvPoint(marker_info[k].vertex[3][0],marker_info[k].vertex[3][1])
00493           ,CV_RGB(colorR*marker_info[k].id, 255-colorR*marker_info[k].id, 50),width);
00494         cvLine(color,cvPoint(marker_info[k].vertex[3][0],marker_info[k].vertex[3][1]),
00495         cvPoint(marker_info[k].vertex[0][0],marker_info[k].vertex[0][1])
00496           ,CV_RGB(colorR*marker_info[k].id, 255-colorR*marker_info[k].id, 50),width);
00497         }
00498       }
00499     
00500       sensor_msgs::ImagePtr threshPtr = sensor_msgs::CvBridge::cvToImgMsg(color, "passthrough");
00501 //       threshPtr.header.frame_id = image_msg.frame_id;
00502 //       threshPtr.header.stamp = image_msg.stamp;
00503       threshPtr->header=image_msg->header;
00504       
00505       thresholded_.publish(threshPtr);
00506       
00507       cvReleaseImage(&color);
00508       //cvReleaseImage(&iplThresh);
00509     }
00510     
00511     if (enable_hist_) {
00512       sensor_msgs::ImagePtr histPtr = sensor_msgs::CvBridge::cvToImgMsg(hist, "passthrough");
00513       histPtr->header=image_msg->header;
00514       histogram_.publish(histPtr);
00515     }
00516 //     ROS_WARN_STREAM("************* Sucessfully converted to bridge\n");
00517    
00518      cvReleaseImage(&im_gray);
00519      cvReleaseImage(&hist);
00520     free(dataPtr);
00521     
00522 //     ROS_WARN_STREAM("************ successfully cleaned up\n");
00523     arMarkerPub_.publish (arPoseMarkers_);
00524     ROS_DEBUG ("Published ar_multi markers");
00525   }
00526 
00527 
00528 }                               // end namespace ar_pose
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Properties Friends Defines


ar_pose_old
Author(s): Ivan Dryanovski, William Morris, Gautier Dumonteil et al.
autogenerated on Fri Jan 25 2013 12:35:34