├── .gitignore
├── README.md
├── datasets
├── UnityEyes
│ └── README.md
├── mpii_gaze.py
└── unity_eyes.py
├── env-linux.yml
├── env-mac.yml
├── eval_mpiigaze.py
├── lbpcascade_frontalface_improved.xml
├── models
├── eyenet.py
├── layers.py
└── losses.py
├── notebooks
├── check_preprocessing.ipynb
├── explore_data.ipynb
└── explore_mpiigaze.ipynb
├── run_with_webcam.py
├── scripts
└── fetch_models.sh
├── static
├── fig1.png
└── ge_screenshot.png
├── test.py
├── test
├── __init__.py
├── data
│ └── imgs
│ │ └── 1.json
└── test_unity_eyes.py
├── train.py
└── util
├── eye_prediction.py
├── eye_sample.py
├── gaze.py
├── preprocess.py
└── softargmax.py
/.gitignore:
--------------------------------------------------------------------------------
1 | datasets/UnityEyes/imgs/
2 | datasets/MPIIGaze/
3 | datasets/UTMultiview/
4 | __pycache__/
5 | runs/
6 | .idea/
7 | .ipynb_checkpoints
8 | *.zip
9 | *.jpg
10 | *.dat
11 | checkpoint*
12 | *.bz2
13 | *.pt
14 | *.tar.gz
15 | *.pdf
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Gaze Estimation with Deep Learning
2 |
3 | This project implements a deep learning model to predict eye region landmarks and gaze direction.
4 | The model is trained on a set of computer generated eye images synthesized with UnityEyes [1]. This work is heavily based on [2] but with some key modifications.
5 | This model achieves ~14% mean angular error on the MPIIGaze evaluation set after training on UnityEyes alone.
6 |
7 | ### Setup
8 |
9 | NOTE: This repo has been tested only on Ubuntu 16.04 and MacOS.
10 |
11 | First, create a conda env for your system and activate it:
12 | ```bash
13 | conda env create -f env-linux.yml
14 | conda activate ge-linux
15 | ```
16 |
17 | Then download the pretrained model files. One is for detecting face landmarks. The other is the main pytorch model.
18 |
19 | ```bash
20 | ./scripts/fetch_models.sh
21 | ```
22 |
23 | Finally, run the webcam demo. You will likely need a GPU and have cuda 10.1 installed in order to get acceptable performance.
24 |
25 | ```bash
26 | python run_with_webcam.py
27 | ```
28 |
29 | If you'd like to train the model yourself, please see the readme under `datasets/UnityEyes`.
30 |
31 | ### Materials and Methods
32 |
33 | Over 100k training images were generated using UnityEyes [1]. These images are each labeled
34 | with a json metadata file. The labels provide eye region landmark positions in screenspace,
35 | the direction the eye is looking in camera space, and other pieces of information. A rectangular region around the eye was extracted from each raw traing image and normalized to have a width equal to the eye width (1.5 times the distance between eye corners).
36 | For each preprocessed image, a set of heatmaps corresponding
37 | to 34 eye region landmarks was created. The model was trained to regress directly on the landmark locations and gaze direction in (pitch, yaw) form. The model was implemented in pytorch. The overall method is summarized in the following figure.
38 | 
39 |
40 | The model architecture is based on the stacked hourglass model [3]. The main modification was to add a separate pre-hourglass layer for predicting the gaze direction. The output of the additional layer is concatenated with the predicted eye-region landmarks before being passed to two fully connected layers. This way, the model can make use of the high-level landmark features for predicting the gaze direction.
41 |
42 | ### Demo Video
43 |
44 | [](https://drive.google.com/open?id=1WUUmd4quXq_YA5ANWDoUxqFGgguE_QJi)
45 |
46 |
47 | ### References
48 |
49 | 1. https://www.cl.cam.ac.uk/research/rainbow/projects/unityeyes/
50 | 2. https://github.com/swook/GazeML
51 | 3. https://github.com/princeton-vl/pytorch_stacked_hourglass
52 |
--------------------------------------------------------------------------------
/datasets/UnityEyes/README.md:
--------------------------------------------------------------------------------
1 | # UnityEyes
2 |
3 | UnityEyes is a application that generates synthetic but realistic eye images that are
4 | annotated with various pieces of information such as eye region locations and look vector.
5 |
6 | You can generate your own training images using the software which can be found at https://www.cl.cam.ac.uk/research/rainbow/projects/unityeyes/
7 |
8 | Please add your images to the `datasets/UnityEyes/imgs/` folder.
9 |
10 |
11 | ### Alternatively
12 |
13 | You can download the exact dataset that we used here https://drive.google.com/open?id=1wqTA4gutC-L4h8TcMMQO_3jJYBL15-h3
14 |
15 | Download this to ./datasets/UnityEyes/imgs.zip and unzip it.
16 |
17 | This dataset contains 100938 images together with their json metadata files.
--------------------------------------------------------------------------------
/datasets/mpii_gaze.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function, division
2 | import torch
3 | import numpy as np
4 | from torch.utils.data import Dataset
5 | import glob
6 | import os
7 | import cv2
8 | import scipy.io as sio
9 | import util.gaze
10 |
11 |
12 | class MPIIGaze(Dataset):
13 |
14 | def __init__(self, mpii_dir: str = 'datasets/MPIIGaze'):
15 |
16 | self.mpii_dir = mpii_dir
17 |
18 | eval_files = glob.glob(f'{mpii_dir}/Evaluation Subset/sample list for eye image/*.txt')
19 |
20 | self.eval_entries = []
21 | for ef in eval_files:
22 | person = os.path.splitext(os.path.basename(ef))[0]
23 | with open(ef) as f:
24 | lines = f.readlines()
25 | for line in lines:
26 | line = line.strip()
27 | if line != '':
28 | img_path, side = [x.strip() for x in line.split()]
29 | day, img = img_path.split('/')
30 | self.eval_entries.append({
31 | 'day': day,
32 | 'img_name': img,
33 | 'person': person,
34 | 'side': side
35 | })
36 |
37 | def __len__(self):
38 | return len(self.eval_entries)
39 |
40 | def __getitem__(self, idx):
41 | if torch.is_tensor(idx):
42 | idx = idx.tolist()
43 |
44 | return self._load_sample(idx)
45 |
46 | def _load_sample(self, i):
47 | entry = self.eval_entries[i]
48 | mat_path = os.path.join(self.mpii_dir, 'Data/Normalized', entry['person'], entry['day'] + '.mat')
49 | mat = sio.loadmat(mat_path)
50 |
51 | filenames = mat['filenames']
52 | row = np.argwhere(filenames == entry['img_name'])[0][0]
53 | side = entry['side']
54 |
55 | img = mat['data'][side][0, 0]['image'][0, 0][row]
56 | img = cv2.resize(img, (160, 96))
57 | img = cv2.equalizeHist(img)
58 | img = img / 255.
59 | img = img.astype(np.float32)
60 | if side == 'right':
61 | img = np.fliplr(img)
62 |
63 | (x, y, z) = mat['data'][side][0, 0]['gaze'][0, 0][row]
64 |
65 | theta = np.arcsin(-y)
66 | phi = np.arctan2(-x, -z)
67 | gaze = np.array([-theta, phi])
68 |
69 | return {
70 | 'img': img,
71 | 'gaze': gaze,
72 | 'side': side
73 | }
74 |
--------------------------------------------------------------------------------
/datasets/unity_eyes.py:
--------------------------------------------------------------------------------
1 | from __future__ import print_function, division
2 | import os
3 | from typing import Optional
4 |
5 | import torch
6 | import numpy as np
7 | import matplotlib.pyplot as plt
8 | from torch.utils.data import Dataset, DataLoader
9 | import glob
10 | import os
11 | import cv2
12 | import json
13 | from util.preprocess import preprocess_unityeyes_image
14 |
15 |
16 | class UnityEyesDataset(Dataset):
17 |
18 | def __init__(self, img_dir: Optional[str] = None):
19 |
20 | if img_dir is None:
21 | img_dir = os.path.join(os.path.dirname(__file__), 'UnityEyes/imgs')
22 |
23 | self.img_paths = glob.glob(os.path.join(img_dir, '*.jpg'))
24 | self.img_paths = sorted(self.img_paths, key=lambda x: int(os.path.splitext(os.path.basename(x))[0]))
25 | self.json_paths = []
26 | for img_path in self.img_paths:
27 | idx = os.path.splitext(os.path.basename(img_path))[0]
28 | self.json_paths.append(os.path.join(img_dir, f'{idx}.json'))
29 |
30 | def __len__(self):
31 | return len(self.img_paths)
32 |
33 | def __getitem__(self, idx):
34 | if torch.is_tensor(idx):
35 | idx = idx.tolist()
36 |
37 | full_img = cv2.imread(self.img_paths[idx])
38 | with open(self.json_paths[idx]) as f:
39 | json_data = json.load(f)
40 |
41 | eye_sample = preprocess_unityeyes_image(full_img, json_data)
42 | sample = {'full_img': full_img, 'json_data': json_data }
43 | sample.update(eye_sample)
44 | return sample
--------------------------------------------------------------------------------
/env-linux.yml:
--------------------------------------------------------------------------------
1 | name: ge-linux
2 | channels:
3 | - pytorch
4 | - conda-forge
5 | - defaults
6 | dependencies:
7 | - _libgcc_mutex=0.1
8 | - absl-py=0.9.0
9 | - attrs=19.3.0
10 | - backcall=0.1.0
11 | - blas=1.0
12 | - bleach=3.1.0
13 | - bzip2=1.0.8
14 | - c-ares=1.15.0
15 | - ca-certificates=2020.1.1
16 | - cairo=1.16.0
17 | - certifi=2019.11.28
18 | - cudatoolkit=10.1.243
19 | - cycler=0.10.0
20 | - dbus=1.13.12
21 | - decorator=4.4.1
22 | - defusedxml=0.6.0
23 | - entrypoints=0.3
24 | - expat=2.2.6
25 | - ffmpeg=4.1.3
26 | - fontconfig=2.13.1
27 | - freetype=2.9.1
28 | - giflib=5.1.4
29 | - glib=2.63.1
30 | - gmp=6.1.2
31 | - gnutls=3.6.5
32 | - graphite2=1.3.13
33 | - grpcio=1.16.1
34 | - gst-plugins-base=1.14.0
35 | - gstreamer=1.14.0
36 | - harfbuzz=2.4.0
37 | - hdf5=1.10.5
38 | - icu=58.2
39 | - importlib_metadata=1.5.0
40 | - intel-openmp=2020.0
41 | - ipykernel=5.1.4
42 | - ipython=7.12.0
43 | - ipython_genutils=0.2.0
44 | - ipywidgets=7.5.1
45 | - jasper=1.900.1
46 | - jedi=0.16.0
47 | - jinja2=2.11.1
48 | - jpeg=9c
49 | - jsonschema=3.2.0
50 | - jupyter=1.0.0
51 | - jupyter_client=5.3.4
52 | - jupyter_console=6.1.0
53 | - jupyter_core=4.6.1
54 | - kiwisolver=1.1.0
55 | - lame=3.100
56 | - ld_impl_linux-64=2.33.1
57 | - libblas=3.8.0
58 | - libcblas=3.8.0
59 | - libedit=3.1.20181209
60 | - libffi=3.2.1
61 | - libgcc-ng=9.1.0
62 | - libgfortran-ng=7.3.0
63 | - libiconv=1.15
64 | - liblapack=3.8.0
65 | - liblapacke=3.8.0
66 | - libpng=1.6.37
67 | - libprotobuf=3.11.3
68 | - libsodium=1.0.16
69 | - libstdcxx-ng=9.1.0
70 | - libtiff=4.1.0
71 | - libuuid=2.32.1
72 | - libwebp=1.0.1
73 | - libxcb=1.13
74 | - libxml2=2.9.9
75 | - markdown=3.1.1
76 | - markupsafe=1.1.1
77 | - matplotlib=3.1.3
78 | - matplotlib-base=3.1.3
79 | - mistune=0.8.4
80 | - mkl=2020.0
81 | - mkl-service=2.3.0
82 | - mkl_fft=1.0.15
83 | - mkl_random=1.1.0
84 | - more-itertools=8.2.0
85 | - nbconvert=5.6.1
86 | - nbformat=5.0.4
87 | - ncurses=6.1
88 | - nettle=3.4.1
89 | - ninja=1.9.0
90 | - notebook=6.0.3
91 | - numpy=1.18.1
92 | - numpy-base=1.18.1
93 | - olefile=0.46
94 | - opencv=4.1.0
95 | - openh264=1.8.0
96 | - openssl=1.1.1d
97 | - packaging=20.1
98 | - pandoc=2.2.3.2
99 | - pandocfilters=1.4.2
100 | - parso=0.6.1
101 | - pcre=8.43
102 | - pexpect=4.8.0
103 | - pickleshare=0.7.5
104 | - pillow=7.0.0
105 | - pip=20.0.2
106 | - pixman=0.38.0
107 | - pluggy=0.13.1
108 | - prometheus_client=0.7.1
109 | - prompt_toolkit=3.0.3
110 | - protobuf=3.11.3
111 | - ptyprocess=0.6.0
112 | - py=1.8.1
113 | - pygments=2.5.2
114 | - pyparsing=2.4.6
115 | - pyqt=5.9.2
116 | - pyrsistent=0.15.7
117 | - pytest=5.3.5
118 | - python=3.6.10
119 | - python-dateutil=2.8.1
120 | - pytorch=1.4.0
121 | - pyzmq=18.1.1
122 | - qt=5.9.7
123 | - qtconsole=4.6.0
124 | - readline=7.0
125 | - send2trash=1.5.0
126 | - setuptools=45.2.0
127 | - sip=4.19.8
128 | - six=1.14.0
129 | - sqlite=3.31.1
130 | - tensorboard=2.0.0
131 | - terminado=0.8.3
132 | - testpath=0.4.4
133 | - tk=8.6.8
134 | - torchvision=0.5.0
135 | - tornado=6.0.3
136 | - traitlets=4.3.3
137 | - wcwidth=0.1.8
138 | - webencodings=0.5.1
139 | - werkzeug=1.0.0
140 | - wheel=0.34.2
141 | - widgetsnbextension=3.5.1
142 | - x264=1!152.20180806
143 | - xorg-kbproto=1.0.7
144 | - xorg-libice=1.0.10
145 | - xorg-libsm=1.2.3
146 | - xorg-libx11=1.6.9
147 | - xorg-libxext=1.3.4
148 | - xorg-libxrender=0.9.10
149 | - xorg-renderproto=0.11.1
150 | - xorg-xextproto=7.3.0
151 | - xorg-xproto=7.0.31
152 | - xz=5.2.4
153 | - zeromq=4.3.1
154 | - zipp=2.2.0
155 | - zlib=1.2.11
156 | - zstd=1.3.7
157 | - pip:
158 | - dlib==19.19.0
159 | - imutils==0.5.3
160 |
--------------------------------------------------------------------------------
/env-mac.yml:
--------------------------------------------------------------------------------
1 | name: ge-mac
2 | channels:
3 | - pytorch
4 | - defaults
5 | dependencies:
6 | - absl-py=0.9.0
7 | - appnope=0.1.0
8 | - attrs=19.3.0
9 | - backcall=0.1.0
10 | - blas=1.0
11 | - bleach=3.1.0
12 | - bzip2=1.0.8
13 | - c-ares=1.15.0
14 | - ca-certificates=2020.1.1
15 | - cairo=1.14.12
16 | - certifi=2019.11.28
17 | - cycler=0.10.0
18 | - dbus=1.13.12
19 | - decorator=4.4.1
20 | - defusedxml=0.6.0
21 | - entrypoints=0.3
22 | - expat=2.2.6
23 | - ffmpeg=4.0
24 | - fontconfig=2.13.0
25 | - freetype=2.9.1
26 | - gettext=0.19.8.1
27 | - glib=2.63.1
28 | - graphite2=1.3.13
29 | - grpcio=1.16.1
30 | - harfbuzz=1.8.8
31 | - hdf5=1.10.2
32 | - icu=58.2
33 | - importlib_metadata=1.5.0
34 | - intel-openmp=2019.4
35 | - ipykernel=5.1.4
36 | - ipython=7.12.0
37 | - ipython_genutils=0.2.0
38 | - ipywidgets=7.5.1
39 | - jasper=2.0.14
40 | - jedi=0.16.0
41 | - jinja2=2.11.1
42 | - jpeg=9b
43 | - jsonschema=3.2.0
44 | - jupyter=1.0.0
45 | - jupyter_client=5.3.4
46 | - jupyter_console=6.1.0
47 | - jupyter_core=4.6.1
48 | - kiwisolver=1.1.0
49 | - libcxx=4.0.1
50 | - libcxxabi=4.0.1
51 | - libedit=3.1.20181209
52 | - libffi=3.2.1
53 | - libgfortran=3.0.1
54 | - libiconv=1.15
55 | - libopencv=3.4.2
56 | - libopus=1.3
57 | - libpng=1.6.37
58 | - libprotobuf=3.11.4
59 | - libsodium=1.0.16
60 | - libtiff=4.1.0
61 | - libvpx=1.7.0
62 | - libxml2=2.9.9
63 | - markdown=3.1.1
64 | - markupsafe=1.1.1
65 | - matplotlib=3.1.3
66 | - matplotlib-base=3.1.3
67 | - mistune=0.8.4
68 | - mkl=2019.4
69 | - mkl-service=2.3.0
70 | - mkl_fft=1.0.15
71 | - mkl_random=1.1.0
72 | - nbconvert=5.6.1
73 | - nbformat=5.0.4
74 | - ncurses=6.1
75 | - ninja=1.9.0
76 | - notebook=6.0.3
77 | - numpy=1.18.1
78 | - numpy-base=1.18.1
79 | - olefile=0.46
80 | - opencv=3.4.2
81 | - openssl=1.1.1d
82 | - pandoc=2.2.3.2
83 | - pandocfilters=1.4.2
84 | - parso=0.6.1
85 | - pcre=8.43
86 | - pexpect=4.8.0
87 | - pickleshare=0.7.5
88 | - pillow=7.0.0
89 | - pip=20.0.2
90 | - pixman=0.38.0
91 | - prometheus_client=0.7.1
92 | - prompt_toolkit=3.0.3
93 | - protobuf=3.11.4
94 | - ptyprocess=0.6.0
95 | - py-opencv=3.4.2
96 | - pygments=2.5.2
97 | - pyparsing=2.4.6
98 | - pyqt=5.9.2
99 | - pyrsistent=0.15.7
100 | - python=3.6.10
101 | - python-dateutil=2.8.1
102 | - pytorch=1.4.0
103 | - pyzmq=18.1.1
104 | - qt=5.9.7
105 | - qtconsole=4.6.0
106 | - readline=7.0
107 | - send2trash=1.5.0
108 | - setuptools=45.2.0
109 | - sip=4.19.8
110 | - six=1.14.0
111 | - sqlite=3.31.1
112 | - tensorboard=2.0.0
113 | - terminado=0.8.3
114 | - testpath=0.4.4
115 | - tk=8.6.8
116 | - torchvision=0.5.0
117 | - tornado=6.0.3
118 | - traitlets=4.3.3
119 | - wcwidth=0.1.8
120 | - webencodings=0.5.1
121 | - werkzeug=1.0.0
122 | - wheel=0.34.2
123 | - widgetsnbextension=3.5.1
124 | - xz=5.2.4
125 | - zeromq=4.3.1
126 | - zipp=2.2.0
127 | - zlib=1.2.11
128 | - zstd=1.3.7
129 | - pip:
130 | - dlib==19.19.0
131 | - imutils==0.5.3
132 |
133 |
--------------------------------------------------------------------------------
/eval_mpiigaze.py:
--------------------------------------------------------------------------------
1 | import torch
2 | from datasets.mpii_gaze import MPIIGaze
3 | from models.eyenet import EyeNet
4 | import os
5 | import numpy as np
6 | import cv2
7 | from util.preprocess import gaussian_2d
8 | from matplotlib import pyplot as plt
9 | import util.gaze
10 |
11 | device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
12 | dataset = MPIIGaze()
13 | checkpoint = torch.load('checkpoint.pt', map_location=device)
14 | nstack = checkpoint['nstack']
15 | nfeatures = checkpoint['nfeatures']
16 | nlandmarks = checkpoint['nlandmarks']
17 | eyenet = EyeNet(nstack=nstack, nfeatures=nfeatures, nlandmarks=nlandmarks).to(device)
18 | eyenet.load_state_dict(checkpoint['model_state_dict'])
19 |
20 | with torch.no_grad():
21 | errors = []
22 |
23 | print('N', len(dataset))
24 | for i, sample in enumerate(dataset):
25 | print(i)
26 | x = torch.tensor([sample['img']]).float().to(device)
27 |
28 | heatmaps_pred, landmarks_pred, gaze_pred = eyenet.forward(x)
29 |
30 | gaze = sample['gaze'].reshape((1, 2))
31 | gaze_pred = np.asarray(gaze_pred.cpu().numpy())
32 |
33 | if sample['side'] == 'right':
34 | gaze_pred[0, 1] = -gaze_pred[0, 1]
35 |
36 | angular_error = util.gaze.angular_error(gaze, gaze_pred)
37 | errors.append(angular_error)
38 | print('---')
39 | print('error', angular_error)
40 | print('mean error', np.mean(errors))
41 | print('side', sample['side'])
42 | print('gaze', gaze)
43 | print('gaze pred', gaze_pred)
44 |
45 | # landmarks_pred = np.asarray(landmarks_pred.cpu().numpy())[0, :]
46 | #
47 | # plt.figure(figsize=(8, 9))
48 | #
49 | # iris_center = landmarks_pred[-2][::-1]
50 | # iris_center *= 2
51 | # img = sample['img']
52 | #
53 | # img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
54 | #
55 | # img_gaze_pred = img.copy()
56 | # util.gaze.draw_gaze(img_gaze_pred, iris_center, gaze_pred[0, :], length=60, color=(255, 0, 0))
57 | #
58 | # img_gaze = img.copy()
59 | # util.gaze.draw_gaze(img_gaze, iris_center, sample['gaze'], length=60, color=(0, 255, 0))
60 | #
61 | # plt.subplot(121)
62 | # plt.imshow(cv2.cvtColor(img_gaze, cv2.COLOR_BGR2RGB))
63 | # plt.title('True Gaze')
64 | #
65 | # plt.subplot(122)
66 | # plt.imshow(cv2.cvtColor(img_gaze_pred, cv2.COLOR_BGR2RGB))
67 | # plt.title('Predicted Gaze')
68 | #
69 | # plt.show()
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/lbpcascade_frontalface_improved.xml:
--------------------------------------------------------------------------------
1 |
2 |
66 |
67 |
68 |
69 | BOOST
70 | LBP
71 | 45
72 | 45
73 |
74 | GAB
75 | 9.9500000476837158e-001
76 | 5.0000000000000000e-001
77 | 9.4999999999999996e-001
78 | 1
79 | 100
80 |
81 | 256
82 | 1
83 | 19
84 |
85 |
86 | <_>
87 | 6
88 | -4.1617846488952637e+000
89 |
90 | <_>
91 |
92 | 0 -1 26 -1 -1 -17409 -1 -1 -1 -1 -1
93 |
94 | -9.9726462364196777e-001 -3.8938775658607483e-001
95 | <_>
96 |
97 | 0 -1 18 -1 -1 -21569 -20545 -1 -1 -20545 -1
98 |
99 | -9.8648911714553833e-001 -2.5386649370193481e-001
100 | <_>
101 |
102 | 0 -1 30 -21569 -16449 1006578219 -20801 -16449 -1 -21585 -1
103 |
104 | -9.6436238288879395e-001 -1.4039695262908936e-001
105 | <_>
106 |
107 | 0 -1 54 -1 -1 -16402 -4370 -1 -1 -1053010 -4456466
108 |
109 | -8.4081345796585083e-001 3.8321062922477722e-001
110 | <_>
111 |
112 | 0 -1 29 -184747280 -705314819 1326353 1364574079 -131073 -5
113 | 2147481147 -1
114 |
115 | -8.1084597110748291e-001 4.3495711684226990e-001
116 | <_>
117 |
118 | 0 -1 89 -142618625 -4097 -37269 -20933 872350430 -268476417
119 | 1207894255 2139032115
120 |
121 | -7.3140043020248413e-001 4.3799084424972534e-001
122 |
123 | <_>
124 | 6
125 | -4.0652265548706055e+000
126 |
127 | <_>
128 |
129 | 0 -1 19 -1 -1 -17409 -1 -1 -1 -1 -1
130 |
131 | -9.9727255105972290e-001 -7.2050148248672485e-001
132 | <_>
133 |
134 | 0 -1 38 -1 1073741823 -1 -1 -1 -1 -1 -1
135 |
136 | -9.8717331886291504e-001 -5.3031939268112183e-001
137 | <_>
138 |
139 | 0 -1 28 -16385 -1 -21569 -20545 -1 -1 -21569 -1
140 |
141 | -9.3442338705062866e-001 6.5213099122047424e-002
142 | <_>
143 |
144 | 0 -1 112 -2097153 -1 -1 -1 -1 -8193 -1 -35467
145 |
146 | -7.9567342996597290e-001 4.2883640527725220e-001
147 | <_>
148 |
149 | 0 -1 48 -134239573 -16465 58663467 -1079022929 -1073758273
150 | -81937 -8412501 -404766817
151 |
152 | -7.1264797449111938e-001 4.1050794720649719e-001
153 | <_>
154 |
155 | 0 -1 66 -17047555 -1099008003 2147479551 -1090584581 -69633
156 | -1342177281 -1090650121 -1472692240
157 |
158 | -7.6119172573089600e-001 4.2042696475982666e-001
159 |
160 | <_>
161 | 7
162 | -4.6904473304748535e+000
163 |
164 | <_>
165 |
166 | 0 -1 12 -1 -1 -17409 -1 -1 -1 -1 -1
167 |
168 | -9.9725550413131714e-001 -8.3142280578613281e-001
169 | <_>
170 |
171 | 0 -1 31 -1 -168429569 -1 -1 -1 -1 -1 -1
172 |
173 | -9.8183268308639526e-001 -3.6373397707939148e-001
174 | <_>
175 |
176 | 0 -1 38 -1 1073741759 -1 -1 -1 -1 -1 -1
177 |
178 | -9.1890293359756470e-001 7.8322596848011017e-002
179 | <_>
180 |
181 | 0 -1 27 -17409 -2097153 -134372726 -21873 -65 -536870913
182 | -161109 -4215889
183 |
184 | -8.0752444267272949e-001 1.9565649330615997e-001
185 | <_>
186 |
187 | 0 -1 46 -469779457 -286371842 -33619971 -212993 -1 -41943049
188 | -134217731 -1346863620
189 |
190 | -6.9232726097106934e-001 3.8141927123069763e-001
191 | <_>
192 |
193 | 0 -1 125 -1896950780 -1964839052 -9 707723004 -34078727
194 | -1074266122 -536872969 -262145
195 |
196 | -8.1760478019714355e-001 3.4172961115837097e-001
197 | <_>
198 |
199 | 0 -1 80 -402657501 654311423 -419533278 -452984853
200 | 1979676215 -1208090625 -167772569 -524289
201 |
202 | -6.3433408737182617e-001 4.3154156208038330e-001
203 |
204 | <_>
205 | 8
206 | -4.2590322494506836e+000
207 |
208 | <_>
209 |
210 | 0 -1 42 -1 -655361 -1 -1 -1 -1 -1 -1
211 |
212 | -9.9715477228164673e-001 -8.6178696155548096e-001
213 | <_>
214 |
215 | 0 -1 40 -1 -705300491 -1 -1 -1 -1 -1 -1
216 |
217 | -9.8356908559799194e-001 -5.7423096895217896e-001
218 | <_>
219 |
220 | 0 -1 43 -65 872413111 -2049 -1 -1 -1 -1 -1
221 |
222 | -9.2525935173034668e-001 -1.3835857808589935e-001
223 | <_>
224 |
225 | 0 -1 111 -1 -5242881 -1 -524289 -4194305 -1 -1 -43148
226 |
227 | -7.8076487779617310e-001 1.8362471461296082e-001
228 | <_>
229 |
230 | 0 -1 25 -145227841 868203194 -1627394049 935050171
231 | 2147483647 1006600191 -268439637 1002437615
232 |
233 | -7.2554033994674683e-001 3.3393219113349915e-001
234 | <_>
235 |
236 | 0 -1 116 -214961408 50592514 -2128 1072162674 -1077940293
237 | -1084489966 -134219854 -1074790401
238 |
239 | -6.1547595262527466e-001 3.9214438199996948e-001
240 | <_>
241 |
242 | 0 -1 3 -294987948 -1124421633 -73729 -268435841 -33654928
243 | 2122317823 -268599297 -33554945
244 |
245 | -6.4863425493240356e-001 3.8784855604171753e-001
246 | <_>
247 |
248 | 0 -1 22 -525585 -26738821 -17895690 1123482236 1996455758
249 | -8519849 -252182980 -461898753
250 |
251 | -5.5464369058609009e-001 4.4275921583175659e-001
252 |
253 | <_>
254 | 8
255 | -4.0009465217590332e+000
256 |
257 | <_>
258 |
259 | 0 -1 82 -1 -1 -1 -1 -33685505 -1 -1 -1
260 |
261 | -9.9707120656967163e-001 -8.9196771383285522e-001
262 | <_>
263 |
264 | 0 -1 84 -1 -1 -1 -1 2147446783 -1 -1 -1
265 |
266 | -9.8670446872711182e-001 -7.5064390897750854e-001
267 | <_>
268 |
269 | 0 -1 79 -1 -1 -262145 -1 -252379137 -1 -1 -1
270 |
271 | -8.9446705579757690e-001 7.0268943905830383e-002
272 | <_>
273 |
274 | 0 -1 61 -1 -8201 -1 -2097153 -16777217 -513 -16777217
275 | -1162149889
276 |
277 | -7.2166109085083008e-001 2.9786801338195801e-001
278 | <_>
279 |
280 | 0 -1 30 -21569 -1069121 1006578211 -134238545 -16450
281 | -268599297 -21617 -14680097
282 |
283 | -6.2449234724044800e-001 3.8551881909370422e-001
284 | <_>
285 |
286 | 0 -1 75 -268701913 -1999962377 1995165474 -453316822
287 | 1744684853 -2063597697 -134226057 -50336769
288 |
289 | -5.5207914113998413e-001 4.2211884260177612e-001
290 | <_>
291 |
292 | 0 -1 21 -352321825 -526489 -420020626 -486605074 1155483470
293 | -110104705 -587840772 -25428801
294 |
295 | -5.3324747085571289e-001 4.4535955786705017e-001
296 | <_>
297 |
298 | 0 -1 103 70270772 2012790229 -16810020 -245764 -1208090635
299 | -753667 -1073741828 -1363662420
300 |
301 | -6.4402890205383301e-001 3.8995954394340515e-001
302 |
303 | <_>
304 | 8
305 | -4.6897511482238770e+000
306 |
307 | <_>
308 |
309 | 0 -1 97 -1 -1 -1 -1 -524289 -524289 -1 -1
310 |
311 | -9.9684870243072510e-001 -8.8232177495956421e-001
312 | <_>
313 |
314 | 0 -1 84 -1 -1 -1 -1 2147438591 -1 -1 -1
315 |
316 | -9.8677414655685425e-001 -7.8965580463409424e-001
317 | <_>
318 |
319 | 0 -1 113 -1 -1 -1 -1 -1048577 -262149 -1048577 -35339
320 |
321 | -9.2621946334838867e-001 -2.9984828829765320e-001
322 | <_>
323 |
324 | 0 -1 33 -2249 867434291 -32769 -33562753 -1 -1073758209
325 | -4165 -1
326 |
327 | -7.2429555654525757e-001 2.2348840534687042e-001
328 | <_>
329 |
330 | 0 -1 98 1659068671 -142606337 587132538 -67108993 577718271
331 | -294921 -134479873 -129
332 |
333 | -5.5495566129684448e-001 3.5419258475303650e-001
334 | <_>
335 |
336 | 0 -1 100 -268441813 788267007 -286265494 -486576145 -8920251
337 | 2138505075 -151652570 -2050
338 |
339 | -5.3362584114074707e-001 3.9479774236679077e-001
340 | <_>
341 |
342 | 0 -1 51 -1368387212 -537102978 -98305 -163843 1065109500
343 | -16777217 -67321939 -1141359619
344 |
345 | -5.6162708997726440e-001 3.8008108735084534e-001
346 | <_>
347 |
348 | 0 -1 127 -268435550 1781120906 -251658720 -143130698
349 | -1048605 -1887436825 1979700688 -1008730125
350 |
351 | -5.1167154312133789e-001 4.0678605437278748e-001
352 |
353 | <_>
354 | 10
355 | -4.2179841995239258e+000
356 |
357 | <_>
358 |
359 | 0 -1 97 -1 -1 -1 -1 -524289 -524289 -1 -1
360 |
361 | -9.9685418605804443e-001 -8.8037383556365967e-001
362 | <_>
363 |
364 | 0 -1 90 -1 -1 -1 -1 -8912897 -524297 -8912897 -1
365 |
366 | -9.7972750663757324e-001 -5.7626229524612427e-001
367 | <_>
368 |
369 | 0 -1 96 -1 -1 -1 -1 -1 -65 -1 -2249
370 |
371 | -9.0239793062210083e-001 -1.7454113066196442e-001
372 | <_>
373 |
374 | 0 -1 71 -1 -4097 -1 -513 -16777217 -268468483 -16797697
375 | -1430589697
376 |
377 | -7.4346423149108887e-001 9.4165161252021790e-002
378 | <_>
379 |
380 | 0 -1 37 1364588304 -581845274 -536936460 -3 -308936705
381 | -1074331649 -4196865 -134225953
382 |
383 | -6.8877440690994263e-001 2.7647304534912109e-001
384 | <_>
385 |
386 | 0 -1 117 -37765187 -540675 -3 -327753 -1082458115 -65537
387 | 1071611901 536827253
388 |
389 | -5.7555085420608521e-001 3.4339720010757446e-001
390 | <_>
391 |
392 | 0 -1 85 -269490650 -1561395522 -1343312090 -857083986
393 | -1073750223 -369098755 -50856110 -2065
394 |
395 | -5.4036927223205566e-001 4.0065473318099976e-001
396 | <_>
397 |
398 | 0 -1 4 -425668880 -34427164 1879048177 -269570140 790740912
399 | -196740 2138535839 -536918145
400 |
401 | -4.8439365625381470e-001 4.4630467891693115e-001
402 | <_>
403 |
404 | 0 -1 92 74726960 -1246482434 -1 -246017 -1078607916
405 | -1073947163 -1644231687 -1359211496
406 |
407 | -5.6686979532241821e-001 3.6671569943428040e-001
408 | <_>
409 |
410 | 0 -1 11 -135274809 -1158173459 -353176850 540195262
411 | 2139086600 2071977814 -546898600 -96272673
412 |
413 | -5.1499199867248535e-001 4.0788397192955017e-001
414 |
415 | <_>
416 | 9
417 | -4.0345416069030762e+000
418 |
419 | <_>
420 |
421 | 0 -1 78 -1 -1 -1 -1 -8912897 -1 -8912897 -1
422 |
423 | -9.9573624134063721e-001 -8.5452395677566528e-001
424 | <_>
425 |
426 | 0 -1 93 -1 -1 -1 -1 -148635649 -524297 -8912897 -1
427 |
428 | -9.7307401895523071e-001 -5.2884924411773682e-001
429 | <_>
430 |
431 | 0 -1 77 -1 -8209 -1 -257 -772734977 -1 -201850881 -1
432 |
433 | -8.6225658655166626e-001 4.3712578713893890e-002
434 | <_>
435 |
436 | 0 -1 68 -570427393 -16649 -69633 -131073 -536944677 -1 -8737
437 | -1435828225
438 |
439 | -6.8078064918518066e-001 2.5120577216148376e-001
440 | <_>
441 |
442 | 0 -1 50 -1179697 -34082849 -3278356 -37429266 -1048578
443 | -555753474 -1015551096 -37489685
444 |
445 | -6.1699724197387695e-001 3.0963841080665588e-001
446 | <_>
447 |
448 | 0 -1 129 -1931606992 -17548804 -16842753 -1075021827
449 | 1073667572 -81921 -1611073620 -1415047752
450 |
451 | -6.0499197244644165e-001 3.0735063552856445e-001
452 | <_>
453 |
454 | 0 -1 136 -269754813 1761591286 -1073811523 2130378623 -17580
455 | -1082294665 -159514800 -1026883840
456 |
457 | -5.6772041320800781e-001 3.5023149847984314e-001
458 | <_>
459 |
460 | 0 -1 65 2016561683 1528827871 -10258447 960184191 125476830
461 | -8511618 -1078239365 187648611
462 |
463 | -5.5894804000854492e-001 3.4856522083282471e-001
464 | <_>
465 |
466 | 0 -1 13 -207423502 -333902 2013200231 -202348848 1042454451
467 | -16393 1073117139 2004162321
468 |
469 | -5.7197356224060059e-001 3.2818377017974854e-001
470 |
471 | <_>
472 | 9
473 | -3.4892759323120117e+000
474 |
475 | <_>
476 |
477 | 0 -1 78 -1 -1 -1 -1 -8912897 -1 -8912897 -1
478 |
479 | -9.8917990922927856e-001 -7.3812037706375122e-001
480 | <_>
481 |
482 | 0 -1 93 -1 -1 -1 -1 -148635649 -524297 -8912897 -1
483 |
484 | -9.3414896726608276e-001 -2.6945295929908752e-001
485 | <_>
486 |
487 | 0 -1 83 -1 -524289 -1 -1048577 1879011071 -32769 -524289
488 | -3178753
489 |
490 | -7.6891708374023438e-001 5.2568886429071426e-002
491 | <_>
492 |
493 | 0 -1 9 -352329729 -17891329 -16810117 -486871042 -688128841
494 | -1358954675 -16777218 -219217968
495 |
496 | -6.2337344884872437e-001 2.5143685936927795e-001
497 | <_>
498 |
499 | 0 -1 130 -2157 -1548812374 -1343233440 -418381854 -953155613
500 | -836960513 -713571200 -709888014
501 |
502 | -4.7277018427848816e-001 3.9616456627845764e-001
503 | <_>
504 |
505 | 0 -1 121 -1094717701 -67240065 -65857 -32899 -5783756
506 | -136446081 -134285352 -2003298884
507 |
508 | -5.1766264438629150e-001 3.5814732313156128e-001
509 | <_>
510 |
511 | 0 -1 23 -218830160 -119671186 5505075 1241491391 -1594469
512 | -2097185 2004828075 -67649541
513 |
514 | -6.5394639968872070e-001 3.0377501249313354e-001
515 | <_>
516 |
517 | 0 -1 115 -551814749 2099511088 -1090732551 -2045546512
518 | -1086341441 1059848178 800042912 252705994
519 |
520 | -5.2584588527679443e-001 3.3847147226333618e-001
521 | <_>
522 |
523 | 0 -1 99 -272651477 578776766 -285233490 -889225217
524 | 2147448656 377454463 2012701952 -68157761
525 |
526 | -6.1836904287338257e-001 2.8922611474990845e-001
527 |
528 | <_>
529 | 9
530 | -3.0220029354095459e+000
531 |
532 | <_>
533 |
534 | 0 -1 36 -1 -570425345 -1 -570425345 -1 -50331649 -6291457 -1
535 |
536 | -9.7703826427459717e-001 -6.2527233362197876e-001
537 | <_>
538 |
539 | 0 -1 124 -1430602241 -33619969 -1 -3 -1074003969 -1073758209
540 | -1073741825 -1073768705
541 |
542 | -8.9538317918777466e-001 -3.1887885928153992e-001
543 | <_>
544 |
545 | 0 -1 88 -1 -268439625 -65601 -268439569 -393809 -270532609
546 | -42076889 -288361721
547 |
548 | -6.8733429908752441e-001 1.2978810071945190e-001
549 | <_>
550 |
551 | 0 -1 132 -755049252 2042563807 1795096575 465121071
552 | -1090585188 -20609 -1459691784 539672495
553 |
554 | -5.7038843631744385e-001 3.0220884084701538e-001
555 | <_>
556 |
557 | 0 -1 20 -94377762 -25702678 1694167798 -231224662 1079955016
558 | -346144140 2029995743 -536918961
559 |
560 | -5.3204691410064697e-001 3.4054222702980042e-001
561 | <_>
562 |
563 | 0 -1 47 2143026943 -285278225 -3 -612438281 -16403 -131074
564 | -1 -1430749256
565 |
566 | -4.6176829934120178e-001 4.1114711761474609e-001
567 | <_>
568 |
569 | 0 -1 74 203424336 -25378820 -35667973 1073360894 -1912815660
570 | -573444 -356583491 -1365235056
571 |
572 | -4.9911966919898987e-001 3.5335537791252136e-001
573 | <_>
574 |
575 | 0 -1 6 -1056773 -1508430 -558153 -102747408 2133997491
576 | -269043865 2004842231 -8947721
577 |
578 | -4.0219521522521973e-001 4.3947893381118774e-001
579 | <_>
580 |
581 | 0 -1 70 -880809694 -1070282769 -1363162108 -838881281
582 | -680395161 -2064124929 -34244753 1173880701
583 |
584 | -5.3891533613204956e-001 3.2062566280364990e-001
585 |
586 | <_>
587 | 8
588 | -2.5489892959594727e+000
589 |
590 | <_>
591 |
592 | 0 -1 39 -1 -572522497 -8519681 -570425345 -4195329 -50333249
593 | -1 -1
594 |
595 | -9.4647216796875000e-001 -3.3662387728691101e-001
596 | <_>
597 |
598 | 0 -1 124 -1430735362 -33619971 -8201 -3 -1677983745
599 | -1073762817 -1074003969 -1142979329
600 |
601 | -8.0300611257553101e-001 -3.8466516882181168e-002
602 | <_>
603 |
604 | 0 -1 91 -67113217 -524289 -671482265 -786461 1677132031
605 | -268473345 -68005889 -70291765
606 |
607 | -5.8367580175399780e-001 2.6507318019866943e-001
608 | <_>
609 |
610 | 0 -1 17 -277872641 -553910292 -268435458 -16843010
611 | 1542420439 -1342178311 -143132940 -2834
612 |
613 | -4.6897178888320923e-001 3.7864661216735840e-001
614 | <_>
615 |
616 | 0 -1 137 -1312789 -290527285 -286326862 -5505280 -1712335966
617 | -2045979188 1165423617 -709363723
618 |
619 | -4.6382644772529602e-001 3.6114525794982910e-001
620 | <_>
621 |
622 | 0 -1 106 1355856590 -109445156 -96665606 2066939898
623 | 1356084692 1549031917 -30146561 -16581701
624 |
625 | -6.3095021247863770e-001 2.9294869303703308e-001
626 | <_>
627 |
628 | 0 -1 104 -335555328 118529 1860167712 -810680357 -33558656
629 | -1368391795 -402663552 -1343225921
630 |
631 | -5.9658926725387573e-001 2.7228885889053345e-001
632 | <_>
633 |
634 | 0 -1 76 217581168 -538349634 1062631419 1039868926
635 | -1090707460 -2228359 -1078042693 -1147128518
636 |
637 | -4.5812287926673889e-001 3.7063929438591003e-001
638 |
639 | <_>
640 | 9
641 | -2.5802578926086426e+000
642 |
643 | <_>
644 |
645 | 0 -1 35 -513 -706873891 -270541825 1564475391 -120602625
646 | -118490145 -3162113 -1025
647 |
648 | -8.9068460464477539e-001 -1.6470588743686676e-001
649 | <_>
650 |
651 | 0 -1 41 -1025 872144563 -2105361 -1078076417 -1048577
652 | -1145061461 -87557413 -1375993973
653 |
654 | -7.1808964014053345e-001 2.2022204473614693e-002
655 | <_>
656 |
657 | 0 -1 95 -42467849 967946223 -811601986 1030598351
658 | -1212430676 270856533 -1392539508 147705039
659 |
660 | -4.9424821138381958e-001 3.0048963427543640e-001
661 | <_>
662 |
663 | 0 -1 10 -218116370 -637284625 -87373174 -521998782
664 | -805355450 -615023745 -814267322 -12069282
665 |
666 | -5.5306458473205566e-001 2.9137542843818665e-001
667 | <_>
668 |
669 | 0 -1 105 -275849241 -527897 -11052049 -69756067 -15794193
670 | -1141376839 -564771 -287095455
671 |
672 | -4.6759819984436035e-001 3.6638516187667847e-001
673 | <_>
674 |
675 | 0 -1 24 -1900898096 -18985228 -44056577 -24675 -1074880639
676 | -283998 796335613 -1079041957
677 |
678 | -4.2737138271331787e-001 3.9243003726005554e-001
679 | <_>
680 |
681 | 0 -1 139 -555790844 410735094 -32106513 406822863 -897632192
682 | -912830145 -117771560 -1204027649
683 |
684 | -4.1896930336952209e-001 3.6744937300682068e-001
685 | <_>
686 |
687 | 0 -1 0 -1884822366 -1406613148 1135342180 -1979127580
688 | -68174862 246469804 1001386992 -708885872
689 |
690 | -5.7093089818954468e-001 2.9880744218826294e-001
691 | <_>
692 |
693 | 0 -1 45 -469053950 1439068142 2117758841 2004671078
694 | 207931006 1265321675 970353931 1541343047
695 |
696 | -6.0491901636123657e-001 2.4652053415775299e-001
697 |
698 | <_>
699 | 9
700 | -2.2425732612609863e+000
701 |
702 | <_>
703 |
704 | 0 -1 58 1481987157 282547485 -14952129 421131223 -391065352
705 | -24212488 -100094241 -1157907473
706 |
707 | -8.2822084426879883e-001 -2.1619293093681335e-001
708 | <_>
709 |
710 | 0 -1 126 -134217889 -543174305 -75497474 -16851650 -6685738
711 | -75834693 -2097200 -262146
712 |
713 | -5.4628932476043701e-001 2.7662658691406250e-001
714 | <_>
715 |
716 | 0 -1 133 -220728227 -604288517 -661662214 413104863
717 | -627323700 -251915415 -626200872 -1157958657
718 |
719 | -4.1643124818801880e-001 4.1700571775436401e-001
720 | <_>
721 |
722 | 0 -1 2 -186664033 -44236961 -1630262774 -65163606 -103237330
723 | -3083265 -1003729 2053105955
724 |
725 | -5.4847818613052368e-001 2.9710745811462402e-001
726 | <_>
727 |
728 | 0 -1 62 -256115886 -237611873 -620250696 387061799
729 | 1437882671 274878849 -8684449 1494294023
730 |
731 | -4.6202757954597473e-001 3.3915829658508301e-001
732 | <_>
733 |
734 | 0 -1 1 -309400577 -275864640 -1056864869 1737132756
735 | -272385089 1609671419 1740601343 1261376789
736 |
737 | -4.6158722043037415e-001 3.3939516544342041e-001
738 | <_>
739 |
740 | 0 -1 102 818197248 -196324552 286970589 -573270699
741 | -1174099579 -662077381 -1165157895 -1626859296
742 |
743 | -4.6193107962608337e-001 3.2456985116004944e-001
744 | <_>
745 |
746 | 0 -1 69 -1042550357 14675409 1367955200 -841482753
747 | 1642443255 8774277 1941304147 1099949563
748 |
749 | -4.9091196060180664e-001 3.3870378136634827e-001
750 | <_>
751 |
752 | 0 -1 72 -639654997 1375720439 -2129542805 1614801090
753 | -626787937 -5779294 1488699183 -525406458
754 |
755 | -4.9073097109794617e-001 3.0637946724891663e-001
756 |
757 | <_>
758 | 9
759 | -1.2258235216140747e+000
760 |
761 | <_>
762 |
763 | 0 -1 118 302046707 -16744240 1360106207 -543735387
764 | 1025700851 -1079408512 1796961263 -6334981
765 |
766 | -6.1358314752578735e-001 2.3539231717586517e-001
767 | <_>
768 |
769 | 0 -1 5 -144765953 -116448726 -653851877 1934829856 722021887
770 | 856564834 1933919231 -540838029
771 |
772 | -5.1209545135498047e-001 3.2506987452507019e-001
773 | <_>
774 |
775 | 0 -1 140 -170132825 -1438923874 1879300370 -1689337194
776 | -695606496 285911565 -1044188928 -154210028
777 |
778 | -5.1769560575485229e-001 3.2290914654731750e-001
779 | <_>
780 |
781 | 0 -1 131 -140776261 -355516414 822178224 -1039743806
782 | -1012208926 134887424 1438876097 -908591660
783 |
784 | -5.0321841239929199e-001 3.0263835191726685e-001
785 | <_>
786 |
787 | 0 -1 64 -2137211696 -1634281249 1464325973 498569935
788 | -1580152080 -2001687927 721783561 265096035
789 |
790 | -4.6532225608825684e-001 3.4638473391532898e-001
791 | <_>
792 |
793 | 0 -1 101 -255073589 -211824417 -972195129 -1063415417
794 | 1937994261 1363165220 -754733105 1967602541
795 |
796 | -4.9611270427703857e-001 3.3260712027549744e-001
797 | <_>
798 |
799 | 0 -1 81 -548146862 -655567194 -2062466596 1164562721
800 | 416408236 -1591631712 -83637777 975344427
801 |
802 | -4.9862930178642273e-001 3.2003280520439148e-001
803 | <_>
804 |
805 | 0 -1 55 -731904652 2147179896 2147442687 2112830847 -65604
806 | -131073 -42139667 -1074907393
807 |
808 | -3.6636069416999817e-001 4.5651626586914063e-001
809 | <_>
810 |
811 | 0 -1 67 1885036886 571985932 -1784930633 724431327
812 | 1940422257 -1085746880 964888398 731867951
813 |
814 | -5.2619713544845581e-001 3.2635414600372314e-001
815 |
816 | <_>
817 | 9
818 | -1.3604533672332764e+000
819 |
820 | <_>
821 |
822 | 0 -1 8 -287609985 -965585953 -2146397793 -492129894
823 | -729029645 -544619901 -645693256 -6565484
824 |
825 | -4.5212322473526001e-001 3.8910505175590515e-001
826 | <_>
827 |
828 | 0 -1 122 -102903523 -145031013 536899675 688195859
829 | -645291520 -1165359094 -905565928 171608223
830 |
831 | -4.9594074487686157e-001 3.4109055995941162e-001
832 | <_>
833 |
834 | 0 -1 134 -790640459 487931983 1778450522 1036604041
835 | -904752984 -954040118 -2134707506 304866043
836 |
837 | -4.1148442029953003e-001 3.9666590094566345e-001
838 | <_>
839 |
840 | 0 -1 141 -303829117 1726939070 922189815 -827983123
841 | 1567883042 1324809852 292710260 -942678754
842 |
843 | -3.5154473781585693e-001 4.8011952638626099e-001
844 | <_>
845 |
846 | 0 -1 59 -161295376 -159215460 -1858041315 2140644499
847 | -2009065472 -133804007 -2003265301 1263206851
848 |
849 | -4.2808216810226440e-001 3.9841541647911072e-001
850 | <_>
851 |
852 | 0 -1 34 -264248081 -667846464 1342624856 1381160835
853 | -2104716852 1342865409 -266612310 -165954877
854 |
855 | -4.3293288350105286e-001 4.0339657664299011e-001
856 | <_>
857 |
858 | 0 -1 32 -1600388464 -40369901 285344639 1394344275
859 | -255680312 -100532214 -1031663944 -7471079
860 |
861 | -4.1385015845298767e-001 4.5087572932243347e-001
862 | <_>
863 |
864 | 0 -1 15 1368521651 280207469 35779199 -105983261 1208124819
865 | -565870452 -1144024288 -591535344
866 |
867 | -4.2956474423408508e-001 4.2176279425621033e-001
868 | <_>
869 |
870 | 0 -1 109 1623607527 -661513115 -1073217263 -2142994420
871 | -1339883309 -89816956 436308899 1426178059
872 |
873 | -4.7764992713928223e-001 3.7551075220108032e-001
874 |
875 | <_>
876 | 9
877 | -4.2518746852874756e-001
878 |
879 | <_>
880 |
881 | 0 -1 135 -116728032 -1154420809 -1350582273 746061691
882 | -1073758277 2138570623 2113797566 -138674182
883 |
884 | -1.7125381529331207e-001 6.5421247482299805e-001
885 | <_>
886 |
887 | 0 -1 63 -453112432 -1795354691 -1342242964 494112553
888 | 209458404 -2114697500 1316830362 259213855
889 |
890 | -3.9870172739028931e-001 4.5807033777236938e-001
891 | <_>
892 |
893 | 0 -1 52 -268172036 294715533 268575185 486785157 -1065303920
894 | -360185856 -2147476808 134777113
895 |
896 | -5.3581339120864868e-001 3.5815808176994324e-001
897 | <_>
898 |
899 | 0 -1 86 -301996882 -345718921 1877946252 -940720129
900 | -58737369 -721944585 -92954835 -530449
901 |
902 | -3.9938014745712280e-001 4.9603295326232910e-001
903 | <_>
904 |
905 | 0 -1 14 -853281886 -756895766 2130706352 -9519120
906 | -1921059862 394133373 2138453959 -538200841
907 |
908 | -4.0230083465576172e-001 4.9537116289138794e-001
909 | <_>
910 |
911 | 0 -1 128 -2133448688 -641138493 1078022185 294060066
912 | -327122776 -2130640896 -2147466247 -1910634326
913 |
914 | -5.8290809392929077e-001 3.4102553129196167e-001
915 | <_>
916 |
917 | 0 -1 53 587265978 -2071658479 1108361221 -578448765
918 | -1811905899 -2008965119 33900729 762301595
919 |
920 | -4.5518967509269714e-001 4.7242793440818787e-001
921 | <_>
922 |
923 | 0 -1 138 -1022189373 -2139094976 16658 -1069445120
924 | -1073555454 -1073577856 1096068 -978351488
925 |
926 | -4.7530207037925720e-001 4.3885371088981628e-001
927 | <_>
928 |
929 | 0 -1 7 -395352441 -1073541103 -1056964605 1053186 269111298
930 | -2012184576 1611208714 -360415095
931 |
932 | -5.0448113679885864e-001 4.1588482260704041e-001
933 |
934 | <_>
935 | 7
936 | 2.7163455262780190e-002
937 |
938 | <_>
939 |
940 | 0 -1 49 783189748 -137429026 -257 709557994 2130460236
941 | -196611 -9580 585428708
942 |
943 | -2.0454545319080353e-001 7.9608374834060669e-001
944 | <_>
945 |
946 | 0 -1 108 1284360448 1057423155 1592696573 -852672655
947 | 1547382714 -1642594369 125705358 797134398
948 |
949 | -3.6474677920341492e-001 6.0925579071044922e-001
950 | <_>
951 |
952 | 0 -1 94 1347680270 -527720448 1091567712 1073745933
953 | -1073180671 0 285745154 -511192438
954 |
955 | -4.6406838297843933e-001 5.5626088380813599e-001
956 | <_>
957 |
958 | 0 -1 73 1705780944 -145486260 -115909 -281793505 -418072663
959 | -1681064068 1877454127 -1912330993
960 |
961 | -4.7043186426162720e-001 5.8430361747741699e-001
962 | <_>
963 |
964 | 0 -1 110 -2118142016 339509033 -285260567 1417764573
965 | 68144392 -468879483 -2033291636 231451911
966 |
967 | -4.8700931668281555e-001 5.4639810323715210e-001
968 | <_>
969 |
970 | 0 -1 119 -1888051818 489996135 -65539 849536890 2146716845
971 | -1107542088 -1275615746 -1119617586
972 |
973 | -4.3356490135192871e-001 6.5175366401672363e-001
974 | <_>
975 |
976 | 0 -1 44 -1879021438 336830528 1073766659 1477541961 8560696
977 | -1207369568 8462472 1493893448
978 |
979 | -5.4343086481094360e-001 5.2777874469757080e-001
980 |
981 | <_>
982 | 7
983 | 4.9174150824546814e-001
984 |
985 | <_>
986 |
987 | 0 -1 57 644098 15758324 1995964260 -463011882 893285175
988 | 83156983 2004317989 16021237
989 |
990 | -1.7073170840740204e-001 9.0782123804092407e-001
991 | <_>
992 |
993 | 0 -1 123 268632845 -2147450864 -2143240192 -2147401728
994 | 8523937 -1878523840 16777416 616824984
995 |
996 | -4.8744434118270874e-001 7.3311311006546021e-001
997 | <_>
998 |
999 | 0 -1 120 -2110735872 803880886 989739810 1673281312 91564930
1000 | -277454958 997709514 -581366443
1001 |
1002 | -4.0291741490364075e-001 8.2450771331787109e-001
1003 | <_>
1004 |
1005 | 0 -1 87 941753434 -1067128905 788512753 -1074450460
1006 | 779101657 -1346552460 938805167 -2050424642
1007 |
1008 | -3.6246949434280396e-001 8.7103593349456787e-001
1009 | <_>
1010 |
1011 | 0 -1 60 208 1645217920 130 538263552 33595552 -1475870592
1012 | 16783361 1375993867
1013 |
1014 | -6.1472141742706299e-001 5.9707164764404297e-001
1015 | <_>
1016 |
1017 | 0 -1 114 1860423179 1034692624 -285213187 -986681712
1018 | 1576755092 -1408205463 -127714 -1246035687
1019 |
1020 | -4.5621752738952637e-001 8.9482426643371582e-001
1021 | <_>
1022 |
1023 | 0 -1 107 33555004 -1861746688 1073807361 -754909184
1024 | 645922856 8388608 134250648 419635458
1025 |
1026 | -5.2466005086898804e-001 7.1834069490432739e-001
1027 |
1028 | <_>
1029 | 2
1030 | 1.9084988832473755e+000
1031 |
1032 | <_>
1033 |
1034 | 0 -1 16 536064 131072 -20971516 524288 576 1048577 0 40960
1035 |
1036 | -8.0000001192092896e-001 9.8018401861190796e-001
1037 | <_>
1038 |
1039 | 0 -1 56 67108864 0 4096 1074003968 8192 536870912 4 262144
1040 |
1041 | -9.6610915660858154e-001 9.2831486463546753e-001
1042 |
1043 | <_>
1044 |
1045 | 0 0 1 1
1046 | <_>
1047 |
1048 | 0 0 3 2
1049 | <_>
1050 |
1051 | 0 1 13 6
1052 | <_>
1053 |
1054 | 0 2 3 14
1055 | <_>
1056 |
1057 | 0 2 4 2
1058 | <_>
1059 |
1060 | 0 6 2 3
1061 | <_>
1062 |
1063 | 0 6 3 2
1064 | <_>
1065 |
1066 | 0 16 1 3
1067 | <_>
1068 |
1069 | 0 20 3 3
1070 | <_>
1071 |
1072 | 0 22 2 3
1073 | <_>
1074 |
1075 | 0 28 4 4
1076 | <_>
1077 |
1078 | 0 35 2 3
1079 | <_>
1080 |
1081 | 1 0 14 7
1082 | <_>
1083 |
1084 | 1 5 3 2
1085 | <_>
1086 |
1087 | 1 6 2 1
1088 | <_>
1089 |
1090 | 1 14 10 9
1091 | <_>
1092 |
1093 | 1 21 4 4
1094 | <_>
1095 |
1096 | 1 23 4 2
1097 | <_>
1098 |
1099 | 2 0 13 7
1100 | <_>
1101 |
1102 | 2 0 14 7
1103 | <_>
1104 |
1105 | 2 33 5 4
1106 | <_>
1107 |
1108 | 2 36 4 3
1109 | <_>
1110 |
1111 | 2 39 3 2
1112 | <_>
1113 |
1114 | 3 1 13 11
1115 | <_>
1116 |
1117 | 3 2 3 2
1118 | <_>
1119 |
1120 | 4 0 7 8
1121 | <_>
1122 |
1123 | 4 0 13 7
1124 | <_>
1125 |
1126 | 5 0 12 6
1127 | <_>
1128 |
1129 | 5 0 13 7
1130 | <_>
1131 |
1132 | 5 1 10 13
1133 | <_>
1134 |
1135 | 5 1 12 7
1136 | <_>
1137 |
1138 | 5 2 7 13
1139 | <_>
1140 |
1141 | 5 4 2 1
1142 | <_>
1143 |
1144 | 5 8 7 4
1145 | <_>
1146 |
1147 | 5 39 3 2
1148 | <_>
1149 |
1150 | 6 3 5 2
1151 | <_>
1152 |
1153 | 6 3 6 2
1154 | <_>
1155 |
1156 | 6 5 4 12
1157 | <_>
1158 |
1159 | 6 9 6 3
1160 | <_>
1161 |
1162 | 7 3 5 2
1163 | <_>
1164 |
1165 | 7 3 6 13
1166 | <_>
1167 |
1168 | 7 5 6 4
1169 | <_>
1170 |
1171 | 7 7 6 10
1172 | <_>
1173 |
1174 | 7 8 6 4
1175 | <_>
1176 |
1177 | 7 32 5 4
1178 | <_>
1179 |
1180 | 7 33 5 4
1181 | <_>
1182 |
1183 | 8 0 1 1
1184 | <_>
1185 |
1186 | 8 0 2 1
1187 | <_>
1188 |
1189 | 8 2 10 7
1190 | <_>
1191 |
1192 | 9 0 6 2
1193 | <_>
1194 |
1195 | 9 2 9 3
1196 | <_>
1197 |
1198 | 9 4 1 1
1199 | <_>
1200 |
1201 | 9 6 2 1
1202 | <_>
1203 |
1204 | 9 28 6 4
1205 | <_>
1206 |
1207 | 10 0 9 3
1208 | <_>
1209 |
1210 | 10 3 1 1
1211 | <_>
1212 |
1213 | 10 10 11 11
1214 | <_>
1215 |
1216 | 10 15 4 3
1217 | <_>
1218 |
1219 | 11 4 2 1
1220 | <_>
1221 |
1222 | 11 27 4 3
1223 | <_>
1224 |
1225 | 11 36 8 2
1226 | <_>
1227 |
1228 | 12 0 2 2
1229 | <_>
1230 |
1231 | 12 23 4 3
1232 | <_>
1233 |
1234 | 12 25 4 3
1235 | <_>
1236 |
1237 | 12 29 5 3
1238 | <_>
1239 |
1240 | 12 33 3 4
1241 | <_>
1242 |
1243 | 13 0 2 2
1244 | <_>
1245 |
1246 | 13 36 8 3
1247 | <_>
1248 |
1249 | 14 0 2 2
1250 | <_>
1251 |
1252 | 15 15 2 2
1253 | <_>
1254 |
1255 | 16 13 3 4
1256 | <_>
1257 |
1258 | 17 0 1 3
1259 | <_>
1260 |
1261 | 17 1 3 3
1262 | <_>
1263 |
1264 | 17 31 5 3
1265 | <_>
1266 |
1267 | 17 35 3 1
1268 | <_>
1269 |
1270 | 18 13 2 3
1271 | <_>
1272 |
1273 | 18 39 2 1
1274 | <_>
1275 |
1276 | 19 0 7 15
1277 | <_>
1278 |
1279 | 19 2 7 2
1280 | <_>
1281 |
1282 | 19 3 7 13
1283 | <_>
1284 |
1285 | 19 14 2 2
1286 | <_>
1287 |
1288 | 19 24 7 4
1289 | <_>
1290 |
1291 | 20 1 6 13
1292 | <_>
1293 |
1294 | 20 8 7 3
1295 | <_>
1296 |
1297 | 20 9 7 3
1298 | <_>
1299 |
1300 | 20 13 1 1
1301 | <_>
1302 |
1303 | 20 14 2 3
1304 | <_>
1305 |
1306 | 20 30 3 2
1307 | <_>
1308 |
1309 | 21 0 3 4
1310 | <_>
1311 |
1312 | 21 0 6 8
1313 | <_>
1314 |
1315 | 21 3 6 2
1316 | <_>
1317 |
1318 | 21 6 6 4
1319 | <_>
1320 |
1321 | 21 37 2 1
1322 | <_>
1323 |
1324 | 22 3 6 2
1325 | <_>
1326 |
1327 | 22 13 1 2
1328 | <_>
1329 |
1330 | 22 22 4 3
1331 | <_>
1332 |
1333 | 23 0 2 3
1334 | <_>
1335 |
1336 | 23 3 6 2
1337 | <_>
1338 |
1339 | 23 9 5 4
1340 | <_>
1341 |
1342 | 23 11 1 1
1343 | <_>
1344 |
1345 | 23 15 1 1
1346 | <_>
1347 |
1348 | 23 16 3 2
1349 | <_>
1350 |
1351 | 23 35 2 1
1352 | <_>
1353 |
1354 | 23 36 1 1
1355 | <_>
1356 |
1357 | 23 39 6 2
1358 | <_>
1359 |
1360 | 24 0 2 3
1361 | <_>
1362 |
1363 | 24 8 6 11
1364 | <_>
1365 |
1366 | 24 28 2 2
1367 | <_>
1368 |
1369 | 24 33 4 4
1370 | <_>
1371 |
1372 | 25 16 4 3
1373 | <_>
1374 |
1375 | 25 31 5 3
1376 | <_>
1377 |
1378 | 26 0 1 2
1379 | <_>
1380 |
1381 | 26 0 2 2
1382 | <_>
1383 |
1384 | 26 0 3 2
1385 | <_>
1386 |
1387 | 26 24 4 4
1388 | <_>
1389 |
1390 | 27 30 4 5
1391 | <_>
1392 |
1393 | 27 36 5 3
1394 | <_>
1395 |
1396 | 28 0 2 2
1397 | <_>
1398 |
1399 | 28 4 2 1
1400 | <_>
1401 |
1402 | 28 21 2 5
1403 | <_>
1404 |
1405 | 29 8 2 1
1406 | <_>
1407 |
1408 | 33 0 2 1
1409 | <_>
1410 |
1411 | 33 0 4 2
1412 | <_>
1413 |
1414 | 33 0 4 6
1415 | <_>
1416 |
1417 | 33 3 1 1
1418 | <_>
1419 |
1420 | 33 6 4 12
1421 | <_>
1422 |
1423 | 33 21 4 2
1424 | <_>
1425 |
1426 | 33 36 4 3
1427 | <_>
1428 |
1429 | 35 1 2 2
1430 | <_>
1431 |
1432 | 36 5 1 1
1433 | <_>
1434 |
1435 | 36 29 3 4
1436 | <_>
1437 |
1438 | 36 39 2 2
1439 | <_>
1440 |
1441 | 37 5 2 2
1442 | <_>
1443 |
1444 | 38 6 2 1
1445 | <_>
1446 |
1447 | 38 6 2 2
1448 | <_>
1449 |
1450 | 39 1 2 12
1451 | <_>
1452 |
1453 | 39 24 1 2
1454 | <_>
1455 |
1456 | 39 36 2 2
1457 | <_>
1458 |
1459 | 40 39 1 2
1460 | <_>
1461 |
1462 | 42 4 1 1
1463 | <_>
1464 |
1465 | 42 20 1 2
1466 | <_>
1467 |
1468 | 42 29 1 2
1469 |
1470 |
--------------------------------------------------------------------------------
/models/eyenet.py:
--------------------------------------------------------------------------------
1 | import torch
2 | from torch import nn
3 | from models.layers import Conv, Hourglass, Pool, Residual
4 | from models.losses import HeatmapLoss
5 | from util.softargmax import softargmax2d
6 |
7 |
8 | class Merge(nn.Module):
9 | def __init__(self, x_dim, y_dim):
10 | super(Merge, self).__init__()
11 | self.conv = Conv(x_dim, y_dim, 1, relu=False, bn=False)
12 |
13 | def forward(self, x):
14 | return self.conv(x)
15 |
16 |
17 | class EyeNet(nn.Module):
18 | def __init__(self, nstack, nfeatures, nlandmarks, bn=False, increase=0, **kwargs):
19 | super(EyeNet, self).__init__()
20 |
21 | self.img_w = 160
22 | self.img_h = 96
23 | self.nstack = nstack
24 | self.nfeatures = nfeatures
25 | self.nlandmarks = nlandmarks
26 |
27 | self.heatmap_w = self.img_w / 2
28 | self.heatmap_h = self.img_h / 2
29 |
30 | self.nstack = nstack
31 | self.pre = nn.Sequential(
32 | Conv(1, 64, 7, 1, bn=True, relu=True),
33 | Residual(64, 128),
34 | Pool(2, 2),
35 | Residual(128, 128),
36 | Residual(128, nfeatures)
37 | )
38 |
39 | self.pre2 = nn.Sequential(
40 | Conv(nfeatures, 64, 7, 2, bn=True, relu=True),
41 | Residual(64, 128),
42 | Pool(2, 2),
43 | Residual(128, 128),
44 | Residual(128, nfeatures)
45 | )
46 |
47 | self.hgs = nn.ModuleList([
48 | nn.Sequential(
49 | Hourglass(4, nfeatures, bn, increase),
50 | ) for i in range(nstack)])
51 |
52 | self.features = nn.ModuleList([
53 | nn.Sequential(
54 | Residual(nfeatures, nfeatures),
55 | Conv(nfeatures, nfeatures, 1, bn=True, relu=True)
56 | ) for i in range(nstack)])
57 |
58 | self.outs = nn.ModuleList([Conv(nfeatures, nlandmarks, 1, relu=False, bn=False) for i in range(nstack)])
59 | self.merge_features = nn.ModuleList([Merge(nfeatures, nfeatures) for i in range(nstack - 1)])
60 | self.merge_preds = nn.ModuleList([Merge(nlandmarks, nfeatures) for i in range(nstack - 1)])
61 |
62 | self.gaze_fc1 = nn.Linear(in_features=int(nfeatures * self.img_w * self.img_h / 64 + nlandmarks*2), out_features=256)
63 | self.gaze_fc2 = nn.Linear(in_features=256, out_features=2)
64 |
65 | self.nstack = nstack
66 | self.heatmapLoss = HeatmapLoss()
67 | self.landmarks_loss = nn.MSELoss()
68 | self.gaze_loss = nn.MSELoss()
69 |
70 | def forward(self, imgs):
71 | # imgs of size 1,ih,iw
72 | x = imgs.unsqueeze(1)
73 | x = self.pre(x)
74 |
75 | gaze_x = self.pre2(x)
76 | gaze_x = gaze_x.flatten(start_dim=1)
77 |
78 | combined_hm_preds = []
79 | for i in torch.arange(self.nstack):
80 | hg = self.hgs[i](x)
81 | feature = self.features[i](hg)
82 | preds = self.outs[i](feature)
83 | combined_hm_preds.append(preds)
84 | if i < self.nstack - 1:
85 | x = x + self.merge_preds[i](preds) + self.merge_features[i](feature)
86 |
87 | heatmaps_out = torch.stack(combined_hm_preds, 1)
88 |
89 | # preds = N x nlandmarks * heatmap_w * heatmap_h
90 | landmarks_out = softargmax2d(preds) # N x nlandmarks x 2
91 |
92 | # Gaze
93 | gaze = torch.cat((gaze_x, landmarks_out.flatten(start_dim=1)), dim=1)
94 | gaze = self.gaze_fc1(gaze)
95 | gaze = nn.functional.relu(gaze)
96 | gaze = self.gaze_fc2(gaze)
97 |
98 | return heatmaps_out, landmarks_out, gaze
99 |
100 | def calc_loss(self, combined_hm_preds, heatmaps, landmarks_pred, landmarks, gaze_pred, gaze):
101 | combined_loss = []
102 | for i in range(self.nstack):
103 | combined_loss.append(self.heatmapLoss(combined_hm_preds[:, i, :], heatmaps))
104 |
105 | heatmap_loss = torch.stack(combined_loss, dim=1)
106 | landmarks_loss = self.landmarks_loss(landmarks_pred, landmarks)
107 | gaze_loss = self.gaze_loss(gaze_pred, gaze)
108 |
109 | return torch.sum(heatmap_loss), landmarks_loss, 1000 * gaze_loss
110 |
--------------------------------------------------------------------------------
/models/layers.py:
--------------------------------------------------------------------------------
1 | from torch import nn
2 |
3 | Pool = nn.MaxPool2d
4 |
5 |
6 | def batchnorm(x):
7 | return nn.BatchNorm2d(x.size()[1])(x)
8 |
9 |
10 | class Conv(nn.Module):
11 | def __init__(self, inp_dim, out_dim, kernel_size=3, stride = 1, bn = False, relu = True):
12 | super(Conv, self).__init__()
13 | self.inp_dim = inp_dim
14 | self.conv = nn.Conv2d(inp_dim, out_dim, kernel_size, stride, padding=(kernel_size-1)//2, bias=True)
15 | self.relu = None
16 | self.bn = None
17 | if relu:
18 | self.relu = nn.ReLU()
19 | if bn:
20 | self.bn = nn.BatchNorm2d(out_dim)
21 |
22 | def forward(self, x):
23 | assert x.size()[1] == self.inp_dim, "{} {}".format(x.size()[1], self.inp_dim)
24 | x = self.conv(x)
25 | if self.bn is not None:
26 | x = self.bn(x)
27 | if self.relu is not None:
28 | x = self.relu(x)
29 | return x
30 |
31 |
32 | class Residual(nn.Module):
33 | def __init__(self, inp_dim, out_dim):
34 | super(Residual, self).__init__()
35 | self.relu = nn.ReLU()
36 | self.bn1 = nn.BatchNorm2d(inp_dim)
37 | self.conv1 = Conv(inp_dim, int(out_dim/2), 1, relu=False)
38 | self.bn2 = nn.BatchNorm2d(int(out_dim/2))
39 | self.conv2 = Conv(int(out_dim/2), int(out_dim/2), 3, relu=False)
40 | self.bn3 = nn.BatchNorm2d(int(out_dim/2))
41 | self.conv3 = Conv(int(out_dim/2), out_dim, 1, relu=False)
42 | self.skip_layer = Conv(inp_dim, out_dim, 1, relu=False)
43 | if inp_dim == out_dim:
44 | self.need_skip = False
45 | else:
46 | self.need_skip = True
47 |
48 | def forward(self, x):
49 | if self.need_skip:
50 | residual = self.skip_layer(x)
51 | else:
52 | residual = x
53 | out = self.bn1(x)
54 | out = self.relu(out)
55 | out = self.conv1(out)
56 | out = self.bn2(out)
57 | out = self.relu(out)
58 | out = self.conv2(out)
59 | out = self.bn3(out)
60 | out = self.relu(out)
61 | out = self.conv3(out)
62 | out += residual
63 | return out
64 |
65 |
66 | class Hourglass(nn.Module):
67 | def __init__(self, n, f, bn=None, increase=0):
68 | super(Hourglass, self).__init__()
69 | nf = f + increase
70 | self.up1 = Residual(f, f)
71 | # Lower branch
72 | self.pool1 = Pool(2, 2)
73 | self.low1 = Residual(f, nf)
74 | self.n = n
75 | # Recursive hourglass
76 | if self.n > 1:
77 | self.low2 = Hourglass(n-1, nf, bn=bn)
78 | else:
79 | self.low2 = Residual(nf, nf)
80 | self.low3 = Residual(nf, f)
81 |
82 | def forward(self, x):
83 | up1 = self.up1(x)
84 | pool1 = self.pool1(x)
85 | low1 = self.low1(pool1)
86 | low2 = self.low2(low1)
87 | low3 = self.low3(low2)
88 | up2 = nn.functional.interpolate(low3, x.shape[2:], mode='bilinear')
89 | return up1 + up2
90 |
--------------------------------------------------------------------------------
/models/losses.py:
--------------------------------------------------------------------------------
1 | import torch
2 |
3 |
4 | class HeatmapLoss(torch.nn.Module):
5 | def __init__(self):
6 | super(HeatmapLoss, self).__init__()
7 |
8 | def forward(self, pred, gt):
9 | loss = ((pred - gt)**2)
10 | loss = torch.mean(loss, dim=(1, 2, 3))
11 | return loss
12 |
13 |
14 | class AngularError(torch.nn.Module):
15 | def __init__(self):
16 | super(AngularError, self).__init__()
17 |
18 | def forward(self, gaze_pred, gaze):
19 | loss = ((gaze_pred - gaze)**2)
20 | loss = torch.mean(loss, dim=(1, 2, 3))
21 | return loss
22 |
--------------------------------------------------------------------------------
/notebooks/check_preprocessing.ipynb:
--------------------------------------------------------------------------------
1 | {
2 | "cells": [
3 | {
4 | "cell_type": "code",
5 | "execution_count": 2,
6 | "metadata": {},
7 | "outputs": [],
8 | "source": [
9 | "import sys\n",
10 | "import os\n",
11 | "module_path = os.path.abspath(os.path.join('..'))\n",
12 | "if module_path not in sys.path:\n",
13 | " sys.path.append(module_path)\n",
14 | "\n",
15 | "import cv2\n",
16 | "import numpy as np\n",
17 | "from matplotlib import pyplot as plt\n",
18 | "from datasets.unity_eyes import UnityEyesDataset\n"
19 | ]
20 | },
21 | {
22 | "cell_type": "markdown",
23 | "metadata": {},
24 | "source": [
25 | "## Let's take look at the first image\n",
26 | "These images are generated from UnityEyes. Each image is a .jpg file and comes with a .json file of metadata. The json file contains locations of all the eye landmark positions withing the image. "
27 | ]
28 | },
29 | {
30 | "cell_type": "code",
31 | "execution_count": 3,
32 | "metadata": {},
33 | "outputs": [],
34 | "source": [
35 | "dataset = UnityEyesDataset()\n",
36 | "sample = dataset[0]\n"
37 | ]
38 | },
39 | {
40 | "cell_type": "code",
41 | "execution_count": 4,
42 | "metadata": {},
43 | "outputs": [
44 | {
45 | "data": {
46 | "text/plain": [
47 | ""
48 | ]
49 | },
50 | "execution_count": 4,
51 | "metadata": {},
52 | "output_type": "execute_result"
53 | },
54 | {
55 | "data": {
56 | "image/png": "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\n",
57 | "text/plain": [
58 | ""
59 | ]
60 | },
61 | "metadata": {
62 | "needs_background": "light"
63 | },
64 | "output_type": "display_data"
65 | }
66 | ],
67 | "source": [
68 | "plt.imshow(sample['full_img'])"
69 | ]
70 | },
71 | {
72 | "cell_type": "markdown",
73 | "metadata": {},
74 | "source": [
75 | "## Ground Truth labels"
76 | ]
77 | },
78 | {
79 | "cell_type": "code",
80 | "execution_count": 5,
81 | "metadata": {},
82 | "outputs": [
83 | {
84 | "data": {
85 | "text/plain": [
86 | ""
87 | ]
88 | },
89 | "execution_count": 5,
90 | "metadata": {},
91 | "output_type": "execute_result"
92 | },
93 | {
94 | "data": {
95 | "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXAAAADqCAYAAAC7kx6uAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjMsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+AADFEAAAgAElEQVR4nO2deWxk15Xev1Mr9ybZZFO9SGotbW2WtbgjaSJnYEujicY2bCNxkLFnEk0iQAigIDYygS0lwCQTDILxP2Plj8QZwcsIiGPZIy9yBGfGGlmyLduQrd2SWq1uSb2wN5LNfa9i3fzBag+/c0tdbK511d8PIMjz6tV7571XPLz87rnnWAgBQggh0iOz2Q4IIYRYGQrgQgiRKArgQgiRKArgQgiRKArgQgiRKArgQgiRKKsK4GZ2p5ntN7ODZnbfWjklhBCiPrbSPHAzywJ4A8AdAPoB/ArAp0IIr62de0IIId6J3CreexOAgyGEtwDAzB4G8HEA7xjAC1YMTWhdxSnFuwKzc9t9Oceoa7v3+3FLqMTnqPBO8VCnzuBHa+TEGjGBkaEQQq/fvpoAvhPA0SV2P4Cbz/aGJrTiZrt9FacUDU+t4Gys1Fk2y69nzh7QrdYxM+6YhTy/ni+4c/L+YcEF7Lm56BRhfv7s76kV9OnlGhHcv0crocUy+LvwyOFa21cTwGv91kWfRjO7B8A9ANCEllWcTgghxFJWM4nZD+DCJfYuAMf9TiGEB0MIe0MIe/MoruJ0QgghlrKaEfivAOwxs0sAHAPw+wA+vSZeiXTIsBxi+fgjlSm6P9zOtpyXVJYxrnDnqbTxf3cLHXyOkOdjZuYWyM6OTEenyIxP8jGcpOI1ci+PRJILAJRKvE+57N7DfkliEWdjxQE8hFA2s38L4G8BZAF8NYTw6pp5JoQQ4qysZgSOEMIPAPxgjXwRQghxDmglphBCJMqqRuDiPCDKp3Zaskvfs7Yaef7dnWQudPM+5RaXAuhPuRDrwAtF9mOmlz/K0338+oKT4fMsb6PtWHN0jpYT7Gd2ymngdfLZba4Ub5tgrT2MT5BdmZnl18vuGNLExRI0AhdCiERRABdCiERRABdCiERRABdCiETRJKZg/MKc7NkX6lh7G9mhtzs65PQlHWSP7eZjzLm3mFv/kp2J3Qzukzu9kxfAbL1kiOy+Np4sfGtoK9mDr7dH52jv4sVBuVme6CwXeRIzuPVIhYl4wrHtON+vwlGewM0Mj5BdmeL3Rwt9ANVXOY/RCFwIIRJFAVwIIRJFAVwIIRJFGvj5hFt4EtXlBmAFV0e7uYntFtaFK1tZ357azRovAAy91xWeeh/r0e/dfoLs6TL78LbTqwGgVGLfr9w+QPa/2fUU2dcW+PXHeq8h+y8zH4jOMdrMunjww50eXnSTK7A+XRqMFwfN7uNtW90zKTr9OuMWToVadctL9QpiSSN/t6IRuBBCJIoCuBBCJIoCuBBCJIo08POIKKfbN1oAkOncQrbXuOd6uMDTzDbOYx7fHY8JSldzAad7r/kp2Z/u4DLyR8t8zK+1/aPomK+OXkD2ha2cP70zN0p2X5Z19R153r+nzSVcAzi2nf24oHuc7H+y60WyLy+eJPvR0zdGx3wSrL3nJ/kZdJa6yM41sd+ZmRoa+BQnyodpVzDL6eZqGvHuQSNwIYRIFAVwIYRIFAVwIYRIFGng72Z83neOH7fXuwGgfGEP2WOXcd73xEX8N3+21+UY98aFS67dyXne1zYdJXtblnX1wQU+xsyCa/gAYGCc881Hpzm/er5yO9nbi2NkvzK+g+z+IW46AQCVMl9rTzPr5B9o3U/2DQXef6KyLzrmz/suIXtqp6vBYnwd+SnWyPOTcaPkpiHOR88OsP4fRvjaK14jd42VRTpoBC6EEImiAC6EEImiAC6EEIkiDfxdTJT33cz6qs/xBmLNe/D9/PrOa1jPvqqLc58rUcGQmJ9MXkn2SzOseT8/fhHZv3iTdWMAyB3mGi2Vedb7n27lfOpKgXOdc9OuBslk3KB4oZnf81qhj+zvdfDNOdp6iOznJy+OjumZ6WNNe5anIBCy7Fd+Iv6VbT/E8wFd+3mfQoWvw5zmHdzrqNSoOS4aEo3AhRAiURTAhRAiURTAhRAiUaSBv5uok/dtLS5Xeivr3UCc5+017z/b812yr85zbvSPZji/GgD+z4lbyH76yKVkz465XOchzvvuOBrr060nWafNzbCW7LVj368yU/K6b3QKzHfwm8anWWv+xihf1yOd15Ndno9/vcK0y8Xv5jole3Zy3fJrO4+TfWBiW3TMl7t2k52d4/mB7jH22yb5mZmvJ+7rhy9ujLeJTUcjcCGESBQFcCGESBQFcCGESBQFcCGESBRNYqZMnSbF1sSTg6GNJy3nuuIiUfNdPFl1RaebVMtzIaQuV4hquBw3Nd53khfAZF/hfXqO8TlbBnmCsjgUNzHIDbuJuPlStM9Z8ZNymXgs09zGk4FNp/lap4/y/Su18esLxXjydY7XF2HhKi5EdWcfN7f4Q9fs4pUtrvgVgM9N/lP26+1esju6ePK6MMyfA5uf5wPWmMRUE4jGRCNwIYRIlLoB3My+amYDZvbKkm3dZva4mR2ofu862zGEEEKsPcsZgf8VgDvdtvsAPBFC2APgiaothBBiA6mrgYcQfmJmu93mjwP4YPXnhwA8BeDza+iXWA7Gf399k2LbwsWq5i9g/XSqL/77Xd7CizrmKqyr/3iWF5Kcdpr3/z5yc+zmftaGu15nPbX9EOvq2dMTZIcpfh0AMMPacWW1TQks1qvNLTBqHuPraDruioO18v7zW7ghMQCM7+Ztp7ezzn5inhtLDDs5et6vSALQlONrn3Drs/xcR66bPwcZp29XuHdz9SBqjNyIrFQD7wshnACA6vd4eZgQQoh1Zd2zUMzsHgD3AEAT4qXbQgghVsZKR+CnzGw7AFS/D7zTjiGEB0MIe0MIe/MovtNuQgghzpGVjsC/D+AuAH9e/f7omnkk3hmf9513hZHaWY8ub+fkoJHLWW8duyLWLfsuHCE7byzCPjK4l+yXTnHxqrl9caPkrfv4PO0HJ8nOnjxNdsUVWwo+TxkAnAYbNSWoVZDpbFg8lvG55eZ0dxtx97/Z5Y3XyNkOWX4mc12siX+7gwtivemaTFdCrNWfGuXzhBa+FxM72c+Q4WfU0uQ08lPx+oDKMDdKhmvCocbIm8Ny0gi/AeAXAK4ws34zuxuLgfsOMzsA4I6qLYQQYgNZThbKp97hpdvX2BchhBDngFZiCiFEoqgWSkr4vO8C66ehnfOUp3ZynvIo9xLGtTe8HZ3iE30vkO1rm3y7nzXa2f2sp259LdbVtxxkTTvSvMc48dhr3lHOMbD2ecchPodvbBDKThP3tWec3755MAA0Z/kZbs1x3vfoHGdqvXxkD9mljhr3Iu/uRR/7MdrN55xymviWTtcUOReP6/Jllyte4nuhvPDNQSNwIYRIFAVwIYRIFAVwIYRIFGngCWEZX/+b//6GFl4oNeu0z8yFrEX/0Y6fRef4RCvnaD81M0T210ucB940xD61HYtrd2cHOIe4Mu5qnXjNezNyimvUQqmn43rd1+eiW+D7DcQjppYF1tnz41y/ZmqAn+n47vhXduo9fP/ef/lhsq/p4MbUz41cRPa+5ovZhymeOwGAzhGeX7EJ/pzA12OvMacg1h6NwIUQIlEUwIUQIlEUwIUQIlEUwIUQIlE0iZkyvgCTm4jzdY8yGZ5kyyAu+DQXeDLqZJlLvY+5bgGdo3zM3Gg8iRmi4lR1FoGsBXUaPtcqXhXhF/LUK5jl9y/Fk7G+UJdvplCIJgO7yZztiicYZ4t8jN/teY3sf97+JtlPt7L9+WFuijxzIC5I1uGaVWRcITU/wX6utcTEytAIXAghEkUBXAghEkUBXAghEkUaeELU02CtxFpojmvuY26Y9dNHT98YnePw/FGyHx+6is/Rz8dodl13M5PupFiG5r0WhY8yrHFnCtyUwJpcN6i8azicqbGQxy0oCrOusa+/rrLXr2Mh2C9aqrhnmnHafK6N5xwK49w0AgAWJvnXeKDEi4HGKny/S8Hp18Y+1OibjOALXGXqzCn4hVEqbrUuaAQuhBCJogAuhBCJogAuhBCJIg08IXyubYTTGbPzLkd7nHXLl4e4ITEA9E9xg4GDx3vJbj3JPhSHXZODaW78CwChVF8bPme85u0aCmc6XKPfLtaFy1tcPnWNe5uZZr+zo1zAKYxyI4qoGbPXxIHoGUUFseZYZ89M8DGbh7j5AgC0HGY9/1t9N5B9cifndQ/Nc2GqyRGX21+rf4YvpJZzzSx8YTX1ON4QNAIXQohEUQAXQohEUQAXQohEkQaeMq6+R6XIuc+lVtYty64h7taWuOFAS841V3AFVTJO28yUnJ5do65JWG0OcI1mCz7PO9PO2vDCLtbuxy91DZ+389il4tLCAaA4zH53HGKdvemQa5jhrr0yXSMP3DerqFM/xdeRaTrhGikA6DzI8xani11k/2D8GrKLzU6bL7nPCd8qAMB8F9+g3JBr8DA1zbbPod+MJh3nARqBCyFEoiiACyFEoiiACyFEokgDb1RqNdl1mrcVWJcsb+F6HzPb+BgXXHya7D/a+fPoFBljTXZohrXl023bya4U3BjA191eC2rU7vbX7vO8J3ZzbvPQDXwvmq8cIburOc5fP3psK9nlZr6/vbOcX12Y8sVn4tro0RxBvbzwGfYrM8wNoQGg5Thr875m+Hw3zxc0d7Ku3r6LzzEI1tQBIDfDx/DNl/21m29UXavmu+qjrBqNwIUQIlEUwIUQIlEUwIUQIlEUwIUQIlE0iZkybsJwoch/j0vtPEl0ddcpsv9xy7G6p3i8c4DsH7dd4M7pJi0zNSYcfbPlumd1769VxMst5Flo54m8qQvYr8J7xsj+3FU/JHtP4WR0ir/c8iGyf3z6WrI7jvBEauEYT3JGjZSxjGuvt7BnNp5szc64gmILPIkZ2vgYd1y4n+wbWg6T/YNuvk4AeHr2arJbTvG150+54mDj/HzgmzUDQFiHZtbnGRqBCyFEotQN4GZ2oZk9aWb7zOxVM/tMdXu3mT1uZgeq37vqHUsIIcTasZwReBnAH4cQrgJwC4B7zexqAPcBeCKEsAfAE1VbCCHEBlFXAw8hnABwovrzhJntA7ATwMcBfLC620MAngLw+XXxUtTGLY7IzrN+mp1m7fjIFP+T9Pw8Nz0AgCZjrXJwlhfymF+H4uXpWnp1DV38nKixkMcTfEMB98luKfLCkp05XsizIxsvuukpcuGoSsE3/3XXWmvx1bniF7f45hcLNZphuE2+KXFTG1/7h9r3kX1nC1973l6MTvHz3kvJnm93OrtvIr0W90LU5Zx+s8xsN4AbADwDoK8a3M8E+W1r7ZwQQoh3ZtkB3MzaAHwbwGdDCOP19l/yvnvM7Fkze7aEGkuLhRBCrIhlBXAzy2MxeH89hPCd6uZTZra9+vp2AAO13htCeDCEsDeEsDePYq1dhBBCrIC6GrgtillfAbAvhPAXS176PoC7APx59fuj6+Lh+UqtQj++0JErGJQb5f9w2lxe8puvcxPj/xY+Ep1iaxMXOnr9FCtj2VmnbbohgNdCAcBy/DHz+dF1i/3XaoK84PV+vhfFYS5mNXiU9f//6XK8dzRznjgAPHl0D9nNJ/li8+PuP0qf61xZffPmUKmjiQMw97nIODfm5/j+Hylxka63S2+QfbS0OzrHwiwfwzf2sDW4VnHuLGchz60A/gWAX5v9ZnbjP2IxcH/LzO4GcATAP1sfF4UQQtRiOVkoTwN4pynl29fWHSGEEMtFKzGFECJRVAslIbweGmZZg80Oc3JQx2HWwEutXC/k7QVuzgAAR7dxYf6FMuvVWVdfZbqHP0LFwbgjbm6CdfW6xf59kwOvAwMIrllCZpRztjsOc56yb8bw4vB7yH6+GJ+jOMTjm64D7GfxJF9XmOF7V1PbX20Tgxr3wkrsV37K7TPI1/79U9eRfaCjj+xnBndH5yic4LmNphE+p83yM63UauAg1hyNwIUQIlEUwIUQIlEUwIUQIlGkgaeErxXt8o7DJGuyeadHtwywjjm9Pf77nd/F2uVFfUNk97dxI9+xBW6AW5ji/GsA6JjgBrg27RrgOq041sTjHGOfAx9GOI+76Oqv9Myxn76WdyUfJ1rlJ/j+Fgaclj84zD5MTbO9UTqwqztiTgLPzPHrx11D4pkyfy76T8WFRduH+Bj5Cafvz/HziJs3K098PdAIXAghEkUBXAghEkUBXAghEkUaeEr4/OioNorrjeh0yYyTJRea4pzif3AB98n8V30/JfvQfC/ZD4TbyJ4YZK0ZAFqOsy6eH+Ec7SgvfBn1P/y1V2a4V6QNsT6dc7p7vskVVqtVv9r3o3TH8HnfFV8LZSU5317P9n01a9SaqbSwnj/bycco97JfV27lunPteb53x4Z5ngMAQobXEJi/NlcLJaw2310sC43AhRAiURTAhRAiURTAhRAiURTAhRAiUTSJmTJRw1tXYMg3wPVzgzWe/kXNPPl3c5EXr+zO8YKZ/9vNhZFe74onMec7eZIt184LjPxkq58gC6VaRaHcpFnZLWqa8sWWuPiVuSbItRovRwtx/KRxnSJca4H305qaon3mO3lCdvoCnsS84pITZN+7/Qmy865TtW9kDQCvbeFtC0U3ueonW8WGoBG4EEIkigK4EEIkigK4EEIkijTwdxO+sazTjvNOFy6MsDYNAL8YuoTsR1t4Yc9shReSDM/yIp1KIdaBZ7tZH81fwAtF/NKUzAiPK3yRLqDWohl37RWnV0eaeXTI+qzH4pQ6C3fMLTgK7XGxsPlO/jWe7+ZrvbbzONk3ueYVJXddvU3cHAMA3GNHyLiFT/46nK1lPeuDRuBCCJEoCuBCCJEoCuBCCJEo0sBTJipu5XReV2ypMMh2x1txYaT+lh1k/9fhj5DdVGTteXKS85JDS6x2jl3K44T5Nn5PRwd/DJsPszZvp+JxRmZiguxIE0edBgKbVWypnubd7Ap9beHmC/M9cY72dA/fn0ob34tS4HM8xynxOFbuIfuloZ3ROQqj7Hduxk0ilFwevopZbQgagQshRKIogAshRKIogAshRKJIA38XETV4cA0IsgMjZHfuj/9+51xe9+Rx1lxne1nbrPTwOZt3xjnErZdxrZPhEa6FMvs66749OdZ923x+OwDffiEz7RoKu0bJdeuYrAcW3996ed4Zp3mXdnSTPXZZXAtl/DK2u7bx/MBEid/ztaEPkP3C4C6yR37NmjgA9B7mZ5A77Zpb1G1qLE18PdAIXAghEkUBXAghEkUBXAghEkUa+LsJX//DNQuujHIt71wNbbljmut5F8ZZAx8tc472fB9rm7ddfCA65ke7XiT717OsuX65cCvZY1N8ztwM68IAUMzx2CMzybo6XJNjnxPvG0DX1MR9c+V6uPogVohrzVjR5bi387WW+7hOzNjlPCdx+n2xT3uuP0r2h3rfIHtigTXwHx67kuyRV1nz7n4tOgXa3+J6NJnTo2RX/P3diDkGoRG4EEKkigK4EEIkSt0AbmZNZvZLM3vJzF41sz+tbr/EzJ4xswNm9k0zi/9fFEIIsW4sZwQ+B+C2EMJ1AK4HcKeZ3QLgCwC+GELYA2AEwN3r56YQQghP3UnMsFiV5szqjHz1KwC4DcCnq9sfAvBfAHxp7V0UKyVa2OMm9motrjA3sdnkJgsLfb6yP5sXNw9Fx/ztJl5YsiP3Ktk/7nsP2fu384RkbiYuulXs7nT7sN/FUZ6kzA+6SbhxtkPJF8M6d8w1Rg6tzdE+lU6+tvlunmCcuoCvdZRvDXZecyo65n0X/z+ybyryc35supfs786+j+yWEzz52n7UfU4A5E65ScvxOsXEtHBnQ1iWBm5mWTN7EcAAgMcBvAlgNITf9DXpBxCXMBNCCLFuLCuAhxAWQgjXA9gF4CYAV9XardZ7zeweM3vWzJ4tYa7WLkIIIVbAOWWhhBBGATwF4BYAnWZ2RoLZBeD4O7znwRDC3hDC3jyKtXYRQgixAupq4GbWC6AUQhg1s2YAv4PFCcwnAXwSwMMA7gLw6Ho6KlaA1yHD2Rf6AABcAazMOBeJahrhhSf5If4IPTl4RXTIHXnWTwfL7WSPzrJWXN7Cfo69Jx5nVNwnNzPPRaKaT/EOHa5JRMtJ1qKtXKMBhFuYE3wf3wXXUCPLO8x3xolZkzvYz5k+fs/cVvYjv4O1+pt7D0XHvCI/TnZLxi2+WuBrnZlg3b1nhK8jP8yfASBuLO0XQkVNpcWGsJyVmNsBPGRmWSyO2L8VQnjMzF4D8LCZ/RmAFwB8ZR39FEII4VhOFsrLAG6osf0tLOrhQgghNgGtxBRCiERRMavzmJoFh5wuHqZYA28+yfpo5xustx7IXRwd8j/v2nZWPxYmXZ53jvXUritYQweAm/sOk11xLR5+fIS7HAy5RgktvXGOtqfs6mMFN9zJOanYnAw8uzU+5vzl/KY9OwfI7mlirdnjGxQDwHcmOSlsrsL38zv915NdOMzJBC2DrGf7eQ8AqMxyBln02VHe96agEbgQQiSKArgQQiSKArgQQiSKNPDzmRq6ZShxM2Cf/5s9yY2Ru1zuc2Ei1pZn3+BtC038npLTmqd2sw/v7TkRHfPfbfsR2e3G19KdZ7+/Ofd+ssc63aKyLXEtlB3bWHvPZ1n3PTHCuvrcBB+ztSvOp/6Xl71A9h92/pLsWadxPzLGfj95yhVHAfA3o04DH+M876Z+1sS797NY33zM5XhPxI2plffdmGgELoQQiaIALoQQiaIALoQQiSINXDBO2wxznP9bGWYNPOfqaHcMc144ALS1sia70MY1Qqa3s3ZcamMd+PgUN/oFgJOuvsdChnOXK65wSXMLX0cpz3r2P7zw7egc/3rbT8huz3CO/HfHbiT7J4OX8/75uPrmdS1HyL4sz/frSJn15/7ZLrIPv821vQGg7U3WuLec5PmAZpfn3Xycz5EZ4Gdama5RC0V53w2JRuBCCJEoCuBCCJEoCuBCCJEoCuBCCJEomsQUjJucqtcYOZR50Y1NxYWQMkWetMy2tvB7yt1kz7Xz6we64narf7LwCbLbCjxh+NYQV5KaGeJjZtp4Yq81F084Xpzja2nP8ORqd44XwMyV+ddpZDpe1PSdAk98Hp3nolxvzvIk5ZMHeeFO+/64wXP3636S0jVwHuVJS784q+Jtv2gHACo1Cp+JTUcjcCGESBQFcCGESBQFcCGESBRp4OLs1G2M7Bb+uGJYAGCuGUDGaax540U3XTkeV2TKvBAIAIb6d5A94D7JvtmCr1U128N69t81xc2Y88bX2pzlgzx5cg/ZJw6yfp0fi8dHP2vmhTk/beXzZqbZr7bDfIyu/bE+3XLINbwYYrsyzVq+L0wVLdKR3p0MGoELIUSiKIALIUSiKIALIUSiSAMXq6OORr64C+vkFadPZ4ZZsy0s8P5bJ7hxAgBseYsLYIUc6+hWcfnsGX59ppdz08drnON7R27iY7h+wk2DPP7ZeozPWRyv0fSA3UAlxwfNzvExmob4ZuVPjcfHPO2KUbm87mhewjdjUGGqZNEIXAghEkUBXAghEkUBXAghEkUauFh/fH2VMuchV6ZZkzVfX8VpugBQcPVV4HLJI3L8US8McEOIZmcDwHwnv8fr6Plxzm8vjHCdmMxkXF8FFac/O7+t7OYQfO2ZGrVmKq7pRpjnxhPSuN+9aAQuhBCJogAuhBCJogAuhBCJIg1cbDyRJs6ad3A53OY1XQCYdGOPzNk1cMtyvrXX1Yujce3uYsHV3vY6u68pMjt71teBGnVH/Ot16rGjxvvVcPj8RSNwIYRIFAVwIYRIlGUHcDPLmtkLZvZY1b7EzJ4xswNm9k0zK9Q7hhBCiLXjXDTwzwDYB+BM0YgvAPhiCOFhM/tfAO4G8KU19k+cj7h61L50B4D6ed+OYDxWiXT16Ti/2uvmES6nOyx4ewV1tWte7NLXpW+Lv2dZI3Az2wXgIwC+XLUNwG0AHqnu8hCAT9R+txBCiPVguRLKAwA+B+DM8GArgNEQwpn0gX4AcetwAGZ2j5k9a2bPllBjZZoQQogVUTeAm9lHAQyEEJ5burnGrjX/twshPBhC2BtC2JtHsdYuQgghVsByNPBbAXzMzD4MoAmLGvgDADrNLFcdhe8CcHz93BRCCOGpG8BDCPcDuB8AzOyDAP5DCOEPzOyvAXwSwMMA7gLw6Dr6KQRzrpN5vhmznyustUDmHF3SBKPYaFaTB/55AP/ezA5iURP/ytq4JIQQYjmc01L6EMJTAJ6q/vwWgJvOtr8QQoj1QysxhRAiUVTMSghA+rVIEo3AhRAiURTAhRAiURTAhRAiURTAhRAiURTAhRAiURTAhRAiURTAhRAiURTAhRAiURTAhRAiURTAhRAiURTAhRAiURTAhRAiURTAhRAiURTAhRAiURTAhRAiURTAhRAiURTAhRAiURTAhRAiURTAhRAiURTAhRAiURTAhRAiURTAhRAiURTAhRAiURTAhRAiUSyEsHEnMxsEcBhAD4ChDTvxypGfa0cKPgLyc62Rn2vDxSGEXr9xQwP4b05q9mwIYe+Gn/gckZ9rRwo+AvJzrZGf64skFCGESBQFcCGESJTNCuAPbtJ5zxX5uXak4CMgP9ca+bmObIoGLoQQYvVIQhFCiETZ0ABuZnea2X4zO2hm923kuethZl81swEze2XJtm4ze9zMDlS/d22yjxea2ZNmts/MXjWzzzSon01m9ksze6nq559Wt19iZs9U/fymmRU2088zmFnWzF4ws8eqdsP5aWaHzOzXZvaimT1b3dZoz73TzB4xs9ern9HfakAfr6jewzNf42b22Ubzc7lsWAA3syyA/wHg9wBcDeBTZnb1Rp1/GfwVgDvdtvsAPBFC2APgiaq9mZQB/HEI4SoAtwC4t3oPG83POQC3hRCuA3A9gDvN7BYAXwDwxaqfIwDu3kQfl/IZAPuW2I3q54dCCNcvSXdrtOf+3wH8TQjhSgDXYfGeNpSPIYT91Xt4PYD3A5gG8F00mJ/LJoSwIV8AfgvA3wew5X0AAALsSURBVC6x7wdw/0adf5k+7gbwyhJ7P4Dt1Z+3A9i/2T46fx8FcEcj+wmgBcDzAG7G4kKJXK3Pwyb6twuLv7C3AXgMgDWon4cA9LhtDfPcAXQAeBvVebVG9LGGz78L4GeN7ufZvjZSQtkJ4OgSu7+6rZHpCyGcAIDq922b7M9vMLPdAG4A8Awa0M+qLPEigAEAjwN4E8BoCKFc3aVRnv8DAD4HoFK1t6Ix/QwAfmhmz5nZPdVtjfTcLwUwCOBrVTnqy2bW2mA+en4fwDeqPzeyn+/IRgZwq7FNKTArwMzaAHwbwGdDCOOb7U8tQggLYfHf1F0AbgJwVa3dNtYrxsw+CmAghPDc0s01dm2Ez+mtIYQbsShB3mtmv73ZDjlyAG4E8KUQwg0AptDAMkR1XuNjAP56s31ZDRsZwPsBXLjE3gXg+AaefyWcMrPtAFD9PrDJ/sDM8lgM3l8PIXynurnh/DxDCGEUwFNY1Ow7zSxXfakRnv+tAD5mZocAPIxFGeUBNJ6fCCEcr34fwKJmexMa67n3A+gPITxTtR/BYkBvJB+X8nsAng8hnKrajernWdnIAP4rAHuqM/wFLP778v0NPP9K+D6Au6o/34VFzXnTMDMD8BUA+0IIf7HkpUbzs9fMOqs/NwP4HSxOaD0J4JPV3TbdzxDC/SGEXSGE3Vj8PP4ohPAHaDA/zazVzNrP/IxF7fYVNNBzDyGcBHDUzK6obrodwGtoIB8dn8LfyydA4/p5djZ40uDDAN7Aoh76nzZ7AsD59g0AJwCUsDiauBuLeugTAA5Uv3dvso8fwOK/8y8DeLH69eEG9PN9AF6o+vkKgD+pbr8UwC8BHMTiv67FzX7uS3z+IIDHGtHPqj8vVb9ePfO704DP/XoAz1af+/cAdDWaj1U/WwCcBrBlybaG83M5X1qJKYQQiaKVmEIIkSgK4EIIkSgK4EIIkSgK4EIIkSgK4EIIkSgK4EIIkSgK4EIIkSgK4EIIkSj/H0hsWGNiaz4gAAAAAElFTkSuQmCC\n",
96 | "text/plain": [
97 | ""
98 | ]
99 | },
100 | "metadata": {
101 | "needs_background": "light"
102 | },
103 | "output_type": "display_data"
104 | }
105 | ],
106 | "source": [
107 | "heatmaps = sample['heatmaps']\n",
108 | "merged_heatmaps = np.mean(heatmaps[16:33], axis=0)\n",
109 | "plt.imshow(merged_heatmaps)"
110 | ]
111 | },
112 | {
113 | "cell_type": "code",
114 | "execution_count": 6,
115 | "metadata": {},
116 | "outputs": [
117 | {
118 | "data": {
119 | "text/plain": [
120 | ""
121 | ]
122 | },
123 | "execution_count": 6,
124 | "metadata": {},
125 | "output_type": "execute_result"
126 | },
127 | {
128 | "data": {
129 | "image/png": "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\n",
130 | "text/plain": [
131 | ""
132 | ]
133 | },
134 | "metadata": {
135 | "needs_background": "light"
136 | },
137 | "output_type": "display_data"
138 | }
139 | ],
140 | "source": [
141 | "plt.imshow(sample['img'])"
142 | ]
143 | },
144 | {
145 | "cell_type": "code",
146 | "execution_count": 7,
147 | "metadata": {},
148 | "outputs": [
149 | {
150 | "data": {
151 | "text/plain": [
152 | "array([[33.516087 , 17.515186 ],\n",
153 | " [29.25981 , 14.860628 ],\n",
154 | " [20.977678 , 19.982723 ],\n",
155 | " [11.359354 , 31.219086 ],\n",
156 | " [ 9.150034 , 45.183544 ],\n",
157 | " [15.333946 , 55.666534 ],\n",
158 | " [22.347504 , 61.888092 ],\n",
159 | " [29.66824 , 64.39625 ],\n",
160 | " [35.430656 , 64.49766 ],\n",
161 | " [37.92424 , 63.95883 ],\n",
162 | " [40.799217 , 60.91427 ],\n",
163 | " [41.691284 , 54.81529 ],\n",
164 | " [41.837326 , 47.023544 ],\n",
165 | " [41.11672 , 36.859245 ],\n",
166 | " [39.741966 , 25.973618 ],\n",
167 | " [37.847527 , 19.782518 ],\n",
168 | " [19.173851 , 24.480421 ],\n",
169 | " [13.450941 , 24.940432 ],\n",
170 | " [ 8.675809 , 27.653122 ],\n",
171 | " [ 5.5754147, 32.205536 ],\n",
172 | " [ 4.621802 , 37.90466 ],\n",
173 | " [ 5.9601398, 43.88277 ],\n",
174 | " [ 9.38669 , 49.229847 ],\n",
175 | " [14.379737 , 53.131775 ],\n",
176 | " [20.179201 , 54.99453 ],\n",
177 | " [25.902151 , 54.534557 ],\n",
178 | " [30.677284 , 51.821865 ],\n",
179 | " [33.777637 , 47.26945 ],\n",
180 | " [34.73129 , 41.570328 ],\n",
181 | " [33.392914 , 35.592182 ],\n",
182 | " [29.966402 , 30.245142 ],\n",
183 | " [24.973314 , 26.343214 ],\n",
184 | " [19.67654 , 39.737488 ],\n",
185 | " [32.095753 , 28.837555 ]], dtype=float32)"
186 | ]
187 | },
188 | "execution_count": 7,
189 | "metadata": {},
190 | "output_type": "execute_result"
191 | }
192 | ],
193 | "source": [
194 | "sample['landmarks']\n"
195 | ]
196 | },
197 | {
198 | "cell_type": "code",
199 | "execution_count": null,
200 | "metadata": {},
201 | "outputs": [],
202 | "source": []
203 | }
204 | ],
205 | "metadata": {
206 | "kernelspec": {
207 | "display_name": "Python 3",
208 | "language": "python",
209 | "name": "python3"
210 | },
211 | "language_info": {
212 | "codemirror_mode": {
213 | "name": "ipython",
214 | "version": 3
215 | },
216 | "file_extension": ".py",
217 | "mimetype": "text/x-python",
218 | "name": "python",
219 | "nbconvert_exporter": "python",
220 | "pygments_lexer": "ipython3",
221 | "version": "3.6.10"
222 | }
223 | },
224 | "nbformat": 4,
225 | "nbformat_minor": 4
226 | }
227 |
--------------------------------------------------------------------------------
/run_with_webcam.py:
--------------------------------------------------------------------------------
1 | from typing import List, Optional
2 |
3 | import torch
4 | from torch.nn import DataParallel
5 |
6 | from models.eyenet import EyeNet
7 | import os
8 | import numpy as np
9 | import cv2
10 | import dlib
11 | import imutils
12 | import util.gaze
13 | from imutils import face_utils
14 |
15 | from util.eye_prediction import EyePrediction
16 | from util.eye_sample import EyeSample
17 |
18 | torch.backends.cudnn.enabled = True
19 |
20 | device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
21 | print(device)
22 |
23 | webcam = cv2.VideoCapture(0)
24 | webcam.set(cv2.CAP_PROP_FRAME_WIDTH, 960)
25 | webcam.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
26 | webcam.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(*'MJPG'))
27 | webcam.set(cv2.CAP_PROP_FPS, 60)
28 |
29 | dirname = os.path.dirname(__file__)
30 | face_cascade = cv2.CascadeClassifier(os.path.join(dirname, 'lbpcascade_frontalface_improved.xml'))
31 | landmarks_detector = dlib.shape_predictor(os.path.join(dirname, 'shape_predictor_5_face_landmarks.dat'))
32 |
33 | checkpoint = torch.load('checkpoint.pt', map_location=device)
34 | nstack = checkpoint['nstack']
35 | nfeatures = checkpoint['nfeatures']
36 | nlandmarks = checkpoint['nlandmarks']
37 | eyenet = EyeNet(nstack=nstack, nfeatures=nfeatures, nlandmarks=nlandmarks).to(device)
38 | eyenet.load_state_dict(checkpoint['model_state_dict'])
39 |
40 | def main():
41 | current_face = None
42 | landmarks = None
43 | alpha = 0.95
44 | left_eye = None
45 | right_eye = None
46 |
47 | while True:
48 | _, frame_bgr = webcam.read()
49 | orig_frame = frame_bgr.copy()
50 | frame = cv2.cvtColor(frame_bgr, cv2.COLOR_BGR2RGB)
51 | gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
52 | faces = face_cascade.detectMultiScale(gray)
53 |
54 | if len(faces):
55 | next_face = faces[0]
56 | if current_face is not None:
57 | current_face = alpha * next_face + (1 - alpha) * current_face
58 | else:
59 | current_face = next_face
60 |
61 | if current_face is not None:
62 | #draw_cascade_face(current_face, orig_frame)
63 | next_landmarks = detect_landmarks(current_face, gray)
64 |
65 | if landmarks is not None:
66 | landmarks = next_landmarks * alpha + (1 - alpha) * landmarks
67 | else:
68 | landmarks = next_landmarks
69 |
70 | #draw_landmarks(landmarks, orig_frame)
71 |
72 |
73 | if landmarks is not None:
74 | eye_samples = segment_eyes(gray, landmarks)
75 |
76 | eye_preds = run_eyenet(eye_samples)
77 | left_eyes = list(filter(lambda x: x.eye_sample.is_left, eye_preds))
78 | right_eyes = list(filter(lambda x: not x.eye_sample.is_left, eye_preds))
79 |
80 | if left_eyes:
81 | left_eye = smooth_eye_landmarks(left_eyes[0], left_eye, smoothing=0.1)
82 | if right_eyes:
83 | right_eye = smooth_eye_landmarks(right_eyes[0], right_eye, smoothing=0.1)
84 |
85 | for ep in [left_eye, right_eye]:
86 | for (x, y) in ep.landmarks[16:33]:
87 | color = (0, 255, 0)
88 | if ep.eye_sample.is_left:
89 | color = (255, 0, 0)
90 | cv2.circle(orig_frame,
91 | (int(round(x)), int(round(y))), 1, color, -1, lineType=cv2.LINE_AA)
92 |
93 | gaze = ep.gaze.copy()
94 | if ep.eye_sample.is_left:
95 | gaze[1] = -gaze[1]
96 | util.gaze.draw_gaze(orig_frame, ep.landmarks[-2], gaze, length=60.0, thickness=2)
97 |
98 | cv2.imshow("Webcam", orig_frame)
99 | cv2.waitKey(1)
100 |
101 |
102 | def detect_landmarks(face, frame, scale_x=0, scale_y=0):
103 | (x, y, w, h) = (int(e) for e in face)
104 | rectangle = dlib.rectangle(x, y, x + w, y + h)
105 | face_landmarks = landmarks_detector(frame, rectangle)
106 | return face_utils.shape_to_np(face_landmarks)
107 |
108 |
109 | def draw_cascade_face(face, frame):
110 | (x, y, w, h) = (int(e) for e in face)
111 | cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)
112 |
113 |
114 | def draw_landmarks(landmarks, frame):
115 | for (x, y) in landmarks:
116 | cv2.circle(frame, (int(x), int(y)), 2, (0, 255, 0), -1, lineType=cv2.LINE_AA)
117 |
118 |
119 | def segment_eyes(frame, landmarks, ow=160, oh=96):
120 | eyes = []
121 |
122 | # Segment eyes
123 | for corner1, corner2, is_left in [(2, 3, True), (0, 1, False)]:
124 | x1, y1 = landmarks[corner1, :]
125 | x2, y2 = landmarks[corner2, :]
126 | eye_width = 1.5 * np.linalg.norm(landmarks[corner1, :] - landmarks[corner2, :])
127 | if eye_width == 0.0:
128 | return eyes
129 |
130 | cx, cy = 0.5 * (x1 + x2), 0.5 * (y1 + y2)
131 |
132 | # center image on middle of eye
133 | translate_mat = np.asmatrix(np.eye(3))
134 | translate_mat[:2, 2] = [[-cx], [-cy]]
135 | inv_translate_mat = np.asmatrix(np.eye(3))
136 | inv_translate_mat[:2, 2] = -translate_mat[:2, 2]
137 |
138 | # Scale
139 | scale = ow / eye_width
140 | scale_mat = np.asmatrix(np.eye(3))
141 | scale_mat[0, 0] = scale_mat[1, 1] = scale
142 | inv_scale = 1.0 / scale
143 | inv_scale_mat = np.asmatrix(np.eye(3))
144 | inv_scale_mat[0, 0] = inv_scale_mat[1, 1] = inv_scale
145 |
146 | estimated_radius = 0.5 * eye_width * scale
147 |
148 | # center image
149 | center_mat = np.asmatrix(np.eye(3))
150 | center_mat[:2, 2] = [[0.5 * ow], [0.5 * oh]]
151 | inv_center_mat = np.asmatrix(np.eye(3))
152 | inv_center_mat[:2, 2] = -center_mat[:2, 2]
153 |
154 | # Get rotated and scaled, and segmented image
155 | transform_mat = center_mat * scale_mat * translate_mat
156 | inv_transform_mat = (inv_translate_mat * inv_scale_mat * inv_center_mat)
157 |
158 | eye_image = cv2.warpAffine(frame, transform_mat[:2, :], (ow, oh))
159 | eye_image = cv2.equalizeHist(eye_image)
160 |
161 | if is_left:
162 | eye_image = np.fliplr(eye_image)
163 | cv2.imshow('left eye image', eye_image)
164 | else:
165 | cv2.imshow('right eye image', eye_image)
166 | eyes.append(EyeSample(orig_img=frame.copy(),
167 | img=eye_image,
168 | transform_inv=inv_transform_mat,
169 | is_left=is_left,
170 | estimated_radius=estimated_radius))
171 | return eyes
172 |
173 |
174 | def smooth_eye_landmarks(eye: EyePrediction, prev_eye: Optional[EyePrediction], smoothing=0.2, gaze_smoothing=0.4):
175 | if prev_eye is None:
176 | return eye
177 | return EyePrediction(
178 | eye_sample=eye.eye_sample,
179 | landmarks=smoothing * prev_eye.landmarks + (1 - smoothing) * eye.landmarks,
180 | gaze=gaze_smoothing * prev_eye.gaze + (1 - gaze_smoothing) * eye.gaze)
181 |
182 |
183 | def run_eyenet(eyes: List[EyeSample], ow=160, oh=96) -> List[EyePrediction]:
184 | result = []
185 | for eye in eyes:
186 | with torch.no_grad():
187 | x = torch.tensor([eye.img], dtype=torch.float32).to(device)
188 | _, landmarks, gaze = eyenet.forward(x)
189 | landmarks = np.asarray(landmarks.cpu().numpy()[0])
190 | gaze = np.asarray(gaze.cpu().numpy()[0])
191 | assert gaze.shape == (2,)
192 | assert landmarks.shape == (34, 2)
193 |
194 | landmarks = landmarks * np.array([oh/48, ow/80])
195 |
196 | temp = np.zeros((34, 3))
197 | if eye.is_left:
198 | temp[:, 0] = ow - landmarks[:, 1]
199 | else:
200 | temp[:, 0] = landmarks[:, 1]
201 | temp[:, 1] = landmarks[:, 0]
202 | temp[:, 2] = 1.0
203 | landmarks = temp
204 | assert landmarks.shape == (34, 3)
205 | landmarks = np.asarray(np.matmul(landmarks, eye.transform_inv.T))[:, :2]
206 | assert landmarks.shape == (34, 2)
207 | result.append(EyePrediction(eye_sample=eye, landmarks=landmarks, gaze=gaze))
208 | return result
209 |
210 |
211 | if __name__ == '__main__':
212 | main()
--------------------------------------------------------------------------------
/scripts/fetch_models.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
4 |
5 | cd ${DIR}/..
6 |
7 | # Download face landmark predictor model
8 | wget http://dlib.net/files/shape_predictor_5_face_landmarks.dat.bz2
9 | bzip2 -d shape_predictor_5_face_landmarks.dat.bz2
10 | rm shape_predictor_5_face_landmarks.dat.bz2
11 |
12 |
13 | # Download trained pytorch model
14 | wget "https://drive.google.com/uc?export=download&id=17aJAUAIl-1VPvJcPeahH8MQrcLRpy9Li" -O checkpoint.pt
15 |
--------------------------------------------------------------------------------
/static/fig1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/david-wb/gaze-estimation/249691893a37944a03e4ad4a3448083b6f63af10/static/fig1.png
--------------------------------------------------------------------------------
/static/ge_screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/david-wb/gaze-estimation/249691893a37944a03e4ad4a3448083b6f63af10/static/ge_screenshot.png
--------------------------------------------------------------------------------
/test.py:
--------------------------------------------------------------------------------
1 | import torch
2 | from datasets.unity_eyes import UnityEyesDataset
3 | from models.eyenet import EyeNet
4 | import os
5 | import numpy as np
6 | import cv2
7 | from util.preprocess import gaussian_2d
8 | from matplotlib import pyplot as plt
9 | from util.gaze import draw_gaze
10 |
11 | device = torch.device('cpu')
12 | dataset = UnityEyesDataset()
13 | checkpoint = torch.load('checkpoint.pt', map_location=device)
14 | nstack = checkpoint['nstack']
15 | nfeatures = checkpoint['nfeatures']
16 | nlandmarks = checkpoint['nlandmarks']
17 | eyenet = EyeNet(nstack=nstack, nfeatures=nfeatures, nlandmarks=nlandmarks).to(device)
18 | eyenet.load_state_dict(checkpoint['model_state_dict'])
19 |
20 | with torch.no_grad():
21 | sample = dataset[2]
22 | x = torch.tensor([sample['img']]).float().to(device)
23 | heatmaps = sample['heatmaps']
24 | heatmaps_pred, landmarks_pred, gaze_pred = eyenet.forward(x)
25 |
26 | landmarks_pred = landmarks_pred.cpu().numpy()[0, :]
27 |
28 | result = [gaussian_2d(w=80, h=48, cx=c[1], cy=c[0], sigma=3) for c in landmarks_pred]
29 |
30 | plt.figure(figsize=(8, 9))
31 |
32 | iris_center = sample['landmarks'][-2][::-1]
33 | iris_center *= 2
34 | img = sample['img']
35 |
36 | img = cv2.cvtColor(img, cv2.COLOR_GRAY2RGB)
37 |
38 | img_gaze_pred = img.copy()
39 | for (y, x) in landmarks_pred[-2:-1]:
40 | cv2.circle(img_gaze_pred, (int(x*2), int(y*2)), 2, (255, 0, 0), -1)
41 | draw_gaze(img_gaze_pred, iris_center, gaze_pred.cpu().numpy()[0, :], length=60, color=(255, 0, 0))
42 |
43 | img_gaze = img.copy()
44 | for (x, y) in sample['landmarks'][-2:-1]:
45 | cv2.circle(img_gaze, (int(x*2), int(y*2)), 2, (0, 255, 0), -1)
46 | draw_gaze(img_gaze, iris_center, sample['gaze'], length=60, color=(0, 255, 0))
47 |
48 | plt.subplot(321)
49 | plt.imshow(cv2.cvtColor(sample['full_img'], cv2.COLOR_BGR2RGB))
50 | plt.title('Raw training image')
51 |
52 | plt.subplot(322)
53 | plt.imshow(img, cmap='gray')
54 | plt.title('Preprocessed training image')
55 |
56 | plt.subplot(323)
57 | plt.imshow(np.mean(heatmaps[16:32], axis=0), cmap='gray')
58 | plt.title('Ground truth heatmaps')
59 |
60 | plt.subplot(324)
61 | plt.imshow(np.mean(result[16:32], axis=0), cmap='gray')
62 | plt.title('Predicted heatmaps')
63 |
64 | plt.subplot(325)
65 | plt.imshow(img_gaze, cmap='gray')
66 | plt.title('Ground truth landmarks and gaze vector')
67 |
68 | plt.subplot(326)
69 | plt.imshow(img_gaze_pred, cmap='gray')
70 | plt.title('Predicted landmarks and gaze vector')
71 | plt.show()
--------------------------------------------------------------------------------
/test/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/david-wb/gaze-estimation/249691893a37944a03e4ad4a3448083b6f63af10/test/__init__.py
--------------------------------------------------------------------------------
/test/data/imgs/1.json:
--------------------------------------------------------------------------------
1 | {
2 | "interior_margin_2d": [
3 | "(371.4855, 296.4230, 8.8595)",
4 | "(364.8002, 307.1421, 8.8963)",
5 | "(377.6998, 328.0000, 8.8956)",
6 | "(405.9977, 352.2230, 8.9568)",
7 | "(441.1661, 357.7870, 9.1683)",
8 | "(467.5667, 342.2133, 9.4351)",
9 | "(483.2352, 324.5502, 9.6703)",
10 | "(489.5518, 306.1135, 9.8769)",
11 | "(489.8072, 291.6013, 10.0333)",
12 | "(488.4502, 285.3214, 9.8645)",
13 | "(480.7827, 278.0810, 9.5506)",
14 | "(465.4229, 275.8344, 9.2366)",
15 | "(445.8000, 275.4666, 9.0163)",
16 | "(420.2020, 277.2814, 8.8672)",
17 | "(392.7874, 280.7436, 8.8285)",
18 | "(377.1956, 285.5146, 8.8521)"
19 | ],
20 | "caruncle_2d": [
21 | "(364.5717, 284.7197, 8.8818)",
22 | "(364.8584, 288.3494, 8.8758)",
23 | "(357.4482, 296.9649, 8.8906)",
24 | "(349.9624, 289.0576, 8.8963)",
25 | "(353.7258, 283.3381, 8.8824)",
26 | "(351.5754, 280.2595, 8.8752)",
27 | "(346.2976, 282.7485, 8.8394)"
28 | ],
29 | "iris_2d": [
30 | "(389.0269, 332.5428, 8.8831)",
31 | "(388.8647, 339.9151, 8.9267)",
32 | "(390.1854, 346.9555, 8.9762)",
33 | "(392.9381, 353.3934, 9.0297)",
34 | "(397.0171, 358.9813, 9.0850)",
35 | "(402.2656, 363.5046, 9.1402)",
36 | "(408.4820, 366.7894, 9.1929)",
37 | "(415.4274, 368.7094, 9.2413)",
38 | "(422.8348, 369.1910, 9.2835)",
39 | "(430.4196, 368.2155, 9.3178)",
40 | "(437.8902, 365.8205, 9.3429)",
41 | "(444.9597, 362.0980, 9.3579)",
42 | "(451.3564, 357.1910, 9.3622)",
43 | "(456.8343, 351.2882, 9.3555)",
44 | "(461.1831, 344.6164, 9.3383)",
45 | "(464.2355, 337.4319, 9.3111)",
46 | "(465.8743, 330.0109, 9.2750)",
47 | "(466.0365, 322.6385, 9.2313)",
48 | "(464.7159, 315.5981, 9.1818)",
49 | "(461.9632, 309.1602, 9.1284)",
50 | "(457.8842, 303.5723, 9.0730)",
51 | "(452.6357, 299.0490, 9.0179)",
52 | "(446.4193, 295.7643, 8.9651)",
53 | "(439.4739, 293.8442, 8.9167)",
54 | "(432.0665, 293.3626, 8.8746)",
55 | "(424.4817, 294.3381, 8.8403)",
56 | "(417.0110, 296.7332, 8.8152)",
57 | "(409.9415, 300.4557, 8.8002)",
58 | "(403.5449, 305.3626, 8.7959)",
59 | "(398.0670, 311.2654, 8.8025)",
60 | "(393.7182, 317.9373, 8.8197)",
61 | "(390.6658, 325.1217, 8.8470)"
62 | ],
63 | "eye_details": {
64 | "look_vec": "(0.3404, 0.3879, -0.8566, 0.0000)",
65 | "pupil_size": "0.1020631",
66 | "iris_size": "0.9349335",
67 | "iris_texture": "eyeball_brown"
68 | },
69 | "lighting_details": {
70 | "skybox_texture": "bergen_2k",
71 | "skybox_exposure": "1.191213",
72 | "skybox_rotation": "231",
73 | "ambient_intensity": "1.15163",
74 | "light_rotation": "(30.0, 248.5, 0.0)",
75 | "light_intensity": "0.8451564"
76 | },
77 | "eye_region_details": {
78 | "pca_shape_coeffs": [
79 | "-0.01061361",
80 | "0.009601755",
81 | "0.01964062",
82 | "0.0175013",
83 | "-0.01174545",
84 | "0.01343334",
85 | "0.005124273",
86 | "0.002106255",
87 | "0.002141998",
88 | "0.004727394",
89 | "-0.008374349",
90 | "-0.002742675",
91 | "0.006649553",
92 | "-0.002045201",
93 | "-0.003022511",
94 | "-0.005640308",
95 | "-0.004294305",
96 | "0.0002127625",
97 | "0.002193088",
98 | "1.924006E-17"
99 | ],
100 | "primary_skin_texture": "f02_color"
101 | },
102 | "head_pose": "(355.0770, 203.8451, 0.0000)"
103 | }
--------------------------------------------------------------------------------
/test/test_unity_eyes.py:
--------------------------------------------------------------------------------
1 | import pytest
2 |
3 | from datasets.unity_eyes import UnityEyesDataset
4 | import os
5 |
6 | def test_unity_eyes():
7 | ds = UnityEyesDataset(img_dir=os.path.join(os.path.dirname(__file__), 'data/imgs'))
8 | sample = ds[0]
9 | assert sample['full_img'].shape == (600, 800, 3)
10 | assert sample['img'].shape == (90, 150, 3)
11 | assert float(sample['json_data']['eye_details']['iris_size']) == 0.9349335
12 |
--------------------------------------------------------------------------------
/train.py:
--------------------------------------------------------------------------------
1 | import os
2 |
3 | import torch
4 | from datasets.unity_eyes import UnityEyesDataset
5 | from torch.utils.data import DataLoader
6 | from models.eyenet import EyeNet
7 | from torch.utils.tensorboard import SummaryWriter
8 | from datetime import datetime
9 | import numpy as np
10 | import cv2
11 | import argparse
12 |
13 | # Set up pytorch
14 | torch.backends.cudnn.enabled = False
15 | torch.manual_seed(0)
16 | device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
17 | print('Device', device)
18 |
19 | # Set up cmdline args
20 | parser = argparse.ArgumentParser(description='Trains an EyeNet model')
21 | parser.add_argument('--nstack', type=int, default=3, help='Number of hourglass layers.')
22 | parser.add_argument('--nfeatures', type=int, default=32, help='Number of feature maps to use.')
23 | parser.add_argument('--nlandmarks', type=int, default=34, help='Number of landmarks to be predicted.')
24 | parser.add_argument('--nepochs', type=int, default=10, help='Number of epochs to iterate over all training examples.')
25 | parser.add_argument('--start_from', help='A model checkpoint file to begin training from. This overrides all other arguments.')
26 | parser.add_argument('--out', default='checkpoint.pt', help='The output checkpoint filename')
27 | args = parser.parse_args()
28 |
29 |
30 | def validate(eyenet: EyeNet, val_loader: DataLoader) -> float:
31 | with torch.no_grad():
32 | val_losses = []
33 | for val_batch in val_loader:
34 | val_imgs = val_batch['img'].float().to(device)
35 | heatmaps = val_batch['heatmaps'].to(device)
36 | landmarks = val_batch['landmarks'].to(device)
37 | gaze = val_batch['gaze'].float().to(device)
38 | heatmaps_pred, landmarks_pred, gaze_pred = eyenet.forward(val_imgs)
39 | heatmaps_loss, landmarks_loss, gaze_loss = eyenet.calc_loss(
40 | heatmaps_pred, heatmaps, landmarks_pred, landmarks, gaze_pred, gaze)
41 | loss = 1000 * heatmaps_loss + landmarks_loss + gaze_loss
42 | val_losses.append(loss.item())
43 | val_loss = np.mean(val_losses)
44 | return val_loss
45 |
46 |
47 | def train_epoch(epoch: int,
48 | eyenet: EyeNet,
49 | optimizer,
50 | train_loader : DataLoader,
51 | val_loader: DataLoader,
52 | best_val_loss: float,
53 | checkpoint_fn: str,
54 | writer: SummaryWriter):
55 |
56 | N = len(train_loader)
57 | for i_batch, sample_batched in enumerate(train_loader):
58 | i_batch += N * epoch
59 | imgs = sample_batched['img'].float().to(device)
60 | heatmaps_pred, landmarks_pred, gaze_pred = eyenet.forward(imgs)
61 |
62 | heatmaps = sample_batched['heatmaps'].to(device)
63 | landmarks = sample_batched['landmarks'].float().to(device)
64 | gaze = sample_batched['gaze'].float().to(device)
65 |
66 | heatmaps_loss, landmarks_loss, gaze_loss = eyenet.calc_loss(
67 | heatmaps_pred, heatmaps, landmarks_pred, landmarks, gaze_pred, gaze)
68 |
69 | loss = 1000 * heatmaps_loss + landmarks_loss + gaze_loss
70 |
71 | optimizer.zero_grad()
72 | loss.backward()
73 | optimizer.step()
74 |
75 | hm = np.mean(heatmaps[-1, 8:16].cpu().detach().numpy(), axis=0)
76 | hm_pred = np.mean(heatmaps_pred[-1, -1, 8:16].cpu().detach().numpy(), axis=0)
77 | norm_hm = cv2.normalize(hm, None, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32F)
78 | norm_hm_pred = cv2.normalize(hm_pred, None, alpha=0, beta=1, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_32F)
79 |
80 | if i_batch % 20 == 0:
81 | cv2.imwrite('true.jpg', norm_hm * 255)
82 | cv2.imwrite('pred.jpg', norm_hm_pred * 255)
83 | cv2.imwrite('eye.jpg', sample_batched['img'].numpy()[-1] * 255)
84 |
85 | writer.add_scalar("Training heatmaps loss", heatmaps_loss.item(), i_batch)
86 | writer.add_scalar("Training landmarks loss", landmarks_loss.item(), i_batch)
87 | writer.add_scalar("Training gaze loss", gaze_loss.item(), i_batch)
88 | writer.add_scalar("Training loss", loss.item(), i_batch)
89 |
90 | if i_batch > 0 and i_batch % 20 == 0:
91 | val_loss = validate(eyenet=eyenet, val_loader=val_loader)
92 | writer.add_scalar("validation loss", val_loss, i_batch)
93 | print('Epoch', epoch, 'Validation loss', val_loss)
94 | if val_loss < best_val_loss:
95 | best_val_loss = val_loss
96 | torch.save({
97 | 'nstack': eyenet.nstack,
98 | 'nfeatures': eyenet.nfeatures,
99 | 'nlandmarks': eyenet.nlandmarks,
100 | 'best_val_loss': best_val_loss,
101 | 'model_state_dict': eyenet.state_dict(),
102 | 'optimizer_state_dict': optimizer.state_dict(),
103 | }, checkpoint_fn)
104 |
105 | return best_val_loss
106 |
107 |
108 | def train(eyenet: EyeNet, optimizer, nepochs: int, best_val_loss: float, checkpoint_fn: str):
109 | timestr = datetime.now().strftime("%m%d%Y-%H%M%S")
110 | writer = SummaryWriter(f'runs/eyenet-{timestr}')
111 | dataset = UnityEyesDataset()
112 | N = len(dataset)
113 | VN = 160
114 | TN = N - VN
115 | train_set, val_set = torch.utils.data.random_split(dataset, (TN, VN))
116 |
117 | train_loader = DataLoader(train_set, batch_size=16, shuffle=True)
118 | val_loader = DataLoader(val_set, batch_size=16, shuffle=True)
119 |
120 | for i in range(nepochs):
121 | best_val_loss = train_epoch(epoch=i,
122 | eyenet=eyenet,
123 | optimizer=optimizer,
124 | train_loader=train_loader,
125 | val_loader=val_loader,
126 | best_val_loss=best_val_loss,
127 | checkpoint_fn=checkpoint_fn,
128 | writer=writer)
129 |
130 |
131 | def main():
132 | learning_rate = 4 * 1e-4
133 |
134 | if args.start_from:
135 | start_from = torch.load(args.start_from, map_location=device)
136 | nstack = start_from['nstack']
137 | nfeatures = start_from['nfeatures']
138 | nlandmarks = start_from['nlandmarks']
139 | best_val_loss = start_from['best_val_loss']
140 | eyenet = EyeNet(nstack=nstack, nfeatures=nfeatures, nlandmarks=nlandmarks).to(device)
141 | optimizer = torch.optim.Adam(eyenet.parameters(), lr=learning_rate)
142 | eyenet.load_state_dict(start_from['model_state_dict'])
143 | optimizer.load_state_dict(start_from['optimizer_state_dict'])
144 | elif os.path.exists(args.out):
145 | raise Exception(f'Out file {args.out} already exists.')
146 | else:
147 | nstack = args.nstack
148 | nfeatures = args.nfeatures
149 | nlandmarks = args.nlandmarks
150 | best_val_loss = float('inf')
151 | eyenet = EyeNet(nstack=nstack, nfeatures=nfeatures, nlandmarks=nlandmarks).to(device)
152 | optimizer = torch.optim.Adam(eyenet.parameters(), lr=learning_rate)
153 |
154 | train(
155 | eyenet=eyenet,
156 | optimizer=optimizer,
157 | nepochs=args.nepochs,
158 | best_val_loss=best_val_loss,
159 | checkpoint_fn=args.out
160 | )
161 |
162 |
163 | if __name__ == '__main__':
164 | main()
--------------------------------------------------------------------------------
/util/eye_prediction.py:
--------------------------------------------------------------------------------
1 | from util.eye_sample import EyeSample
2 |
3 |
4 | class EyePrediction():
5 | def __init__(self, eye_sample: EyeSample, landmarks, gaze):
6 | self._eye_sample = eye_sample
7 | self._landmarks = landmarks
8 | self._gaze = gaze
9 |
10 | @property
11 | def eye_sample(self):
12 | return self._eye_sample
13 |
14 | @property
15 | def landmarks(self):
16 | return self._landmarks
17 |
18 | @property
19 | def gaze(self):
20 | return self._gaze
21 |
--------------------------------------------------------------------------------
/util/eye_sample.py:
--------------------------------------------------------------------------------
1 |
2 | class EyeSample:
3 | def __init__(self, orig_img, img, is_left, transform_inv, estimated_radius):
4 | self._orig_img = orig_img.copy()
5 | self._img = img.copy()
6 | self._is_left = is_left
7 | self._transform_inv = transform_inv
8 | self._estimated_radius = estimated_radius
9 | @property
10 | def orig_img(self):
11 | return self._orig_img
12 |
13 | @property
14 | def img(self):
15 | return self._img
16 |
17 | @property
18 | def is_left(self):
19 | return self._is_left
20 |
21 | @property
22 | def transform_inv(self):
23 | return self._transform_inv
24 |
25 | @property
26 | def estimated_radius(self):
27 | return self._estimated_radius
--------------------------------------------------------------------------------
/util/gaze.py:
--------------------------------------------------------------------------------
1 | """Utility methods for gaze angle and error calculations."""
2 | import cv2 as cv
3 | import numpy as np
4 |
5 | def pitchyaw_to_vector(pitchyaws):
6 | r"""Convert given yaw (:math:`\theta`) and pitch (:math:`\phi`) angles to unit gaze vectors.
7 |
8 | Args:
9 | pitchyaws (:obj:`numpy.array`): yaw and pitch angles :math:`(n\times 2)` in radians.
10 |
11 | Returns:
12 | :obj:`numpy.array` of shape :math:`(n\times 3)` with 3D vectors per row.
13 | """
14 | n = pitchyaws.shape[0]
15 | sin = np.sin(pitchyaws)
16 | cos = np.cos(pitchyaws)
17 | out = np.empty((n, 3))
18 | out[:, 0] = np.multiply(cos[:, 0], sin[:, 1])
19 | out[:, 1] = sin[:, 0]
20 | out[:, 2] = np.multiply(cos[:, 0], cos[:, 1])
21 | return out
22 |
23 |
24 | def vector_to_pitchyaw(vectors):
25 | r"""Convert given gaze vectors to yaw (:math:`\theta`) and pitch (:math:`\phi`) angles.
26 |
27 | Args:
28 | vectors (:obj:`numpy.array`): gaze vectors in 3D :math:`(n\times 3)`.
29 |
30 | Returns:
31 | :obj:`numpy.array` of shape :math:`(n\times 2)` with values in radians.
32 | """
33 | n = vectors.shape[0]
34 | out = np.empty((n, 2))
35 | vectors = np.divide(vectors, np.linalg.norm(vectors, axis=1).reshape(n, 1))
36 | out[:, 0] = np.arcsin(vectors[:, 1]) # theta
37 | out[:, 1] = np.arctan2(vectors[:, 0], vectors[:, 2]) # phi
38 | return out
39 |
40 | radians_to_degrees = 180.0 / np.pi
41 |
42 |
43 | def angular_error(a, b):
44 | """Calculate angular error (via cosine similarity)."""
45 | a = pitchyaw_to_vector(a) if a.shape[1] == 2 else a
46 | b = pitchyaw_to_vector(b) if b.shape[1] == 2 else b
47 |
48 | ab = np.sum(np.multiply(a, b), axis=1)
49 | a_norm = np.linalg.norm(a, axis=1)
50 | b_norm = np.linalg.norm(b, axis=1)
51 |
52 | # Avoid zero-values (to avoid NaNs)
53 | a_norm = np.clip(a_norm, a_min=1e-7, a_max=None)
54 | b_norm = np.clip(b_norm, a_min=1e-7, a_max=None)
55 |
56 | similarity = np.divide(ab, np.multiply(a_norm, b_norm))
57 |
58 | return np.arccos(similarity) * radians_to_degrees
59 |
60 |
61 | def mean_angular_error(a, b):
62 | """Calculate mean angular error (via cosine similarity)."""
63 | return np.mean(angular_error(a, b))
64 |
65 |
66 | def draw_gaze(image_in, eye_pos, pitchyaw, length=40.0, thickness=2, color=(0, 0, 255)):
67 | """Draw gaze angle on given image with a given eye positions."""
68 | image_out = image_in
69 | if len(image_out.shape) == 2 or image_out.shape[2] == 1:
70 | image_out = cv.cvtColor(image_out, cv.COLOR_GRAY2BGR)
71 | dx = -length * np.sin(pitchyaw[1])
72 | dy = length * np.sin(pitchyaw[0])
73 | cv.arrowedLine(image_out, tuple(np.round(eye_pos).astype(np.int32)),
74 | tuple(np.round([eye_pos[0] + dx, eye_pos[1] + dy]).astype(int)), color,
75 | thickness, cv.LINE_AA, tipLength=0.2)
76 | return image_out
77 |
--------------------------------------------------------------------------------
/util/preprocess.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import cv2
3 | import util.gaze
4 | from scipy.spatial.transform import Rotation as R
5 |
6 | def preprocess_unityeyes_image(img, json_data):
7 | ow = 160
8 | oh = 96
9 | # Prepare to segment eye image
10 | ih, iw = img.shape[:2]
11 | ih_2, iw_2 = ih/2.0, iw/2.0
12 |
13 | heatmap_w = int(ow/2)
14 | heatmap_h = int(oh/2)
15 |
16 | img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
17 |
18 | def process_coords(coords_list):
19 | coords = [eval(l) for l in coords_list]
20 | return np.array([(x, ih-y, z) for (x, y, z) in coords])
21 |
22 | interior_landmarks = process_coords(json_data['interior_margin_2d'])
23 | caruncle_landmarks = process_coords(json_data['caruncle_2d'])
24 | iris_landmarks = process_coords(json_data['iris_2d'])
25 |
26 | left_corner = np.mean(caruncle_landmarks[:, :2], axis=0)
27 | right_corner = interior_landmarks[8, :2]
28 | eye_width = 1.5 * abs(left_corner[0] - right_corner[0])
29 | eye_middle = np.mean([np.amin(interior_landmarks[:, :2], axis=0),
30 | np.amax(interior_landmarks[:, :2], axis=0)], axis=0)
31 |
32 | # Normalize to eye width.
33 | scale = ow/eye_width
34 |
35 | translate = np.asmatrix(np.eye(3))
36 | translate[0, 2] = -eye_middle[0] * scale
37 | translate[1, 2] = -eye_middle[1] * scale
38 |
39 | rand_x = np.random.uniform(low=-10, high=10)
40 | rand_y = np.random.uniform(low=-10, high=10)
41 | recenter = np.asmatrix(np.eye(3))
42 | recenter[0, 2] = ow/2 + rand_x
43 | recenter[1, 2] = oh/2 + rand_y
44 |
45 | scale_mat = np.asmatrix(np.eye(3))
46 | scale_mat[0, 0] = scale
47 | scale_mat[1, 1] = scale
48 |
49 | angle = 0 #np.random.normal(0, 1) * 20 * np.pi/180
50 | rotation = R.from_rotvec([0, 0, angle]).as_matrix()
51 |
52 | transform = recenter * rotation * translate * scale_mat
53 | transform_inv = np.linalg.inv(transform)
54 |
55 | # Apply transforms
56 | eye = cv2.warpAffine(img, transform[:2], (ow, oh))
57 |
58 | rand_blur = np.random.uniform(low=0, high=20)
59 | eye = cv2.GaussianBlur(eye, (5, 5), rand_blur)
60 |
61 | # Normalize eye image
62 | eye = cv2.equalizeHist(eye)
63 | eye = eye.astype(np.float32)
64 | eye = eye / 255.0
65 |
66 | # Gaze
67 | # Convert look vector to gaze direction in polar angles
68 | look_vec = np.array(eval(json_data['eye_details']['look_vec']))[:3].reshape((1, 3))
69 | #look_vec = np.matmul(look_vec, rotation.T)
70 |
71 | gaze = util.gaze.vector_to_pitchyaw(-look_vec).flatten()
72 | gaze = gaze.astype(np.float32)
73 |
74 | iris_center = np.mean(iris_landmarks[:, :2], axis=0)
75 |
76 | landmarks = np.concatenate([interior_landmarks[:, :2], # 8
77 | iris_landmarks[::2, :2], # 8
78 | iris_center.reshape((1, 2)),
79 | [[iw_2, ih_2]], # Eyeball center
80 | ]) # 18 in total
81 |
82 | landmarks = np.asmatrix(np.pad(landmarks, ((0, 0), (0, 1)), 'constant', constant_values=1))
83 | landmarks = np.asarray(landmarks * transform[:2].T) * np.array([heatmap_w/ow, heatmap_h/oh])
84 | landmarks = landmarks.astype(np.float32)
85 |
86 | # Swap columns so that landmarks are in (y, x), not (x, y)
87 | # This is because the network outputs landmarks as (y, x) values.
88 | temp = np.zeros((34, 2), dtype=np.float32)
89 | temp[:, 0] = landmarks[:, 1]
90 | temp[:, 1] = landmarks[:, 0]
91 | landmarks = temp
92 |
93 | heatmaps = get_heatmaps(w=heatmap_w, h=heatmap_h, landmarks=landmarks)
94 |
95 | assert heatmaps.shape == (34, heatmap_h, heatmap_w)
96 |
97 | return {
98 | 'img': eye,
99 | 'transform': np.asarray(transform),
100 | 'transform_inv': np.asarray(transform_inv),
101 | 'eye_middle': np.asarray(eye_middle),
102 | 'heatmaps': np.asarray(heatmaps),
103 | 'landmarks': np.asarray(landmarks),
104 | 'gaze': np.asarray(gaze)
105 | }
106 |
107 |
108 | def gaussian_2d(w, h, cx, cy, sigma=1.0):
109 | """Generate heatmap with single 2D gaussian."""
110 | xs, ys = np.meshgrid(
111 | np.linspace(0, w - 1, w, dtype=np.float32),
112 | np.linspace(0, h - 1, h, dtype=np.float32)
113 | )
114 |
115 | assert xs.shape == (h, w)
116 | alpha = -0.5 / (sigma ** 2)
117 | heatmap = np.exp(alpha * ((xs - cx) ** 2 + (ys - cy) ** 2))
118 | return heatmap
119 |
120 |
121 | def get_heatmaps(w, h, landmarks):
122 | heatmaps = []
123 | for (y, x) in landmarks:
124 | heatmaps.append(gaussian_2d(w, h, cx=x, cy=y, sigma=2.0))
125 | return np.array(heatmaps)
126 |
--------------------------------------------------------------------------------
/util/softargmax.py:
--------------------------------------------------------------------------------
1 | import numpy as np
2 | import torch
3 | import torch.nn as nn
4 |
5 |
6 | def softargmax2d(input, beta=100, dtype=torch.float32):
7 | *_, h, w = input.shape
8 |
9 | input = input.reshape(*_, h * w)
10 | input = nn.functional.softmax(beta * input, dim=-1)
11 |
12 | indices_c, indices_r = np.meshgrid(
13 | np.linspace(0, 1, w),
14 | np.linspace(0, 1, h),
15 | indexing='xy'
16 | )
17 |
18 | indices_r = torch.tensor(np.reshape(indices_r, (-1, h * w)))
19 | indices_c = torch.tensor(np.reshape(indices_c, (-1, h * w)))
20 |
21 | device = input.get_device()
22 | if device >= 0:
23 | indices_r = indices_r.to(device)
24 | indices_c = indices_c.to(device)
25 |
26 | result_r = torch.sum((h - 1) * input * indices_r, dim=-1)
27 | result_c = torch.sum((w - 1) * input * indices_c, dim=-1)
28 |
29 | result = torch.stack([result_r, result_c], dim=-1)
30 |
31 | return result.type(dtype)
32 |
33 |
34 | def softargmax1d(input, beta=100):
35 | *_, n = input.shape
36 | input = nn.functional.softmax(beta * input, dim=-1)
37 | indices = torch.linspace(0, 1, n)
38 | result = torch.sum((n - 1) * input * indices, dim=-1)
39 | return result
40 |
41 |
--------------------------------------------------------------------------------