1 #include "gaze/pipeline_steps/gaze_point_calculation.h" 
    6 #include "dlib/gui_widgets.h" 
    7 #include "opencv2/opencv.hpp" 
    8 #include "yaml-cpp/yaml.h" 
   10 #include "gaze/util/config.h" 
   11 #include "gaze/util/data.h" 
   12 #include "gaze/util/dlibcv.h" 
   13 #include "gaze/util/pipeline_utils.h" 
   22   int delim = aspect_ratio_string.
find(
":");
 
   24     delim = aspect_ratio_string.
find(
"/");
 
   27     double width_rate = std::stod(aspect_ratio_string.
substr(0, delim));
 
   28     double height_rate = std::stod(aspect_ratio_string.
substr(delim + 1));
 
   29     aspect_ratio = width_rate / height_rate;
 
   31     aspect_ratio = std::stod(aspect_ratio_string);
 
   39   } 
else if (value > max) {
 
   49 GazePointCalculation::GazePointCalculation()
 
   50     : eye_ball_centers(2) {
 
   55   this->name = config[
"name"] ?
 
   58   if (config[
"eye_ball_centers"]) {
 
   59     this->eye_ball_centers =
 
   62     this->eye_ball_centers[0] = 
cv::Vec3d(-0.029205, 0.0327, -0.0395);
 
   63     this->eye_ball_centers[1] = 
cv::Vec3d(0.029205, 0.0327, -0.0395);
 
   66   if (config[
"model"]) {
 
   72       {0.0, -0.0636, -0.0125},
 
   73       {-0.0433, 0.0327, -0.026},
 
   74       {0.0433, 0.0327, -0.026},
 
   75       {-0.0289, -0.0289, -0.0241},
 
   76       {0.0289, -0.0289, -0.0241}
 
   81   YAML::Node camera_config = meta_config[
"camera"];
 
   82   double sensor_aspect_ratio = camera_config[
"sensor_aspect_ratio"] ?
 
   84         camera_config[
"sensor_aspect_ratio"].as<std::string>())
 
   87   this->set_sensor_size(
 
   88       camera_config[
"sensor_size"] ?
 
   89         camera_config[
"sensor_size"].as<double>() : 0.00635,
 
   92   this->camera_matrix = camera_config[
"camera_matrix"].as<
cv::Mat>();
 
   93   this->distortion_coefficients =
 
   94     camera_config[
"distortion_coefficients"].as<
cv::Mat>();
 
   96   this->pixel_width = this->sensor_width /
 
   97     camera_config[
"resolution"][
"width"].as<
double>();
 
   98   this->pixel_height = this->sensor_height /
 
   99     camera_config[
"resolution"][
"height"].as<
double>();
 
  101   this->focal_length = camera_config[
"focal_length"] ?
 
  102     camera_config[
"focal_length"].as<
double>() : 0.01;
 
  104   this->camera_offset_x = camera_config[
"position"][
"x"].as<
double>();
 
  105   this->camera_offset_y = camera_config[
"position"][
"y"].as<
double>();
 
  108   YAML::Node screen_config = meta_config[
"screen"];
 
  109   this->screen_width_m =
 
  110     screen_config[
"measurements"][
"width"].as<
double>();
 
  111   this->screen_height_m =
 
  112     screen_config[
"measurements"][
"height"].as<
double>();
 
  113   this->screen_width_px =
 
  114     screen_config[
"resolution"][
"width"].as<
int>();
 
  115   this->screen_height_px =
 
  116     screen_config[
"resolution"][
"height"].as<
int>();
 
  118   if (meta_config[
"target"]) {
 
  119     this->target_width = meta_config[
"target"][
"width"].as<
int>();
 
  120     this->target_height = meta_config[
"target"][
"height"].as<
int>();
 
  122     this->target_width = this->screen_width_px;
 
  123     this->target_height = this->screen_height_px;
 
  127 double GazePointCalculation::calculate_distance(
 
  128     const dlib::point& p0, 
const dlib::point& p1,
 
  129     double expected_model_distance) {
 
  130   double interex_dist_px = dlib::length(p0 - p1);
 
  131   double distance = (this->focal_length * expected_model_distance) /
 
  132     (interex_dist_px * this->pixel_width);
 
  136 cv::Matx34d GazePointCalculation::invertProjection(
 
  141   return transformation;
 
  154       this->camera_matrix, this->distortion_coefficients);
 
  156   for (
const cv::Vec2d& point : restored_points) {
 
  157     cv::Vec3d unprojected(point[0], point[1], 1);
 
  159         rcam * rotation * ((unprojected / distance) - translation));
 
  161   return unprojectedPoints;
 
  164 cv::Vec3d GazePointCalculation::get_model_to_camera_dir(
 
  169 cv::Vec3d GazePointCalculation::get_camera_pos(
 
  170     const cv::Vec3d& model_to_camera_dir, 
double distance) {
 
  171   return distance * model_to_camera_dir;
 
  177     cv::Vec3d(-this->camera_offset_x, -this->camera_offset_y, 0);
 
  182     return rotation.
t() * in + camera_pos;
 
  188 cv::Matx32d GazePointCalculation::calculate_gaze_point(
 
  197   cv::Vec3d tuv = (raycast.
inv() * (eye_ball_center - screen_a));
 
  198   cv::Vec3d gaze_point = eye_ball_center + (pupil - eye_ball_center) * tuv[0];
 
  206 void GazePointCalculation::set_sensor_size(
 
  207     double sensor_diagonal,
 
  208     double aspect_ratio) {
 
  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;
 
  221   for (
auto i : this->landmark_indices) {
 
  228   cv::Matx34d transformation = this->invertProjection(landmarks);
 
  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();
 
  240   double distance = this->calculate_distance(
 
  247   cv::Vec3d camera_pos = this->get_camera_pos(model_to_camera_dir, distance);
 
  250     this->get_screen_corners(camera_pos, R);
 
  254   for (
auto i = decltype(data.
gaze_points.size()){0};
 
  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]);
 
  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);
 
  264   screen_coord_coeffs /= 2;
 
  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);
 
  270       this->target_width * screen_coord_coeffs[0],
 
  271       this->target_height * screen_coord_coeffs[1]);
 
  276   this->widget->clear_overlay();
 
  282   double distance = this->calculate_distance(
 
  290   for (
auto i = decltype(data.
landmarks.num_parts()){0};
 
  302   cv::Vec3d camera_pos = this->get_camera_pos(camera_dir, distance);
 
  306     this->get_screen_corners(camera_pos, R);
 
  312   auto add_to_overlay =
 
  314                      dlib::rgb_pixel color) -> 
void {
 
  315       for (
auto p : points) {
 
  316         overlay_dots.
push_back({{p[0], p[1], p[2]}, color});
 
  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});
 
  328   for (
auto i = decltype(pupils_image.size()){0}; i < pupils_image.size();
 
  330     pupils_image[i] += chips[i].rect.tl_corner();
 
  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);
 
  337   add_to_overlay(pupils_world, {255, 255, 255});
 
  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)});
 
  344   this->widget->add_overlay(overlay_dots);
 
  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);
 
  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})});
 
  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})});
 
  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})});
 
  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],
 
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)
 
double parse_aspect_ratio(std::string aspect_ratio_string)
 
void distance(_InputIterator __first, _InputIterator __last, _Distance &__n)
 
int estimateAffine3D(InputArray src, InputArray dst, OutputArray out, OutputArray inliers, double ransacThreshold=3, double confidence=0.99)
 
dlib::array< dlib::point > centers
 
Matx< double, n, m > inv(int method=DECOMP_LU, bool *p_is_ok=NULL) const
 
std::vector< cv::Vec3d > gaze_points
 
cv::Vec2d estimated_gaze_point
 
Matx< double, n, m > t() const
 
basic_string substr(size_type __pos=0, size_type __n=npos) const
 
size_type find(const char *__s, size_type __pos, size_type __n) const noexcept
 
void push_back(const value_type &__x)
 
dlib::full_object_detection landmarks
 
static Vec< _Tp, cn > normalize(const Vec< _Tp, cn > &v)
 
_OutputIterator transform(_InputIterator __first, _InputIterator __last, _OutputIterator __result, _UnaryOperation __unary_op)
 
double clamp(double value, double min, double max)
 
void hconcat(const Mat *src, size_t nsrc, OutputArray dst)
 
Wraps the data acquired per frame into a single instance. 
 
std::vector< cv::Vec3d > pupils
 
complex< _Tp > sqrt(const complex< _Tp > &)