zero-order.cpp
Go to the documentation of this file.
1 // License: Apache 2.0. See LICENSE file in root directory.
2 // Copyright(c) 2019 Intel Corporation. All Rights Reserved.
3 
4 #include "zero-order.h"
5 #include <iomanip>
6 #include "l500/l500-depth.h"
7 
8 const double METER_TO_MM = 1000;
9 
10 namespace librealsense
11 {
13  {
17  RS2_OPTION_FILTER_ZO_BASELINE = static_cast<rs2_option>(RS2_OPTION_COUNT + 3),
19  RS2_OPTION_FILTER_ZO_MAX_VALUE = static_cast<rs2_option>(RS2_OPTION_COUNT + 5),
23  };
24 
25  double get_pixel_rtd(const rs2::vertex& v, int baseline)
26  {
27  auto x = (double)v.x*METER_TO_MM;
28  auto y = (double)v.y*METER_TO_MM;
29  auto z = (double)v.z*METER_TO_MM;
30 
31  auto rtd = sqrt(x*x + y*y + z*z) + sqrt((x - baseline) *(x - baseline) + y*y + z*z);
32  return v.z ? rtd : 0;
33  }
34 
35  void z2rtd(const rs2::vertex* vertices, double* rtd, const rs2_intrinsics& intrinsics, int baseline)
36  {
37  for (auto i = 0;i < intrinsics.height*intrinsics.width; i++)
38  {
39  rtd[i] = get_pixel_rtd(vertices[i], baseline);
40  }
41  }
42 
43  template<typename T>
44  std::vector <T> get_zo_point_values(const T* frame_data_in, const rs2_intrinsics& intrinsics, int zo_point_x, int zo_point_y, int patch_r)
45  {
46  std::vector<T> values;
47  values.reserve((patch_r + 2ULL) *(patch_r + 2ULL));
48 
49  for (auto i = zo_point_y - 1 - patch_r; i <= (zo_point_y + patch_r) && i < intrinsics.height; i++)
50  {
51  for (auto j = (zo_point_x - 1 - patch_r); j <= (zo_point_x + patch_r) && i < intrinsics.width; j++)
52  {
53  values.push_back(frame_data_in[i*intrinsics.width + j]);
54  }
55  }
56 
57  return values;
58  }
59 
60  template<typename T>
61  T get_zo_point_value(std::vector<T>& values)
62  {
63  std::sort(values.begin(), values.end());
64 
65  if ((values.size()) % 2 == 0)
66  {
67  return (values[values.size() / 2 - 1] + values[values.size() / 2]) / 2;
68  }
69  else if (values.size() > 0)
70  return values[values.size() / 2];
71 
72  return 0;
73  }
74 
75  bool try_get_zo_rtd_ir_point_values(const double* rtd, const uint16_t* depth_data_in, const uint8_t* ir_data,
76  const rs2_intrinsics& intrinsics, const zero_order_options& options, int zo_point_x, int zo_point_y,
77  double *rtd_zo_value, uint8_t* ir_zo_data)
78  {
79  if (zo_point_x - options.patch_size < 0 || zo_point_x + options.patch_size >= intrinsics.width ||
80  zo_point_y - options.patch_size < 0 || zo_point_y + options.patch_size >= intrinsics.height)
81  return false;
82 
83  auto values_rtd = get_zo_point_values(rtd, intrinsics, zo_point_x, zo_point_y, options.patch_size);
84  auto values_ir = get_zo_point_values(ir_data, intrinsics, zo_point_x, zo_point_y, options.patch_size);
85  auto values_z = get_zo_point_values(depth_data_in, intrinsics, zo_point_x, zo_point_y, options.patch_size);
86 
87  for (auto i = 0; i < values_rtd.size(); i++)
88  {
89  if ((values_z[i] / 8.0) > options.z_max || (values_ir[i] < options.ir_min))
90  {
91  values_rtd[i] = 0;
92  values_ir[i] = 0;
93  }
94  }
95 
96  values_rtd.erase(std::remove_if(values_rtd.begin(), values_rtd.end(), [](double val)
97  {
98  return val == 0;
99  }), values_rtd.end());
100 
101  values_ir.erase(std::remove_if(values_ir.begin(), values_ir.end(), [](uint8_t val)
102  {
103  return val == 0;
104  }), values_ir.end());
105 
106  if (values_rtd.empty() || values_ir.empty())
107  return false;
108 
109  *rtd_zo_value = get_zo_point_value(values_rtd);
110  *ir_zo_data = get_zo_point_value(values_ir);
111 
112  return true;
113  }
114 
115  template<class T>
116  void detect_zero_order(const double * rtd, const uint16_t* depth_data_in, const uint8_t* ir_data, T zero_pixel,
117  const rs2_intrinsics& intrinsics, const zero_order_options& options,
118  double zo_value, uint8_t iro_value)
119  {
120  const double ir_dynamic_range = 256.0;
121 
122  double r = std::exp((ir_dynamic_range / 2.0 + options.threshold_offset - iro_value) / (double)options.threshold_scale);
123 
124  double res = (1.0 + r);
125  double i_threshold_relative = options.ir_threshold / res;
126  for (auto i = 0; i < intrinsics.height*intrinsics.width; i++)
127  {
128  double rtd_val = rtd[i];
129  uint8_t ir_val = ir_data[i];
130 
131  bool zero = (depth_data_in[i] > 0) &&
132  (ir_val < i_threshold_relative) &&
133  (rtd_val > (zo_value - options.rtd_low_threshold)) &&
134  (rtd_val < (zo_value + options.rtd_high_threshold));
135 
136  zero_pixel(i, zero);
137  }
138  }
139 
140  template<class T>
141  bool zero_order_invalidation(const uint16_t * depth_data_in, const uint8_t * ir_data, T zero_pixel,
142  const rs2::vertex* vertices,
144  const zero_order_options& options, int zo_point_x, int zo_point_y)
145  {
146  std::vector<double> rtd(size_t(intrinsics.height)*intrinsics.width);
147  z2rtd(vertices, rtd.data(), intrinsics, int(options.baseline));
148  double rtd_zo_value;
149  uint8_t ir_zo_value;
150 
151  if (try_get_zo_rtd_ir_point_values(rtd.data(), depth_data_in, ir_data, intrinsics,
152  options,zo_point_x, zo_point_y, &rtd_zo_value, &ir_zo_value))
153  {
154  detect_zero_order(rtd.data(), depth_data_in, ir_data, zero_pixel, intrinsics,
155  options, rtd_zo_value, ir_zo_value);
156  return true;
157  }
158  return false;
159  }
160 
161  zero_order::zero_order(std::shared_ptr<bool_option> is_enabled_opt)
162  : generic_processing_block("Zero Order Fix"), _first_frame(true), _is_enabled_opt(is_enabled_opt),
163  _resolutions_depth { 0 }
164  {
165  auto ir_threshold = std::make_shared<ptr_option<uint8_t>>(
166  0,
167  255,
168  1,
169  115,
171  "IR threshold");
172  ir_threshold->on_set([ir_threshold](float val)
173  {
174  if (!ir_threshold->is_valid(val))
176  << "Unsupported ir threshold " << val << " is out of range.");
177  });
178 
179  register_option(static_cast<rs2_option>(RS2_OPTION_FILTER_ZO_IR_THRESHOLD), ir_threshold);
180 
181  auto rtd_high_threshold = std::make_shared<ptr_option<uint16_t>>(
182  0,
183  400,
184  1,
185  200,
187  "RTD high threshold");
188  rtd_high_threshold->on_set([rtd_high_threshold](float val)
189  {
190  if (!rtd_high_threshold->is_valid(val))
192  << "Unsupported rtd high threshold " << val << " is out of range.");
193  });
194 
195  register_option(static_cast<rs2_option>(RS2_OPTION_FILTER_ZO_RTD_HIGH_THRESHOLD), rtd_high_threshold);
196 
197  auto rtd_low_threshold = std::make_shared<ptr_option<uint16_t>>(
198  0,
199  400,
200  1,
201  200,
203  "RTD high threshold");
204  rtd_low_threshold->on_set([rtd_low_threshold](float val)
205  {
206  if (!rtd_low_threshold->is_valid(val))
208  << "Unsupported rtd low threshold " << val << " is out of range.");
209  });
210 
211  register_option(static_cast<rs2_option>(RS2_OPTION_FILTER_ZO_RTD_LOW_THRESHOLD), rtd_low_threshold);
212 
213  auto baseline = std::make_shared<ptr_option<float>>(
214  -50.f,
215  50.f,
216  1.f,
217  -10.f,
219  "Baseline");
220  baseline->on_set([baseline](float val)
221  {
222  if (!baseline->is_valid(val))
224  << "Unsupported patch size value " << val << " is out of range.");
225  });
226  register_option(static_cast<rs2_option>(RS2_OPTION_FILTER_ZO_BASELINE), baseline);
227 
228  auto patch_size = std::make_shared<ptr_option<int>>(
229  0,
230  50,
231  1,
232  5,
234  "Patch size");
235  patch_size->on_set([patch_size](float val)
236  {
237  if (!patch_size->is_valid(val))
239  << "Unsupported patch size value " << val << " is out of range.");
240  });
241  register_option(static_cast<rs2_option>(RS2_OPTION_FILTER_ZO_PATCH_SIZE), patch_size);
242 
243  auto zo_max = std::make_shared<ptr_option<int>>(
244  0,
245  65535,
246  1,
247  1200,
248  &_options.z_max,
249  "ZO max value");
250  zo_max->on_set([zo_max](float val)
251  {
252  if (!zo_max->is_valid(val))
254  << "Unsupported patch size value " << val << " is out of range.");
255  });
256  register_option(static_cast<rs2_option>(RS2_OPTION_FILTER_ZO_MAX_VALUE), zo_max);
257 
258  auto ir_min = std::make_shared<ptr_option<int>>(
259  0,
260  256,
261  1,
262  75,
263  &_options.ir_min,
264  "Minimum IR value (saturation)");
265  ir_min->on_set([ir_min](float val)
266  {
267  if (!ir_min->is_valid(val))
269  << "Unsupported patch size value " << val << " is out of range.");
270  });
271  register_option(static_cast<rs2_option>(RS2_OPTION_FILTER_ZO_IR_MIN_VALUE), ir_min);
272 
273  auto offset = std::make_shared<ptr_option<int>>(
274  0,
275  1000,
276  1,
277  10,
279  "Threshold offset");
280  offset->on_set([offset](float val)
281  {
282  if (!offset->is_valid(val))
284  << "Unsupported patch size value " << val << " is out of range.");
285  });
287 
288  auto scale = std::make_shared<ptr_option<int>>(
289  0,
290  2000,
291  1,
292  20,
294  "Threshold scale");
295  scale->on_set([scale](float val)
296  {
297  if (!scale->is_valid(val))
299  << "Unsupported patch size value " << val << " is out of range.");
300  });
302  }
303 
305  {
306  switch (static_cast<zero_order_invalidation_options>(option))
307  {
309  return "IR Threshold";
311  return "RTD high Threshold";
313  return "RTD Low Threshold";
315  return "Baseline";
317  return "Patch size";
319  return "ZO max value";
321  return "IR min value";
323  return "Threshold offset";
325  return "Threshold scale";
326  }
327 
328  return options_container::get_option_name(option);
329  }
330 
332  {
333  if (auto sensor = ((frame_interface*)frame.get())->get_sensor())
334  {
335  if(auto l5 = dynamic_cast<l500_depth_sensor_interface*>(sensor.get()))
336  {
337  _options.baseline = l5->read_baseline();
338  return true;
339  }
340  // For playback
341  else
342  {
343  auto extendable = As<librealsense::extendable_interface>(sensor);
344  if (extendable && extendable->extend_to(TypeToExtension<librealsense::l500_depth_sensor_interface>::value, (void**)(&l5)))
345  {
346  return l5->read_baseline();
347  }
348  }
349  }
350  return false;
351  }
352 
354  {
355  if (auto sensor = ((frame_interface*)frame.get())->get_sensor())
356  {
358 
359  if (auto l5 = dynamic_cast<l500_depth_sensor_interface*>(sensor.get()))
360  {
361  return l500_depth_sensor::get_intrinsic_params(profile.width(), profile.height(), l5->get_intrinsic());
362  }
363  // For playback
364  else
365  {
366  auto extendable = As<librealsense::extendable_interface>(sensor);
367  if (extendable && extendable->extend_to(TypeToExtension<librealsense::l500_depth_sensor_interface>::value, (void**)(&l5)))
368  {
369  return l500_depth_sensor::get_intrinsic_params(profile.width(), profile.height(), l5->get_intrinsic());
370  }
371  }
372  }
373  throw std::runtime_error("didn't succeed to get intrinsics");
374  }
375 
376  std::pair<int, int> zero_order::get_zo_point(const rs2::frame& frame)
377  {
378  auto intrinsics = try_read_intrinsics(frame);
379  return { (int)(intrinsics.zo.x), (int)(intrinsics.zo.y) };
380  }
381 
383  {
384  // If is_enabled_opt is false, meaning this processing block is not active,
385  // return the frame as is.
386  if (auto is_enabled = _is_enabled_opt.lock())
387  if (!is_enabled->is_true())
388  // zero order is disabled, passthrough the frame
389  return f;
390 
391  std::vector<rs2::frame> result;
392 
393  if (_first_frame)
394  {
395  auto zo = get_zo_point(f);
396  LOG_DEBUG("ZO values: "<<zo.first<<", "<<zo.second);
397 
398  if (!try_read_baseline(f))
399  LOG_WARNING("Couldn't read the baseline value");
400 
401  _first_frame = false;
402  }
403 
404  auto data = f.as<rs2::frameset>();
405  if (!data)
406  {
407  LOG_ERROR("Frame received is not a frameset.");
408  return f;
409  }
410 
411  if (_source_profile_depth.get() != data.get_depth_frame().get_profile().get())
412  {
413  _source_profile_depth = data.get_depth_frame().get_profile();
415  }
416 
417  auto depth_frame = data.get_depth_frame();
418  auto ir_frame = data.get_infrared_frame();
419  auto confidence_frame = data.first_or_default(RS2_STREAM_CONFIDENCE);
420 
422 
424 
425  rs2::frame confidence_out;
426  if (confidence_frame)
427  {
428  if (_source_profile_confidence.get() != confidence_frame.get_profile().get())
429  {
430  _source_profile_confidence = confidence_frame.get_profile();
432 
433  }
434  confidence_out = source.allocate_video_frame(_source_profile_confidence, confidence_frame, 0, 0, 0, 0, RS2_EXTENSION_VIDEO_FRAME);
435  }
436  auto depth_intrinsics = depth_frame.get_profile().as<rs2::video_stream_profile>().get_intrinsics();
437 
438  auto depth_output = (uint16_t*)depth_out.get_data();
439  uint8_t* confidence_output;
440 
441  if (confidence_frame)
442  {
443  confidence_output = (uint8_t*)confidence_out.get_data();
444  }
445 
446  auto zo = get_zo_point(depth_frame);
447 
448  if (zero_order_invalidation((const uint16_t*)depth_frame.get_data(),
449  (const uint8_t*)ir_frame.get_data(),
450  [&](int index, bool zero)
451  {
452  depth_output[index] = zero ? 0 : ((uint16_t*)depth_frame.get_data())[index];
453 
454  if (confidence_frame)
455  {
456  confidence_output[index] = zero ? 0 : ((uint8_t*)confidence_frame.get_data())[index];
457  }
458  },
461  _options, zo.first, zo.second))
462  {
463  result.push_back(depth_out);
464  if (confidence_frame)
465  result.push_back(confidence_out);
466  }
467  else
468  {
469  result.push_back(depth_frame);
470  if (confidence_frame)
471  result.push_back(confidence_frame);
472  }
473  return source.allocate_composite_frame(result);
474  }
475 
477  {
478  // Zero order might get frames to process even if it is disabled by option.
479  // In such case, it should passthrough all of the frames it receives, except for IR frames,
480  // which are handled by processing blocks and must me droped.
481 
482  if (auto set = frame.as<rs2::frameset>())
483  {
484  if (!set.get_depth_frame() || !set.get_infrared_frame())
485  {
486  return false;
487  }
488  auto depth_frame = set.get_depth_frame();
489 
490  auto zo = get_zo_point(depth_frame);
491 
492  if (zo.first - _options.patch_size < 0 || zo.first + _options.patch_size >= depth_frame.get_width() ||
493  (zo.second - _options.patch_size < 0 || zo.second + _options.patch_size >= depth_frame.get_height()))
494  {
495  return false;
496  }
497  return true;
498 
499  }
500  else if (frame.get_profile().stream_type() == RS2_STREAM_INFRARED)
501  // a single IR frame received, drop it.
502  return false;
503 
504  return true;
505  }
506 
508  {
509  if (auto composite = input.as<rs2::frameset>())
510  {
511  composite.foreach_rs([&](rs2::frame f)
512  {
514  results.size() > 0)
515  results.push_back(f);
516  });
517  }
518 
519  if (results.size())
520  return source.allocate_composite_frame(results);
521  else return rs2::frame{};
522  }
523 }
int get_width() const
Definition: archive.h:279
rs2::stream_profile _source_profile_depth
Definition: zero-order.h:65
GLint y
rs2_frame * get() const
Definition: rs_frame.hpp:590
rs2_option
Defines general configuration controls. These can generally be mapped to camera UVC controls...
Definition: rs_option.h:22
rs2::frame process_frame(const rs2::frame_source &source, const rs2::frame &f) override
Definition: zero-order.cpp:382
static ivcam2::intrinsic_params get_intrinsic_params(const uint32_t width, const uint32_t height, ivcam2::intrinsic_depth intrinsic)
Definition: l500-depth.h:126
GLenum GLenum GLenum GLenum GLenum scale
Definition: glext.h:10806
std::weak_ptr< bool_option > _is_enabled_opt
Definition: zero-order.h:76
T get_zo_point_value(std::vector< T > &values)
Definition: zero-order.cpp:61
#define LOG_WARNING(...)
Definition: src/types.h:241
std::vector< T > get_zo_point_values(const T *frame_data_in, const rs2_intrinsics &intrinsics, int zo_point_x, int zo_point_y, int patch_r)
Definition: zero-order.cpp:44
stream_profile get_profile() const
Definition: rs_frame.hpp:557
bool should_process(const rs2::frame &frame) override
Definition: zero-order.cpp:476
const void * get_data() const
Definition: rs_frame.hpp:545
unsigned short uint16_t
Definition: stdint.h:79
bool try_get_zo_rtd_ir_point_values(const double *rtd, const uint16_t *depth_data_in, const uint8_t *ir_data, const rs2_intrinsics &intrinsics, const zero_order_options &options, int zo_point_x, int zo_point_y, double *rtd_zo_value, uint8_t *ir_zo_data)
Definition: zero-order.cpp:75
rs2::stream_profile _target_profile_confidence
Definition: zero-order.h:69
zero_order(std::shared_ptr< bool_option > is_enabled_opt=nullptr)
Definition: zero-order.cpp:161
GLdouble GLdouble z
unsigned char uint8_t
Definition: stdint.h:78
void sort(sort_type m_sort_type, const std::string &in, const std::string &out)
rs2::frame prepare_output(const rs2::frame_source &source, rs2::frame input, std::vector< rs2::frame > results) override
Definition: zero-order.cpp:507
GLuint index
void register_option(rs2_option id, std::shared_ptr< option > option)
Definition: options.h:86
frame allocate_video_frame(const stream_profile &profile, const frame &original, int new_bpp=0, int new_width=0, int new_height=0, int new_stride=0, rs2_extension frame_type=RS2_EXTENSION_VIDEO_FRAME) const
double get_pixel_rtd(const rs2::vertex &v, int baseline)
Definition: zero-order.cpp:25
GLuint GLfloat * val
GLdouble f
GLdouble GLdouble r
bool zero_order_invalidation(const uint16_t *depth_data_in, const uint8_t *ir_data, T zero_pixel, const rs2::vertex *vertices, rs2_intrinsics intrinsics, const zero_order_options &options, int zo_point_x, int zo_point_y)
Definition: zero-order.cpp:141
GLdouble x
float3 * get_vertices()
Definition: archive.cpp:26
points calculate(frame depth) const
frame allocate_composite_frame(std::vector< frame > frames) const
GLint j
#define LOG_ERROR(...)
Definition: src/types.h:242
int stream_index() const
Definition: rs_frame.hpp:34
dictionary intrinsics
Definition: t265_stereo.py:142
void z2rtd(const rs2::vertex *vertices, double *rtd, const rs2_intrinsics &intrinsics, int baseline)
Definition: zero-order.cpp:35
GLsizei const GLfloat * values
void detect_zero_order(const double *rtd, const uint16_t *depth_data_in, const uint8_t *ir_data, T zero_pixel, const rs2_intrinsics &intrinsics, const zero_order_options &options, double zo_value, uint8_t iro_value)
Definition: zero-order.cpp:116
std::pair< int, int > get_zo_point(const rs2::frame &frame)
Definition: zero-order.cpp:376
rs2_format format() const
Definition: rs_frame.hpp:44
zero_order_invalidation_options
Definition: zero-order.cpp:12
static const struct @18 vertices[3]
rs2::stream_profile _source_profile_confidence
Definition: zero-order.h:68
GLenum GLenum GLenum input
Definition: glext.h:10805
ivcam2::intrinsic_params try_read_intrinsics(const rs2::frame &frame)
Definition: zero-order.cpp:353
const rs2_stream_profile * get() const
Definition: rs_frame.hpp:137
bool try_read_baseline(const rs2::frame &frame)
Definition: zero-order.cpp:331
const double METER_TO_MM
Definition: zero-order.cpp:8
Video stream intrinsics.
Definition: rs_types.h:58
GLsizei GLsizei GLchar * source
zero_order_options _options
Definition: zero-order.h:75
int i
GLuint res
Definition: glext.h:8856
const char * get_option_name(rs2_option option) const override
Definition: zero-order.cpp:304
#define LOG_DEBUG(...)
Definition: src/types.h:239
virtual const char * get_option_name(rs2_option option) const override
Definition: options.h:119
rs2_stream stream_type() const
Definition: rs_frame.hpp:39
GLuint64EXT * result
Definition: glext.h:10921
GLdouble v
rs2::stream_profile _target_profile_depth
Definition: zero-order.h:66
stream_profile clone(rs2_stream type, int index, rs2_format format) const
Definition: rs_frame.hpp:63
rs2::pointcloud _pc
Definition: zero-order.h:71
Definition: parser.hpp:150
int get_height() const
Definition: archive.h:280
GLintptr offset
T as() const
Definition: rs_frame.hpp:580
std::string to_string(T value)


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