$search
00001 /* 00002 * Copyright (c) 2011, Jeannette Bohg and Mårten Björkman 00003 * ({bohg,celle}@csc.kth.se) 00004 * All rights reserved. 00005 * 00006 * Redistribution and use in source and binary forms, with or without 00007 * modification, are permitted provided that the following conditions are 00008 * met: 00009 * 00010 * 1.Redistributions of source code must retain the above copyright 00011 * notice, this list of conditions and the following disclaimer. 00012 * 2.Redistributions in binary form must reproduce the above 00013 * copyright notice, this list of conditions and the following 00014 * disclaimer in the documentation and/or other materials provided 00015 * with the distribution. 00016 * 3.The name of Jeannette Bohg or Mårten Björkman may not be used to 00017 * endorse or promote products derived from this software without 00018 * specific prior written permission. 00019 * 00020 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00021 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00022 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00023 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00024 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00025 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00026 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00027 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00028 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00029 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00030 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00031 */ 00032 00033 #include "fast_plane_detector/plane_transform.h" 00034 #include <geometry_msgs/Pose.h> 00035 00036 namespace fast_plane_detection { 00037 00038 PlaneTransform::PlaneTransform(const sensor_msgs::CameraInfo &camera_info, 00039 float baseline, float up_direction) 00040 : camera_info_(camera_info) 00041 , baseline_(baseline) 00042 , up_direction_(up_direction) 00043 {} 00044 00045 PlaneTransform::~PlaneTransform() 00046 {} 00047 00048 void PlaneTransform::setParameters( float alpha, 00049 float beta, 00050 float d, 00051 int min_x, int max_x, 00052 int min_y, int max_y, 00053 std_msgs::Header header) 00054 { 00055 alpha_ = alpha; 00056 beta_ = beta; 00057 d_ = d; 00058 00059 min_x_ = min_x; 00060 max_x_ = max_x; 00061 00062 min_y_ = min_y; 00063 max_y_ = max_y; 00064 00065 header_ = header; 00066 } 00067 00068 bool PlaneTransform::getPlane( Plane &plane ){ 00069 00070 //pcl::ModelCoefficients plane_coefficients 00071 std::vector<double> plane_coefficients 00072 = convertTo3DPlane( camera_info_, alpha_, beta_, d_); 00073 00074 tf::Transform plane_trans 00075 = getPlaneTransform (plane_coefficients, up_direction_); 00076 00077 sensor_msgs::PointCloud plane_limits; 00078 plane_limits.header.frame_id = header_.frame_id; 00079 plane_limits.header.stamp = ros::Time::now(); 00080 plane_limits.points.resize(4); 00081 00082 get3DTableLimits(plane_limits); 00083 00084 if(!transformPlanePoints(plane_trans, plane_limits)) 00085 return false; 00086 00087 plane = constructPlaneMsg(plane_limits, plane_coefficients, plane_trans); 00088 00089 return true; 00090 } 00091 00092 00093 std::vector<double> PlaneTransform::convertTo3DPlane(const sensor_msgs::CameraInfo &camera_info, 00094 float alpha, 00095 float beta, 00096 float d ) 00097 { 00098 float fx = camera_info.P[0*4+0]; 00099 float cx = camera_info.P[0*4+2]; 00100 float cy = camera_info.P[1*4+2]; 00101 00102 float A = alpha/baseline_; 00103 float B = beta/baseline_; 00104 float C = d/(baseline_ * fx) + (A*cx + B*cy)/fx; 00105 00106 ROS_DEBUG("Camera Parameters:"); 00107 ROS_DEBUG("Focal length: %f", fx); 00108 ROS_DEBUG("Principal point: %f %f", cx, cy); 00109 ROS_DEBUG("Baseline %f", baseline_); 00110 ROS_DEBUG("alpha, beta and d %f %f %f", alpha, beta, d); 00111 00112 // calc disparity for principal point 00113 float disp = alpha*cx + beta*cy + d; 00114 // convert point to 3D 00115 float Z = baseline_*fx/disp; 00116 float D = C * Z; 00117 ROS_DEBUG("Apart from rounding error D should be 1 and is %f", D); 00118 00119 00120 float NMod = sqrt(A*A+B*B+C*C); 00121 00122 A/=NMod; 00123 B/=NMod; 00124 C/=NMod; 00125 D/=NMod; 00126 00127 ROS_DEBUG("3D Table plane parameters: %f %f %f %f", A, B, C, D); 00128 00129 // pcl::ModelCoefficients table_coefficients; 00130 std::vector<double> table_coefficients; 00131 table_coefficients.push_back(A); 00132 table_coefficients.push_back(B); 00133 table_coefficients.push_back(C); 00134 table_coefficients.push_back(D); 00135 00136 return table_coefficients; 00137 } 00138 00139 tf::Transform 00140 PlaneTransform::getPlaneTransform ( const std::vector<double> &coeffs, 00141 //const pcl::ModelCoefficients &coeffs, 00142 double up_direction) 00143 { 00144 ROS_ASSERT(coeffs.size() > 3); 00145 double a = coeffs[0], b = coeffs[1], 00146 c = coeffs[2], d = coeffs[3]; 00147 //asume plane coefficients are normalized 00148 btVector3 position(a*d, b*d, c*d); 00149 btVector3 z(a, b, c); 00150 //make sure z points "up" 00151 ROS_DEBUG("z.dot: %0.3f", z.dot(btVector3(0,0,1))); 00152 ROS_DEBUG("in getPlaneTransform, z: %0.3f, %0.3f, %0.3f", 00153 z[0], z[1], z[2]); 00154 if ( z.dot( btVector3(0, 0, up_direction) ) < 0) 00155 { 00156 z = -1.0 * z; 00157 ROS_DEBUG("flipped z"); 00158 } 00159 ROS_DEBUG("in getPlaneTransform, z: %0.3f, %0.3f, %0.3f", 00160 z[0], z[1], z[2]); 00161 00162 //try to align the x axis with the x axis of the original frame 00163 //or the y axis if z and x are too close too each other 00164 btVector3 x(1, 0, 0); 00165 if ( fabs(z.dot(x)) > 1.0 - 1.0e-4) x = btVector3(0, 1, 0); 00166 btVector3 y = z.cross(x).normalized(); 00167 x = y.cross(z).normalized(); 00168 00169 btMatrix3x3 rotation; 00170 rotation[0] = x; // x 00171 rotation[1] = y; // y 00172 rotation[2] = z; // z 00173 rotation = rotation.transpose(); 00174 btQuaternion orientation; 00175 rotation.getRotation(orientation); 00176 return tf::Transform(orientation, position); 00177 } 00178 00179 bool PlaneTransform::transformPlanePoints ( const tf::Transform& plane_trans, 00180 sensor_msgs::PointCloud &plane_limits ) 00181 { 00182 // Transform the data 00183 // tf::TransformListener listener(ros::Duration(2.0) , false); 00184 //tf::TransformListener listener; 00185 tf::StampedTransform plane_pose_frame(plane_trans, 00186 plane_limits.header.stamp, 00187 plane_limits.header.frame_id, 00188 "plane_frame"); 00189 listener.setTransform(plane_pose_frame); 00190 std::string error_msg; 00191 00192 if (!listener.canTransform("plane_frame", plane_limits.header.frame_id, 00193 plane_limits.header.stamp, &error_msg)) 00194 { 00195 ROS_ERROR("Cannot transform point cloud from frame %s to plane frame; error %s", 00196 plane_limits.header.frame_id.c_str(), error_msg.c_str()); 00197 return false; 00198 } 00199 try 00200 { 00201 listener.transformPointCloud("plane_frame", plane_limits, plane_limits); 00202 } 00203 catch (tf::TransformException ex) 00204 { 00205 ROS_ERROR("Failed to transform point cloud from frame %s into plane_frame; error %s", 00206 plane_limits.header.frame_id.c_str(), ex.what()); 00207 return false; 00208 } 00209 plane_limits.header.frame_id = "plane_frame"; 00210 return true; 00211 } 00212 00213 00214 Plane 00215 PlaneTransform::constructPlaneMsg(const sensor_msgs::PointCloud &plane_limits, 00216 const std::vector<double> &coeffs, 00217 //const pcl::ModelCoefficients &coeffs, 00218 const tf::Transform &plane_trans) 00219 { 00220 00221 Plane plane; 00222 00223 ROS_ASSERT(coeffs.size() > 3); 00224 double a = coeffs[0], b = coeffs[1], 00225 c = coeffs[2]; 00226 00227 plane.normal.header = plane_limits.header; 00228 plane.normal.vector.x = a; 00229 plane.normal.vector.y = b; 00230 plane.normal.vector.z = c; 00231 00232 00233 geometry_msgs::Pose plane_pose; 00234 tf::poseTFToMsg(plane_trans, plane_pose); 00235 00236 plane.top_left = plane_limits.points[0]; 00237 plane.top_right = plane_limits.points[1]; 00238 plane.bottom_left = plane_limits.points[3]; 00239 plane.bottom_right = plane_limits.points[2]; 00240 00241 00242 ROS_DEBUG("Plane Pose: [%f %f %f] [%f %f %f %f] ", 00243 plane_pose.position.x, plane_pose.position.y, 00244 plane_pose.position.z, 00245 plane_pose.orientation.x, plane_pose.orientation.y, 00246 plane_pose.orientation.z, 00247 plane_pose.orientation.w); 00248 00249 plane.pose.pose = plane_pose; 00250 plane.pose.header = plane_limits.header; 00251 00252 return plane; 00253 } 00254 00255 void PlaneTransform::get3DTableLimits(sensor_msgs::PointCloud &plane_limits) 00256 { 00257 Point p; 00258 get3DPlanePoint(min_x_, min_y_, p); 00259 plane_limits.points[0] = p; 00260 00261 get3DPlanePoint(max_x_, min_y_, p); 00262 plane_limits.points[1] = p; 00263 00264 get3DPlanePoint(max_x_, max_y_, p); 00265 plane_limits.points[2] = p; 00266 00267 get3DPlanePoint(min_x_, max_y_, p); 00268 plane_limits.points[3] = p; 00269 } 00270 00271 void PlaneTransform::get3DPlanePoint( int u, int v, 00272 Point &p) 00273 { 00274 float disp = alpha_*u + beta_*v + d_; 00275 00276 float fx = camera_info_.P[0*4+0]; 00277 float fy = camera_info_.P[1*4+1]; 00278 float cx = camera_info_.P[0*4+2]; 00279 float cy = camera_info_.P[1*4+2]; 00280 00281 p.z = (fx * baseline_) / disp; 00282 p.x = (u - cx) * p.z / fx; 00283 p.y = (v - cy) * p.z / fy; 00284 } 00285 00286 } // fast_plane_detection 00287