ar_kinect.cpp
Go to the documentation of this file.
00001 /*
00002  *  Multi Marker Pose Estimation using ARToolkit & Kinect
00003  *  Copyright (C) 2010, CCNY Robotics Lab, 2011 ILS 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  *  Michael Ferguson <ferguson@cs.albany.edu>
00010  *  http://robotics.ils.albany.edu
00011  *
00012  *  This program is free software: you can redistribute it and/or modify
00013  *  it under the terms of the GNU General Public License as published by
00014  *  the Free Software Foundation, either version 3 of the License, or
00015  *  (at your option) any later version.
00016  *
00017  *  This program is distributed in the hope that it will be useful,
00018  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020  *  GNU General Public License for more details.
00021  *
00022  *  You should have received a copy of the GNU General Public License
00023  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00024  */
00025 
00026 #include <math.h>
00027 #include "ar_kinect/ar_kinect.h"
00028 #include "ar_kinect/object.h"
00029 
00030 int main (int argc, char **argv)
00031 {
00032   ros::init (argc, argv, "ar_kinect");
00033   ros::NodeHandle n;
00034   ar_pose::ARPublisher ar_kinect (n);
00035   ros::spin ();
00036   return 0;
00037 }
00038 
00039 namespace ar_pose
00040 {
00041   tf::Transform tfFromEigen(Eigen::Matrix4f trans)
00042   {
00043     tf::Matrix3x3 btm;
00044     btm.setValue(trans(0,0),trans(0,1),trans(0,2),
00045                trans(1,0),trans(1,1),trans(1,2),
00046                trans(2,0),trans(2,1),trans(2,2));
00047     tf::Transform ret;
00048     ret.setOrigin(tf::Vector3(trans(0,3),trans(1,3),trans(2,3)));
00049     ret.setBasis(btm);
00050     return ret;
00051   }
00052 
00053   pcl::PointXYZRGB makeRGBPoint( float x, float y, float z )
00054   {
00055     pcl::PointXYZRGB p;
00056     p.x = x;
00057     p.y = y; 
00058     p.z = z;
00059     return p;
00060   }
00061 
00062   ARPublisher::ARPublisher (ros::NodeHandle & n):n_ (n), configured_(false)
00063   {
00064     std::string path;
00065     std::string package_path = ros::package::getPath (ROS_PACKAGE_NAME);
00066     ros::NodeHandle n_param ("~");
00067     XmlRpc::XmlRpcValue xml_marker_center;
00068 
00069     // **** get parameters
00070 
00071     if (!n_param.getParam ("publish_tf", publishTf_))
00072       publishTf_ = true;
00073     ROS_INFO ("\tPublish transforms: %d", publishTf_);
00074 
00075     if (!n_param.getParam ("publish_visual_markers", publishVisualMarkers_))
00076       publishVisualMarkers_ = true;
00077     ROS_INFO ("\tPublish visual markers: %d", publishVisualMarkers_);
00078 
00079     if (!n_param.getParam ("threshold", threshold_))
00080       threshold_ = 100;
00081     ROS_INFO ("\tThreshold: %d", threshold_);
00082 
00083     if (!n_param.getParam ("marker_pattern_list", path)){
00084       sprintf(pattern_filename_, "%s/data/objects_kinect", package_path.c_str());
00085     }else{
00086       sprintf(pattern_filename_, "%s", path.c_str());
00087     }    
00088     ROS_INFO ("Marker Pattern Filename: %s", pattern_filename_);
00089 
00090     if (!n_param.getParam ("marker_data_directory", path)){
00091       sprintf(data_directory_, "%s", package_path.c_str());
00092     }else{
00093       sprintf(data_directory_, "%s", path.c_str());
00094     }    
00095     ROS_INFO ("Marker Data Directory: %s", data_directory_);
00096 
00097     // **** subscribe
00098 
00099     configured_ = false;
00100     cloud_sub_ = n_.subscribe(cloudTopic_, 1, &ARPublisher::getTransformationCallback, this);
00101 
00102     // **** advertise 
00103 
00104     arMarkerPub_ = n_.advertise < ar_pose::ARMarkers > ("ar_pose_markers",0);
00105     if(publishVisualMarkers_)
00106     {
00107                 rvizMarkerPub_ = n_.advertise < visualization_msgs::Marker > ("visualization_marker", 0);
00108          }
00109   }
00110 
00111   ARPublisher::~ARPublisher (void)
00112   {
00113     arVideoCapStop ();
00114     arVideoClose ();
00115   }
00116 
00117   /* 
00118    * Setup artoolkit
00119    */
00120   void ARPublisher::arInit ()
00121   {
00122     arInitCparam (&cam_param_);
00123     ROS_INFO ("*** Camera Parameter ***");
00124     arParamDisp (&cam_param_);
00125 
00126     // load in the object data - trained markers and associated bitmap files
00127     if ((object = ar_object::read_ObjData (pattern_filename_, data_directory_, &objectnum)) == NULL)
00128       ROS_BREAK ();
00129     ROS_DEBUG ("Objectfile num = %d", objectnum);
00130 
00131     sz_ = cvSize (cam_param_.xsize, cam_param_.ysize);
00132     capture_ = cvCreateImage (sz_, IPL_DEPTH_8U, 4);
00133     configured_ = true;
00134   }
00135 
00136   /* 
00137    * One and only one callback, now takes cloud, does everything else needed. 
00138    */
00139   void ARPublisher::getTransformationCallback (const sensor_msgs::PointCloud2ConstPtr & msg)
00140   {
00141     sensor_msgs::ImagePtr image_msg(new sensor_msgs::Image);
00142     ARUint8 *dataPtr;
00143     ARMarkerInfo *marker_info;
00144     int marker_num;
00145     int i, k, j;
00146 
00147     /* do we need to initialize? */
00148     if(!configured_)
00149     {
00150       if(msg->width == 0 || msg->height == 0)
00151       {
00152         ROS_ERROR ("Deformed cloud! Size = %d, %d.", msg->width, msg->height);
00153         return;
00154       }
00155 
00156       cam_param_.xsize = msg->width;
00157       cam_param_.ysize = msg->height;
00158 
00159       cam_param_.dist_factor[0] = msg->width/2;         // x0 = cX from openCV calibration
00160       cam_param_.dist_factor[1] = msg->height/2;        // y0 = cY from openCV calibration
00161       cam_param_.dist_factor[2] = 0;                    // f = -100*k1 from CV. Note, we had to do mm^2 to m^2, hence 10^8->10^2
00162       cam_param_.dist_factor[3] = 1.0;                  // scale factor, should probably be >1, but who cares...
00163       
00164       arInit ();
00165     }
00166 
00167     /* convert cloud to PCL */
00168     PointCloud cloud;
00169     pcl::fromROSMsg(*msg, cloud);
00170  
00171     /* get an OpenCV image from the cloud */
00172     pcl::toROSMsg (cloud, *image_msg);
00173     try
00174     {
00175       capture_ = bridge_.imgMsgToCv (image_msg, "bgr8");
00176     }
00177     catch (sensor_msgs::CvBridgeException & e)
00178     {
00179       ROS_ERROR ("Could not convert from '%s' to 'bgr8'.", image_msg->encoding.c_str ());
00180     }
00181     dataPtr = (ARUint8 *) capture_->imageData;
00182 
00183     /* detect the markers in the video frame */
00184     if (arDetectMarkerLite (dataPtr, threshold_, &marker_info, &marker_num) < 0)
00185     {
00186       argCleanup ();
00187       return;
00188     }
00189  
00190     arPoseMarkers_.markers.clear ();
00191     /* check for known patterns */
00192     for (i = 0; i < objectnum; i++)
00193     {
00194       k = -1;
00195       for (j = 0; j < marker_num; j++)
00196       {
00197         if (object[i].id == marker_info[j].id)
00198         {
00199           if (k == -1)
00200             k = j;
00201           else                  // make sure you have the best pattern (highest confidence factor)
00202           if (marker_info[k].cf < marker_info[j].cf)
00203             k = j;
00204         }
00205       }
00206       if (k == -1)
00207       {
00208         object[i].visible = 0;
00209         continue;
00210       }
00211       
00212       /* create a cloud for marker corners */
00213       int d = marker_info[k].dir;
00214       PointCloud marker;
00215       marker.push_back( cloud.at( (int)marker_info[k].vertex[(4-d)%4][0], (int)marker_info[k].vertex[(4-d)%4][1] ) ); // upper left
00216       marker.push_back( cloud.at( (int)marker_info[k].vertex[(5-d)%4][0], (int)marker_info[k].vertex[(5-d)%4][1] ) ); // upper right
00217       marker.push_back( cloud.at( (int)marker_info[k].vertex[(6-d)%4][0], (int)marker_info[k].vertex[(6-d)%4][1] ) ); // lower right
00218       marker.push_back( cloud.at( (int)marker_info[k].vertex[(7-d)%4][0], (int)marker_info[k].vertex[(7-d)%4][1] ) );
00219 
00220       /* create an ideal cloud */
00221       double w = object[i].marker_width;
00222       PointCloud ideal;
00223       ideal.push_back( makeRGBPoint(-w/2,w/2,0) );
00224       ideal.push_back( makeRGBPoint(w/2,w/2,0) );
00225       ideal.push_back( makeRGBPoint(w/2,-w/2,0) );
00226       ideal.push_back( makeRGBPoint(-w/2,-w/2,0) );
00227 
00228       /* get transformation */
00229       Eigen::Matrix4f t;
00230       TransformationEstimationSVD obj;
00231       obj.estimateRigidTransformation( marker, ideal, t );
00232       
00233       /* get final transformation */
00234       tf::Transform transform = tfFromEigen(t.inverse());
00235    
00236       // any(transform == nan)
00237       tf::Matrix3x3  m = transform.getBasis();
00238       tf::Vector3    p = transform.getOrigin();
00239       bool invalid = false;
00240       for(int i=0; i < 3; i++)
00241         for(int j=0; j < 3; j++)
00242           invalid = (invalid || isnan(m[i][j]) || fabs(m[i][j]) > 1.0);
00243 
00244       for(int i=0; i < 3; i++)
00245           invalid = (invalid || isnan(p[i]));
00246        
00247 
00248       if(invalid)
00249         continue; 
00250 
00251       /* publish the marker */
00252       ar_pose::ARMarker ar_pose_marker;
00253       ar_pose_marker.header.frame_id = msg->header.frame_id;
00254       ar_pose_marker.header.stamp = msg->header.stamp;
00255       ar_pose_marker.id = object[i].id;
00256 
00257       ar_pose_marker.pose.pose.position.x = transform.getOrigin().getX();
00258       ar_pose_marker.pose.pose.position.y = transform.getOrigin().getY();
00259       ar_pose_marker.pose.pose.position.z = transform.getOrigin().getZ();
00260 
00261       ar_pose_marker.pose.pose.orientation.x = transform.getRotation().getAxis().getX();
00262       ar_pose_marker.pose.pose.orientation.y = transform.getRotation().getAxis().getY();
00263       ar_pose_marker.pose.pose.orientation.z = transform.getRotation().getAxis().getZ();
00264       ar_pose_marker.pose.pose.orientation.w = transform.getRotation().getW();
00265 
00266       ar_pose_marker.confidence = marker_info->cf;
00267       arPoseMarkers_.markers.push_back (ar_pose_marker);
00268 
00269       /* publish transform */
00270       if (publishTf_)
00271       {
00272             broadcaster_.sendTransform(tf::StampedTransform(transform, msg->header.stamp, msg->header.frame_id, object[i].name));
00273       }
00274 
00275       /* publish visual marker */
00276 
00277       if (publishVisualMarkers_)
00278       {
00279         tf::Vector3 markerOrigin (0, 0, 0.25 * object[i].marker_width * AR_TO_ROS);
00280         tf::Transform m (tf::Quaternion::getIdentity (), markerOrigin);
00281         tf::Transform markerPose = transform * m; // marker pose in the camera frame
00282 
00283         tf::poseTFToMsg (markerPose, rvizMarker_.pose);
00284 
00285         rvizMarker_.header.frame_id = msg->header.frame_id;
00286         rvizMarker_.header.stamp = msg->header.stamp;
00287         rvizMarker_.id = object[i].id;
00288 
00289         rvizMarker_.scale.x = 1.0 * object[i].marker_width * AR_TO_ROS;
00290         rvizMarker_.scale.y = 1.0 * object[i].marker_width * AR_TO_ROS;
00291         rvizMarker_.scale.z = 0.5 * object[i].marker_width * AR_TO_ROS;
00292         rvizMarker_.ns = "basic_shapes";
00293         rvizMarker_.type = visualization_msgs::Marker::CUBE;
00294         rvizMarker_.action = visualization_msgs::Marker::ADD;
00295         switch (i)
00296         {
00297           case 0:
00298             rvizMarker_.color.r = 0.0f;
00299             rvizMarker_.color.g = 0.0f;
00300             rvizMarker_.color.b = 1.0f;
00301             rvizMarker_.color.a = 1.0;
00302             break;
00303           case 1:
00304             rvizMarker_.color.r = 1.0f;
00305             rvizMarker_.color.g = 0.0f;
00306             rvizMarker_.color.b = 0.0f;
00307             rvizMarker_.color.a = 1.0;
00308             break;
00309           default:
00310             rvizMarker_.color.r = 0.0f;
00311             rvizMarker_.color.g = 1.0f;
00312             rvizMarker_.color.b = 0.0f;
00313             rvizMarker_.color.a = 1.0;
00314         }
00315         rvizMarker_.lifetime = ros::Duration ();
00316 
00317         rvizMarkerPub_.publish (rvizMarker_);
00318         ROS_DEBUG ("Published visual marker");
00319       }
00320     }
00321     arMarkerPub_.publish (arPoseMarkers_);
00322     ROS_DEBUG ("Published ar_multi markers");
00323   }
00324 
00325 }                               // end namespace ar_pose


ar_kinect
Author(s): Michael Ferguson
autogenerated on Tue Jan 7 2014 11:04:08