Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • labrobotica/algorithms/laser_scan_utils
1 result
Show changes
Commits on Source (3)
File moved
...@@ -91,48 +91,59 @@ void LaserScan::ranges2xy(const LaserScanParams& _scan_params, Eigen::Matrix4s _ ...@@ -91,48 +91,59 @@ void LaserScan::ranges2xy(const LaserScanParams& _scan_params, Eigen::Matrix4s _
for (ii = 0; ii < ranges_raw_.size(); ii++) for (ii = 0; ii < ranges_raw_.size(); ii++)
{ {
//check raw range integrity //check raw range integrity
if ((ranges_raw_[ii] > _scan_params.range_min_) && (ranges_raw_[ii] < _scan_params.range_max_-0.2) && (!std::isnan(ranges_raw_[ii])) && (!std::isinf(ranges_raw_[ii]))) //invalid range
if (!isValidRange(ranges_raw_[ii], _scan_params))
{ {
//set as valid range // fix if it is a single value between two valid values
ranges_[ii] = ranges_raw_[ii]; if (ii > 0 && ii < ranges_raw_.size() && isValidRange(ranges_raw_[ii-1], _scan_params) && isValidRange(ranges_raw_[ii+1], _scan_params))
{
//transform the laser hit from polar to 3D euclidean homogeneous ranges_[ii] = (ranges_raw_[ii-1] + ranges_raw_[ii+1])/2.0;
point_laser << ranges_[ii] * cos(azimuth), ranges_[ii] * sin(azimuth), 0, 1; }
// definitely invalid range
//apply device mounting point calibration (p_r = T * p_l) else
point_ref = _device_T * point_laser; {
ranges_[ii] = -1.;
//set to points_all_ as a 2D homogeneous jumps_mask_[ii] = true;
points_all_.col(ii) << point_ref(0), point_ref(1), 1; points_all_.col(ii) << 0, 0, 0;
//prev_range = 0;
//set to points_ as a 2D homogeneous
points_.col(ii_ok) << point_ref(0), point_ref(1), 1; //increment azimuth with angle step
azimuth += _scan_params.angle_step_;
//check jump. continue;
//Min dist between consecutive points is r*sin(angle_step_). A jump occurs when this min dist is overpassed by kr times }
if (fabs(ranges_[ii] - prev_range) > _jump_th) //jump condition
{
jumps_indexes_.push_back(ii_ok); //indexes over points_
jumps_mask_[ii] = true; //masks over ranges_
}
else
jumps_mask_[ii] = false;
//increment ok counter
ii_ok++;
//keep current range as previous for the next iteration
prev_range = ranges_raw_[ii];
}
else //invalid raw value
{
ranges_[ii] = -1.;
jumps_mask_[ii] = true;
points_all_.col(ii) << 0, 0, 0;
//prev_range = 0;
} }
// valid range
//increment azimuth with angle step ranges_[ii] = ranges_raw_[ii];
//transform the laser hit from polar to 3D euclidean homogeneous
point_laser << ranges_[ii] * cos(azimuth), ranges_[ii] * sin(azimuth), 0, 1;
//apply device mounting point calibration (p_r = T * p_l)
point_ref = _device_T * point_laser;
//set to points_all_ as a 2D homogeneous
points_all_.col(ii) << point_ref(0), point_ref(1), 1;
//set to points_ as a 2D homogeneous
points_.col(ii_ok) << point_ref(0), point_ref(1), 1;
//check jump.
//Min dist between consecutive points is r*sin(angle_step_). A jump occurs when this min dist is overpassed by kr times
if (fabs(ranges_[ii] - prev_range) > _jump_th) //jump condition
{
jumps_indexes_.push_back(ii_ok); //indexes over points_
jumps_mask_[ii] = true; //masks over ranges_
}
else
jumps_mask_[ii] = false;
//increment ok counter
ii_ok++;
//keep current range as previous for the next iteration
prev_range = ranges_raw_[ii];
//increment azimuth with angle step
azimuth += _scan_params.angle_step_; azimuth += _scan_params.angle_step_;
} }
...@@ -172,117 +183,128 @@ void LaserScan::processRaw(const LaserScanParams& _scan_params, bool _compute_pa ...@@ -172,117 +183,128 @@ void LaserScan::processRaw(const LaserScanParams& _scan_params, bool _compute_pa
//for each range, check correctness of value and translate from polar to xy coordinates //for each range, check correctness of value and translate from polar to xy coordinates
for (ii = 0; ii < ranges_raw_.size(); ii++) for (ii = 0; ii < ranges_raw_.size(); ii++)
{ {
//check raw range integrity // prev out of range
if (!std::isnan(ranges_raw_[ii]) && !std::isinf(ranges_raw_[ii])) prev_out_of_range = out_of_range;
{
// fill as valid range //check raw range integrity
ranges_[ii] = ranges_raw_[ii]; if (!isValidRange(ranges_raw_[ii], _scan_params))
{
//transform the laser hit from polar to 3D euclidean homogeneous // fix if it is a single value between two valid values
point_laser << ranges_[ii] * cos(azimuth), ranges_[ii] * sin(azimuth), 0, 1; if (ii > 0 && ii < ranges_raw_.size() && isValidRange(ranges_raw_[ii-1], _scan_params) && isValidRange(ranges_raw_[ii+1], _scan_params))
{
//apply device mounting point calibration (p_r = T * p_l) ranges_[ii] = (ranges_raw_[ii-1] + ranges_raw_[ii+1])/2.0;
point_ref = _device_T * point_laser; out_of_range = false;
}
// out of range // definitely invalid range
prev_out_of_range = out_of_range; else
out_of_range = ranges_raw_[ii] <= _scan_params.range_min_ || ranges_raw_[ii] >= _scan_params.range_max_; {
ranges_[ii] = -1.;
// store in points_all_ as a 2D homogeneous jumps_mask_[ii] = true;
points_all_.col(ii) << point_ref(0), point_ref(1), 1; points_all_.col(ii) << 0, 0, 0;
out_of_range = true;
// store in points_ as a 2D homogeneous if not out of range }
if (!out_of_range) }
points_.col(ii_ok) << point_ref(0), point_ref(1), 1; // valid range
else
{
// OPEN NEW SEGMENT (without closing any) ranges_[ii] = ranges_raw_[ii];
if ( prev_out_of_range && !out_of_range) // valid point after out of range out_of_range = false;
{ }
//std::cout << "OPEN NEW SEGMENT " << std::endl;
assert(open_segment == false && "opening a segment without closing the last one"); // store in points_ as a 2D homogeneous if not out of range
if (!out_of_range)
segment_list_.push_back(ScanSegment()); {
//transform the laser hit from polar to 3D euclidean homogeneous
// first index point_laser << ranges_[ii] * cos(azimuth), ranges_[ii] * sin(azimuth), 0, 1;
segment_list_.back().idx_first_ = ii_ok;
//apply device mounting point calibration (p_r = T * p_l)
// prev point point_ref = _device_T * point_laser;
if (prev_ii == -1)
// no previous points: prev = current // store in points_all_ as a 2D homogeneous
segment_list_.back().prev_point_ = points_all_.col(ii); points_all_.col(ii) << point_ref(0), point_ref(1), 1;
else points_.col(ii_ok) << point_ref(0), point_ref(1), 1;
// prev = previous point (out of range or not) }
segment_list_.back().prev_point_ = points_all_.col(prev_ii);
// OPEN NEW SEGMENT (without closing any)
open_segment = true; if ( prev_out_of_range && !out_of_range) // valid point after out of range
} {
// CLOSE SEGMENT (without opening any) //std::cout << "OPEN NEW SEGMENT " << std::endl;
else if ( out_of_range && !prev_out_of_range) // out of range after a ok point assert(open_segment == false && "opening a segment without closing the last one");
{
//std::cout << "CLOSE SEGMENT " << std::endl; segment_list_.push_back(ScanSegment());
assert(open_segment == true && "closing an already closed segment");
// first index
// last index segment_list_.back().idx_first_ = ii_ok;
segment_list_.back().idx_last_ = ii_ok-1;
// prev point
// points if (prev_ii == -1)
unsigned int n_points = segment_list_.back().idx_last_ - segment_list_.back().idx_first_+1; // no previous points: prev = current
segment_list_.back().points_ = points_.middleCols(segment_list_.back().idx_first_, n_points); segment_list_.back().prev_point_ = points_all_.col(ii);
else
// next point: current // prev = previous point (out of range or not)
segment_list_.back().next_point_ = points_all_.col(ii); segment_list_.back().prev_point_ = points_all_.col(prev_ii);
//check _compute_params to compute all segment params open_segment = true;
if (_compute_params) }
segment_list_.back().computeAll(); // CLOSE SEGMENT (without opening any)
else if ( out_of_range && !prev_out_of_range) // out of range after a ok point
open_segment = false; {
} //std::cout << "CLOSE SEGMENT " << std::endl;
// CLOSE SEGMENT & OPEN NEW SEGMENT assert(open_segment == true && "closing an already closed segment");
else if ( !out_of_range && !prev_out_of_range && fabs(ranges_[ii] - ranges_[prev_ii]) > _jump_th ) // jump from valid points
{ // last index
//std::cout << "CLOSE & OPEN SEGMENT " << std::endl; segment_list_.back().idx_last_ = ii_ok-1;
assert(open_segment == true && "closing an already closed segment");
// points
// CLOSE unsigned int n_points = segment_list_.back().idx_last_ - segment_list_.back().idx_first_+1;
// last index segment_list_.back().points_ = points_.middleCols(segment_list_.back().idx_first_, n_points);
segment_list_.back().idx_last_ = ii_ok-1;
// next point: current
// points segment_list_.back().next_point_ = points_all_.col(ii);
unsigned int n_points = segment_list_.back().idx_last_ - segment_list_.back().idx_first_+1;
segment_list_.back().points_ = points_.middleCols(segment_list_.back().idx_first_, n_points); //check _compute_params to compute all segment params
if (_compute_params)
// next point: current segment_list_.back().computeAll();
segment_list_.back().next_point_ = points_all_.col(ii);
open_segment = false;
//check _compute_params to compute all segment params }
if (_compute_params) // CLOSE SEGMENT & OPEN NEW SEGMENT
segment_list_.back().computeAll(); else if ( !out_of_range && !prev_out_of_range && fabs(ranges_[ii] - ranges_[prev_ii]) > _jump_th ) // jump from valid points
{
// OPEN //std::cout << "CLOSE & OPEN SEGMENT " << std::endl;
segment_list_.push_back(ScanSegment()); assert(open_segment == true && "closing an already closed segment");
// first index // CLOSE
segment_list_.back().idx_first_ = ii_ok; // last index
segment_list_.back().idx_last_ = ii_ok-1;
// prev point
segment_list_.back().prev_point_ = points_all_.col(prev_ii); // points
} unsigned int n_points = segment_list_.back().idx_last_ - segment_list_.back().idx_first_+1;
segment_list_.back().points_ = points_.middleCols(segment_list_.back().idx_first_, n_points);
//increment ok counter
if (!out_of_range) // next point: current
ii_ok++; segment_list_.back().next_point_ = points_all_.col(ii);
// keep previous non-nan non-inf index //check _compute_params to compute all segment params
prev_ii = ii; if (_compute_params)
} segment_list_.back().computeAll();
else //invalid raw value
{ // OPEN
ranges_[ii] = -1.; segment_list_.push_back(ScanSegment());
jumps_mask_[ii] = true;
points_all_.col(ii) << 0, 0, 0; // first index
} segment_list_.back().idx_first_ = ii_ok;
// prev point
segment_list_.back().prev_point_ = points_all_.col(prev_ii);
}
//increment ok counter
if (!out_of_range)
ii_ok++;
// keep previous non-nan non-inf index
prev_ii = ii;
//increment azimuth with angle step //increment azimuth with angle step
azimuth += _scan_params.angle_step_; azimuth += _scan_params.angle_step_;
......
...@@ -166,6 +166,11 @@ class LaserScan ...@@ -166,6 +166,11 @@ class LaserScan
**/ **/
void findSegments(const LaserScanParams& _scan_params, std::list<laserscanutils::ScanSegment>& _segment_list, bool _compute_params = true, const ScalarT& _jump_th_segment = 1); void findSegments(const LaserScanParams& _scan_params, std::list<laserscanutils::ScanSegment>& _segment_list, bool _compute_params = true, const ScalarT& _jump_th_segment = 1);
bool isValidRange(const ScalarT& range, const LaserScanParams& _scan_params) const
{
return (range > _scan_params.range_min_) && (range < _scan_params.range_max_-0.2) && (!std::isnan(range)) && (!std::isinf(range));
}
}; };
} //namespace } //namespace
......
...@@ -21,25 +21,59 @@ LineFinderIterative::~LineFinderIterative() ...@@ -21,25 +21,59 @@ LineFinderIterative::~LineFinderIterative()
void LineFinderIterative::setIlfParams(const LineFinderIterativeParams & _params) void LineFinderIterative::setIlfParams(const LineFinderIterativeParams & _params)
{ {
ilf_params_.max_fit_error_ = _params.max_fit_error_; ilf_params_.max_fit_error_ = _params.max_fit_error_;
ilf_params_.min_supports_ = _params.min_supports_; ilf_params_.min_segment_points_ = _params.min_segment_points_;
} }
unsigned int LineFinderIterative::findLines( const Eigen::MatrixXs & _points, unsigned int LineFinderIterative::findLines( const Eigen::MatrixXs & _points,
std::list<laserscanutils::LineSegment> & _line_list) std::list<laserscanutils::LineSegment> & _line_list)
{ {
//If not enough points, return, nothing to do.
if ( _points.cols() < ilf_params_.min_segment_points_ )
return 0;
//If segment too short, return, nothing to do.
if ((_points.col(0)-_points.col(_points.cols()-1)).head(2).norm() < ilf_params_.min_segment_dist_ )
return 0;
//Find lines recursively //Find lines recursively
this->findLinesRecursive(_points, _line_list, 0, _points.cols()-1); this->findLinesRecursive(_points, _line_list, 0, _points.cols()-1);
// discard polylines with any inner line (not considering first and last lines) that is too small (in points or distance)
if (_line_list.size() > 2)
for (auto line_it = std::next(_line_list.begin()); line_it != std::prev(_line_list.end()); line_it++)
if (line_it->np_ < ilf_params_.min_segment_points_ || line_it->length_ < ilf_params_.min_segment_dist_)
{
_line_list.clear();
return 0;
}
//return number of lines detected //return number of lines detected
return _line_list.size(); return _line_list.size();
} }
unsigned int LineFinderIterative::findLines( const laserscanutils::ScanSegment & _segment, unsigned int LineFinderIterative::findLines( const laserscanutils::ScanSegment & _segment,
std::list<laserscanutils::LineSegment> & _line_list) const std::list<laserscanutils::LineSegment> & _line_list) const
{ {
//If not enough points, return, nothing to do.
if ( _segment.points_.cols() < ilf_params_.min_segment_points_ )
return 0;
//If segment too short, return, nothing to do.
if ((_segment.points_.col(0)-_segment.points_.col(_segment.points_.cols()-1)).head(2).norm() < ilf_params_.min_segment_dist_ )
return 0;
//Find lines recursively //Find lines recursively
this->findLinesRecursive(_segment.points_, _line_list, 0, _segment.points_.cols()-1); this->findLinesRecursive(_segment.points_, _line_list, 0, _segment.points_.cols()-1);
// discard polylines with any inner line (not considering first and last lines) that is too small (in points or distance)
if (_line_list.size() > 2)
for (auto line_it = std::next(_line_list.begin()); line_it != std::prev(_line_list.end()); line_it++)
if (line_it->np_ < ilf_params_.min_segment_points_ || line_it->length_ < ilf_params_.min_segment_dist_)
{
_line_list.clear();
return 0;
}
//return number of lines detected //return number of lines detected
return _line_list.size(); return _line_list.size();
} }
...@@ -161,10 +195,6 @@ unsigned int LineFinderIterative::findLinesRecursive( const Eigen::Matrix<Scalar ...@@ -161,10 +195,6 @@ unsigned int LineFinderIterative::findLinesRecursive( const Eigen::Matrix<Scalar
unsigned int _idx_o, unsigned int _idx_o,
unsigned int _idx_e) const unsigned int _idx_e) const
{ {
//If not enough points, return, nothing to do.
if ( (_idx_e-_idx_o + 1) < ilf_params_.min_supports_ )
return 0;
LineSegment line;//, line1, line2; LineSegment line;//, line1, line2;
ScalarT max_dist, dist; ScalarT max_dist, dist;
unsigned int max_ii; unsigned int max_ii;
...@@ -180,8 +210,14 @@ unsigned int LineFinderIterative::findLinesRecursive( const Eigen::Matrix<Scalar ...@@ -180,8 +210,14 @@ unsigned int LineFinderIterative::findLinesRecursive( const Eigen::Matrix<Scalar
max_dist = (_points.middleCols(_idx_o, _idx_e-_idx_o+1).transpose() * line.abc_).array().abs().maxCoeff(&max_ii); max_dist = (_points.middleCols(_idx_o, _idx_e-_idx_o+1).transpose() * line.abc_).array().abs().maxCoeff(&max_ii);
max_ii += _idx_o; max_ii += _idx_o;
//check if farthest point at distance lower than threshold // n_points and length
if ( max_dist < ilf_params_.max_fit_error_ ) //straight line case line.np_ = _idx_e - _idx_o + 1;
line.length_ = (_points.col(0)-_points.col(_points.cols()-1)).head(2).norm();
//check if farthest point at distance lower than threshold (or line too small to keep splitting)
if ( max_dist < ilf_params_.max_fit_error_ ||
line.np_ < ilf_params_.min_segment_points_ ||
line.length_ < ilf_params_.min_segment_dist_) //straight line case
{ {
//Fit line //Fit line
fitLine(_points.middleCols(_idx_o, _idx_e-_idx_o+1), line); fitLine(_points.middleCols(_idx_o, _idx_e-_idx_o+1), line);
...@@ -189,14 +225,17 @@ unsigned int LineFinderIterative::findLinesRecursive( const Eigen::Matrix<Scalar ...@@ -189,14 +225,17 @@ unsigned int LineFinderIterative::findLinesRecursive( const Eigen::Matrix<Scalar
//fill line segment attributes //fill line segment attributes
line.pointProjectionToLine(_points.col(_idx_o), line.point_first_); //line.point_first_ << _points.col(_idx_o); line.pointProjectionToLine(_points.col(_idx_o), line.point_first_); //line.point_first_ << _points.col(_idx_o);
line.pointProjectionToLine(_points.col(_idx_e), line.point_last_); //line.point_last_ << _points.col(_idx_e); line.pointProjectionToLine(_points.col(_idx_e), line.point_last_); //line.point_last_ << _points.col(_idx_e);
line.np_ = _idx_e - _idx_o + 1;
line.idx_first_ = _idx_o; line.idx_first_ = _idx_o;
line.idx_last_ = _idx_e; line.idx_last_ = _idx_e;
// correct length
line.length_ = (line.point_first_ - line.point_last_).norm();
//push back the line //push back the line
_line_list.push_back(line); _line_list.push_back(line);
} }
else //non straight line case -> carry on recursivity //non straight line case -> carry on recursivity
else
{ {
//split _points into two subsets and call findLinesRecursive again for each subset //split _points into two subsets and call findLinesRecursive again for each subset
this->findLinesRecursive(_points, _line_list, _idx_o, max_ii ); this->findLinesRecursive(_points, _line_list, _idx_o, max_ii );
......
...@@ -16,7 +16,8 @@ namespace laserscanutils ...@@ -16,7 +16,8 @@ namespace laserscanutils
struct LineFinderIterativeParams struct LineFinderIterativeParams
{ {
ScalarT max_fit_error_; //maximum allowed fit error to consider a straight line ScalarT max_fit_error_; //maximum allowed fit error to consider a straight line
unsigned int min_supports_; //Min supports at the hough grid to consider a cell as a line unsigned int min_segment_points_; //Min points of a segment to be considered
ScalarT min_segment_dist_; //Min distance of a segment to be considered
ScalarT range_jump_segment_; //range difference (w.r.t previous range) threshold for considering a new segment ScalarT range_jump_segment_; //range difference (w.r.t previous range) threshold for considering a new segment
ScalarT dist_th_defined_; //distance of the next/prev point to the line for considering a defined line extreme point ScalarT dist_th_defined_; //distance of the next/prev point to the line for considering a defined line extreme point
ScalarT std_dev_points_; // standard deviation of the detected points (TODO: modeling from sensor noise) ScalarT std_dev_points_; // standard deviation of the detected points (TODO: modeling from sensor noise)
...@@ -64,6 +65,10 @@ class LineFinderIterative : public LineFinder ...@@ -64,6 +65,10 @@ class LineFinderIterative : public LineFinder
* *
**/ **/
void setIlfParams(const LineFinderIterativeParams & _params); void setIlfParams(const LineFinderIterativeParams & _params);
LineFinderIterativeParams getIlfParams() const
{
return ilf_params_;
}
/** \brief Find lines using Iterative line Fit. Result as a list of Line's /** \brief Find lines using Iterative line Fit. Result as a list of Line's
* *
......