depth_sensor_pose.cpp
Go to the documentation of this file.
00001 /******************************************************************************
00002  * Software License Agreement (BSD License)
00003  *
00004  * Copyright (c) 2015, Michal Drwiega (drwiega.michal@gmail.com)
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted provided that the following conditions are met:
00009  *     1. Redistributions of source code must retain the above copyright
00010  *        notice, this list of conditions and the following disclaimer.
00011  *     2. Redistributions in binary form must reproduce the above copyright
00012  *        notice, this list of conditions and the following disclaimer in the
00013  *        documentation and/or other materials provided with the distribution.
00014  *     3. Neither the name of the copyright holder nor the names of its
00015  *        contributors may be used to endorse or promote products derived
00016  *        from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00019  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00020  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
00021  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
00022  * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00023  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00024  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00025  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00026  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00027  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00028  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00029  *****************************************************************************/
00037 #include <depth_sensor_pose/depth_sensor_pose.h>
00038 
00039 using namespace depth_sensor_pose;
00040 
00041 //=================================================================================================
00042 // Public methods
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   // Update data based on depth sensor parameters only if new params values
00064   // or turned on continuous data calculations
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     // Calculate vertical field of view angles
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   // Check if image encoding is correctly
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 // Private methods
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   // Angle between ray and optical center
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; // Sensor tilt angle in radians
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   // Calculations for each row of image
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   // Loop over each row in image from bottom of img
00344   for (unsigned int j = 0; j < (unsigned int)depth_msg->height; j += depth_image_step_row_)
00345   {
00346     // Loop over each column in image
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       // Check if distance to point is greater than distance to ground plane
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   // Get ground points
00400   getGroundPoints(depth_msg, points);
00401 
00402   if (points->size() >= 3)
00403   {
00404     // Estimate model parameters with RANSAC
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     // Calculate height and
00417     float A = ground_coeffs[0], B = ground_coeffs[1];
00418     float C = ground_coeffs[2], D = ground_coeffs[3];
00419 
00420     // Dot product two vectors v=[A,B,C], w=[1,1,0]
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 


depth_sensor_pose
Author(s): Michal Drwiega
autogenerated on Thu Jun 6 2019 22:10:50