kinect_filtering.cpp
Go to the documentation of this file.
00001 
00002 /*
00003  * Copyright (c) 2008, Willow Garage, Inc.
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 met:
00008  *
00009  *     * Redistributions of source code must retain the above copyright
00010  *       notice, this list of conditions and the following disclaimer.
00011  *     * 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  *     * Neither the name of the Willow Garage, Inc. nor the names of its
00015  *       contributors may be used to endorse or promote products derived from
00016  *       this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028  * POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  */
00031 
00040 #include <ros/ros.h>
00041 #include <ar_track_alvar/kinect_filtering.h>
00042 #include <tf/transform_datatypes.h>
00043 #include <Eigen/Core>
00044 
00045 namespace ar_track_alvar
00046 {
00047 
00048   namespace gm=geometry_msgs;
00049 
00050   using std::vector;
00051   using std::cerr;
00052   using std::endl;
00053   using std::ostream;
00054 
00055   // Distance threshold for plane fitting: how far are points
00056   // allowed to be off the plane?
00057   const double distance_threshold_ = 0.005;
00058 
00059   PlaneFitResult fitPlane (ARCloud::ConstPtr cloud)
00060   {
00061     PlaneFitResult res;
00062     pcl::PointIndices::Ptr inliers=boost::make_shared<pcl::PointIndices>();
00063 
00064     pcl::SACSegmentation<ARPoint> seg;
00065     seg.setOptimizeCoefficients(true);
00066     seg.setModelType(pcl::SACMODEL_PLANE);
00067     seg.setMethodType(pcl::SAC_RANSAC);
00068     seg.setDistanceThreshold(distance_threshold_);
00069 
00070     seg.setInputCloud(cloud);
00071     seg.segment(*inliers, res.coeffs);
00072 
00073     pcl::ExtractIndices<ARPoint> extracter;
00074     extracter.setInputCloud(cloud);
00075     extracter.setIndices(inliers);
00076     extracter.setNegative(false);
00077     extracter.filter(*res.inliers);
00078   
00079     return res;
00080   }
00081 
00082   ARCloud::Ptr filterCloud (const ARCloud& cloud, const vector<cv::Point>& pixels)
00083   {
00084     ARCloud::Ptr out(new ARCloud());
00085     //ROS_INFO("  Filtering %zu pixels", pixels.size());
00086     //for (const cv::Point& p : pixels)
00087     for(size_t i=0; i<pixels.size(); i++)
00088       {
00089         const cv::Point& p = pixels[i];
00090         const ARPoint& pt = cloud(p.x, p.y);
00091         if (isnan(pt.x) || isnan(pt.y) || isnan(pt.z)){
00092           //ROS_INFO("    Skipping (%.4f, %.4f, %.4f)", pt.x, pt.y, pt.z);
00093         }
00094         else
00095           out->points.push_back(pt);
00096       }
00097     return out;
00098   }
00099 
00100   gm::Point centroid (const ARCloud& points)
00101   {
00102     gm::Point sum;
00103     sum.x = 0;
00104     sum.y = 0;
00105     sum.z = 0;
00106     //for (const Point& p : points)
00107     for(size_t i=0; i<points.size(); i++)
00108       {
00109         sum.x += points[i].x;
00110         sum.y += points[i].y;
00111         sum.z += points[i].z;
00112       }
00113   
00114     gm::Point center;
00115     const size_t n = points.size();
00116     center.x = sum.x/n;
00117     center.y = sum.y/n;
00118     center.z = sum.z/n;
00119     return center;
00120   }
00121 
00122   // Helper function to construct a geometry_msgs::Quaternion
00123   inline
00124   gm::Quaternion makeQuaternion (double x, double y, double z, double w)
00125   {
00126     gm::Quaternion q;
00127     q.x = x;
00128     q.y = y;
00129     q.z = z;
00130     q.w = w;
00131     return q;
00132   }
00133 
00134   // Extract and normalize plane coefficients
00135   int getCoeffs (const pcl::ModelCoefficients& coeffs, double* a, double* b,
00136                  double* c, double* d)
00137   {
00138     if(coeffs.values.size() != 4)
00139       return -1;
00140     const double s = coeffs.values[0]*coeffs.values[0] +
00141       coeffs.values[1]*coeffs.values[1] + coeffs.values[2]*coeffs.values[2];
00142     if(fabs(s) < 1e-6)
00143       return -1;
00144     *a = coeffs.values[0]/s;
00145     *b = coeffs.values[1]/s;
00146     *c = coeffs.values[2]/s;
00147     *d = coeffs.values[3]/s;
00148     return 0;
00149   }
00150 
00151   // Project point onto plane
00152   btVector3 project (const ARPoint& p, const double a, const double b,
00153                      const double c, const double d)
00154   {
00155     const double t = a*p.x + b*p.y + c*p.z + d;
00156     return btVector3(p.x-t*a, p.y-t*b, p.z-t*c);
00157   }
00158 
00159   ostream& operator<< (ostream& str, const btMatrix3x3& m)
00160   {
00161     str << "[" << m[0][0] << ", " << m[0][1] << ", " << m[0][2] << "; "
00162         << m[1][0] << ", " << m[1][1] << ", " << m[1][2] << "; "
00163         << m[2][0] << ", " << m[2][1] << ", " << m[2][2] << "]";
00164     return str;
00165   }
00166 
00167   ostream& operator<< (ostream& str, const btQuaternion& q)
00168   {
00169     str << "[(" << q.x() << ", " << q.y() << ", " << q.z() <<
00170       "), " << q.w() << "]";
00171     return str;
00172   }
00173 
00174   ostream& operator<< (ostream& str, const btVector3& v)
00175   {
00176     str << "(" << v.x() << ", " << v.y() << ", " << v.z() << ")";
00177     return str;
00178   }
00179 
00180   int extractFrame (const pcl::ModelCoefficients& coeffs,
00181                     const ARPoint& p1, const ARPoint& p2,
00182                     const ARPoint& p3, const ARPoint& p4,
00183                     btMatrix3x3 &retmat)
00184   {
00185     // Get plane coeffs and project points onto the plane
00186     double a=0, b=0, c=0, d=0;
00187     if(getCoeffs(coeffs, &a, &b, &c, &d) < 0)
00188       return -1;
00189   
00190     const btVector3 q1 = project(p1, a, b, c, d);
00191     const btVector3 q2 = project(p2, a, b, c, d);
00192     const btVector3 q3 = project(p3, a, b, c, d);
00193     const btVector3 q4 = project(p4, a, b, c, d);
00194   
00195     // Make sure points aren't the same so things are well-defined
00196     if((q2-q1).length() < 1e-3)
00197       return -1;
00198   
00199     // (inverse) matrix with the given properties
00200     const btVector3 v = (q2-q1).normalized();
00201     const btVector3 n(a, b, c);
00202     const btVector3 w = -v.cross(n); 
00203     btMatrix3x3 m(v[0], v[1], v[2], w[0], w[1], w[2], n[0], n[1], n[2]);
00204   
00205     // Possibly flip things based on third point
00206     const btVector3 diff = (q4-q3).normalized();
00207     //ROS_INFO_STREAM("w = " << w << " and d = " << diff);
00208     if (w.dot(diff)<0)
00209       {
00210         //ROS_INFO_STREAM("Flipping normal based on p3.  Current value: " << m);
00211         m[1] = -m[1];
00212         m[2] = -m[2];
00213         //ROS_INFO_STREAM("New value: " << m);
00214       }
00215 
00216     // Invert and return
00217     retmat = m.inverse();
00218     //cerr << "Frame is " << retmat << endl;
00219     return 0;
00220   }
00221 
00222 
00223   int getQuaternion (const btMatrix3x3& m, btQuaternion &retQ)
00224   {
00225     if(m.determinant() <= 0)
00226       return -1;
00227     
00228     //btScalar y=0, p=0, r=0;
00229     //m.getEulerZYX(y, p, r);
00230     //retQ.setEulerZYX(y, p, r);
00231 
00232     //Use Eigen for this part instead, because the ROS version of bullet appears to have a bug
00233     Eigen::Matrix3f eig_m;
00234     for(int i=0; i<3; i++){
00235         for(int j=0; j<3; j++){
00236             eig_m(i,j) = m[i][j];
00237         }
00238     }
00239     Eigen::Quaternion<float> eig_quat(eig_m);
00240     
00241     // Translate back to bullet
00242     btScalar ex = eig_quat.x();
00243     btScalar ey = eig_quat.y();
00244     btScalar ez = eig_quat.z();
00245     btScalar ew = eig_quat.w();
00246     btQuaternion quat(ex,ey,ez,ew);
00247     retQ = quat.normalized();
00248     
00249     return 0;
00250   }
00251 
00252 
00253   int extractOrientation (const pcl::ModelCoefficients& coeffs,
00254                           const ARPoint& p1, const ARPoint& p2,
00255                           const ARPoint& p3, const ARPoint& p4,
00256                           gm::Quaternion &retQ)
00257   {
00258     btMatrix3x3 m;
00259     if(extractFrame(coeffs, p1, p2, p3, p4, m) < 0)
00260       return -1;
00261     btQuaternion q;
00262     if(getQuaternion(m,q) < 0)
00263       return -1;
00264     tf::quaternionTFToMsg(q, retQ);
00265     return 0;
00266   }
00267 
00268 } // namespace


ar_track_alvar
Author(s): Scott Niekum
autogenerated on Sun Oct 5 2014 22:16:26