Go to the documentation of this file.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
00037 #include <laserscan_kinect/laserscan_kinect_node.h>
00038
00039 #define TIME_MEASUREMENT 0 /// Measurement of processing time
00040
00041 #if TIME_MEASUREMENT
00042 #include <boost/chrono.hpp>
00043 #endif
00044
00045 using namespace laserscan_kinect;
00046
00047
00048
00049
00050 LaserScanKinect::LaserScanKinect():
00051 is_scan_msg_configurated_(false), scan_msg_(new sensor_msgs::LaserScan()) { }
00052
00053
00054 sensor_msgs::LaserScanPtr LaserScanKinect::prepareLaserScanMsg(
00055 const sensor_msgs::ImageConstPtr& depth_msg,
00056 const sensor_msgs::CameraInfoConstPtr& info_msg)
00057 {
00058 #if TIME_MEASUREMENT
00059 boost::chrono::high_resolution_clock::time_point start = boost::chrono::high_resolution_clock::now();
00060 #endif
00061
00062 if(!is_scan_msg_configurated_ || cam_model_update_)
00063 {
00064 camera_model_.fromCameraInfo(info_msg);
00065
00066 const double cx = camera_model_.cx(), cy = camera_model_.cy();
00067 double min_angle, max_angle, vertical_fov;
00068
00069
00070 fieldOfView(min_angle, max_angle, cx, 0, cx, cy, cx, depth_msg->height - 1);
00071 vertical_fov = max_angle - min_angle;
00072
00073
00074 fieldOfView(min_angle, max_angle, 0, cy, cx, cy, depth_msg->width - 1, cy);
00075
00076 if ( ground_remove_enable_ )
00077 calcGroundDistancesForImgRows(vertical_fov);
00078
00079 if ( tilt_compensation_enable_ )
00080 calcTiltCompensationFactorsForImgRows(vertical_fov);
00081
00082 scan_msg_->angle_min = min_angle;
00083 scan_msg_->angle_max = max_angle;
00084 scan_msg_->angle_increment = (max_angle - min_angle) / (depth_msg->width - 1);
00085 scan_msg_->time_increment = 0.0;
00086 scan_msg_->scan_time = SCAN_TIME;
00087
00088
00089 if (tilt_compensation_enable_)
00090 {
00091 scan_msg_->range_min = range_min_ * *std::min_element( tilt_compensation_factor_.begin(),
00092 tilt_compensation_factor_.end() );
00093 scan_msg_->range_max = range_max_ * *std::max_element( tilt_compensation_factor_.begin(),
00094 tilt_compensation_factor_.end() );
00095 }
00096 else
00097 {
00098 scan_msg_->range_min = range_min_;
00099 scan_msg_->range_max = range_max_;
00100 }
00101
00102
00103 calcScanMsgIndexForImgCols(depth_msg);
00104
00105
00106 if(scan_height_ / 2 > cy || scan_height_ / 2 > depth_msg->height - cy)
00107 {
00108 std::stringstream ss;
00109 ss << "scan_height ( " << scan_height_ << " pixels) is too large for the image height.";
00110 throw std::runtime_error(ss.str());
00111 }
00112 is_scan_msg_configurated_ = true;
00113 }
00114
00115
00116 scan_msg_->header = depth_msg->header;
00117 if(output_frame_id_.length() > 0)
00118 scan_msg_->header.frame_id = output_frame_id_;
00119
00120 scan_msg_->ranges.assign(depth_msg->width, std::numeric_limits<float>::quiet_NaN());
00121
00122
00123 if (depth_msg->encoding == sensor_msgs::image_encodings::TYPE_16UC1)
00124 {
00125 convertDepthToPolarCoords(depth_msg);
00126 }
00127 else
00128 {
00129 std::stringstream ss;
00130 ss << "Depth image has unsupported encoding: " << depth_msg->encoding;
00131 throw std::runtime_error(ss.str());
00132 }
00133
00134 #if TIME_MEASUREMENT // End of time measurement
00135 boost::chrono::milliseconds ms = boost::chrono::duration_cast<boost::chrono::milliseconds>
00136 (boost::chrono::high_resolution_clock::now() - start);
00137 ROS_DEBUG_STREAM("\nProcessing takes " << ms.count() << " ms.");
00138 #endif
00139
00140 return scan_msg_;
00141 }
00142
00143
00144 void LaserScanKinect::setRangeLimits(const float rmin, const float rmax)
00145 {
00146 if (rmin >= 0 && rmin < rmax)
00147 range_min_ = rmin;
00148 else
00149 {
00150 range_min_ = 0;
00151 ROS_ERROR("Incorrect value of range minimal parameter. Set default value: 0.");
00152 }
00153 if (rmax >= 0 && rmin < rmax)
00154 range_max_ = rmax;
00155 else
00156 {
00157 range_max_ = 10;
00158 ROS_ERROR("Incorrect value of range maximum parameter. Set default value: 10.");
00159 }
00160 }
00161
00162
00163 void LaserScanKinect::setScanHeight(const int scan_height)
00164 {
00165 if(scan_height > 0)
00166 scan_height_ = scan_height;
00167 else
00168 {
00169 scan_height_ = 10;
00170 ROS_ERROR("Incorrect value of scan height parameter. Set default value: 100.");
00171 }
00172 }
00173
00174
00175 void LaserScanKinect::setDepthImgRowStep(const int row_step)
00176 {
00177 if( row_step > 0 )
00178 depth_img_row_step_ = row_step;
00179 else
00180 {
00181 depth_img_row_step_ = 1;
00182 ROS_ERROR("Incorrect value depth imgage row step parameter. Set default value: 1.");
00183 }
00184 }
00185
00186
00187 void LaserScanKinect::setSensorMountHeight (const float height)
00188 {
00189 if( height > 0)
00190 sensor_mount_height_ = height;
00191 else
00192 {
00193 sensor_mount_height_ = 0;
00194 ROS_ERROR("Incorrect value of sensor mount height parameter. Set default value: 0.");
00195 }
00196 }
00197
00198
00199 void LaserScanKinect::setSensorTiltAngle (const float angle)
00200 {
00201 if( angle < 90 && angle > -90)
00202 sensor_tilt_angle_ = angle;
00203 else
00204 {
00205 sensor_tilt_angle_ = 0;
00206 ROS_ERROR("Incorrect value of sensor tilt angle parameter. Set default value: 0.");
00207 }
00208 }
00209
00210
00211 void LaserScanKinect::setGroundMargin (const float margin)
00212 {
00213 if( margin > 0)
00214 ground_margin_ = margin;
00215 else
00216 {
00217 ground_margin_ = 0;
00218 ROS_ERROR("Incorrect value of ground margin parameter. Set default value: 0.");
00219 }
00220 }
00221
00222
00223
00224
00225 double LaserScanKinect::lengthOfVector(const cv::Point3d& vec) const
00226 {
00227 return sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z);
00228 }
00229
00230
00231 double LaserScanKinect::angleBetweenRays(const cv::Point3d& ray1, const cv::Point3d& ray2) const
00232 {
00233 double dot = ray1.x * ray2.x + ray1.y * ray2.y + ray1.z * ray2.z;
00234
00235 return acos(dot / (lengthOfVector(ray1) * lengthOfVector(ray2)));
00236 }
00237
00238
00239 void LaserScanKinect::fieldOfView( double & min, double & max, double x1, double y1,
00240 double xc, double yc, double x2, double y2)
00241 {
00242 cv::Point2d raw_pixel_left(x1, y1);
00243 cv::Point2d rect_pixel_left = camera_model_.rectifyPoint(raw_pixel_left);
00244 cv::Point3d left_ray = camera_model_.projectPixelTo3dRay(rect_pixel_left);
00245
00246 cv::Point2d raw_pixel_right(x2, y2);
00247 cv::Point2d rect_pixel_right = camera_model_.rectifyPoint(raw_pixel_right);
00248 cv::Point3d right_ray = camera_model_.projectPixelTo3dRay(rect_pixel_right);
00249
00250 cv::Point2d raw_pixel_center(xc, yc);
00251 cv::Point2d rect_pixel_center = camera_model_.rectifyPoint(raw_pixel_center);
00252 cv::Point3d center_ray = camera_model_.projectPixelTo3dRay(rect_pixel_center);
00253
00254 min = -angleBetweenRays(center_ray, right_ray);
00255 max = angleBetweenRays(left_ray, center_ray);
00256
00257 ROS_ASSERT(min < 0 && max > 0);
00258 }
00259
00260
00261 void LaserScanKinect::calcGroundDistancesForImgRows(double vertical_fov)
00262 {
00263 const double alpha = sensor_tilt_angle_ * M_PI / 180.0;
00264 const int img_height = camera_model_.fullResolution().height;
00265
00266 ROS_ASSERT(img_height >= 0);
00267
00268 dist_to_ground_.resize(img_height);
00269
00270 for(int i = 0; i < img_height; i++)
00271 {
00272
00273 double delta = vertical_fov * (i - camera_model_.cy() - 0.5) / ((double)img_height - 1);
00274
00275 if ((delta + alpha) > 0)
00276 {
00277 dist_to_ground_[i] = sensor_mount_height_ * sin(M_PI/2-delta) * 1000
00278 / cos(M_PI/2-delta-alpha);
00279 ROS_ASSERT(dist_to_ground_[i] > 0);
00280 }
00281 else
00282 dist_to_ground_[i] = 100 * 1000;
00283 }
00284 }
00285
00286
00287 void LaserScanKinect::calcTiltCompensationFactorsForImgRows(double vertical_fov)
00288 {
00289 const double alpha = sensor_tilt_angle_ * M_PI / 180.0;
00290 const int img_height = camera_model_.fullResolution().height;
00291
00292 ROS_ASSERT(img_height >= 0);
00293
00294 tilt_compensation_factor_.resize(img_height);
00295
00296 for(int i = 0; i < img_height; i++)
00297 {
00298 double delta = vertical_fov * (i - camera_model_.cy() - 0.5) / ((double)img_height - 1);
00299
00300 tilt_compensation_factor_[i] = sin(M_PI/2 - delta - alpha) / sin(M_PI/2 - delta);
00301 ROS_ASSERT(tilt_compensation_factor_[i] > 0 && tilt_compensation_factor_[i] < 10);
00302 }
00303 }
00304
00305
00306 void LaserScanKinect::calcScanMsgIndexForImgCols(const sensor_msgs::ImageConstPtr& depth_msg)
00307 {
00308 scan_msg_index_.resize((int)depth_msg->width);
00309
00310 for (int u = 0; u < (int)depth_msg->width; u++)
00311 {
00312 double th = -atan2((double)(u - camera_model_.cx()) * 0.001f / camera_model_.fx(), 0.001f);
00313 scan_msg_index_[u] = (th - scan_msg_->angle_min) / scan_msg_->angle_increment;
00314 }
00315 }
00316
00317
00318 void LaserScanKinect::convertDepthToPolarCoords(const sensor_msgs::ImageConstPtr &depth_msg)
00319 {
00320 const uint16_t* depth_row = reinterpret_cast<const uint16_t*>(&depth_msg->data[0]);
00321 const int offset = (int)(camera_model_.cy()- scan_height_ / 2);
00322 const int row_size = depth_msg->step / sizeof(uint16_t);
00323
00324 const unsigned int range_min_mm = range_min_ * 1000;
00325 const unsigned int range_max_mm = range_max_ * 1000;
00326 const int ground_margin_mm = ground_margin_ * 1000;
00327
00328
00329 for (int j = 0; j < (int)depth_msg->width; j++)
00330 {
00331 float depth_min = MAX_UINT16;
00332
00333
00334 for (int i = offset; i < offset + scan_height_; i += depth_img_row_step_)
00335 {
00336 uint16_t depth_raw = depth_row[row_size * i + j];
00337 float depth;
00338
00339
00340 if ( tilt_compensation_enable_ )
00341 depth = depth_raw * tilt_compensation_factor_[i] / 1000.0f;
00342 else
00343 depth = depth_raw / 1000.0f;
00344
00345
00346 if ( ground_remove_enable_ )
00347 {
00348
00349 if( depth_raw >= range_min_mm && depth_raw <= range_max_mm &&
00350 depth < depth_min && depth_raw < (dist_to_ground_[i] - ground_margin_mm) )
00351 {
00352 depth_min = depth;
00353 }
00354 }
00355 else
00356 {
00357
00358 if( depth_raw >= range_min_mm && depth_raw <= range_max_mm && depth < depth_min )
00359 {
00360 depth_min = depth;
00361 }
00362 }
00363 }
00364
00365 if (depth_min != MAX_UINT16)
00366 {
00367
00368 float x = (j - camera_model_.cx()) * depth_min / camera_model_.fx();
00369
00370
00371 scan_msg_->ranges[ scan_msg_index_[j] ] = sqrt(x * x + depth_min * depth_min);
00372 }
00373 else
00374 scan_msg_->ranges[scan_msg_index_[j]] = NAN;
00375 }
00376 }