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 <cliff_detector/cliff_detector_node.h>
00038
00039 using namespace cliff_detector;
00040
00041
00042
00043
00044 CliffDetector::CliffDetector(): depth_sensor_params_update(false) { }
00045
00046
00047 void CliffDetector::detectCliff( const sensor_msgs::ImageConstPtr& depth_msg,
00048 const sensor_msgs::CameraInfoConstPtr& info_msg)
00049 {
00050
00051
00052 if(!depth_sensor_params_update || cam_model_update_)
00053 {
00054 camera_model_.fromCameraInfo(info_msg);
00055
00056 double angle_min, angle_max, vertical_fov;
00057 double cx = camera_model_.cx(), cy = camera_model_.cy();
00058
00059 ROS_ASSERT(cx > 0 && cy > 0);
00060
00061
00062 fieldOfView(angle_min, angle_max, cx, 0, cx, cy, cx, depth_msg->height -1);
00063 vertical_fov = angle_max - angle_min;
00064
00065 ROS_ASSERT(vertical_fov > 0);
00066
00067
00068 calcDeltaAngleForImgRows(vertical_fov);
00069
00070
00071 calcGroundDistancesForImgRows(vertical_fov);
00072
00073
00074 calcTiltCompensationFactorsForImgRows(vertical_fov);
00075
00076
00077 if (used_depth_height_ > depth_msg->height)
00078 {
00079 ROS_ERROR("Parameter used_depth_height is higher than height of image.");
00080 used_depth_height_ = depth_msg->height;
00081 }
00082 depth_sensor_params_update = true;
00083 }
00084
00085
00086 if (depth_msg->encoding == sensor_msgs::image_encodings::TYPE_16UC1)
00087 {
00088 findCliffInDepthImage(depth_msg);
00089 }
00090 else
00091 {
00092 std::stringstream ss;
00093 ss << "Depth image has unsupported encoding: " << depth_msg->encoding;
00094 throw std::runtime_error(ss.str());
00095 }
00096 }
00097
00098
00099 void CliffDetector::setRangeLimits( const float rmin, const float rmax )
00100 {
00101 if (rmin >= 0 && rmin < rmax)
00102 range_min_ = rmin;
00103 else
00104 {
00105 range_min_ = 0;
00106 ROS_ERROR("Incorrect value of range minimal parameter. Set default value: 0.");
00107 }
00108 if (rmax >= 0 && rmin < rmax)
00109 range_max_ = rmax;
00110 else
00111 {
00112 range_max_ = 10;
00113 ROS_ERROR("Incorrect value of range maximum parameter. Set default value: 10.");
00114 }
00115 }
00116
00117
00118 void CliffDetector::setSensorMountHeight (const float height)
00119 {
00120 if( height > 0)
00121 sensor_mount_height_ = height;
00122 else
00123 {
00124 sensor_mount_height_ = 0;
00125 ROS_ERROR("Incorrect value of sensor mount height parameter. Set default value: 0.");
00126 }
00127 }
00128
00129
00130 void CliffDetector::setSensorTiltAngle (const float angle)
00131 {
00132 if( angle < 90 && angle > -90)
00133 sensor_tilt_angle_ = angle;
00134 else
00135 {
00136 sensor_tilt_angle_ = 0;
00137 ROS_ERROR("Incorrect value of sensor tilt angle parameter. Set default value: 0.");
00138 }
00139 }
00140
00141
00142 void CliffDetector::setUsedDepthHeight(const unsigned int height)
00143 {
00144 if( height > 0)
00145 used_depth_height_ = height;
00146 else
00147 {
00148 used_depth_height_ = 100;
00149 ROS_ERROR("Incorrect value of used depth height parameter. Set default value: 100.");
00150 }
00151 }
00152
00153
00154 void CliffDetector::setBlockSize(const int size)
00155 {
00156 if( size > 0 && (size % 2 == 0))
00157 block_size_ = size;
00158 else
00159 {
00160 block_size_ = 8;
00161 ROS_ERROR("Incorrect value of block size. Set default value: 8.");
00162 }
00163 }
00164
00165
00166 void CliffDetector::setBlockPointsThresh(const int thresh)
00167 {
00168 if( thresh > 0 )
00169 block_points_thresh_ = thresh;
00170 else
00171 {
00172 block_points_thresh_ = 1;
00173 ROS_ERROR("Incorrect value of block points threshold parameter. Set default value: 1.");
00174 }
00175 }
00176
00177
00178 void CliffDetector::setDepthImgStepRow(const int step)
00179 {
00180 if( step > 0 )
00181 depth_image_step_row_ = step;
00182 else
00183 {
00184 depth_image_step_row_ = 1;
00185 ROS_ERROR("Incorrect value depth image row step parameter. Set default value: 1.");
00186 }
00187 }
00188
00189
00190 void CliffDetector::setDepthImgStepCol(const int step)
00191 {
00192 if( step > 0 )
00193 depth_image_step_col_ = step;
00194 else
00195 {
00196 depth_image_step_col_ = 1;
00197 ROS_ERROR("Incorrect value depth image column step parameter. Set default value: 1.");
00198 }
00199 }
00200
00201
00202 void CliffDetector::setGroundMargin (const float margin)
00203 {
00204 if( margin > 0)
00205 ground_margin_ = margin;
00206 else
00207 {
00208 ground_margin_ = 0;
00209 ROS_ERROR("Incorrect value of ground margin parameter. Set default value: 0.");
00210 }
00211 }
00212
00213
00214
00215
00216 double CliffDetector::lengthOfVector(const cv::Point3d& vec) const
00217 {
00218 return sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z);
00219 }
00220
00221
00222 double CliffDetector::angleBetweenRays(const cv::Point3d& ray1, const cv::Point3d& ray2) const
00223 {
00224 double dot = ray1.x*ray2.x + ray1.y*ray2.y + ray1.z*ray2.z;
00225
00226 return acos(dot / (lengthOfVector(ray1) * lengthOfVector(ray2)));
00227 }
00228
00229
00230 void CliffDetector::fieldOfView(double & min, double & max, double x1, double y1,
00231 double xc, double yc, double x2, double y2)
00232 {
00233 cv::Point2d raw_pixel_left(x1, y1);
00234 cv::Point2d rect_pixel_left = camera_model_.rectifyPoint(raw_pixel_left);
00235 cv::Point3d left_ray = camera_model_.projectPixelTo3dRay(rect_pixel_left);
00236
00237 cv::Point2d raw_pixel_right(x2, y2);
00238 cv::Point2d rect_pixel_right = camera_model_.rectifyPoint(raw_pixel_right);
00239 cv::Point3d right_ray = camera_model_.projectPixelTo3dRay(rect_pixel_right);
00240
00241 cv::Point2d raw_pixel_center(xc, yc);
00242 cv::Point2d rect_pixel_center = camera_model_.rectifyPoint(raw_pixel_center);
00243 cv::Point3d center_ray = camera_model_.projectPixelTo3dRay(rect_pixel_center);
00244
00245 min = -angleBetweenRays(center_ray, right_ray);
00246 max = angleBetweenRays(left_ray, center_ray);
00247
00248 ROS_ASSERT(min < 0 && max > 0);
00249 }
00250
00251
00252
00253 void CliffDetector::calcDeltaAngleForImgRows(double vertical_fov)
00254 {
00255 const unsigned int img_height = camera_model_.fullResolution().height;
00256
00257 delta_row_.resize(img_height);
00258
00259
00260 for(unsigned int i = 0; i < img_height; i++)
00261 delta_row_[i] = vertical_fov * (i - camera_model_.cy() - 0.5) / ((double)img_height - 1);
00262 }
00263
00264
00265 void CliffDetector::calcGroundDistancesForImgRows(double vertical_fov)
00266 {
00267 const double alpha = sensor_tilt_angle_ * M_PI / 180.0;
00268 const unsigned int img_height = camera_model_.fullResolution().height;
00269
00270 ROS_ASSERT(img_height >= 0);
00271
00272 dist_to_ground_.resize(img_height);
00273
00274
00275 for(unsigned int i = 0; i < img_height; i++)
00276 {
00277
00278
00279
00280 if ((delta_row_[i] + alpha) > 0)
00281 {
00282 dist_to_ground_[i] = sensor_mount_height_ * sin(M_PI/2 - delta_row_[i]) * 1000
00283 / cos(M_PI/2 - delta_row_[i] - alpha);
00284 ROS_ASSERT(dist_to_ground_[i] > 0);
00285 }
00286 else
00287 dist_to_ground_[i] = 100 * 1000;
00288 }
00289 }
00290
00291
00292 void CliffDetector::calcTiltCompensationFactorsForImgRows(double vertical_fov)
00293 {
00294 const double alpha = sensor_tilt_angle_ * M_PI / 180.0;
00295 const unsigned int img_height = camera_model_.fullResolution().height;
00296
00297 ROS_ASSERT(img_height >= 0);
00298
00299 tilt_compensation_factor_.resize(img_height);
00300
00301 for(unsigned int i = 0; i < img_height; i++)
00302 {
00303
00304
00305 tilt_compensation_factor_[i] = sin(M_PI/2 - delta_row_[i] - alpha)
00306 / sin(M_PI/2 - delta_row_[i]);
00307 ROS_ASSERT(tilt_compensation_factor_[i] > 0 && tilt_compensation_factor_[i] < 10);
00308 }
00309 }
00310
00311
00312 void CliffDetector::findCliffInDepthImage( const sensor_msgs::ImageConstPtr &depth_msg)
00313 {
00314 enum point { Row, Col, Depth };
00315
00316 const uint16_t* depth_row = reinterpret_cast<const uint16_t*>(&depth_msg->data[0]);
00317
00318 const unsigned int row_size = depth_msg->step / sizeof(uint16_t);
00319
00320 const unsigned int img_height = camera_model_.fullResolution().height;
00321 const unsigned int img_width = camera_model_.fullResolution().width;
00322
00323 if ( (block_size_ % 2) !=0 )
00324 {
00325 ROS_ERROR("Block size should be even number. Value will be decreased by one.");
00326 block_size_--;
00327 }
00328
00329 const unsigned int block_cols_nr = img_width / block_size_;
00330 const unsigned int block_rows_nr = used_depth_height_ / block_size_;
00331
00332 const int ground_margin_mm = ground_margin_ * 1000;
00333 const unsigned int range_min_mm = range_min_ * 1000;
00334 const unsigned int range_max_mm = range_max_ * 1000;
00335
00336
00337 if (block_points_thresh_ >= (block_size_ * block_size_ / depth_image_step_col_
00338 / depth_image_step_row_))
00339 {
00340 ROS_ERROR("Block points threshold is too big. Maximum admissible value will be set.");
00341 block_points_thresh_ = block_size_*block_size_ / depth_image_step_col_ / depth_image_step_row_;
00342 }
00343
00344
00345
00346 std::vector<std::vector<int> >tpoints (block_size_ * block_size_, std::vector<int>(3));
00347
00348
00349
00350 std::vector<std::vector<int> > stairs_points;
00351
00352
00353
00354
00355 std::vector<int> px_nr;
00356
00357
00358
00359 px_nr.resize(block_size_ * block_size_);
00360
00361
00362 const unsigned int c = block_size_ / 2;
00363 std::vector<unsigned int> center_points(4);
00364 center_points[0] = c * block_size_ + c-1;
00365 center_points[1] = c * block_size_ + c;
00366 center_points[2] = (c-1) * block_size_ + c-1;
00367 center_points[3] = (c-1)*block_size_ + c ;
00368
00369
00370 for (unsigned int bj = 0; bj < block_rows_nr; ++bj)
00371 {
00372
00373 for (unsigned int bi = 0; bi < block_cols_nr; ++bi)
00374 {
00375
00376
00377 unsigned int block_cnt = 0;
00378 std::fill(px_nr.begin(), px_nr.end(), -1);
00379
00380
00381 for (unsigned int j = 0; j < block_size_; j += depth_image_step_row_)
00382 {
00383
00384 for (unsigned int i = 0; i < block_size_; i += depth_image_step_col_)
00385 {
00386
00387 unsigned int row = (img_height - 1 ) - ( bj * block_size_+ j );
00388 unsigned int col = bi * block_size_ + i;
00389 ROS_ASSERT(row < img_height && col < img_width);
00390
00391 unsigned int d = depth_row[row_size * row + col];
00392
00393
00394 if (d > (dist_to_ground_[row] + ground_margin_mm) &&
00395 d > range_min_mm && d < range_max_mm)
00396 {
00397 tpoints[block_cnt][Row] = row;
00398 tpoints[block_cnt][Col] = col;
00399 tpoints[block_cnt][Depth] = d;
00400 px_nr[j * block_size_ + i] = block_cnt;
00401 block_cnt++;
00402 }
00403 }
00404 }
00405
00406 if (block_cnt >= block_points_thresh_)
00407 {
00408
00409 if (px_nr[center_points[0]] > 0)
00410 stairs_points.push_back(tpoints[px_nr[center_points[0]]]);
00411 else if (px_nr[center_points[1]] > 0)
00412 stairs_points.push_back(tpoints[px_nr[center_points[1]]]);
00413 else if (px_nr[center_points[2]] > 0)
00414 stairs_points.push_back(tpoints[px_nr[center_points[2]]]);
00415 else if (px_nr[center_points[3]] > 0)
00416 stairs_points.push_back(tpoints[px_nr[center_points[3]]]);
00417 else
00418 {
00419 stairs_points.insert(stairs_points.end(), tpoints.begin(), tpoints.begin() + block_cnt);
00420 }
00421 }
00422 block_cnt = 0;
00423
00424 }
00425 }
00426
00427
00428
00429
00430 std::vector<std::vector<int> >::iterator it;
00431 geometry_msgs::Point32 pt;
00432
00433 if (publish_depth_enable_)
00434 new_depth_msg_ = *depth_msg;
00435
00436 uint16_t* new_depth_row = reinterpret_cast<uint16_t*>(&new_depth_msg_.data[0]);
00437
00438
00439 stairs_points_msg_.header = depth_msg->header;
00440 stairs_points_msg_.size = (unsigned int) stairs_points.size();
00441 stairs_points_msg_.points.clear();
00442 pt.y = 0;
00443
00444 for(it = stairs_points.begin(); it != stairs_points.end(); ++it)
00445 {
00446
00447
00448 unsigned int row = (*it)[Row];
00449 pt.z = sensor_mount_height_ / std::tan(sensor_tilt_angle_ * M_PI / 180.0 + delta_row_[row]);
00450
00451
00452
00453 double depth = sensor_mount_height_ / std::sin(sensor_tilt_angle_*M_PI/180.0 + delta_row_[row]);
00454
00455 pt.x = ((*it)[Col] - camera_model_.cx()) * depth / camera_model_.fx();
00456
00457
00458 stairs_points_msg_.points.push_back(pt);
00459
00460 if (publish_depth_enable_)
00461 {
00462 ROS_ASSERT(row_size * (*it)[Row] + (*it)[Col] < (new_depth_msg_.height * new_depth_msg_.width));
00463 new_depth_row[row_size * (*it)[Row] + (*it)[Col]] = 10000U;
00464 }
00465 }
00466 ROS_DEBUG_STREAM("Stairs points: " << stairs_points.size());
00467 }
00468
00469
00470