rs-trajectory.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 <librealsense2/rs.hpp>
5 #include "example.hpp" // Include short list of convenience functions for rendering
6 #include <cstring>
7 
8 struct short3
9 {
10  uint16_t x, y, z;
11 };
12 
13 #include "t265.h"
14 
15 // Struct to store trajectory points
17 {
19  unsigned int confidence;
20 };
21 
22 // Class to store the trajectory and draw it
23 class tracker
24 {
25 public:
26  // Calculates transformation matrix based on pose data from the device
27  void calc_transform(rs2_pose& pose_data, float mat[16])
28  {
29  auto q = pose_data.rotation;
30  auto t = pose_data.translation;
31  // Set the matrix as column-major for convenient work with OpenGL and rotate by 180 degress (by negating 1st and 3rd columns)
32  mat[0] = -(1 - 2 * q.y*q.y - 2 * q.z*q.z); mat[4] = 2 * q.x*q.y - 2 * q.z*q.w; mat[8] = -(2 * q.x*q.z + 2 * q.y*q.w); mat[12] = t.x;
33  mat[1] = -(2 * q.x*q.y + 2 * q.z*q.w); mat[5] = 1 - 2 * q.x*q.x - 2 * q.z*q.z; mat[9] = -(2 * q.y*q.z - 2 * q.x*q.w); mat[13] = t.y;
34  mat[2] = -(2 * q.x*q.z - 2 * q.y*q.w); mat[6] = 2 * q.y*q.z + 2 * q.x*q.w; mat[10] = -(1 - 2 * q.x*q.x - 2 * q.y*q.y); mat[14] = t.z;
35  mat[3] = 0.0f; mat[7] = 0.0f; mat[11] = 0.0f; mat[15] = 1.0f;
36  }
37 
38  // Updates minimum and maximum coordinates of the trajectory, used in order to scale the viewport accordingly
40  {
41  max_coord.x = std::max(max_coord.x, point.x);
42  max_coord.y = std::max(max_coord.y, point.y);
43  max_coord.z = std::max(max_coord.z, point.z);
44  min_coord.x = std::min(min_coord.x, point.x);
45  min_coord.y = std::min(min_coord.y, point.y);
46  min_coord.z = std::min(min_coord.z, point.z);
47  }
48 
49  // Register new point in the trajectory
51  {
52  // If first element, add to trajectory and initialize minimum and maximum coordinates
53  if (trajectory.size() == 0)
54  {
55  trajectory.push_back(p);
56  max_coord = p.point;
57  min_coord = p.point;
58  }
59  else
60  {
61  // Check if new element is far enough - more than 1 mm (to keep trajectory vector as small as possible)
62  rs2_vector prev = trajectory.back().point;
63  rs2_vector curr = p.point;
64  if (sqrt(pow((curr.x - prev.x), 2) + pow((curr.y - prev.y), 2) + pow((curr.z - prev.z), 2)) < 0.001)
65  {
66  // If new point is too close to previous point and has higher confidence, replace the previous point with the new one
67  if (p.confidence > trajectory.back().confidence)
68  {
69  trajectory.back() = p;
70  update_min_max(p.point);
71  }
72  }
73  else
74  {
75  // If new point is far enough, add it to trajectory
76  trajectory.push_back(p);
77  update_min_max(p.point);
78  }
79  }
80  }
81 
82  // Draw trajectory with colors according to point confidence
84  {
85  float3 colors[]{
86  { 0.7f, 0.7f, 0.7f },
87  { 1.0f, 0.0f, 0.0f },
88  { 1.0f, 1.0f, 0.0f },
89  { 0.0f, 1.0f, 0.0f },
90  };
91 
92  glLineWidth(2.0f);
94  for (auto&& v : trajectory)
95  {
96  auto c = colors[v.confidence];
97  glColor3f(c.x, c.y, c.z);
98  glVertex3f(v.point.x, v.point.y, v.point.z);
99  }
100  glEnd();
101  glLineWidth(0.5f);
102  }
103 
105  {
106  return max_coord;
107  }
108 
110  {
111  return min_coord;
112  }
113 private:
114  std::vector<tracked_point> trajectory;
117 };
118 
119 // Class that handles rendering of the T265 3D model
120 class camera_renderer
121 {
122 public:
123  // Initialize renderer with data needed to draw the camera
125  {
126  uncompress_t265_obj(positions, normals, indexes);
127  }
128 
129  // Render the camera model
131  {
135 
136  // Scale camera drawing to match view
137  glScalef(0.001f, 0.001f, 0.001f);
138 
140  // Draw the camera
141  for (auto& i : indexes)
142  {
143  glVertex3fv(&positions[i.x].x);
144  glVertex3fv(&positions[i.y].x);
145  glVertex3fv(&positions[i.z].x);
146  glColor4f(0.036f, 0.044f, 0.051f, 0.3f);
147  }
148  glEnd();
151  }
152 private:
153  std::vector<float3> positions, normals;
154  std::vector<short3> indexes;
155 };
156 
157 // Renders grid for the 3D view
158 void draw_grid()
159 {
160  glPushMatrix();
161  glBegin(GL_LINES);
162  glColor4f(0.4f, 0.4f, 0.4f, 1.f);
163  for (int i = 0; i <= 8; i++)
164  {
165  glVertex3i(-i + 4, -4, 0);
166  glVertex3i(-i + 4, 4, 0);
167  glVertex3i(4, -i+4, 0);
168  glVertex3i(-4, -i+4, 0);
169  }
170  glEnd();
171  glPopMatrix();
172 }
173 
174 // Sets the 3D view and handles user manipulations
175 void render_scene(glfw_state app_state)
176 {
177  glClearColor(0.0, 0.0, 0.0, 1.0);
178  glColor3f(1.0, 1.0, 1.0);
179 
181  glLoadIdentity();
182  gluPerspective(60.0, 4 / 3, 0.5, 100);
183 
186 
187  glLoadIdentity();
188  gluLookAt(1, -1, 4, 0, 1, 0, 0, 0, 1);
189  glTranslatef(0, 0, app_state.offset_y);
190  glRotated(app_state.pitch, -1, 0, 0);
191  glRotated(app_state.yaw, 0, 0, -1);
192  draw_grid();
193 }
194 
195 
196 // Draws seprating lines between viewports
198 {
200  glLoadIdentity();
201  glColor4f(0.4f, 0.4f, 0.4f, 1.f);
203  glVertex2i(1, 0);
204  glVertex2i(-1, 0);
205  glVertex2i(0, 0);
206  glVertex2i(0, 1);
207  glVertex2i(0, -1);
208  glEnd();
209 }
210 
211 // Calculates and prints the scale of the viewport in meters
212 float display_scale(float scale_factor, float x_pos, float y_pos)
213 {
214  glColor3f(1.0f, 1.0f, 1.0f);
215  // Set default width for the scale bar (in OpenGL units)
216  float bar_width = 0.1f;
217  // Calculate the ratio of the default width to the current scale factor
218  float bar_scale = bar_width / scale_factor;
219  // If scale is less than 1 meter, display it as is
220  if (bar_scale > 1)
221  {
222  // If scale is between 1 and 2, round to 1
223  bar_scale = floor(bar_scale);
224  // If scale is above 2, round down to the nearest multiple of 5
225  if (bar_scale > 2)
226  {
227  int diff = 5 - int(bar_scale) % 5;
228  bar_scale = bar_scale + diff;
229  }
230  // Calculate the bar width matching the calculated scale
231  bar_width = scale_factor * bar_scale;
232  }
233  // Print scale
234  std::stringstream ss;
235  ss << bar_scale << " m";
236  auto str = ss.str();
237  draw_text(int(x_pos), int(y_pos), str.c_str());
238  ss.clear(); ss.str("");
239  return bar_width;
240 }
241 
242 // Draw x, y, z axes
243 void draw_axes()
244 {
245  glBegin(GL_LINES);
246  glColor3f(1, 0, 0); glVertex3f(0, 0, 0); glVertex3f(-1, 0, 0);
247  glColor3f(0, 1, 0); glVertex3f(0, 0, 0); glVertex3f(0, -1, 0);
248  glColor3f(0, 0, 1); glVertex3f(0, 0, 0); glVertex3f(0, 0, 1);
249  glEnd();
250 }
251 
252 typedef float rs2_vector::* pos;
253 
254 // Base class for rendering a viewport
255 class view
256 {
257 public:
259  : width(width), height(height), aspect (height / width), t(tracker), renderer(r) { }
260 
261  // Setup viewport
262  void load_matrices(float2 pos, float app_width, float app_height)
263  {
264  width = app_width;
265  height = app_height;
266  aspect = height / width;
267 
268  // Set viewport to 1/4 of the app window and enable scissor test to avoid rendering outside the current viewport
269  glViewport(int(pos.x), int(pos.y), int(width / 2), int(height / 2));
271  glScissor(int(pos.x), int(pos.y), int(width / 2), int(height / 2));
272 
273  // Setup orthogonal projection matrix
275  glPushMatrix();
276  glOrtho(-1.0, 1.0, -1.0 * aspect, 1.0 * aspect, -100.0, 100.0);
277 
279  glPushMatrix();
280  glLoadIdentity();
281  }
282 
283  // Return to default setup
285  {
286  // Pop LookAt matrix
287  glPopMatrix();
288  // Pop Projection matrix
290  glPopMatrix();
291  // Set viewport back to full screen
292  glViewport(0, 0, int(width), int(height));
294  }
295 
296  // Draw trajectoy and render camera according to the given transformation matrix
297  void draw_cam_trajectory(float angle, float3 axes, float r[16])
298  {
299  glPushMatrix();
300  // Set initial camera position (rotate by given angle)
301  glRotatef(angle, axes.x, axes.y, axes.z);
302  t.draw_trajectory();
303  glMultMatrixf(r);
304  renderer.render_camera();
305  glPopMatrix();
306  }
307 protected:
308  float width, height;
309  float aspect;
311 private:
313 };
314 
315 // Class for rendering 2d view of the camera and trajectory
316 class view_2d : public view
317 {
318 public:
319  view_2d(float width, float height, tracker& tracker, camera_renderer& renderer, rs2_vector lookat_eye, pos a, pos b, pos c)
320  : view(width, height, tracker, renderer), a(a), b(b), c(c), lookat_eye(lookat_eye), window_borders{ 1, aspect }
321  { }
322 
323  // Renders a viewport on 1/4 of the app window
324  void draw_view(float2 pos, float width, float height, float2 scale_pos, float r[16])
325  {
326  // Calculate and print scale in meters
327  float bar_width = display_scale(scale_factor, scale_pos.x, scale_pos.y);
328 
329  rs2_vector min_coord = t.get_min_coord();
330  rs2_vector max_coord = t.get_max_coord();
331 
332  // Prepare viewport for rendering
333  load_matrices(pos, width, height);
334 
335  glBegin(GL_LINES);
336  // Draw scale bar
337  glColor3f(1.0f, 1.0f, 1.0f);
338  glVertex3f(0.8f, -0.9f * aspect, 0); glVertex3f(0.8f + bar_width, -0.9f * aspect, 0);
339  glEnd();
340  // Set a 2D view using OpenGL's LookAt matrix
341  gluLookAt(lookat_eye.x, lookat_eye.y, lookat_eye.z, 0, 0, 0, 0, 1, 0);
342  // Draw axes (only two are visible)
343  draw_axes();
344  // Scale viewport according to current scale factor
345  glScalef(scale_factor, scale_factor, scale_factor);
346  // If trajectory reached one of the viewport's borders, zoom out and update scale factor
347  if (min_coord.*a < -window_borders.x || max_coord.*a > window_borders.x
348  || min_coord.*b < -window_borders.y || max_coord.*b > window_borders.y)
349  {
350  glScalef(0.5, 0.5, 0.5);
351  scale_factor *= 0.5;
352  window_borders.x = window_borders.x * 2;
353  window_borders.y = window_borders.y * 2;
354  }
355  // Draw trajectory and camera
356  draw_cam_trajectory(180, { 0, 1, 0 }, r);
357  // Return the default configuration of OpenGL's matrices
358  clean_matrices();
359  }
360 private:
362  float scale_factor = 1.0;
364  pos a, b, c;
365 };
366 
367 // Class for rendering 3D view of the camera and trajectory
368 class view_3d : public view
369 {
370 public:
371  view_3d(float width, float height, tracker& tracker, camera_renderer& renderer)
372  : view(width, height, tracker, renderer) { }
373 
374  void draw_view(float2 pos, float app_width, float app_height, glfw_state app_state, float r[16])
375  {
376  // Prepare viewport for rendering
377  load_matrices(pos, app_width, app_height);
378  // Set the scene configuration and handle user's manipulations
379  render_scene(app_state);
380  // Draw trajectory and camera
381  draw_cam_trajectory(90, { 1, 0, 0 }, r);
382  // // Return the default configuration of OpenGL's matrices
383  clean_matrices();
384  }
385 };
386 
387 
389 {
390 public:
391  split_screen_renderer(float app_width, float app_height, tracker& tracker, camera_renderer& renderer)
392  : top(app_width, app_height, tracker, renderer, rs2_vector{ 0, 10, -(1e-3f) }, &rs2_vector::x, &rs2_vector::z, &rs2_vector::y),
393  front(app_width, app_height, tracker, renderer, rs2_vector{ 0, 0, -10 }, &rs2_vector::x, &rs2_vector::y, &rs2_vector::z),
394  side(app_width, app_height, tracker, renderer, rs2_vector{ 10, 0, 0 }, &rs2_vector::z, &rs2_vector::y, &rs2_vector::x),
395  three_dim(app_width, app_height, tracker, renderer)
396  { }
397 
398  void draw_windows(float app_width, float app_height, glfw_state app_state, float r[16])
399  {
400  // Clear screen
401  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
403 
404  // Upper left window: top perspective (x and z axes)
405  top.draw_view({ 0, app_height / 2 }, app_width, app_height, float2{ float(0.457) * app_width, float(0.49) * app_height }, r);
406  // Lower left window: front perspective (x and y axes)
407  front.draw_view({ 0, 0 }, app_width, app_height, float2{ float(0.457) * app_width, float(0.99) * app_height }, r);
408  // Lower right window: side perspective (y and z axes)
409  side.draw_view({ app_width / 2, 0 }, app_width, app_height, float2{ float(0.957) * app_width, float(0.99) * app_height }, r);
410  // Upper right window: 3D view
411  three_dim.draw_view({ app_width / 2, app_height / 2 }, app_width, app_height, app_state, r);
412 
413  // Draw viewport titles
414  glColor3f(1.0f, 1.0f, 1.0f);
415  draw_text(int(0.005f * app_width), int(0.02f * app_height), "TOP");
416  draw_text(int(0.005f * app_width), int(0.52f * app_height), "FRONT");
417  draw_text(int(0.505f * app_width), int(0.52f * app_height), "SIDE");
418  draw_text(int(0.505f * app_width), int(0.02f * app_height), "3D");
419 
420  // Label axes
421  glColor3f(1.0f, 0.0f, 0.0f);
422  draw_text(int(0.494f * app_width), int(0.261f * app_height), "x");
423  draw_text(int(0.494f * app_width), int(0.761f * app_height), "x");
424  glColor3f(0.0f, 0.0f, 1.0f);
425  draw_text(int(0.245f * app_width), int(0.01f * app_height), "z");
426  draw_text(int(0.503f * app_width), int(0.761f * app_height), "z");
427  glColor3f(0.0f, 1.0f, 0.0f);
428  draw_text(int(0.245f * app_width), int(0.995f * app_height), "y");
429  draw_text(int(0.745f * app_width), int(0.995f * app_height), "y");
430 
431  // Draw lines bounding each viewport
432  draw_borders();
433  }
434 private:
435  view_2d top, front, side;
437 };
438 
439 // In this example, we show how to track the camera's motion using a T265 device
440 int main(int argc, char * argv[]) try
441 {
442  // Initialize window for rendering
443  window app(1280, 720, "RealSense Trajectory Example");
444 
445  // Construct an object to manage view state
446  glfw_state app_state(0.0, 0.0);
447  // Register callbacks to allow manipulation of the view state
448  register_glfw_callbacks(app, app_state);
449 
450  // Create objects for rendering the camera, the trajectory and the split screen
451  camera_renderer cam_renderer;
453  split_screen_renderer screen_renderer(app.width(), app.height(), tracker, cam_renderer);
454 
455  // Declare RealSense pipeline, encapsulating the actual device and sensors
457  // Create a configuration for configuring the pipeline with a non default profile
459  // Add pose stream
461 
462  // Start pipeline with chosen configuration
463  pipe.start(cfg);
464 
465  // Main loop
466  while (app)
467  {
468  // Wait for the next set of frames from the camera
469  auto frames = pipe.wait_for_frames();
470  // Get a frame from the pose stream
471  auto f = frames.first_or_default(RS2_STREAM_POSE);
472  // Cast the frame to pose_frame and get its data
473  auto pose_data = f.as<rs2::pose_frame>().get_pose_data();
474  float r[16];
475  // Calculate current transformation matrix
476  tracker.calc_transform(pose_data, r);
477  // From the matrix we found, get the new location point
478  rs2_vector tr{ r[12], r[13], r[14] };
479  // Create a new point to be added to the trajectory
480  tracked_point p{ tr , pose_data.tracker_confidence };
481  // Register the new point
482  tracker.add_to_trajectory(p);
483  // Draw the trajectory from different perspectives
484  screen_renderer.draw_windows(app.width(), app.height(), app_state, r);
485  }
486 
487  return EXIT_SUCCESS;
488 }
489 catch (const rs2::error & e)
490 {
491  std::cerr << "RealSense error calling " << e.get_failed_function() << "(" << e.get_failed_args() << "):\n " << e.what() << std::endl;
492  return EXIT_FAILURE;
493 }
494 catch (const std::exception& e)
495 {
496  std::cerr << e.what() << std::endl;
497  return EXIT_FAILURE;
498 }
float z
Definition: example.hpp:36
GLboolean GLboolean GLboolean b
void draw_view(float2 pos, float width, float height, float2 scale_pos, float r[16])
void draw_cam_trajectory(float angle, float3 axes, float r[16])
#define glRotatef
GLdouble GLdouble GLdouble top
float z
Definition: rs_types.h:131
rs2_vector min_coord
#define GL_ONE
#define GL_SCISSOR_TEST
float width
#define glOrtho
void draw_axes()
#define glBegin
float x
Definition: example.hpp:68
GLfloat GLfloat p
Definition: glext.h:12687
double yaw
Definition: example.hpp:875
def axes(out, pos, rotation=np.eye(3), size=0.075, thickness=2)
#define glPopMatrix
#define GL_PROJECTION
rs2_vector translation
Definition: rs_types.h:142
uint16_t z
Definition: rs-motion.cpp:10
double pitch
Definition: example.hpp:876
#define glVertex3fv
GLfloat angle
Definition: glext.h:6819
unsigned short uint16_t
Definition: stdint.h:79
#define GL_BLEND
rs2_vector get_max_coord()
#define glLoadIdentity
rs2_vector lookat_eye
#define glColor4f
#define glVertex3f
e
Definition: rmse.py:177
point
Definition: rmse.py:166
tracker & t
#define glEnable
std::vector< tracked_point > trajectory
int main(int argc, char *argv[])
void load_matrices(float2 pos, float app_width, float app_height)
GLdouble t
GLboolean GLboolean GLboolean GLboolean a
const std::string & get_failed_args() const
Definition: rs_types.hpp:117
camera_renderer & renderer
float y
Definition: rs_types.h:131
GLdouble f
void render_scene(glfw_state app_state)
split_screen_renderer(float app_width, float app_height, tracker &tracker, camera_renderer &renderer)
float3 colors[]
Definition: rs-pcl.cpp:44
float aspect
float2 window_borders
rs2_vector get_min_coord()
rs2_vector point
#define GL_COLOR_BUFFER_BIT
float y
Definition: example.hpp:68
const GLubyte * c
Definition: glext.h:12690
GLdouble GLdouble r
#define GL_LINES
#define glScissor
float width() const
Definition: example.hpp:627
#define glLineWidth
#define glPushMatrix
#define glClear
GLint GLsizei GLsizei height
float offset_y
Definition: example.hpp:881
rs2_quaternion rotation
Definition: rs_types.h:145
#define glTranslatef
void uncompress_t265_obj(std::vector< float3 > &vertex_data, std::vector< float3 > &normals, std::vector< short3 > &index_data)
Definition: t265.h:8
view_2d(float width, float height, tracker &tracker, camera_renderer &renderer, rs2_vector lookat_eye, pos a, pos b, pos c)
#define glEnd
float y
Definition: example.hpp:36
view_3d(float width, float height, tracker &tracker, camera_renderer &renderer)
float x
Definition: rs_types.h:131
void enable_stream(rs2_stream stream_type, int stream_index, int width, int height, rs2_format format=RS2_FORMAT_ANY, int framerate=0)
void draw_borders()
#define glViewport
#define GL_DEPTH_BUFFER_BIT
#define GL_MODELVIEW
#define glVertex2i
float height() const
Definition: example.hpp:628
uint16_t x
Definition: rs-motion.cpp:10
void draw_view(float2 pos, float app_width, float app_height, glfw_state app_state, float r[16])
3D vector in Euclidean coordinate space
Definition: rs_types.h:129
#define glColor3f
unsigned int confidence
GLdouble GLdouble GLdouble q
rs2_vector max_coord
#define glVertex3i
int min(int a, int b)
Definition: lz4s.c:73
#define glScalef
void draw_text(int x, int y, const char *text)
Definition: example.hpp:109
view(float width, float height, tracker &tracker, camera_renderer &r)
void clean_matrices()
void add_to_trajectory(tracked_point &p)
void calc_transform(rs2_pose &pose_data, float mat[16])
#define glClearColor
std::ostream & cerr()
#define GL_LINE_STRIP
float rs2_vector::* pos
int i
#define glRotated
void draw_grid()
#define glBlendFunc
#define glMultMatrixf
void draw_trajectory()
void register_glfw_callbacks(window &app, glfw_state &app_state)
Definition: example.hpp:1037
float display_scale(float scale_factor, float x_pos, float y_pos)
GLdouble v
#define glMatrixMode
const std::string & get_failed_function() const
Definition: rs_types.hpp:112
void draw_windows(float app_width, float app_height, glfw_state app_state, float r[16])
GLint GLsizei width
float x
Definition: example.hpp:36
uint16_t y
Definition: rs-motion.cpp:10
#define GL_TRIANGLES
#define GL_DEPTH_TEST
#define glDisable
void update_min_max(rs2_vector point)


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