speckle_filter.h
Go to the documentation of this file.
1 /*
2  * Software License Agreement (BSD License)
3  *
4  * Robot Operating System code by Eurotec B.V.
5  * Copyright (c) 2020, Eurotec B.V.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above
13  * copyright notice, this list of conditions and the following
14  * disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above
17  * copyright notice, this list of conditions and the following
18  * disclaimer in the documentation and/or other materials provided
19  * with the distribution.
20  *
21  * 3. Neither the name of the copyright holder nor the names of its
22  * contributors may be used to endorse or promote products derived
23  * from this software without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
29  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
30  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
31  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
32  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
33  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
34  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36  *
37  * speckle_filter.h
38  */
39 
40 #ifndef SPECKLE_FILTER_H
41 #define SPECKLE_FILTER_H
42 
43 #include <dynamic_reconfigure/server.h>
44 #include <filters/filter_base.h>
45 #include <laser_filters/SpeckleFilterConfig.h>
46 #include <sensor_msgs/LaserScan.h>
47 
48 namespace laser_filters
49 {
50 
52 {
53 public:
54  virtual bool checkWindowValid(const sensor_msgs::LaserScan& scan, size_t idx, size_t window, double max_range_difference) = 0;
55 };
56 
58 {
59  virtual bool checkWindowValid(const sensor_msgs::LaserScan& scan, size_t idx, size_t window, double max_range_difference)
60  {
61  const float& range = scan.ranges[idx];
62  if (range != range) {
63  return false;
64  }
65 
66  for (size_t neighbor_idx_nr = 1; neighbor_idx_nr < window; ++neighbor_idx_nr)
67  {
68  size_t neighbor_idx = idx + neighbor_idx_nr;
69  if (neighbor_idx < scan.ranges.size()) // Out of bound check
70  {
71  const float& neighbor_range = scan.ranges[neighbor_idx];
72  if (neighbor_range != neighbor_range || fabs(neighbor_range - range) > max_range_difference)
73  {
74  return false;
75  }
76  }
77  }
78  return true;
79  }
80 };
81 
83 {
84  virtual bool checkWindowValid(const sensor_msgs::LaserScan& scan, size_t idx, size_t window, double max_distance)
85  {
86  int num_neighbors = 0;
87  const float& r1 = scan.ranges[idx];
88  float r2 = 0.;
89 
90  // Look around the current point until either the window is exceeded
91  // or the number of neighbors was found.
92  for (int y = -(int)window; y < (int)window + 1 && num_neighbors < (int)window; y++)
93  {
94  int j = idx + y;
95  r2 = scan.ranges[j];
96 
97  if (j < 0 || j >= static_cast<int>(scan.ranges.size()) || idx == j || std::isnan(r2))
98  { // Out of scan bounds or itself or infinity
99  continue;
100  }
101 
102  // Explanation:
103  //
104  // Distance between two points:
105  // d² = (x2 - x1)² + (y2 - y1)²
106  //
107  // Substitute x with r * cos(phi) and y with r * sin(phi):
108  // d² = (r2 * cos(phi2) - r1 * cos(phi1))² + (r2 * sin(phi2) - r1 * sin(phi1))²
109  //
110  // Apply binomial theorem:
111  // d² = ((r2² * cos(phi2)² + r1² * cos(phi1)² - 2 * r1 * r2 * cos(phi1) * cos(phi2)) +
112  // ((r2² * sin(phi2)² + r1² * sin(phi1)² - 2 * r1 * r2 * sin(phi1) * sin(phi2))
113  //
114  // Merge sums:
115  // d² = r2² * (cos(phi2)² + sin(phi2)²) + r1² * (cos(phi1)² + sin(phi1)² -
116  // 2 * r1 * r2 * (cos(phi1) * cos(phi2) + sin(phi1) * sin(phi2))
117  //
118  // Apply cos² + sin² = 1:
119  // d² = r2² + r1² - 2 * r1 * r2 * (cos(phi1) * cos(phi2) + sin(phi1) * sin(phi2))
120  //
121  // Note the following:
122  // cos(phi1) * cos(phi2) = 1/2 * (cos(phi1 - phi2) + cos(phi1 + phi2))
123  // sin(phi1) * sin(phi2) = 1/2 * (cos(phi1 - phi2) - cos(phi1 + phi2))
124  //
125  // cos(phi1) * cos(phi2) + sin(phi1) * sin(phi2) = cos(phi1 - phi2)
126  //
127  // Finally, phi1 - phi2 is our included_angle.
128 
129  const float d = sqrt(
130  pow(r1,2) + pow(r2,2) -
131  (2 * r1 * r2 * cosf(y * scan.angle_increment)));
132 
133 
134  if (d <= max_distance)
135  {
136  num_neighbors++;
137  }
138  }
139 
140  // consider the window to be the number of neighbors we need
141  if (num_neighbors < window)
142  {
143  return false;
144  }
145  else
146  {
147  return true;
148  }
149  }
150 };
151 
155 class LaserScanSpeckleFilter : public filters::FilterBase<sensor_msgs::LaserScan>
156 {
157 public:
160  bool configure();
161  bool update(const sensor_msgs::LaserScan& input_scan, sensor_msgs::LaserScan& output_scan);
162 
163 private:
164  std::shared_ptr<dynamic_reconfigure::Server<laser_filters::SpeckleFilterConfig>> dyn_server_;
165  void reconfigureCB(laser_filters::SpeckleFilterConfig& config, uint32_t level);
166  boost::recursive_mutex own_mutex_;
167 
168  SpeckleFilterConfig config_ = SpeckleFilterConfig::__getDefault__();
170 };
171 }
172 #endif /* speckle_filter.h */
d
virtual bool checkWindowValid(const sensor_msgs::LaserScan &scan, size_t idx, size_t window, double max_range_difference)=0
LaserScanMaskFilter removes points on directions defined in a mask from a laser scan.
virtual bool checkWindowValid(const sensor_msgs::LaserScan &scan, size_t idx, size_t window, double max_range_difference)
void update(const std::string &key, const XmlRpc::XmlRpcValue &v)
std::shared_ptr< dynamic_reconfigure::Server< laser_filters::SpeckleFilterConfig > > dyn_server_
INLINE Rall1d< T, V, S > sqrt(const Rall1d< T, V, S > &arg)
This is a filter that removes speckle points in a laser scan based on consecutive ranges...
INLINE Rall1d< T, V, S > pow(const Rall1d< T, V, S > &arg, double m)
virtual bool checkWindowValid(const sensor_msgs::LaserScan &scan, size_t idx, size_t window, double max_distance)


laser_filters
Author(s): Tully Foote
autogenerated on Mon Feb 28 2022 22:39:24