v4r_laser_line_filter_node.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 #include "v4r_laser_filter/v4r_laser_line_filter_node.h"
00031 
00032 #include <fstream>
00033 
00034 using namespace LaserFilter;
00035 
00036 int main(int argc, char **argv) {
00037 
00038     ros::init(argc, argv, "LineFilter");
00039     ros::NodeHandle n;
00040     LaserLineFilterNode my_node(n);
00041     ros::spin();
00042     return 0;
00043 }
00044 
00045 LaserLineFilterNode::LaserLineFilterNode ( ros::NodeHandle &n )
00046     :n_ ( n ), n_param_ ( "~" ) {
00047     sub_ = n_.subscribe("scan", 1000, &LaserLineFilterNode::callback, this);
00048     pub_laser_line_split_ = n_.advertise<sensor_msgs::LaserScan>("scan_lines_split", 1000);
00049     pub_laser_line_fit_ = n_.advertise<sensor_msgs::LaserScan>("scan_lines_fit", 1000);
00050     pub_laser_input_ = n_.advertise<sensor_msgs::LaserScan>("scan_input", 1000);
00051     pub_marker_ =  n.advertise<visualization_msgs::Marker>("visualization_marker", 1000);
00052     pub_laser_lines_ = n_.advertise<geometry_msgs::PolygonStamped>("line_segments", 1000);
00053 
00054     double tmp;
00055 
00056     n_param_.param<bool>("publish_marker", param_.publish_marker, V4R_LASER_LINE_FILTER_PUBLISH_MARKER);
00057     ROS_INFO("%s: publish_marker: %s", n_param_.getNamespace().c_str(), ((param_.publish_marker) ? "true" : "false"));
00058 
00059     n_param_.param<bool>("publish_lines", param_.publish_lines, V4R_LASER_LINE_FILTER_PUBLISH_LINES);
00060     ROS_INFO("%s: publish_lines: %s", n_param_.getNamespace().c_str(), ((param_.publish_lines) ? "true" : "false"));
00061 
00062     n_param_.param<bool>("fit_lines", param_.fit_lines, V4R_LASER_LINE_FILTER_FIT_LINES);
00063     ROS_INFO("%s: fit_lines: %s", n_param_.getNamespace().c_str(), ((param_.fit_lines) ? "true" : "false"));
00064 
00065     n_param_.param<bool>("split_scan", param_.split_scan, V4R_LASER_LINE_FILTER_SPLIT_SCAN);
00066     ROS_INFO("%s: split_scan: %s", n_param_.getNamespace().c_str(), ((param_.split_scan) ? "true" : "false"));
00067 
00068 
00069     n_param_.getParam("read_scan", param_.read_scan);
00070     ROS_INFO("%s: read_scan: %s", n_param_.getNamespace().c_str(), ((param_.read_scan) ? "true" : "false"));
00071     n_param_.getParam("write_scan", param_.write_scan);
00072     ROS_INFO("%s: write_scan: %s", n_param_.getNamespace().c_str(), ((param_.write_scan) ? "true" : "false"));
00073     n_param_.getParam("scan_filename", param_.scan_filename);
00074     ROS_INFO("%s: scan_filename: %s", n_param_.getNamespace().c_str(), param_.scan_filename.c_str());
00075 
00076     n_param_.param<double>("threshold_split", tmp, V4R_LASER_LINE_FILTER_THRESHOLD_SPLIT);
00077     param_.threshold_split = tmp;
00078     ROS_INFO("%s: threshold_split: %4.3f", n_param_.getNamespace().c_str(), param_.threshold_split);
00079     n_param_.getParam("threshold_split_neighbor", param_.threshold_split_neighbor);
00080     ROS_INFO("%s: threshold_split_neighbor: %s", n_param_.getNamespace().c_str(), ((param_.threshold_split_neighbor) ? "true" : "false"));
00081 
00082     n_param_.param<double>("min_length", tmp, V4R_LASER_LINE_FILTER_MIN_LENGTH);
00083     param_.min_length = tmp;
00084     ROS_INFO("%s: min_length: %4.3f", n_param_.getNamespace().c_str(), param_.min_length);
00085 
00086     n_param_.param<int>("min_points_per_line",  param_.min_points_per_line, V4R_LASER_LINE_FILTER_MIN_POINTS_PER_LINE);
00087     ROS_INFO("%s: min_points_per_line: %i", n_param_.getNamespace().c_str(), param_.min_points_per_line);
00088 
00089     n_param_.param<double>("min_points_per_meter",  tmp, V4R_LASER_LINE_FILTER_MIN_POINTS_PER_METER);
00090     param_.min_points_per_meter = tmp;
00091     ROS_INFO("%s: min_points_per_meter: %4.3f", n_param_.getNamespace().c_str(), param_.min_points_per_meter);
00092 
00093 
00094 
00095     reconfigureFnc_ = boost::bind(&LaserLineFilterNode::callbackParameters, this,  _1, _2);
00096     reconfigureServer_.setCallback(reconfigureFnc_);
00097 }
00098 
00099 void LaserLineFilterNode::callbackParameters ( v4r_laser_filter::LineFilterConfig &config, uint32_t level ) {
00100     param_.publish_marker = config.publish_marker;
00101     param_.threshold_split = config.threshold_split;
00102     param_.threshold_split_neighbor = config.threshold_split_neighbor;
00103     param_.min_length = config.min_length;
00104     param_.min_points_per_line = config.min_points;
00105     param_.min_points_per_meter = config.min_points_per_meter;
00106     param_.fit_lines = config.fit_lines;
00107     param_.split_scan = config.split_scan;
00108     param_.write_scan = config.write_scan;
00109     param_.read_scan = config.read_scan;
00110 }
00111 
00112 void LaserLineFilterNode::callback (const sensor_msgs::LaserScan::ConstPtr& _msg) {
00113 
00114     if(param_.write_scan) LaserFilter::writeScan(param_.scan_filename, *_msg);
00115     if(param_.read_scan)  LaserFilter::readScan(param_.scan_filename, msg_scan_);
00116     else msg_scan_ = *_msg;
00117 
00118     if(pub_laser_input_.getNumSubscribers() > 0) {
00119         pub_laser_input_.publish(msg_scan_);
00120     }
00121 
00122     LaserFilter::copy(msg_scan_, measurments_, beams_);
00123 
00124     splitStart();
00125     sensor_msgs::LaserScan msg = msg_scan_;
00126     if(param_.split_scan) {
00127         for (int i = 0; i < msg_scan_.ranges.size(); i++) msg.ranges[i] = nanf("");
00128 
00129         for(unsigned int i = 0; i < lineSegments_.size(); i++) {
00130             for(unsigned int idx = lineSegments_[i].idx.first; idx < lineSegments_[i].idx.second; idx++) {
00131                 msg.ranges[idx] = msg_scan_.ranges[idx];
00132             }
00133         }
00134     }
00135     pub_laser_line_split_.publish(msg);
00136 
00137 
00138     if(param_.fit_lines) {
00139         lineFitStart();
00140     }
00141 
00142     if(param_.publish_marker) {
00143         publish_marker();
00144     }
00145     
00146     if(param_.publish_lines){
00147       msg_lines.header = msg.header;
00148       msg_lines.polygon.points.clear();
00149       msg_lines.polygon.points.reserve(lineSegments_.size()*2);
00150       geometry_msgs::Point32 p0, p1;
00151       for(unsigned int i = 0; i < lineSegments_.size(); i++) {
00152           p0.x = lineSegments_[i].p0.x, p0.y = lineSegments_[i].p0.y, p0.z = 0;
00153           p1.x = lineSegments_[i].p1.x, p1.y = lineSegments_[i].p1.y, p0.z = 0;
00154           msg_lines.polygon.points.push_back(p0);
00155           msg_lines.polygon.points.push_back(p1);
00156       }    
00157       pub_laser_lines_.publish(msg_lines);
00158     }
00159 }
00160 
00161 void LaserLineFilterNode::publish_marker () {
00162     msg_line_list_.header = msg_scan_.header;
00163     msg_line_list_.ns = "lines";
00164     msg_line_list_.action = visualization_msgs::Marker::ADD;
00165     msg_line_list_.pose.orientation.w = 1.0;
00166     msg_line_list_.id = 0;
00167     msg_line_list_.type = visualization_msgs::Marker::LINE_LIST;
00168     msg_line_list_.scale.x = 0.01;
00169     msg_line_list_.color.r = 1.0;
00170     msg_line_list_.color.g = 0.0;
00171     msg_line_list_.color.b = 0.0;
00172     msg_line_list_.color.a = 1.0;
00173     geometry_msgs::Point p0, p1;
00174     msg_line_list_.points.clear();
00175     for(unsigned int i = 0; i < lineSegments_.size(); i++) {
00176         p0.x = lineSegments_[i].p0.x, p0.y = lineSegments_[i].p0.y;
00177         p1.x = lineSegments_[i].p1.x, p1.y = lineSegments_[i].p1.y;
00178         msg_line_list_.points.push_back(p0);
00179         msg_line_list_.points.push_back(p1);
00180     }
00181     pub_marker_.publish(msg_line_list_);
00182 }
00183 
00184 void LaserLineFilterNode::lineFitStart() {
00185 
00186     std::vector<cv::Point2f> points;
00187     lines_.resize(lineSegments_.size());
00188     for(unsigned int i = 0; i < lineSegments_.size(); i++) {
00189         lineSegments_[i].estimator_theilsen(measurments_, lineSegments_[i]);
00190         lines_[i].set(lineSegments_[i].p0,lineSegments_[i].p1);
00191     }
00192 }
00193 
00194 void LaserLineFilterNode::splitStart() {
00195     connectedMeasurments_.clear();
00196     lineSegments_.clear();
00197 
00198     if(measurments_.size() > 0) {
00199 
00200         std::pair< unsigned int, unsigned int> idx;
00201         idx.first = 0;
00202 
00203         while(idx.first < measurments_.size()) {
00204             idx.second = idx.first + 1;
00205             float threshold = 4 * cv::norm(measurments_[idx.second] - measurments_[idx.second+1]);
00206             while((idx.second < measurments_.size()) && (measurments_[idx.second].valid)) {
00207                 if(param_.threshold_split_neighbor) {       
00208                     float d = cv::norm(measurments_[idx.second] - measurments_[idx.second+1]);
00209                     if(d > threshold) {
00210                         break;
00211                     }
00212                     threshold = 4 * d;
00213                 }
00214                 idx.second++;
00215             }
00216             if((idx.second - idx.first) > 2) {
00217                 connectedMeasurments_.push_back(idx);
00218             }
00219             idx.first = idx.second+1;
00220         }
00221 
00222         for(unsigned int i = 0; i < connectedMeasurments_.size(); i++) {
00223             unsigned int idx0 = connectedMeasurments_[i].first;
00224             unsigned int idx1 = connectedMeasurments_[i].second;
00225             while((idx0 < connectedMeasurments_[i].second) && (measurments_[idx0].valid == false)) {
00226                 idx0++;
00227             }
00228             while((idx1 > idx0) && (measurments_[idx1].valid == false)) {
00229                 idx1--;
00230             }
00231             if(idx1 > idx0) {
00232                 LineSegment line;
00233                 line.set(idx0, idx1, measurments_);
00234                 split(line);
00235             }
00236         }
00237     }
00238 }
00239 
00240 void LaserLineFilterNode::split(LineSegment &line) {
00241     unsigned int idxMax=line.idx.first;
00242     float d;
00243     float dMax = 0;
00244     for(unsigned int i = line.idx.first; i < line.idx.second; i++) {
00245         d = fabs(line.distance(measurments_[i]));
00246         if(d > dMax) {
00247             dMax = d,  idxMax = i;
00248         }
00249     }
00250     if(dMax > param_.threshold_split) {
00251         LineSegment l0,l1;
00252         if(line.idx.first+param_.min_points_per_line < idxMax) {
00253             l0.set(line.idx.first, idxMax, measurments_);
00254             split(l0);
00255         }
00256         if(idxMax+param_.min_points_per_line < line.idx.second) {
00257             l1.set(idxMax, line.idx.second, measurments_);
00258             split(l1);
00259         }
00260     } else {
00261         if(line.length() < param_.min_length) {
00262             return;
00263         }
00264         if(((float) line.nrSupportPoint()) / line.length() < param_.min_points_per_meter) {
00265             return;
00266         }
00267         if(fabs(line.distance(cv::Point2f(0,0))) < (param_.threshold_split*param_.threshold_split)) {
00268             // line passed the scan center
00269             return;
00270         }
00271         line.id = lineSegments_.size();
00272         lineSegments_.push_back(line);
00273     }
00274 }
00275 


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