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
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "depthcloud_encoder/depthcloud_encoder.h"
00038
00039 #include <boost/bind.hpp>
00040 #include <boost/cstdint.hpp>
00041
00042 #include <cv_bridge/cv_bridge.h>
00043
00044 namespace depthcloud
00045 {
00046
00047 using namespace message_filters::sync_policies;
00048 namespace enc = sensor_msgs::image_encodings;
00049
00050 static int queue_size_ = 10;
00051 static int target_resolution_ = 512;
00052 static int max_depth_per_tile = 2.0;
00053
00054 DepthCloudEncoder::DepthCloudEncoder(ros::NodeHandle& nh, ros::NodeHandle& pnh) :
00055 nh_(nh),
00056 pnh_(pnh),
00057 depth_sub_(),
00058 color_sub_(),
00059 pub_it_(nh_),
00060 crop_size_(target_resolution_)
00061 {
00062
00063 ros::NodeHandle priv_nh_("~");
00064
00065
00066 priv_nh_.param<std::string>("depth", depthmap_topic_, "/camera/depth/image");
00067
00068
00069 priv_nh_.param<std::string>("rgb", rgb_image_topic_, "/camera/rgb/image_color");
00070
00071
00072 image_transport::SubscriberStatusCallback connect_cb = boost::bind(&DepthCloudEncoder::connectCb, this);
00073
00074 boost::lock_guard<boost::mutex> lock(connect_mutex_);
00075
00076 pub_ = pub_it_.advertise("depthcloud_encoded", 1, connect_cb, connect_cb);
00077 }
00078 DepthCloudEncoder::~DepthCloudEncoder()
00079 {
00080 }
00081
00082 void DepthCloudEncoder::connectCb()
00083 {
00084 boost::lock_guard<boost::mutex> lock(connect_mutex_);
00085
00086 if (pub_.getNumSubscribers())
00087 {
00088 subscribe(depthmap_topic_, rgb_image_topic_);
00089 }
00090 else
00091 {
00092 unsubscribe();
00093 }
00094 }
00095
00096 void DepthCloudEncoder::subscribe(std::string& depth_topic, std::string& color_topic)
00097 {
00098 unsubscribe();
00099
00100 ROS_DEBUG_STREAM("Subscribing to "<< color_topic);
00101 ROS_DEBUG_STREAM("Subscribing to "<< depth_topic);
00102
00103 if (!depth_topic.empty())
00104 {
00105 try
00106 {
00107 image_transport::ImageTransport depth_it(pnh_);
00108 image_transport::ImageTransport color_it(pnh_);
00109
00110
00111 depth_sub_->subscribe(depth_it, depth_topic, 1, image_transport::TransportHints("raw"));
00112
00113 if (!color_topic.empty())
00114 {
00115
00116 color_sub_->subscribe(color_it, color_topic, 1, image_transport::TransportHints("raw"));
00117
00118
00119 sync_depth_color_->connectInput(*depth_sub_, *color_sub_);
00120 sync_depth_color_->setInterMessageLowerBound(0, ros::Duration(1.5));
00121 sync_depth_color_->setInterMessageLowerBound(1, ros::Duration(1.5));
00122 sync_depth_color_->registerCallback(boost::bind(&DepthCloudEncoder::depthColorCB, this, _1, _2));
00123 }
00124 else
00125 {
00126 depth_sub_->registerCallback(boost::bind(&DepthCloudEncoder::depthCB, this, _1));
00127 }
00128 }
00129 catch (ros::Exception& e)
00130 {
00131 ROS_ERROR("Error subscribing: %s", e.what());
00132 }
00133 }
00134 }
00135
00136
00137 void DepthCloudEncoder::unsubscribe()
00138 {
00139 try
00140 {
00141
00142 sync_depth_color_.reset(new SynchronizerDepthColor(SyncPolicyDepthColor(10)));
00143 depth_sub_.reset(new image_transport::SubscriberFilter());
00144 color_sub_.reset(new image_transport::SubscriberFilter());
00145 }
00146 catch (ros::Exception& e)
00147 {
00148 ROS_ERROR("Error unsubscribing: %s", e.what());
00149 }
00150 }
00151
00152 void DepthCloudEncoder::depthCB(const sensor_msgs::ImageConstPtr& depth_msg)
00153 {
00154 process(depth_msg, sensor_msgs::ImageConstPtr(), crop_size_);
00155 }
00156
00157 void DepthCloudEncoder::depthColorCB(const sensor_msgs::ImageConstPtr& depth_msg,
00158 const sensor_msgs::ImageConstPtr& color_msg)
00159 {
00160 ROS_DEBUG("Image depth/color pair received");
00161 process(depth_msg, color_msg, crop_size_);
00162 }
00163
00164 void DepthCloudEncoder::process(const sensor_msgs::ImageConstPtr& depth_msg,
00165 const sensor_msgs::ImageConstPtr& color_msg,
00166 const std::size_t crop_size)
00167 {
00168
00169 int depth_bits = enc::bitDepth(depth_msg->encoding);
00170 int depth_channels = enc::numChannels(depth_msg->encoding);
00171
00172 int color_bits = 0;
00173 int color_channels = 0;
00174
00175 if ((depth_bits != 32) || (depth_channels != 1))
00176 {
00177 ROS_DEBUG_STREAM( "Invalid color depth image format ("<<depth_msg->encoding <<")");
00178 return;
00179 }
00180
00181
00182 cv_bridge::CvImagePtr color_cv_ptr;
00183
00184
00185 if (color_msg)
00186 {
00187 try
00188 {
00189 color_cv_ptr = cv_bridge::toCvCopy(color_msg, "bgr8");
00190
00191 }
00192 catch (cv_bridge::Exception& e)
00193 {
00194 ROS_ERROR_STREAM("OpenCV-ROS bridge error: " << e.what());
00195 return;
00196 }
00197
00198 if (depth_msg->width != color_msg->width || depth_msg->height != color_msg->height)
00199 {
00200 ROS_DEBUG_STREAM( "Depth image resolution (" << (int)depth_msg->width << "x" << (int)depth_msg->height << ") "
00201 "does not match color image resolution (" << (int)color_msg->width << "x" << (int)color_msg->height << ")");
00202 return;
00203 }
00204 }
00205
00206
00207 sensor_msgs::ImagePtr depth_int_msg(new sensor_msgs::Image());
00208 sensor_msgs::ImagePtr valid_mask_msg(new sensor_msgs::Image());
00209
00210 depthInterpolation(depth_msg, depth_int_msg, valid_mask_msg);
00211
00212 unsigned int pix_size = enc::bitDepth(enc::BGR8) / 8 * 3;
00213
00214
00215 sensor_msgs::ImagePtr output_msg(new sensor_msgs::Image);
00216 output_msg->header = depth_int_msg->header;
00217 output_msg->encoding = enc::BGR8;
00218 output_msg->width = crop_size * 2;
00219 output_msg->height = crop_size * 2;
00220 output_msg->step = output_msg->width * pix_size;
00221 output_msg->is_bigendian = depth_int_msg->is_bigendian;
00222
00223
00224 output_msg->data.resize(output_msg->width * output_msg->height * pix_size, 0xFF);
00225
00226 std::size_t input_width = depth_int_msg->width;
00227 std::size_t input_height = depth_int_msg->height;
00228
00229
00230 {
00231 std::size_t y, x, left_x, top_y, width_x, width_y;
00232
00233
00234 int top_bottom_corner = (input_height - crop_size) / 2;
00235 int left_right_corner = (input_width - crop_size) / 2;
00236
00237 if (top_bottom_corner < 0)
00238 {
00239 top_y = 0;
00240 width_y = input_height;
00241 }
00242 else
00243 {
00244 top_y = top_bottom_corner;
00245 width_y = input_height - top_bottom_corner;
00246 }
00247
00248 if (left_right_corner < 0)
00249 {
00250 left_x = 0;
00251 width_x = input_width;
00252 }
00253 else
00254 {
00255 left_x = left_right_corner;
00256 width_x = input_width - left_right_corner;
00257 }
00258
00259
00260 uint8_t* dest_ptr = &output_msg->data[((top_y - top_bottom_corner) * output_msg->width + left_x - left_right_corner)
00261 * pix_size];
00262 const std::size_t dest_y_step = output_msg->step;
00263
00264
00265 const float* source_depth_ptr = (const float*)&depth_int_msg->data[(top_y * input_width + left_x) * sizeof(float)];
00266
00267
00268 const uint8_t* source_mask_ptr = &valid_mask_msg->data[(top_y * input_width + left_x) * sizeof(uint8_t)];
00269
00270
00271 const uint8_t* source_color_ptr = 0;
00272 std::size_t source_color_y_step = 0;
00273 if (color_msg)
00274 {
00275 source_color_y_step = input_width * pix_size;
00276 source_color_ptr = static_cast<const uint8_t*>(&color_cv_ptr->image.data[(top_y * input_width + left_x) * pix_size]);
00277 }
00278
00279
00280 const std::size_t right_frame_shift = crop_size * pix_size;
00281 ;
00282 const std::size_t down_frame_shift = dest_y_step * crop_size;
00283
00284
00285 for (y = top_y; y < width_y;
00286 ++y, source_color_ptr += source_color_y_step, source_depth_ptr += input_width, source_mask_ptr += input_width, dest_ptr +=
00287 dest_y_step)
00288 {
00289 const float *depth_ptr = source_depth_ptr;
00290
00291
00292 const uint8_t *color_ptr = source_color_ptr;
00293 const uint8_t *mask_ptr = source_mask_ptr;
00294
00295 uint8_t *out_depth_low_ptr = dest_ptr;
00296 uint8_t *out_depth_high_ptr = dest_ptr + right_frame_shift;
00297 uint8_t *out_color_ptr = dest_ptr + right_frame_shift + down_frame_shift;
00298
00299 for (x = left_x; x < width_x; ++x)
00300 {
00301 uint16_t depth_pix_low;
00302 uint16_t depth_pix_high;
00303
00304 if (*depth_ptr == *depth_ptr)
00305 {
00306 depth_pix_low = std::min(std::max(0.0f, (*depth_ptr / 2.0f) * (float)(0xFF * 3)), (float)(0xFF * 3));
00307 depth_pix_high = std::min(std::max(0.0f, ((*depth_ptr - max_depth_per_tile) / 2.0f) * (float)(0xFF) * 3), (float)(0xFF * 3));
00308 }
00309 else
00310 {
00311 depth_pix_low = 0;
00312 depth_pix_high = 0;
00313
00314 }
00315
00316 uint8_t *mask_pix_ptr = out_depth_low_ptr + down_frame_shift;
00317 if (*mask_ptr == 0)
00318 {
00319
00320 memset(mask_pix_ptr, 0x00, pix_size);
00321 }
00322 else
00323 {
00324
00325 memset(mask_pix_ptr, 0xFF, pix_size);
00326 }
00327
00328 uint8_t depth_pix_low_r = depth_pix_low / 3;
00329 uint8_t depth_pix_low_g = depth_pix_low / 3;
00330 uint8_t depth_pix_low_b = depth_pix_low / 3;
00331
00332 if (depth_pix_low % 3 == 1) ++depth_pix_low_r;
00333 if (depth_pix_low % 3 == 2) ++depth_pix_low_g;
00334
00335 *out_depth_low_ptr = depth_pix_low_r; ++out_depth_low_ptr;
00336 *out_depth_low_ptr = depth_pix_low_g; ++out_depth_low_ptr;
00337 *out_depth_low_ptr = depth_pix_low_b; ++out_depth_low_ptr;
00338
00339 uint8_t depth_pix_high_r = depth_pix_high / 3;
00340 uint8_t depth_pix_high_g = depth_pix_high / 3;
00341 uint8_t depth_pix_high_b = depth_pix_high / 3;
00342
00343 if ((depth_pix_high % 3) == 1)
00344 ++depth_pix_high_r;
00345 if ((depth_pix_high % 3) == 2)
00346 ++depth_pix_high_g;
00347
00348 *out_depth_high_ptr = depth_pix_high_r; ++out_depth_high_ptr;
00349 *out_depth_high_ptr = depth_pix_high_g; ++out_depth_high_ptr;
00350 *out_depth_high_ptr = depth_pix_high_b; ++out_depth_high_ptr;
00351
00352 if (color_ptr)
00353 {
00354
00355 *out_color_ptr = *color_ptr; ++out_color_ptr; ++color_ptr;
00356
00357 *out_color_ptr = *color_ptr; ++out_color_ptr; ++color_ptr;
00358
00359 *out_color_ptr = *color_ptr; ++out_color_ptr; ++color_ptr;
00360 }
00361
00362
00363 ++mask_ptr;
00364 ++depth_ptr;
00365
00366 }
00367 }
00368 }
00369 pub_.publish(output_msg);
00370 }
00371
00372 void DepthCloudEncoder::depthInterpolation(sensor_msgs::ImageConstPtr depth_msg, sensor_msgs::ImagePtr depth_int_msg,
00373 sensor_msgs::ImagePtr mask_msg)
00374 {
00375 const std::size_t input_width = depth_msg->width;
00376 const std::size_t input_height = depth_msg->height;
00377
00378
00379 depth_int_msg->header = depth_msg->header;
00380 depth_int_msg->encoding = depth_msg->encoding;
00381 depth_int_msg->width = input_width;
00382 depth_int_msg->height = input_height;
00383 depth_int_msg->step = depth_msg->step;
00384 depth_int_msg->is_bigendian = depth_msg->is_bigendian;
00385 depth_int_msg->data.resize(depth_int_msg->step * depth_int_msg->height, 0);
00386
00387
00388 mask_msg->header = depth_msg->header;
00389 mask_msg->encoding = enc::TYPE_8UC1;
00390 mask_msg->width = input_width;
00391 mask_msg->height = input_height;
00392 mask_msg->step = depth_msg->step;
00393 mask_msg->is_bigendian = depth_msg->is_bigendian;
00394 mask_msg->data.resize(mask_msg->step * mask_msg->height, 0xFF);
00395
00396 const float* depth_ptr = (const float*)&depth_msg->data[0];
00397 float* depth_int_ptr = (float*)&depth_int_msg->data[0];
00398 uint8_t* mask_ptr = (uint8_t*)&mask_msg->data[0];
00399
00400 float leftVal = -1.0f;
00401
00402 unsigned int y, len;
00403 for (y = 0; y < input_height; ++y, depth_ptr += input_width, depth_int_ptr += input_width, mask_ptr += input_width)
00404 {
00405 const float* in_depth_ptr = depth_ptr;
00406 float* out_depth_int_ptr = depth_int_ptr;
00407 uint8_t* out_mask_ptr = mask_ptr;
00408
00409 const float* in_depth_end_ptr = depth_ptr + input_width;
00410
00411 while (in_depth_ptr < in_depth_end_ptr)
00412 {
00413 len = 0;
00414 const float* last_valid_pix_ptr = in_depth_ptr;
00415 while ((isnan(*in_depth_ptr) || (*in_depth_ptr == 0)) && (in_depth_ptr < in_depth_end_ptr))
00416 {
00417 ++in_depth_ptr;
00418 ++len;
00419 }
00420 if (len > 0)
00421 {
00422
00423
00424
00425 float rightVal;
00426 if (in_depth_ptr < in_depth_end_ptr)
00427 {
00428 rightVal = *in_depth_ptr;
00429 }
00430 else
00431 {
00432 rightVal = leftVal;
00433 }
00434
00435
00436 if (isnan(leftVal) || (leftVal < 0.0f))
00437 leftVal = rightVal;
00438
00439 float incVal = (rightVal - leftVal) / (float)len;
00440 float fillVal = leftVal;
00441 const float* fill_ptr;
00442
00443 for (fill_ptr = last_valid_pix_ptr; fill_ptr < in_depth_ptr; ++fill_ptr)
00444 {
00445
00446 *out_depth_int_ptr = fillVal;
00447 ++out_depth_int_ptr;
00448
00449
00450 *out_mask_ptr = 0xFF; ++out_mask_ptr;
00451
00452 fillVal += incVal;
00453 }
00454
00455 leftVal = rightVal;
00456 }
00457 else
00458 {
00459
00460
00461 leftVal = *in_depth_ptr;
00462
00463 *out_depth_int_ptr = *in_depth_ptr;
00464
00465
00466 *out_mask_ptr = 0; ++out_mask_ptr;
00467
00468 ++in_depth_ptr;
00469 ++out_depth_int_ptr;
00470 }
00471
00472 }
00473
00474 }
00475
00476 }
00477
00478
00479 }
00480