v4r_laser_filter_utils.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002  * Copyright (c) 2014 Markus Bader <markus.bader@tuwien.ac.at>
00003  * All rights reserved.
00004  * 
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions are met:
00007  * 1. Redistributions of source code must retain the above copyright
00008  *    notice, this list of conditions and the following disclaimer.
00009  * 2. Redistributions in binary form must reproduce the above copyright
00010  *    notice, this list of conditions and the following disclaimer in the
00011  *    documentation and/or other materials provided with the distribution.
00012  * 3. All advertising materials mentioning features or use of this software
00013  *    must display the following acknowledgement:
00014  *    This product includes software developed by the TU-Wien.
00015  * 4. Neither the name of the TU-Wien nor the
00016  *    names of its contributors may be used to endorse or promote products
00017  *    derived from this software without specific prior written permission.
00018  * 
00019  * THIS SOFTWARE IS PROVIDED BY Markus Bader ''AS IS'' AND ANY
00020  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00021  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00022  * DISCLAIMED. IN NO EVENT SHALL Markus Bader BE LIABLE FOR ANY
00023  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00024  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00025  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00026  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00027  * (INCLUDING 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  ***************************************************************************/
00030 
00031 #include "v4r_laser_filter/v4r_laser_filter_utils.h"
00032 
00033 #include <fstream>
00034 #include <boost/foreach.hpp>
00035 using namespace LaserFilter;
00036 
00037 // Start Pose ---------------------------------------------
00038 
00039 Pose::Pose() {};
00040 Pose::Pose(float _x, float _y, float _angle): cv::Vec3f(_x, _y, _angle) {};
00041 void Pose::set( float _x, float _y, float _angle) {
00042     val[0] = _x, val[1] = _y, val[2] = _angle;
00043 }
00044 const cv::Point2f& Pose::point() const {
00045     return *((cv::Point2f*) val);
00046 }
00047 cv::Point2f& Pose::point() {
00048     return *((cv::Point2f*) val);
00049 }
00050 const float& Pose::x() const {
00051     return val[0];
00052 };
00053 float& Pose::x() {
00054     return val[0];;
00055 };
00056 const float& Pose::y() const {
00057     return val[1];
00058 };
00059 float& Pose::y() {
00060     return val[1];;
00061 };
00062 const float& Pose::angle() const {
00063     return val[2];
00064 };
00065 float& Pose::angle() {
00066     return val[2];
00067 };
00068 void Pose::normalizeAngle() {
00069     while(val[2] >  M_PI) val[2] -= 2*M_PI;
00070     while(val[2] < -M_PI) val[2] += 2*M_PI;
00071 }
00072 
00073 //  End Pose ---------------------------------------------
00074 
00075 //  Start Beam ---------------------------------------------
00076 Beam::Beam() {};
00077 void Beam::set(float _alpha, float _range) {
00078     alpha = _alpha, range = _range;
00079 }
00080 //  End Beam ---------------------------------------------
00081 
00082 
00083 //  Start LineEq ---------------------------------------------
00084 LineEq::LineEq() {};
00085 
00086 LineEq::LineEq(const cv::Vec3f& l)
00087     :cv::Vec3f(l) {};
00088 
00089 LineEq::LineEq(float _a, float _b, float _c)
00090     : cv::Vec3f(_a, _b, _c) {};
00091 
00092 void LineEq::set(const cv::Point2f &p0, const cv::Point2f &p1) {
00093     val[0] = +(p0.y *   1. - 1.   * p1.y);
00094     val[1] = -(p0.x *   1. - 1.   * p1.x);
00095     val[2] = +(p0.x * p1.y - p0.y * p1.x);
00096     float r = sqrt( val[0]* val[0]+ val[1]* val[1]);
00097     val[0] =  val[0] / r,  val[1] =  val[1] / r,  val[2] =  val[2] / r;
00098 }
00099 float LineEq::distance(const cv::Point2f &p) const {
00100     return LaserFilter::dot(*this, p);
00101 }
00102 //  End LineEq ---------------------------------------------
00103 
00104 
00105 //  Start Line ---------------------------------------------
00106 
00107 Line::Line()
00108     :LineEq() {};
00109 Line::Line(const cv::Vec3f& l)
00110     :LineEq(l) {};
00111 Line::Line(const Line& l)
00112     :LineEq(l), p0(l.p0), p1(l.p1) {};
00113 Line::Line(const cv::Point2f &_p0, const cv::Point2f &_p1) {
00114     set(_p0,_p1);
00115 };
00116 void Line::set(const cv::Point2f &_p0, const cv::Point2f &_p1) {
00117     p0 = _p0, p1 = _p1;
00118     computeEquation();
00119 }
00120 void Line::computeEquation() {
00121     LineEq::set(p0, p1);
00122 }
00123 float Line::angle() const {
00124     cv::Vec2f v = vector();
00125     return atan2(v[1], v[0]);
00126 }
00127 float Line::angleDiff(const Line &l) const {
00128     float a0 = this->angle();
00129     float a1 = l.angle();
00130     float angle_between_lines = atan2(sin(a1 - a0), cos(a1 - a0));
00131     return angle_between_lines;
00132 }
00133 float Line::length() const {
00134     return norm(vector());
00135 }
00136 cv::Vec2f Line::vector() const {
00137     return cv::Vec2f(p1.x-p0.x, p1.y-p0.y);
00138 }
00139 //  End Line ---------------------------------------------
00140 
00141 //  Start LineSegment ---------------------------------------------
00142 
00143 LineSegment::LineSegment()
00144     :Line(), id(0), idx(0,0) {}
00145 LineSegment::LineSegment(const cv::Vec3f& l)
00146     : Line(l), id(0), idx(0,0) {}
00147 LineSegment::LineSegment(const Line& l)
00148     : Line(l), id(0), idx(0,0) {}
00149 LineSegment::LineSegment(const LineSegment& l)
00150     : Line(l), id(l.id), idx(l.idx) {}
00151 LineSegment::LineSegment(unsigned int idx0, unsigned int idx1,  const std::vector<Measurment> &measurments)
00152     : Line(measurments[idx0], measurments[idx1]), id(0), idx(idx0,idx1) {}
00153 
00154 bool LineSegment::isSupportPoint(int i) {
00155     if( (i < idx.first) || (i > idx.second)) {
00156         return false;
00157     } else {
00158         return true;
00159     }
00160 }
00161 unsigned int LineSegment::nrSupportPoint() {
00162     return idx.second - idx.first + 1;
00163 }
00164 void LineSegment::set(unsigned int _idx0, unsigned int _idx1, const std::vector<Measurment> &measurments) {
00165     idx.first = _idx0, idx.second = _idx1;
00166     Line::set(measurments[idx.first], measurments[idx.second]);
00167 }
00168 
00169 void LineSegment::updateLineStatistic(const std::vector<Measurment> &measurments) {
00170     float sum_mean = 0, sum_var = 0;
00171     for(unsigned int i = idx.first; i <= idx.second; i++) {
00172         float d = this->distance(measurments[i]);
00173         sum_mean += d;
00174         sum_var += d*d;
00175     }
00176     distances_mean = sum_mean / nrSupportPoint();
00177     distances_variance = sum_var / nrSupportPoint();
00178     distances_error = sqrt(distances_variance) / length();
00179 }
00180 
00181 
00182 void LineSegment::estimator_theilsen(const std::vector<Measurment> &measurments, Line &line) {
00183     // http://en.wikipedia.org/wiki/Theil%E2%80%93Sen_estimator
00184     unsigned nrOfPoints = nrSupportPoint();
00185     if(nrSupportPoint() <= 3) return;
00186     float slopeYX, slopeXY, offset;
00187     std::vector<float> slopsXY, slopsYX, offsets;
00188     slopsYX.reserve(nrOfPoints);
00189     slopsXY.reserve(nrOfPoints);
00190     for(unsigned int i = idx.first; i <= idx.second; i++) {
00191         for(unsigned int j = i; j <= idx.second; j++) {
00192             if(i == j) continue;
00193             const cv::Point2f &pi = measurments[i];
00194             const cv::Point2f &pj = measurments[j];
00195             float dx = pi.x-pj.x;
00196             float dy = pi.y-pj.y;
00197             if(fabs(dx) > FLT_MIN) {
00198                 float s = dy/dx;
00199                 slopsYX.push_back(s);
00200             }
00201             if(fabs(dy) > FLT_MIN) {
00202                 float s = dx/dy;
00203                 slopsXY.push_back(s);
00204             }
00205         }
00206     }
00207     std::sort(slopsYX.begin(), slopsYX.end());
00208     slopeYX = slopsYX[ (slopsYX.size() % 2?slopsYX.size() / 2:slopsYX.size()/2 - 1) ];
00209     std::sort(slopsXY.begin(), slopsXY.end());
00210     slopeXY = slopsXY[ (slopsXY.size() % 2?slopsXY.size() / 2:slopsXY.size()/2 - 1) ];
00211 
00212     offsets.reserve(nrOfPoints);
00213     if(fabs(slopeYX) < 1.0) {
00214 
00215         for(unsigned int i = idx.first; i <= idx.second; i++) {
00216             const cv::Point2f &p = measurments[i];
00217             offsets.push_back(p.y - slopeYX*p.x);
00218         }
00219 
00220         std::sort(offsets.begin(), offsets.end());
00221         offset = offsets[offsets.size()/2];
00222         if ((offsets.size() % 2) == 0) {
00223             offset = (offset + offsets[offsets.size()/2 - 1]) / 2.;
00224         } else {
00225 
00226         }
00227         line.p0.x = measurments[idx.first].x;
00228         line.p1.x = measurments[idx.second].x;
00229         line.p0.y = slopeYX * line.p0.x + offset;
00230         line.p1.y = slopeYX * line.p1.x + offset;
00231         line.computeEquation();
00232     } else {
00233         for(unsigned int i = idx.first; i <= idx.second; i++) {
00234             const cv::Point2f &p = measurments[i];
00235             offsets.push_back(p.x - slopeXY*p.y);
00236         }
00237 
00238         std::sort(offsets.begin(), offsets.end());
00239         offset = offsets[offsets.size()/2];
00240         if ((offsets.size() % 2) == 0) {
00241             offset = (offset + offsets[offsets.size()/2 - 1]) / 2.;
00242         } else {
00243 
00244         }
00245         line.p0.y = measurments[idx.first].y;
00246         line.p1.y = measurments[idx.second].y;
00247         line.p0.x = slopeXY * line.p0.y + offset;
00248         line.p1.x = slopeXY * line.p1.y + offset;
00249         line.computeEquation();
00250     }
00251 }
00252 //  End LineSegment ---------------------------------------------
00253 
00254 
00255 //  Start Measurment ---------------------------------------------
00256 
00257 void Measurment::set(float _alpha, float _range) {
00258     nan = isnan(_range), inf = isinf(_range);
00259     if(nan || inf) {
00260         valid = false;
00261     } else {
00262         x = cos(_alpha) * _range;
00263         y = sin(_alpha) * _range;
00264         valid = true;
00265     }
00266 }
00267 //  End Measurment ---------------------------------------------
00268 
00269 //  Start Corner ---------------------------------------------
00270 
00271 Corner::Corner() 
00272 : error(FLT_MAX) {};
00273 
00274 Corner::Corner(const Corner &c)
00275 : Pose(c), error(c.error), l0(c.l0), l1(c.l1)  {};
00276 
00277 void Corner::set(const LineSegment &_l0, const LineSegment &_l1) {
00278     l0 = _l0, l1 = _l1;
00279     intersection(l0, l1, point());
00280     float angle_between_lines = l0.angleDiff(l1);
00281     this->angle() = l0.angle() - angle_between_lines / 2;
00282     normalizeAngle();
00283 }
00284 
00285 bool Corner::isCorner(float threshold_angle, float max_line_diff) {
00286     bool result = false;
00287     float line_diff;
00288     float angle_between_lines = l0.angleDiff(l1);    
00289     if(fabs(fabs(angle_between_lines) - M_PI/2) < threshold_angle) {
00290         intersection(l0, l1, point());
00291         float n1 = l0.length();
00292         float n2 = l1.length();
00293         line_diff = ( n1>n2 ? n1/n2 : n2/n1);
00294         if(line_diff < max_line_diff) {
00295             result = true;
00296         }
00297     }
00298     return result;
00299 }
00300 
00301 void Corner::redefine(const std::vector<Measurment> &measurments) {
00302     l0.estimator_theilsen(measurments, l0);
00303     l1.estimator_theilsen(measurments, l1);
00304     set(l0, l1);
00305 }
00306 float Corner::updateError(const std::vector<Measurment> &measurments){
00307   l0.updateLineStatistic(measurments);
00308   l1.updateLineStatistic(measurments);
00309   error = sqrt(l0.distances_error*l0.distances_error + l1.distances_error*l1.distances_error);
00310   return error;
00311 }
00312 
00313 //  End Corner ---------------------------------------------
00314 
00315 
00316 //  Start General Functions ---------------------------------------------
00317 
00318 void LaserFilter::copy(const sensor_msgs::LaserScan& _msg, std::vector<Measurment> &_desMeasurments, std::vector<Beam> &_desBeams) {
00319     unsigned int nrOfRanges = _msg.ranges.size();
00320     _desMeasurments.resize(nrOfRanges);
00321     _desBeams.resize(nrOfRanges);
00322     float angle_increment_ = _msg.angle_increment;
00323     float angle_increment_sin_ = sin(angle_increment_);
00324     for (int i = 0; i < nrOfRanges; i++) {
00325         const float &range = _msg.ranges[i];
00326         float alpha = _msg.angle_min + (_msg.angle_increment * i);
00327         _desBeams[i].set(alpha, range);
00328         _desMeasurments[i].set(alpha, range);
00329     }
00330 }
00331 
00332 void LaserFilter::intersection(const cv::Vec3f &l1, const cv::Vec3f &l2, cv::Point2f &p) {
00333     cv::Vec3f c = l1.cross(l2);
00334     p.x = c[0] / c[2], p.y = c[1] / c[2];
00335 }
00336 float LaserFilter::dot(const cv::Vec3f &l1, const cv::Point2f &p) {
00337     return l1[0]*p.x+ l1[1]*p.y+ l1[2];
00338 }
00339 
00340 void LaserFilter::readScan(const std::string &filename, sensor_msgs::LaserScan &msg ) {
00341 
00342     std::ifstream ifs(filename.c_str(), std::ios::in|std::ios::binary);
00343     ifs.seekg (0, std::ios::end);
00344     std::streampos end = ifs.tellg();
00345     ifs.seekg (0, std::ios::beg);
00346     std::streampos begin = ifs.tellg();
00347 
00348     uint32_t file_size = end-begin;
00349     boost::shared_array<uint8_t> ibuffer(new uint8_t[file_size]);
00350     ifs.read((char*) ibuffer.get(), file_size);
00351     ros::serialization::IStream istream(ibuffer.get(), file_size);
00352     ros::serialization::deserialize(istream, msg);
00353     ifs.close();
00354 }
00355 void LaserFilter::writeScan(const std::string &filename, const sensor_msgs::LaserScan &msg ) {
00356     std::ofstream ofs(filename.c_str(), std::ios::out|std::ios::binary);
00357 
00358     uint32_t serial_size = ros::serialization::serializationLength(msg);
00359     boost::shared_array<uint8_t> obuffer(new uint8_t[serial_size]);
00360 
00361     ros::serialization::OStream ostream(obuffer.get(), serial_size);
00362     ros::serialization::serialize(ostream, msg);
00363     ofs.write((char*) obuffer.get(), serial_size);
00364     ofs.close();
00365 }


v4r_laser_filter
Author(s):
autogenerated on Wed Aug 26 2015 16:41:46