reflectivity.cpp
Go to the documentation of this file.
1 // License: Apache 2.0. See LICENSE file in root directory.
2 // Copyright(c) 2020 Intel Corporation. All Rights Reserved.
3 
4 #include <numeric>
5 #include "reflectivity.h"
6 #include <types.h>
7 
8 using namespace rs2;
9 
10 
11 static const size_t N_STD_FRAMES = 100;
12 static const int NINETY_FIVE_PERCENT_OF_STD_PERIOD = static_cast< int >( 0.95 * N_STD_FRAMES );
13 static const float MAX_RANGE_IN_UNIT = 65536.0f;
14 static const float LONG_THERMAL = 74.5f;
15 static const float INDOOR_MAX_RANGE = 9.0f;
16 
17 // TODO try to read from LRS
18 static const float FOV_H = 0.610865f;
19 static const float FOV_V = 0.479966f;
20 
21 static const int VGA_WIDTH = 640;
22 static const int VGA_HEIGHT = 480;
23 static const int VGA_HALF_WIDTH = VGA_WIDTH / 2;
24 static const int VGA_HALF_HEIGHT = VGA_HEIGHT / 2;
25 
26 static bool is_close_to_zero( float x )
27 {
28  return ( std::abs( x ) < std::numeric_limits< float >::epsilon() );
29 }
30 
31 
33  : _history_size( 0 )
34 {
35  _dist_queue.assign( N_STD_FRAMES,
36  0 ); // Allocate size for all samples in advance to minimize runtime.
37 }
38 
39 // Reflectivity analysis is based on STD and normalized IR.Final reflectivity values are weighted
40 // average between them
41 float reflectivity::get_reflectivity( float raw_noise_estimation,
42  float max_usable_range,
43  float ir_val ) const
44 {
45  // Calculating STD over time(temporal noise), when there are more than 5 % invalid return high
46  // value
47  std::vector< float > _filt_dist_arr( _dist_queue.size() );
48 
49  // Copy non zero (or close to zero) elements in history
50  auto new_end = std::copy_if( _dist_queue.begin(),
51  _dist_queue.end(),
52  _filt_dist_arr.begin(),
53  []( float elem ) { return ! is_close_to_zero( elem ); } );
54 
55  _filt_dist_arr.resize( new_end - _filt_dist_arr.begin() );
56 
57  if( 0 == _filt_dist_arr.size() )
58  throw std::logic_error( "reflectivity N/A, not enough data was collected" );
59 
60  float sum = std::accumulate( _filt_dist_arr.begin(), _filt_dist_arr.end(), 0.0f );
61  float mean = sum / _filt_dist_arr.size();
62 
63  float standard_deviation = 9999.0f;
64 
65  if( _filt_dist_arr.size() >= NINETY_FIVE_PERCENT_OF_STD_PERIOD )
66  {
67  float variance = 0.0f;
68  for( auto val : _filt_dist_arr )
69  variance += std::pow( val - mean, 2.0f );
70 
71  variance = variance / _filt_dist_arr.size();
72  standard_deviation = std::sqrt( variance );
73  }
74 
75  // Range is calculated based on position in map(assuming 0 tilt) Distance is just based on plane distance
76  auto range = mean / 1000.0f;
77 
78  // Normalized IR instead of IR is used to be robust to high ambient, RSS is assumed between echo to noise
79  auto nest = raw_noise_estimation / 16.0f;
80  auto normalized_ir = 0.0f;
81  if( ir_val > nest )
82  normalized_ir = std::pow( std::pow( ir_val, 2.0f ) - std::pow( nest, 2.0f ), 0.5f );
83 
84  auto ref_from_ir = 0.0f;
85  auto ref_from_std = 0.0f;
86  auto i_ref = 0.0f;
87  auto s_ref = 0.0f;
88  auto i_dist_85 = 0.0f;
89  auto s_dist_85 = 0.0f;
90  auto ref = 0.0f;
91 
92 
93  if( nest <= LONG_THERMAL * 2.0f )
94  {
95  // We can hold reflectivity information from IR
96  if( normalized_ir < 70.0f )
97  ref_from_ir = 0.5f; // Low confidence as IR values are low
98  else
99  ref_from_ir = 1.0f; // High confidence as IR values hold good SNR
100 
101  // Analyzing reflectivity based on 85 % reflectivity data
102  i_dist_85 = 6.75f * std::exp( -0.012f * normalized_ir );
103 
104  i_dist_85 = i_dist_85 * max_usable_range / INDOOR_MAX_RANGE;
105 
106  if( 0.0f < i_dist_85 ) // protect devision by zero
107  {
108  i_ref = static_cast<float>(0.85f * std::pow( ( range / i_dist_85 ), 2 ));
109 
110  if( i_ref > 0.95f )
111  {
112  ref_from_ir = 0.75f;
113  i_ref = 0.95f;
114  }
115  }
116  else
117  ref_from_ir = 0.0f;
118  }
119 
120  // STD based analysis
121  // STD values are at the edges, hard to get data
122  if( standard_deviation >= 1.5f || standard_deviation <= 10.f )
123  {
124  if( standard_deviation > 2.5f )
125  ref_from_std = 0.5f; // Low confidence data due to low STD values
126  else
127  ref_from_std = 1.0f; // High confidence data
128 
129  // STD based analysis based on 85% reflectivity data
130  if( range > 0.0f )
131  {
132  s_dist_85 = ( 2.25f * ( std::log( standard_deviation ) ) + 1.56f ) * max_usable_range
134  if( 0 < s_dist_85 ) // protect devision by zero
135  {
136  s_ref = 0.85f * std::pow( ( range / s_dist_85 ), 2.0f );
137  if( s_ref > 0.95f )
138  {
139  ref_from_std = ref_from_std * 0.75f;
140  s_ref = 0.95f;
141  }
142  }
143  else
144  ref_from_std = 0.0f;
145  }
146  else
147  {
148  ref_from_std = 0.0f;
149  }
150  }
151  // Calculating Final reflectivity
152  if( is_close_to_zero( ref_from_ir + ref_from_std ) )
153  throw std::logic_error( "reflectivity N/A" );
154 
155 
156  ref = ( i_ref * ref_from_ir + s_ref * ref_from_std ) / ( ref_from_ir + ref_from_std );
157 
158  // Force 15% resolution
159  if( ref >= 0.85f )
160  ref = 0.85f;
161  else if( ref >= 0.7f )
162  ref = 0.7f;
163  else if( ref >= 0.55f )
164  ref = 0.55f;
165  else if( ref >= 0.4f )
166  ref = 0.4f;
167  else if( ref >= 0.25f )
168  ref = 0.25f;
169  else
170  ref = 0.1f;
171 
172  return ref;
173 }
174 
175 void reflectivity::add_depth_sample( float depth_val, int x_in_image, int y_in_image )
176 {
177  if( x_in_image >= 0 && x_in_image < VGA_WIDTH && y_in_image >= 0 && y_in_image < VGA_HEIGHT )
178  {
179  auto dist_z = round( depth_val * 16000.f / MAX_RANGE_IN_UNIT ); // convert to mm units
180  float x_ang = FOV_H * std::abs( VGA_HALF_WIDTH - x_in_image ) / VGA_HALF_WIDTH;
181  float y_ang = FOV_V * std::abs( VGA_HALF_HEIGHT - y_in_image ) / VGA_HALF_HEIGHT;
182  auto dist_r = dist_z * std::sqrt( 1.0f + (std::pow( 2.0f * std::tan( x_ang ), 2.0f ) + std::pow( 2.0f * std::tan( y_ang ), 2.0f ) ) / 4.0f );
183 
184  if( _dist_queue.size() >= N_STD_FRAMES ) // Keep queue as N_STD_FRAMES size queue
185  _dist_queue.pop_front();
186 
187  _dist_queue.push_back( dist_r );
188  if( _history_size < N_STD_FRAMES )
189  _history_size++;
190  }
191 }
192 
194 {
195  if( _history_size > 0 )
196  {
197  _dist_queue.assign( N_STD_FRAMES, 0 );
198  _history_size = 0;
199  }
200 }
201 
203 {
204  return static_cast< float >( history_size() ) / history_capacity();
205 }
206 
208 {
209  return history_size() == history_capacity();
210 }
211 
212 // Return the history queue capacity
214 {
215  return N_STD_FRAMES;
216 }
217 
218 // Return the history queue current size
220 {
221  return _history_size;
222 }
bool is_history_full() const
float get_reflectivity(float raw_noise_estimation, float max_usable_range, float ir_val) const
static const int VGA_HALF_WIDTH
Definition: cah-model.h:10
static const float LONG_THERMAL
variance
Definition: rmse.py:157
GLuint GLfloat * val
static const float FOV_H
GLdouble f
static const int VGA_HEIGHT
static const float FOV_V
GLdouble x
std::deque< float > _dist_queue
Definition: reflectivity.h:44
static bool is_close_to_zero(float x)
static const int VGA_HALF_HEIGHT
float get_samples_ratio() const
static const int VGA_WIDTH
static const float INDOOR_MAX_RANGE
static const float MAX_RANGE_IN_UNIT
void log(std::string message)
GLint ref
size_t history_size() const
void add_depth_sample(float depth_val, int x_in_image, int y_in_image)
size_t history_capacity() const
GLsizei range
static const int NINETY_FIVE_PERCENT_OF_STD_PERIOD
static const size_t N_STD_FRAMES


librealsense2
Author(s): Sergey Dorodnicov , Doron Hirshberg , Mark Horn , Reagan Lopez , Itay Carpis
autogenerated on Mon May 3 2021 02:47:39