00001 #include <ros/ros.h>
00002 #include <nodelet/nodelet.h>
00003 #include <image_transport/image_transport.h>
00004 #include <image_transport/subscriber_filter.h>
00005 #include <message_filters/subscriber.h>
00006 #include <message_filters/synchronizer.h>
00007 #include <message_filters/sync_policies/approximate_time.h>
00008 #include <tf/transform_listener.h>
00009 #include <sensor_msgs/image_encodings.h>
00010 #include <image_geometry/pinhole_camera_model.h>
00011 #include <Eigen/Core>
00012 #include "names.h"
00013
00014 namespace openni_camera {
00015
00016 using namespace message_filters::sync_policies;
00017 namespace enc = sensor_msgs::image_encodings;
00018
00019 class RegisterNodelet : public nodelet::Nodelet
00020 {
00021 boost::shared_ptr<image_transport::ImageTransport> it_;
00022
00023
00024 image_transport::SubscriberFilter sub_depth_image_;
00025 message_filters::Subscriber<sensor_msgs::CameraInfo> sub_depth_info_, sub_rgb_info_;
00026 boost::shared_ptr<tf::TransformListener> tf_;
00027 typedef ApproximateTime<sensor_msgs::Image, sensor_msgs::CameraInfo, sensor_msgs::CameraInfo> SyncPolicy;
00028 typedef message_filters::Synchronizer<SyncPolicy> Synchronizer;
00029 boost::shared_ptr<Synchronizer> sync_;
00030 bool subscribed_;
00031
00032
00033 image_transport::CameraPublisher pub_registered_;
00034
00035 image_geometry::PinholeCameraModel depth_model_, rgb_model_;
00036
00037 virtual void onInit();
00038
00039 void connectCb();
00040
00041 void imageCb(const sensor_msgs::ImageConstPtr& depth_image_msg,
00042 const sensor_msgs::CameraInfoConstPtr& depth_info_msg,
00043 const sensor_msgs::CameraInfoConstPtr& rgb_info_msg);
00044 };
00045
00046 void RegisterNodelet::onInit()
00047 {
00048 ros::NodeHandle& nh = getNodeHandle();
00049 it_.reset( new image_transport::ImageTransport(nh) );
00050 tf_.reset( new tf::TransformListener );
00051
00052
00053 subscribed_ = false;
00054 image_transport::SubscriberStatusCallback image_connect_cb = boost::bind(&RegisterNodelet::connectCb, this);
00055 ros::SubscriberStatusCallback info_connect_cb = boost::bind(&RegisterNodelet::connectCb, this);
00056 pub_registered_ = it_->advertiseCamera(resolve(nh, "depth_registered/image_rect_raw"),
00057 1, image_connect_cb, image_connect_cb,
00058 info_connect_cb, info_connect_cb);
00059
00060
00062 int queue_size = 5;
00063 sync_.reset( new Synchronizer(SyncPolicy(queue_size), sub_depth_image_, sub_depth_info_, sub_rgb_info_) );
00064 sync_->registerCallback(boost::bind(&RegisterNodelet::imageCb, this, _1, _2, _3));
00065 }
00066
00067
00068 void RegisterNodelet::connectCb()
00069 {
00070
00071 if (pub_registered_.getNumSubscribers() == 0)
00072 {
00073
00074 sub_depth_image_.unsubscribe();
00075 sub_depth_info_ .unsubscribe();
00076 sub_rgb_info_ .unsubscribe();
00077 subscribed_ = false;
00078 }
00079 else if (!subscribed_)
00080 {
00081
00082 ros::NodeHandle& nh = getNodeHandle();
00083 sub_depth_image_.subscribe(*it_, resolve(nh, "depth/image_rect_raw"), 1);
00084 sub_depth_info_ .subscribe(nh, resolve(nh, "depth/camera_info"), 1);
00085 sub_rgb_info_ .subscribe(nh, resolve(nh, "rgb/camera_info"), 1);
00086 subscribed_ = true;
00087 }
00088 }
00089
00090 void RegisterNodelet::imageCb(const sensor_msgs::ImageConstPtr& depth_image_msg,
00091 const sensor_msgs::CameraInfoConstPtr& depth_info_msg,
00092 const sensor_msgs::CameraInfoConstPtr& rgb_info_msg)
00093 {
00094
00095 if (depth_image_msg->encoding != enc::TYPE_16UC1)
00096 {
00097 NODELET_ERROR("Expected depth data of type [%s], got [%s]",
00098 enc::TYPE_16UC1.c_str(), depth_image_msg->encoding.c_str());
00099 return;
00100 }
00101
00102
00103 depth_model_.fromCameraInfo(depth_info_msg);
00104 rgb_model_ .fromCameraInfo(rgb_info_msg);
00105
00106
00107 Eigen::Matrix4d depth_to_rgb;
00108 try
00109 {
00110 ros::Duration timeout(1.0 / 30);
00111 tf_->waitForTransform(rgb_info_msg->header.frame_id, depth_info_msg->header.frame_id,
00112 depth_info_msg->header.stamp, timeout);
00113 tf::StampedTransform transform;
00114 tf_->lookupTransform (rgb_info_msg->header.frame_id, depth_info_msg->header.frame_id,
00115 depth_info_msg->header.stamp, transform);
00116
00117 btMatrix3x3& R = transform.getBasis();
00118 btVector3& T = transform.getOrigin();
00119 depth_to_rgb << R[0][0], R[0][1], R[0][2], T[0],
00120 R[1][0], R[1][1], R[1][2], T[1],
00121 R[2][0], R[2][1], R[2][2], T[2],
00122 0, 0, 0, 1;
00123 }
00124 catch (tf::TransformException& ex)
00125 {
00126 NODELET_WARN_THROTTLE(2, "TF exception:\n%s", ex.what());
00127 return;
00130 }
00131
00132
00133 sensor_msgs::ImagePtr registered_msg( new sensor_msgs::Image );
00134 registered_msg->header.stamp = depth_image_msg->header.stamp;
00135 registered_msg->header.frame_id = rgb_info_msg->header.frame_id;
00136 registered_msg->encoding = depth_image_msg->encoding;
00137
00138 cv::Size resolution = rgb_model_.reducedResolution();
00139 registered_msg->height = resolution.height;
00140 registered_msg->width = resolution.width;
00141 registered_msg->step = registered_msg->width * sizeof(uint16_t);
00142 registered_msg->data.resize( registered_msg->height * registered_msg->step );
00143
00144
00145 double inv_depth_fx = 1.0 / depth_model_.fx();
00146 double inv_depth_fy = 1.0 / depth_model_.fy();
00147 double depth_cx = depth_model_.cx(), depth_cy = depth_model_.cy();
00148 double depth_Tx = depth_model_.Tx(), depth_Ty = depth_model_.Ty();
00149 double rgb_fx = rgb_model_.fx(), rgb_fy = rgb_model_.fy();
00150 double rgb_cx = rgb_model_.cx(), rgb_cy = rgb_model_.cy();
00151 double rgb_Tx = rgb_model_.Tx(), rgb_Ty = rgb_model_.Ty();
00152
00153
00155 const uint16_t* raw_data = reinterpret_cast<const uint16_t*>(&depth_image_msg->data[0]);
00156 uint16_t* reg_data = reinterpret_cast<uint16_t*>(®istered_msg->data[0]);
00157 int raw_index = 0;
00158 for (unsigned v = 0; v < depth_image_msg->height; ++v)
00159 {
00160 for (unsigned u = 0; u < depth_image_msg->width; ++u, ++raw_index)
00161 {
00162 double depth = raw_data[raw_index] * 0.001;
00163
00164
00165 Eigen::Vector4d xyz_depth;
00166 xyz_depth << ((u - depth_cx)*depth - depth_Tx) * inv_depth_fx,
00167 ((v - depth_cy)*depth - depth_Ty) * inv_depth_fy,
00168 depth,
00169 1;
00170
00171
00172 Eigen::Vector4d xyz_rgb = depth_to_rgb * xyz_depth;
00173
00174
00175 double inv_Z = 1.0 / xyz_rgb.z();
00176 int u_rgb = (rgb_fx*xyz_rgb.x() + rgb_Tx)*inv_Z + rgb_cx + 0.5;
00177 int v_rgb = (rgb_fy*xyz_rgb.y() + rgb_Ty)*inv_Z + rgb_cy + 0.5;
00178
00179 if (u_rgb < 0 || u_rgb >= (int)registered_msg->width ||
00180 v_rgb < 0 || v_rgb >= (int)registered_msg->height)
00181 continue;
00182
00183 uint16_t& reg_depth = reg_data[v_rgb*registered_msg->width + u_rgb];
00184 uint16_t new_depth = (xyz_rgb.z() * 1000.0) + 0.5;
00186
00187 if (reg_depth == 0 || reg_depth > new_depth)
00188 reg_depth = new_depth;
00189 }
00190 }
00191
00192
00193 sensor_msgs::CameraInfoPtr registered_info_msg( new sensor_msgs::CameraInfo(*rgb_info_msg) );
00194 registered_info_msg->header.stamp = registered_msg->header.stamp;
00195
00196 pub_registered_.publish(registered_msg, registered_info_msg);
00197 }
00198
00199 }
00200
00201
00202 #include <pluginlib/class_list_macros.h>
00203 PLUGINLIB_DECLARE_CLASS (openni_camera, register, openni_camera::RegisterNodelet, nodelet::Nodelet);