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 <depth_sensor_pose/depth_sensor_pose.h>
00038
00039 using namespace depth_sensor_pose;
00040
00041
00042
00043
00044
00045
00046
00047 DepthSensorPose::DepthSensorPose(): reconf_serv_params_updated_(true)
00048 {
00049 }
00050
00051
00052 DepthSensorPose::~DepthSensorPose()
00053 {
00054 }
00055
00056
00057 void DepthSensorPose::estimateParams( const sensor_msgs::ImageConstPtr& depth_msg,
00058 const sensor_msgs::CameraInfoConstPtr& info_msg )
00059 {
00060 #if DEBUG
00061 ROS_DEBUG("Start estimation procedure");
00062 #endif
00063
00064
00065 if(reconf_serv_params_updated_ || cam_model_update_)
00066 {
00067 camera_model_.fromCameraInfo(info_msg);
00068
00069 double cx = camera_model_.cx(), cy = camera_model_.cy(), vert_min, vert_max;
00070
00071
00072 fieldOfView(vert_min, vert_max, cx, 0, cx, cy, cx, depth_msg->height -1);
00073 double vertical_fov = vert_max - vert_min;
00074
00075 #if DEBUG
00076 ROS_DEBUG("Recalculate distance to ground coefficients for image rows.");
00077 #endif
00078 calcDeltaAngleForImgRows(vertical_fov);
00079 dist_to_ground_max_.resize(camera_model_.fullResolution().height);
00080 dist_to_ground_min_.resize(camera_model_.fullResolution().height);
00081 calcGroundDistancesForImgRows(mount_height_max_,tilt_angle_min_, dist_to_ground_max_);
00082 calcGroundDistancesForImgRows(mount_height_min_,tilt_angle_max_, dist_to_ground_min_);
00083
00084 reconf_serv_params_updated_ = false;
00085 #ifdef DEBUG_INFO
00086 std::ostringstream s;
00087 for(int v = 0; v < depth_msg->height; v+=8)
00088 s << " " << rowFloorThreshold_[v];
00089 ROS_INFO_STREAM_THROTTLE(2,"rowFloorThreshold = " << s.str());
00090 #endif
00091
00092 #ifdef DEBUG_INFO
00093 const uint16_t* depthRoww = reinterpret_cast<const uint16_t*>(&depth_msg->data[0]);
00094 int rowStepp = depth_msg->step / sizeof(uint16_t);
00095 std::ostringstream s, sss;
00096 for(int v = 0; v < depth_msg->height; v+=40, depthRoww += (rowStepp*40))
00097 sss << " " << (int)depthRoww[320] * tiltCompensationFactor_[v];
00098 for(int v = 0; v < depth_msg->height; v+=8)
00099 s << " " << tiltCompensationFactor_[v];
00100 ROS_INFO_STREAM_THROTTLE(2,"tiltCompensation = " << s.str());
00101 ROS_INFO_STREAM_THROTTLE(0.4,"depth_tilt_compensation" << sss.str());
00102 #endif
00103 }
00104
00105 #ifdef DEBUG_INFO
00106 const uint16_t* depthRow = reinterpret_cast<const uint16_t*>(&depth_msg->data[0]);
00107 int rowStep = depth_msg->step / sizeof(uint16_t);
00108 std::ostringstream ss, sss, stream;
00109 for(int v = 0; v < depth_msg->height; v+=40, depthRow += (rowStep*40))
00110 {
00111 ss << " " << (int)depthRow[320] * 0.001f;
00112 }
00113 ROS_INFO_STREAM_THROTTLE(0.4,"depth" << ss.str());
00114 #endif
00115 #ifdef DATA_TO_FILE
00116 depthRow = reinterpret_cast<const uint16_t*>(&depth_msg->data[0]);
00117 for(int v = 0; v < depth_msg->height; v++, depthRow += rowStep)
00118 stream << " " << (int)depthRow[320] * 0.001f;
00119 std::ofstream file("/home/themin/kinect_data.txt", std::ios::out | std::ios::app);
00120 file << stream.str() << "\n";
00121 file.close();
00122 #endif
00123
00124
00125 if (depth_msg->encoding == sensor_msgs::image_encodings::TYPE_16UC1)
00126 {
00127 double tilt, height;
00128
00129 sensorPoseCalibration(depth_msg, tilt, height);
00130
00131 tilt_angle_est_ = tilt;
00132 mount_height_est_ = height;
00133 }
00134 else
00135 {
00136 std::stringstream ss;
00137 ss << "Depth image has unsupported encoding: " << depth_msg->encoding;
00138 throw std::runtime_error(ss.str());
00139 }
00140 }
00141
00142
00143 void DepthSensorPose::setRangeLimits( const float rmin, const float rmax )
00144 {
00145 if (rmin >= 0 && rmin < rmax)
00146 range_min_ = rmin;
00147 else
00148 {
00149 range_min_ = 0;
00150 ROS_ERROR("Incorrect value of range minimal parameter. Set default value: 0.");
00151 }
00152 if (rmax >= 0 && rmin < rmax)
00153 range_max_ = rmax;
00154 else
00155 {
00156 range_max_ = 10;
00157 ROS_ERROR("Incorrect value of range maximum parameter. Set default value: 10.");
00158 }
00159 }
00160
00161
00162 void DepthSensorPose::setSensorMountHeightMin (const float height)
00163 {
00164 if( height > 0)
00165 mount_height_min_ = height;
00166 else
00167 {
00168 mount_height_min_ = 0;
00169 ROS_ERROR("Incorrect value of sensor mount height parameter. Set default value: 0.");
00170 }
00171 }
00172
00173
00174 void DepthSensorPose::setSensorMountHeightMax (const float height)
00175 {
00176 if( height > 0)
00177 mount_height_max_ = height;
00178 else
00179 {
00180 mount_height_max_ = 1;
00181 ROS_ERROR("Incorrect value of sensor mount height parameter. Set default value: 1m.");
00182 }
00183 }
00184
00185
00186 void DepthSensorPose::setSensorTiltAngleMin (const float angle)
00187 {
00188 if( angle < 90 && angle > -90)
00189 tilt_angle_min_ = angle;
00190 else
00191 {
00192 tilt_angle_min_ = 0;
00193 ROS_ERROR("Incorrect value of sensor tilt angle parameter. Set default value: 0.");
00194 }
00195 }
00196
00197
00198 void DepthSensorPose::setSensorTiltAngleMax (const float angle)
00199 {
00200 if( angle < 90 && angle > -90)
00201 tilt_angle_max_ = angle;
00202 else
00203 {
00204 tilt_angle_max_ = 0;
00205 ROS_ERROR("Incorrect value of sensor tilt angle parameter. Set default value: 0.");
00206 }
00207 }
00208
00209
00210 void DepthSensorPose::setUsedDepthHeight(const unsigned int height)
00211 {
00212 if( height > 0)
00213 used_depth_height_ = height;
00214 else
00215 {
00216 used_depth_height_ = 200;
00217 ROS_ERROR("Incorrect value of used depth height parameter. Set default value: 200.");
00218 }
00219 }
00220
00221
00222 void DepthSensorPose::setDepthImgStepRow(const int step)
00223 {
00224 if( step > 0 )
00225 depth_image_step_row_ = step;
00226 else
00227 {
00228 depth_image_step_row_ = 1;
00229 ROS_ERROR("Incorrect value depth image row step parameter. Set default value: 1.");
00230 }
00231 }
00232
00233
00234 void DepthSensorPose::setDepthImgStepCol(const int step)
00235 {
00236 if( step > 0 )
00237 depth_image_step_col_ = step;
00238 else
00239 {
00240 depth_image_step_col_ = 1;
00241 ROS_ERROR("Incorrect value depth image column step parameter. Set default value: 1.");
00242 }
00243 }
00244
00245
00246
00247
00248
00249 double DepthSensorPose::lengthOfVector(const cv::Point3d& vec) const
00250 {
00251 return sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z);
00252 }
00253
00254
00255 double DepthSensorPose::angleBetweenRays(const cv::Point3d& ray1, const cv::Point3d& ray2) const
00256 {
00257 double dot = ray1.x*ray2.x + ray1.y*ray2.y + ray1.z*ray2.z;
00258
00259 return acos(dot / (lengthOfVector(ray1) * lengthOfVector(ray2)));
00260 }
00261
00262
00263 void DepthSensorPose::fieldOfView(double & min, double & max, double x1, double y1,
00264 double xc, double yc, double x2, double y2)
00265 {
00266 cv::Point2d raw_pixel_left(x1, y1);
00267 cv::Point2d rect_pixel_left = camera_model_.rectifyPoint(raw_pixel_left);
00268 cv::Point3d left_ray = camera_model_.projectPixelTo3dRay(rect_pixel_left);
00269
00270 cv::Point2d raw_pixel_right(x2, y2);
00271 cv::Point2d rect_pixel_right = camera_model_.rectifyPoint(raw_pixel_right);
00272 cv::Point3d right_ray = camera_model_.projectPixelTo3dRay(rect_pixel_right);
00273
00274 cv::Point2d raw_pixel_center(xc, yc);
00275 cv::Point2d rect_pixel_center = camera_model_.rectifyPoint(raw_pixel_center);
00276 cv::Point3d center_ray = camera_model_.projectPixelTo3dRay(rect_pixel_center);
00277
00278 min = -angleBetweenRays(center_ray, right_ray);
00279 max = angleBetweenRays(left_ray, center_ray);
00280
00281 ROS_ASSERT(min < 0 && max > 0);
00282 }
00283
00284
00285 void DepthSensorPose::calcDeltaAngleForImgRows(double vertical_fov)
00286 {
00287 const unsigned int img_height = camera_model_.fullResolution().height;
00288
00289 delta_row_.resize(img_height);
00290
00291
00292 for(unsigned int i = 0; i < img_height; i++)
00293 delta_row_[i] = vertical_fov * (i - camera_model_.cy() - 0.5) / ((double)img_height - 1);
00294 }
00295
00296
00297 void DepthSensorPose::calcGroundDistancesForImgRows(double mount_height, double tilt_angle,
00298 std::vector<unsigned int>& distances)
00299 {
00300 const double alpha = tilt_angle * M_PI / 180.0;
00301 const unsigned int img_height = camera_model_.fullResolution().height;
00302
00303 ROS_ASSERT(img_height >= 0 && mount_height > 0);
00304
00305 distances.resize(img_height);
00306
00307
00308 for(unsigned int i = 0; i < img_height; i++)
00309 {
00310 if ((delta_row_[i] + alpha) > 0)
00311 {
00312 distances[i] = mount_height * sin(M_PI/2 - delta_row_[i]) * 1000
00313 / cos(M_PI/2 - delta_row_[i] - alpha);
00314 ROS_ASSERT(distances[i] > 0);
00315 }
00316 else
00317 distances[i] = 100 * 1000;
00318 }
00319 }
00320
00321
00322 void DepthSensorPose::getGroundPoints( const sensor_msgs::ImageConstPtr& depth_msg,
00323 pcl::PointCloud<pcl::PointXYZ>::Ptr& points)
00324 {
00325 enum point { Row, Col, Depth };
00326
00327 #ifdef DEBUG_CALIBRATION
00328 std::vector<double> deltaVec;
00329 #endif
00330 const unsigned int img_height = camera_model_.fullResolution().height;
00331
00332 const unsigned int range_min_mm = range_min_ * 1000;
00333 const unsigned int range_max_mm = range_max_ * 1000;
00334
00335 const uint16_t* depth_row = reinterpret_cast<const uint16_t*>(&depth_msg->data[0]);
00336 const unsigned int row_size = depth_msg->step / sizeof(uint16_t);
00337
00338 if (publish_depth_enable_)
00339 new_depth_msg_ = *depth_msg;
00340
00341 uint16_t* new_depth_row = reinterpret_cast<uint16_t*>(&new_depth_msg_.data[0]);
00342
00343
00344 for (unsigned int j = 0; j < (unsigned int)depth_msg->height; j += depth_image_step_row_)
00345 {
00346
00347 for (unsigned int i = 0; i < (unsigned int)depth_msg->width; i += depth_image_step_col_)
00348 {
00349 unsigned int row = (img_height - 1 ) - j;
00350 ROS_ASSERT(row < img_height);
00351
00352 unsigned int d = (depth_row[row_size * row + i]);
00353
00354
00355 if (points->size() <= max_ground_points_ && d > range_min_mm && d < range_max_mm &&
00356 d > dist_to_ground_min_[row] && d < dist_to_ground_max_[row])
00357 {
00358 double z = d * 0.001f;
00359 double x = z * ((double)j - camera_model_.cx()) / camera_model_.fx();
00360 double y = z * ((double)i - camera_model_.cy()) / camera_model_.fy();
00361
00362 points->push_back(pcl::PointXYZ(x, y, z));
00363
00364 if (publish_depth_enable_)
00365 new_depth_row[row_size * row + i] = 10000U;
00366 }
00367 }
00368 }
00369
00370 #ifdef DEBUG_CALIBRATION
00371 std::ostringstream s;
00372 s << " getGroundPoints: imgHeight = " << imgH
00373 << "\n coarseTilt = " << alpha << " fov = " << fov
00374 << "\n cx = " << camModel_.cx() << " cy = " << camModel_.cy()
00375 << "\n rowsThresh_size = " << rowThreshCalibration.size()
00376 << "\n deltaVec_size = " << rowThreshCalibration.size()
00377 << "\n deltaVec[] = ";
00378 for(int v = 0; v < deltaVec.size(); v++)
00379 s << " " << deltaVec[v];
00380 s << "\n rowThreshCalibration[] = ";
00381 for(int v = 0; v < rowThreshCalibration.size(); v++)
00382 s << " " << rowThreshCalibration[v];
00383 ROS_INFO_STREAM_THROTTLE(2, s.str());
00384 #endif
00385 }
00386
00387
00388 void DepthSensorPose::sensorPoseCalibration(
00389 const sensor_msgs::ImageConstPtr& depth_msg, double& tilt, double& height)
00390 {
00391
00392
00393
00394
00395
00396 pcl::PointCloud<pcl::PointXYZ>::Ptr points(new pcl::PointCloud<pcl::PointXYZ>);
00397
00398
00399
00400 getGroundPoints(depth_msg, points);
00401
00402 if (points->size() >= 3)
00403 {
00404
00405 pcl::SampleConsensusModelPlane<pcl::PointXYZ>::Ptr
00406 model (new pcl::SampleConsensusModelPlane<pcl::PointXYZ> (points));
00407
00408 pcl::RandomSampleConsensus<pcl::PointXYZ> ransac (model);
00409 ransac.setDistanceThreshold (ransacDistanceThresh_);
00410 ransac.setMaxIterations(ransacMaxIter_);
00411 ransac.computeModel();
00412
00413 Eigen::VectorXf ground_coeffs(4);
00414 ransac.getModelCoefficients(ground_coeffs);
00415
00416
00417 float A = ground_coeffs[0], B = ground_coeffs[1];
00418 float C = ground_coeffs[2], D = ground_coeffs[3];
00419
00420
00421 tilt_angle_est_ = std::acos ((B*B + A*A) /
00422 (std::sqrt(B*B + A*A) * std::sqrt(A*A+B*B+C*C))) * 180.0 / M_PI;
00423 mount_height_est_ = std::abs(D) / std::sqrt(A*A+B*B+C*C);
00424
00425 ROS_ERROR("11height = %.4f angle = %.4f", mount_height_est_, tilt_angle_est_);
00426
00427 #ifdef DEBUG_CALIBRATION
00428 std::ostringstream s;
00429 s << " sensorLocationCalibration: points_size = " << points->size()
00430 << "\n A = " << ground_coeffs[0]
00431 << "\n B = " << ground_coeffs[1]
00432 << "\n C = " << ground_coeffs[2]
00433 << "\n D = " << ground_coeffs[3]
00434 << "\n t1 = " << acos((A+B)/(sqrt(2)*sqrt(A*A+B*B+C*C))) * 180.0 / M_PI
00435 << "\n t2 = " << acos((A+C)/(sqrt(2)*sqrt(A*A+B*B+C*C))) * 180.0 / M_PI
00436 << "\n t3 = " << acos((B+C)/(sqrt(2)*sqrt(A*A+B*B+C*C))) * 180.0 / M_PI
00437 << "\n t4 = " << acos((A)/(sqrt(1)*sqrt(A*A+B*B+C*C))) * 180.0 / M_PI
00438 << "\n t5 = " << acos((B)/(sqrt(1)*sqrt(A*A+B*B+C*C))) * 180.0 / M_PI
00439 << "\n t6 = " << acos((C)/(sqrt(1)*sqrt(A*A+B*B+C*C))) * 180.0 / M_PI
00440 << "\n height = " << height
00441 << "\n tilt = " << tilt;
00442 ROS_INFO_STREAM_THROTTLE(1, s.str());
00443 #endif
00444 }
00445 else
00446 {
00447 ROS_ERROR("Ground points not detected");
00448 }
00449 }
00450
00451