gaze  0.1.0
Perform gaze tracking with common webcams.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Groups Pages
Public Member Functions | Protected Member Functions | List of all members
gaze::pipeline::GazePointCalculation Class Referencefinal

Calculates the gaze point. More...

#include "gaze/pipeline_steps/gaze_point_calculation.h"

Inheritance diagram for gaze::pipeline::GazePointCalculation:
gaze::PipelineStep gaze::gui::Visualizeable< widget_type > gaze::gui::VisualizeableBase

Public Member Functions

void process (util::Data &data) override
 
void visualize (util::Data &data) override
 
- Public Member Functions inherited from gaze::PipelineStep
 PipelineStep ()
 
std::string get_name ()
 
virtual ~PipelineStep ()=default
 
- Public Member Functions inherited from gaze::gui::Visualizeable< widget_type >
std::shared_ptr< dlib::drawable > init (dlib::drawable_window &parent, int width, int height, std::string text="No visualization.") final
 
void remove_widget () override
 
- Public Member Functions inherited from gaze::gui::VisualizeableBase
virtual ~VisualizeableBase ()=default
 

Protected Member Functions

void set_sensor_size (double sensor_diagonal, double aspect_ratio)
 

Additional Inherited Members

- Protected Attributes inherited from gaze::PipelineStep
int number
 
std::string name
 
- Protected Attributes inherited from gaze::gui::Visualizeable< widget_type >
std::shared_ptr< widget_type > widget
 

Detailed Description

Calculates the gaze point.

///

Todo:
shoeffner: Write documentation for GazePointCalculation.

Definition at line 53 of file gaze_point_calculation.h.

Member Function Documentation

void gaze::pipeline::GazePointCalculation::process ( util::Data data)
overridevirtual

Calculates the gaze point given a head pose and eye centers.

Parameters
dataThe data object to be updated.
Returns
via data the modified data object.

Implements gaze::PipelineStep.

Definition at line 214 of file gaze_point_calculation.cpp.

References gaze::util::Data::centers, gaze::util::clamp(), gaze::util::Data::estimated_gaze_point, gaze::util::Data::gaze_points, gaze::util::get_eyes_chip_details(), gaze::util::Data::head_rotation, gaze::util::Data::head_translation, gaze::util::Data::landmarks, gaze::util::Data::pupils, std::vector< _Tp, _Alloc >::push_back(), and cv::Rodrigues().

214  {
215  if (data.landmarks.num_parts() < 5) {
216  return;
217  }
218 
219  // Convert landmarks to OpenCV data structures
220  std::vector<cv::Vec3d> landmarks;
221  for (auto i : this->landmark_indices) {
222  cv::Vec3d landmark(data.landmarks.part(i).x(), data.landmarks.part(i).y(),
223  0);
224  landmarks.push_back(landmark);
225  }
226 
227  // Project pupils into model
228  cv::Matx34d transformation = this->invertProjection(landmarks);
229 
231  util::get_eyes_chip_details(data.landmarks);
232 
233  for (auto i = decltype(data.pupils.size()){0};
234  i < data.pupils.size(); ++i) {
235  dlib::point eye = data.centers[i] + eyes[i].rect.tl_corner();
236  data.pupils[i] = transformation * cv::Vec4d(eye.x(), eye.y(), 0, 1);
237  }
238 
239  // Calculate distance
240  double distance = this->calculate_distance(
241  data.landmarks.part(36), data.landmarks.part(45), 0.08671);
242  cv::Matx33d R;
243  cv::Rodrigues(data.head_rotation, R);
244 
245  cv::Vec3d model_to_camera_dir =
246  this->get_model_to_camera_dir(data.head_translation, R);
247  cv::Vec3d camera_pos = this->get_camera_pos(model_to_camera_dir, distance);
248 
249  std::vector<cv::Vec3d> screen_tl_tr_br_bl =
250  this->get_screen_corners(camera_pos, R);
251 
252  // Ray cast
253  cv::Vec2d screen_coord_coeffs(0, 0);
254  for (auto i = decltype(data.gaze_points.size()){0};
255  i < data.gaze_points.size(); ++i) {
256  cv::Matx32d gaze_point = this->calculate_gaze_point(
257  this->eye_ball_centers[i], data.pupils[i],
258  screen_tl_tr_br_bl[0], screen_tl_tr_br_bl[1], screen_tl_tr_br_bl[3]);
259  data.gaze_points[i] =
260  cv::Vec3d(gaze_point(0, 0), gaze_point(1, 0), gaze_point(2, 0));
261  screen_coord_coeffs[0] += gaze_point(1, 1);
262  screen_coord_coeffs[1] += gaze_point(1, 2);
263  }
264  screen_coord_coeffs /= 2;
265  // swap left and right
266  screen_coord_coeffs[0] = 1 - util::clamp(screen_coord_coeffs[0], 0, 1);
267  screen_coord_coeffs[1] = util::clamp(screen_coord_coeffs[1], 0, 1);
268 
269  data.estimated_gaze_point = cv::Vec2d(
270  this->target_width * screen_coord_coeffs[0],
271  this->target_height * screen_coord_coeffs[1]);
272 }
void Rodrigues(InputArray src, OutputArray dst, OutputArray jacobian=noArray())
std::vector< dlib::chip_details > get_eyes_chip_details(const dlib::full_object_detection object_detection)
void distance(_InputIterator __first, _InputIterator __last, _Distance &__n)
void push_back(const value_type &__x)
Vec< double, 2 > Vec2d
double clamp(double value, double min, double max)
Vec< double, 3 > Vec3d
Vec< double, 4 > Vec4d
void gaze::pipeline::GazePointCalculation::set_sensor_size ( double  sensor_diagonal,
double  aspect_ratio 
)
protected

Calculates the sensor width and sensor height from the sensor diagonal and its aspect ratio.

Definition at line 206 of file gaze_point_calculation.cpp.

References std::sqrt().

208  {
209  this->sensor_height = std::sqrt(sensor_diagonal * sensor_diagonal
210  / (1 + aspect_ratio * aspect_ratio));
211  this->sensor_width = aspect_ratio * this->sensor_height;
212 }
complex< _Tp > sqrt(const complex< _Tp > &)
void gaze::pipeline::GazePointCalculation::visualize ( util::Data data)
overridevirtual

Visualizes the estimated gaze point.

Parameters
dataThe data object to be visualized.
Todo:
shoeffner: Add pipeline step to visualize 2D gaze point / area

Implements gaze::gui::VisualizeableBase.

Definition at line 274 of file gaze_point_calculation.cpp.

References gaze::util::Data::head_rotation, gaze::util::Data::head_translation, gaze::util::Data::landmarks, gaze::util::Data::pupils, std::vector< _Tp, _Alloc >::push_back(), and cv::Rodrigues().

274  {
275  // TODO(shoeffner): Add pipeline step to visualize 2D gaze point / area
276  this->widget->clear_overlay();
277  if (data.landmarks.num_parts() < 5) {
278  return;
279  }
280 
281  // Recalculate distance, etc.
282  double distance = this->calculate_distance(
283  data.landmarks.part(36), data.landmarks.part(45), 0.08671);
284  cv::Matx33d R;
285  cv::Rodrigues(data.head_rotation, R);
286 
287  // Move landmarks into model coordinates for an intuitive visualization of
288  // where the direction of the camera plane is
289  std::vector<cv::Vec2d> image_landmarks;
290  for (auto i = decltype(data.landmarks.num_parts()){0};
291  i < data.landmarks.num_parts(); ++i) {
292  image_landmarks.push_back(
293  cv::Vec2d(data.landmarks.part(i).x(), data.landmarks.part(i).y()));
294  }
295  std::vector<cv::Vec3d> world_landmarks = this->unprojectPoints(
296  image_landmarks, data.head_translation, R, distance);
297 
298  // Find camera direction
299  cv::Vec3d camera_dir =
300  this->get_model_to_camera_dir(data.head_translation, R);
301 
302  cv::Vec3d camera_pos = this->get_camera_pos(camera_dir, distance);
303 
304  // Calculate screen corners
305  std::vector<cv::Vec3d> screen_corners =
306  this->get_screen_corners(camera_pos, R);
307 
308  // Helpers to draw points
310  overlay_dots;
311 
312  auto add_to_overlay =
313  [&overlay_dots] (std::vector<cv::Vec3d> points,
314  dlib::rgb_pixel color) -> void {
315  for (auto p : points) {
316  overlay_dots.push_back({{p[0], p[1], p[2]}, color});
317  }
318  };
319 
320  add_to_overlay(this->model, {255, 255, 0});
321  add_to_overlay(data.pupils, {0, 255, 255});
322  add_to_overlay(this->eye_ball_centers, {255, 0, 255});
323  add_to_overlay(world_landmarks, {0, 255, 0});
324 
326  util::get_eyes_chip_details(data.landmarks);
327  std::vector<dlib::point> pupils_image = {data.centers[0], data.centers[1]};
328  for (auto i = decltype(pupils_image.size()){0}; i < pupils_image.size();
329  ++i) {
330  pupils_image[i] += chips[i].rect.tl_corner();
331  }
332  std::vector<cv::Vec3d> pupils_world =
333  this->unprojectPoints({cv::Vec2d(pupils_image[0].x(), pupils_image[0].y()),
334  cv::Vec2d(pupils_image[1].x(), pupils_image[1].y())},
335  data.head_translation, R, distance);
336 
337  add_to_overlay(pupils_world, {255, 255, 255});
338 
339  // Visualize camera position
340  cv::Vec3d camera = this->get_camera_pos(camera_dir, distance);
341  overlay_dots.push_back({{camera[0], camera[1], camera[2]},
342  dlib::rgb_pixel(255, 255, 255)});
343 
344  this->widget->add_overlay(overlay_dots);
345 
346  auto to_line = [](const cv::Vec3d& p0, const cv::Vec3d& p1,
347  dlib::rgb_pixel color) ->
348  dlib::perspective_display::overlay_line {
349  return dlib::perspective_display::overlay_line(
350  {p0[0], p0[1], p0[2]}, {p1[0], p1[1], p1[2]}, color);
351  };
352 
353  // Draw coordinate axes
354  cv::Vec3d origin(0, 0, 0);
355  cv::Vec3d xdir(.1, 0, 0);
356  cv::Vec3d ydir(0, .1, 0);
357  cv::Vec3d zdir(0, 0, .1);
358 
359  this->widget->add_overlay({
360  to_line(origin, xdir, {255, 0, 0}),
361  to_line(origin, ydir, {0, 255, 0}),
362  to_line(origin, zdir, {0, 0, 255}),
363  to_line(origin, origin + camera_dir, {255, 255, 0})});
364 
365  this->widget->add_overlay({
366  to_line(screen_corners[0], screen_corners[1], {255, 255, 0}),
367  to_line(screen_corners[1], screen_corners[2], {255, 255, 0}),
368  to_line(screen_corners[2], screen_corners[3], {255, 255, 0}),
369  to_line(screen_corners[3], screen_corners[0], {255, 255, 0})});
370 
371  this->widget->add_overlay({
372  to_line(this->eye_ball_centers[0], data.pupils[0], {0, 255, 255}),
373  to_line(this->eye_ball_centers[1], data.pupils[1], {0, 255, 255})});
374 
375  this->widget->add_overlay({
376  to_line(this->eye_ball_centers[0], data.gaze_points[0], {255, 255, 255}),
377  to_line(this->eye_ball_centers[1], data.gaze_points[1],
378  {255, 255, 255})});
379 }
void Rodrigues(InputArray src, OutputArray dst, OutputArray jacobian=noArray())
std::vector< dlib::chip_details > get_eyes_chip_details(const dlib::full_object_detection object_detection)
std::shared_ptr< widget_type > widget
void distance(_InputIterator __first, _InputIterator __last, _Distance &__n)
void push_back(const value_type &__x)
Vec< double, 2 > Vec2d
size_type size() const noexcept

The documentation for this class was generated from the following files: