├── .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 | ![alt text](static/fig1.png "Logo Title Text 1") 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 | [![Watch the video](static/ge_screenshot.png)](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": "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\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": "iVBORw0KGgoAAAANSUhEUgAAAXAAAADrCAYAAABwz80LAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjMsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+AADFEAAAgAElEQVR4nO29a6xlyXkdtuo8b9/br+mZnp4XySFFitRbpCiJkoMgkGzoEUFUABmgIjiMw4B/klg2HFikBUQJ4B8SYlhyAEcOYdkmAsG0QysRwTgWBFkCkj+MSEmWKI4oUqRIDWc4PcOZ7unue+95Vn7Ut75d9e2qs/e5987tPkotoPvcvc9+1K69zzmrVq3v+5z3HhUVFRUVu4fB/W5ARUVFRcXJUL/AKyoqKnYU9Qu8oqKiYkdRv8ArKioqdhT1C7yioqJiR1G/wCsqKip2FKf6AnfO/aBz7rPOuc875z5wVo2qqKioqOiGO6kP3Dk3BPAnAP4KgGcB/A6An/Def+bsmldRUVFRUcJpGPh3Afi89/4L3vs5gI8AePfZNKuioqKiogujU+z7JIA/j5afBfDdm3bYu7rnDx6/CMABAMj9vXfJds41o4LmndJIwWXftcc8Tbxp6VierfPl97jvem2OYZZP1cAuuO5Ntsbm27HdvqZ/sT5BeywsNXEdHWzb0AelduZoUdf5u9CnfTzHtpdykqbJOdwg3XkwyB8sfv712bebmmPaY/F7wZkdXXGh2Zarm2PklwG73IZz+fOXztXav0eH2/M/95nbL3nvr9vtTvMFnrvGVsucc+8H8H4A2H/sAD/0z9+NtQ9P+JKv6/SJHw2aT8bIhb8HLv9pscci7DHXGz4ASz8svpc71mqdnnMVvc9t+TpbhC4+mo2TY8yP0mU/29yG08BNV2d+zFJ7+5zL7uvmaf8OZqf/xVlP00fRTzb/Ktg29EGpnfbcfc7fhT7t4zm2vd8nefZ4jsmFRbL+wnSR2zx5/vnst54Dc0x7rOl4CSD9frDLQ/uefG9w/d4wHHMgX67c137PjHW5fS/Hg7R/B+CxVrJv+mqPMcx8lw2weZuf/ZaPf6m1E073Bf4sgNdFy08BeM5u5L3/EIAPAcDD3/CIB5pO0pOfoRfGftlu3HbLL+6KMl6LH4ldBb/Y4y9yfgGf9ou8D/p+IbNNJ/m55JXNe24fExa2z/YJ19tj8oucZAjmizz3ObVf5AQ/8yNsfl4XQs7GmWHWYh2OYb/ICSWLLl3O/RicFqf5hvodAG9xzr3ROTcB8B4AHzubZlVUVFRUdOHEDNx7v3TO/dcAfh3AEMA/9d7/0aZ9HMLQZGHkDg5frAwSY114ryTDNPul/CLHuksSSelcdrtlRkLpK52UsGnIfB4sri9eC+adkyCA7aQVy4K3kUhK/dt1DLeQeY+xT9oQt6O4b6EfyUptm3JtKbXP9hvbqe9vcQvX+vER9jxOP0/zafp889zDxaZ7x2OFPlrLdczk2mfYS7buklqAttzC1+kwrF8OKIOGc0wGy2R/br/OyR1mHZn4UjqH7H8hx6aU0nwXZe4TJRsZ26w2fBcm7ey1VQHe+38D4N+c5hgVFRUVFSfDqb7AT4KB86or8XeT7DrHxEusfJtJynCcYXY/oM24S0y7dO542TLvEuMuTgL2YIpd21i2pprjGbLl0xyL+1p22XVdORbbxcq3mWjsQqmdltHaZaDhXGuyzZ4Tjvb9Tfp2X6btlmY70wS7nBzDnN4PzbXezR9rkJ/bTLAeywhGzuFH5jOu5w6fseV4AgC4E28j99X2L9n61YtHAIC9UWDcZMszN0qWm8nNpjPsxKeeU757yO5n6/CZn8pFz/wo2T+er2zY+TDZJjfRmUOdpauoqKjYUZw7A49Bq06JiQNleyB/9U5qAcwdexumHUNnx1Fm3l3OgL76ZQ6WTZYcD2dpVezDwK3FjGDflJh4r/PLNfLau/qpxUbN+zlGbttXOmZJQ15Hu5WYIVHqK6L1PEV91dUXpfZtw7z77sOPbsP229tZcsmP4ZqXyGXL7s32GgMS9bNl7+th+GzOL4aD35R+tIzcauVDYy+M19GKqBD9fGDcKWTitBfCt59vy87HyDPyEioDr6ioqNhRnDsDX3vXcqGcBJs0baCsa+ccJidh2jGs0+QscBrHBVFi4mfhyDhLXb2L6W5qV+lautgxVtJncsr4KNSpYa6N5yrdG2rLftRfX+9i3na7rO/a9B/bz2tayeOpfaIi7NmF6KrWbZg3te+YgQ9Waf+UmHbpKbWD7uTrxLB3svqh9M3qbtiAjPyFW8HhwmfwytVDAPmgoano5s13yCzbPquJz9fCsk3AT3oRVCNKzpU8KgOvqKio2FHUL/CKioqKHcW5SigeDrN1+5SbAnh0GzN5adHXCpgLurEoSSUWZyGdnCQHB9HXCneacxRlmIJ00kcSUDnATMydRkoBJR0jnVDWsJNtXqUTCR6J5QROOG456WulEwamxOgKQul6pnL925oUlvUqpczSACO91mEhYKrPZOayMLTvYxc0kknJh8D5w9bkqjlHMokpj7rj/ZVtKaUM5hJYxIlzmexc7YXl23dkw0thx7i/rQWRWPo0OGhPpBMNxzd5VdYZ6UoDiYyU0oXKwCsqKip2FOfKwNfe4Xi13SlLofBkzzYzIFGyBOaCbk4Ksqc+TLwUkNE3iCXGSYJQtsVZMu4SSky8hFwbdOJO+sSGbJO9lS1ydmIP8JwUNvyGTLavfTC+T+zP6Ybw7xiljH3a6j5ZH+WcretgOwvP0aYjN30gy7pxflJ4JX/kAnnU8mcefWszbCZIffZYOQbPY64mLtmHTJznYPCQTkAfSyj7LAQJxakBaEHkROfB1Ewpy9cJv7MmQ5mINJkO4+80axO0E53DjtzKlYFXVFRU7CjOWQNvLDXboisnt11f2u+1QMymyMYtM+3Sey0TPw+WnUMX8y4x7i5GGaM0YjlNXmrY8HYbLl4gMjn21tjtzPKWjsnYbriaSDMLo40Z7WzGqmgDkGzCJ6A7+VaXJXWbPOJrhPY3qQFEU6aESxsfd2D/RrdnXWDeukvGegg0LHqgwUGZvOuir6sWvvbJ8kqKSWjAkWHmfpBn5EDDym/Jc3p09RgAsLwo2vcqNIz2wePV5hzkQBMoVEo5u+zQwisDr6ioqNhRnC8D9y5hxKW0rTl0OVW6jnVexRlKuniJkXeFk5/GQdKFHHM7LeNmAARQnmPomjuw15xrp20XU496JkSibjrvCLE3Gi4Q6eGrlI31DT1nwqc40VOTalbmcDBJ1k9n6TlaOu8gPWY8QlsPC2kYjBOnFGCkCbbY1g1zDV2hP6prG+K42stsa9qj/Uz3CY9h+oLMOzsiMqycjLvFyEW+LmnkHAWsxtE9NKO6+XwfQDk8n26Vmcz7kZmnDFxS0co9pBulbxGIysArKioqdhTnroGv1oNO3TrGeZY1s4xwG13XootlWgdGyQN9kgRPXdjEvE+qccfM2647rdtHrytihrY96ha406EZyiFsDyRsem50Ur5n3RElXZ23Ibodw+Om9G3SnkXhtRBuTma7jphh78wUou9qaL0wytVCWKkcc515joYFTb40L9AKdx/FI4b8PsP2I1Q4trRbjpPTwnX0Ie+pG8kw8gGvXY5Fxq2JtaJ73PjSB8k+/rbMx+2FUdULl/Lh+XStJOH5LDBR8JJ3oTLwioqKih3FuUdixuw7Fx2ZWz5L5NhgiSWfBSPvirQrMfFNKLk1ujzlfb3dwPbXehKWzXOUnBnWPbGaNNddumfqBz8uMEWy6g1sumFr6TJZccmnvAmWkeoxhWgN5+mxqdXq/oY9x/q66uOq85r1xvVB3Xc1Dcvjezx2Oz2rRSl9rG0Lt2uOlZlj4DsyEhiILp1LgBUfa9VqX6RTyz7c1TpW+Do0Fu5GCxeXj/Tzci86tnGu2MRZfF5HkjBrNQ2fCbpWbhtGDjSsXL8X5bxVA6+oqKj4C47zTSfr++ndp9VM+2LbXCbcfhM7zWnBQHNNJUbeJ6KxxNK31c1zzPukEZXbjFJs37BPeO7ZFkUvSgUzVKs1jgYY9mTZ9XDRMB27TYkdk62VWPNGaHskSm+ZMkS9LrpORtRmKd5G2wxSXVdPQUZt2PuQLP4et5PXQlrXbaDHMsUZVtHt8qv8PMBwli5bBm5HCH20fx5rdMxzFO6l9D/7me4VRKOF1So/QhkUClK4FeMHwnPOfCu3ouecXvJHLt9LjplzrGSvb+O7FRUVFRUPLO5rSTWbn+S1ZN6b2HZXLo7T5PsgSo6MbfKpdGXx64vc9ZzGcRMjvo7SMbV8lckloU4SYdrW8RDnOfESFUdwWzLwoTIuJMujYzKudHk4a5iOsmHDip1hzWRvbtG//1XSXK+TY3NZXQ/qZKHjwaXLUdfQW65MvMDaR6N0fcNkydTLIwjLWLmPtsHo6wy4Jivl+nhd11yDbm+KM6xFu19lPjJenSnhlfeffaKjKo6etA12OT0OAAzM+ewcg3Ww8JO+bLnnGwY+Q3CsvCTLlomv1pWBV1RUVPyFxLn7wLd1mPTRnTftZ9E3811uHzLXk7Yph5PkFD+LEQFwuvaXijfHbbP9VNLzODrREYbkZKZzZGCiFAPyuU5U85SJ/vFhYFaTu1KsVjTQ4ZFkexPm7ZYxAycbTlmx84ahWtasB2hfY7MP2yt/LGnXKLBfJ9fumMNbGPggOomax/NsfS05r5n7uskXkmrndn1oZ16bt9B9R+kxmlFAlBfGMlmbH5xsfsr3IccIr0uJ6qTjKPaVM1eMRr6aY6/mvC5xjIDLaZt43fGoL54nSY7JXOMcbUi7ybx5jpWJ7I1BJn7PfCbzRdsaVAZeUVFRsaN4IDTwTbifzPtBR1c+krOcU+g7Uoj7uTRSIBO395/7knGrr1b060FER6xDhCSUjHt0JIz7WPT2w5UcI/SNo469aodmuoLumLDeHIxunUc4tpeNnZq2yXTTc3vmOfGpVq6MPAbXjeW+M6f0gro5mXnaTurpeq5B5tjrtH3Wnlw6hjLxcdMn1h3jjTa/mhr3DKc7jOZciugEoqyNwobXwqQbX3eq5ZORb/LjW9dR47uX9hdyo7O9uebSM84Rwy1cAtC4U7pQGXhFRUXFjuL8IzEzrPu1dJ+chnmfRGvmtZQ8z6eBZdz2HFZjti6PTW6fLoZd6kfrQe/jiLHPANvDY5GVUMee3AnMZ3y3YUMjatn09S7JvMm05XVOxr2S7aSPVptn98PBjd7cYq49GW0EZbA8v+jSsLo7sUoZuqKkmQNwcxqpU91cuaeOEKRPlNmacjoxOuYBWnlhSn0FwAsbp3uG7Hw1lXay/q20u/GWpw4jOw8CNFkotRkmmld1dFtBaJX6wPlcjTKjPnUnmX6yzhw9Jv3jsv0w87Xi1BsfPgvLOwdh3466AJWBV1RUVOwo6hd4RUVFxY7i3As6zBajYrj5Jmxrt+sjnZzUjtdnYrVLMum6nj4h6S3JpCPsVtFjkrMUqm7RKr4QH6OjGWpFvBkS4+/dDOeYvhLe33s5XA8tgKN7zfjY2v9o/dOgGl1eJq8tiSInRZgJwtaEoePkm/TJiIWVpRDxnoROX2j6107ctcPxuZxeh04WLntMulq5ha/LVFdwtmwxrYpDmWBNLIrIo2W72yxNuUhO8kzHSjlpwfeMJZVNkO05Ub04YIi6NCW2ERoZo5WAis2fpq/gJKbx7aVyh5WP0nOo5bJQtk2PErV3xFJ08qg4DdfvTiwGVAZeUVFRsbO4LzbC80pWFeOsgl+AkwXfdKFPiTJCQ9EN4x4WGPg2petKzLuUopaTRJxsSbaTvxmYQ0Y+lgT4w8Owr1SgwvRWOMbeK6n1b3w39MHguOkjDW+XSUqyTGXaZJ+WlS7T/vS078UsWyf/hukywUnBeRqMwytvTfSFqwEQFc+VybLlJO3XxrbGmTs5pYw4lKHHgUecqGWwjRl9WEbeZVV08YxkLnAog2ai12yX2U0nSw14bYSWTlvyNZ3kXKxM8QXzd9jWtlO2s03grebjouHxcfuE+Ztd1yZ4qWk/D52WgMslDdMUAKY4dBfF7vxkO+de55z7LefcM865P3LO/ZSsv+ac+w3n3Ofk9aGuY1VUVFRUnB36UOElgL/tvf9d59wlAJ9yzv0GgP8cwG9673/OOfcBAB8A8NOvXVO3w1ky7vuBTczbgsx7VKrxpU61/kzcat7WjkUwAGF83H6fIcO0fVELpC1wdCT2wENq3PLKMPfDsAOZt4sZOK1ylmkLw/aWBa82h6wna8m4jV7uNG/oIN3O0Uonr8dk6E3CrcE8ULn1RCyTYh9c7ksiKptoapBqoKs90YHJRudN24Zyr6x10loUyci1eLG1NAoS+6Nl5V3WykLSreSYuUChCDrKWKVasmrOWvg5DfwByqlxtR9F826VgjPHZmIqN2020YRYhaLKltU32rjszy7LhOQ3I4d8WoESOj/R3vvnvfe/K3/fAfAMgCcBvBvAh2WzDwP4sa5jVVRUVFScHbYSo51zTwN4O4BPALjhvX8eCF/yzrlHz7x1/z/ASRJKkYmXNO+u/XJMnNq31bwHHcVsNezdFOUFmhn98T0y7TTMfTBPg29G94RpHwnzPhTqbhM/AcqovbofSJ1IdwyrXJntDLuOGbvq4QPDtDXQhcybkRmD5H03Ch8rdYwAGB6FzhhMpJ+l3NbwmMw87LuayusFYegXGMySsk13obmH1MeHwvxbjJx6uQ0aMs6cEiMH2kFJNiiocU3kg3RifdiyymKaXmnnUN0d6etwzlD7dpj+SkLp2V+W4ZaYrdXA45JqhBZMzqScTda3nDoonrv53DBBVy6BW2a/zW9HJ3fuIoB/DeBveu9f3WK/9zvnPumc++Ty9r3uHSoqKioqeqEXA3fOjRG+vH/Fe/+rsvoF59zjwr4fB3Azt6/3/kMAPgQA+295YouaUwGvhePjfqKLcffxyFsG3ZeJ2/3ivu10m5B1GF3bsuzRUbPP5I5JKGXD3I/FXTIj85aDGU+xX0ifxSXLmDmITJysUbYtaeB+VaA00fb6Vy5hFNCKoXZk3mSpE9G+x83Hy8k6R7fMjExV2Po0vD8QBj5YyDHWLMfFcHMyzOjShOUOp2TgHOFIagLtdxlVUSPnAEOYrnfteYIWG7dzDqO0L5SBm3SyaRFm69VmYim6TNL1qjmrNu6TYw6PmjYyHH/Iws3iMSeTpv5sy7Ktje9a12e+flZIR502oZqFbW/MzEsjAVvUooQ+LhQH4JcBPOO9/wfRWx8D8F75+70Afq3XGSsqKioqzgR9GPhfAvDXAPyhc+73Zd3fBfBzAP6Vc+59AL4M4K++Nk187bCpGEGMk+jUfYv9bhOV2ukiKbxtfeC37l4AkF5/SfNmibKBmLjJsFXXvmsKJhw39II+7uFh2NnNyD5lmRos2Zwwb0+vNhk32fai6Stuo4yaLE7dJj0iLrvAfSwT57E1C5S0m6eehZGEiz3nbBd1dOrkSylUTYfIjPp5qvcuWKOMhuXIecFyZUv1LksyMEnIRIfLQBm6FIAWl0+jfcs5Io85rJfcouUQkb4YpWw6G1HI7jOpZ5uoVB6TzwHXm6LekT4/WKSJsdS1szBzCSZBlqNmjlQz9xu+IXnpWry4UPChKZSReU8TiZlj9yww3fkF7r3/f2C9LQ2+v9dZKioqKirOHOcaErleOxzNxmdWQPckyOVIscz7NGyZUaan1br7RKsybUNXbhRbPFr74E7TF4yOpMZNxk2Nm6ldp7fz+UlUZ4292szncbQl4ya75nrq2pEeW2TausEJGPe2IPOWfnWb8lbw2pjchJo8uNqnr+prp4dbil2INr48aE7GyETqvGSV8zGZN1OjyvuTlKWqZm5dK0DbS27mJ5rl9HKHXqJDl8xjEjtFqJOnyxa21BtzjPBc7Mo4KlXzq8h5PXV/udY1mbn2QdhvwVHAXnruLEyOE1tqTdtt081uKkAh23I0VWLmFjUXSkVFRcWO4r7kQikVBX4tHCebshJ2Me+ugglErE13lTPbNhNjrk+6tHtehz0XtW8yb7JuABjdTbOxWVcJHSXUtVv6Ntn2rDlnK1pyaZwjXDYat5/P5X1ZJnstse0cSg4Si7Nk6to+1vyKmCGZdem8HFFodKew58O0tNZYd5ugjZSJk11aD/lAbtFYctFolKdxrQAZ5wp1aW238ZAzo6Ewbk2zEuU/GQqrZ7HltThvbJHlUmCxIlNUmtMSzQiGWnw4B59OLdfG8m2FKMr4LtlYBzJv69Vu8qj0fAajfTa5X3KoDLyioqJiR3GuDHww8Bu14U3vnaSobl+clHnn3icbP2lhYW6vubKP2l5twplsf3qMibAhU96M+0+EeZN1h3XyKq6S6W1h2OIqsRkBW9kAmXc7jpY0EZSqaZNtCkNXxu2NPlzybJ8l+jL1TbBauKOvOTqN1bzFhaJ9MSo8J2TunD+QY8Z33AldI8v0A4mCHKWOCjJCeozpu6Z7grmv6VoBGu14dCiM+pifDXkOuOEyHUXpeuYad9FnitkcJS8MNXcycm+85ZqhcW1GLTYfSw6MMiV7Fr19rVGdsp6sekBWnfZVblsbWanl2vbSfi9FnobzyDaGgfel1pWBV1RUVOwo7osGfhKQJZ9WJ9+UpbDk5iD6aOBEiXmX1tvrsrlJgLJXu5VZTX6X18P0XPR0j++E5enthl3w78nt0AfjVyUfick1rYxbq6mYSjextktPMJn3MmXryrxN/hJvmdZJYCvOboNttPZN+8fPhYYXunQbSdfX0shbx0zzg/hhlI3wMH2mybxXE+YjQfK6okYuMjrZ5ug4nGO51zxz1Mm9iajUJ0sePm03GfiGotE6UlGdWpj4mB75QiZDje4sf21Ztt4wXMPqxR9OBw4/M2TXmp97Q0Qk+8Iy75VMNa0tq9Y2Nn/nqgptg8rAKyoqKnYU9Qu8oqKiYkexMxJKF7omL3PSyXkEFOUmIzehNFEJAMO7MswrpXItzfkxF79YBFlQYe+VZofxHSlfdie1BbYCODhZZQvn2iRHQCOZrIx9kK9dFr4tZBBniwSU9rXbZeUajn3PTtLxJlBHz9s1dKbkMmLhh/Z1MaCFyZ40ediUKWnTob5KKaa4Ae2GcVImtfrZQhPyOrobnhe2StPMinbh7POCKNyey4vUNMD1LA5Nm2EuMVY4Xm6iMS/hNImxuI8EMYmkMmol4YraResh+5GZB4x0spRgIJYZpDxiE8IBjYO2aV96HV2oDLyioqJiR/EXhoGfJTgpaSctS+tzaDFvY/UrlSiziAsp2MRStH0NhFk3TDy1SGlwjildNnm1oVoDJjZiQI4peKCTliUGblO/Au0iC4bJsnCCTvL0CUnvQqFcV6tIA8FzZYJu+CZtgS3Yyc4+IwamD5C+cYUCv3oKpmflxJ5M9MWTcnaCTm2BWgg5PcfyYp4Zssj0MGbgY8PeNV0stwgzoZaJt/q5T4paC8P2m6RQZQauh7Th94UiESzLphOSIya3kpHHJEoapsUhwuviIGXeiwNuJzbNcdouMncX9a9l5V0FHCwqA6+oqKjYUewMAy/ZB/tqy9wu1sI7LYmFgJ6TFAcmex5K8d9YB8tBtbDoF5nMiDERLKpA+9dwxqRF6fKQJctMwikXp+XUJPppsqLm/TQBVTEh1XJDqgCmCxVmaxM5eZsR6QQolkNjsQBd3qCFq069zi5bhr4VNPik4xkySa0sxyQTBzKMlOySqVTNLVlcCce88rrbyfpbL1wCAIxebr4WxndS1rkepss2/L2V1Iy3IUqx4AvBU/rseYbv2+eBgUppgYQYzcggn6JWQ/4Lj6mWtlN3YXOflsK0OXfAV2relnlTA+8z2t6WeROVgVdUVFTsKO5LOtmToMS0rWujBIaVb0onuy0jz6EUqEMt26Zr1Vlz+wu8Tt8HGo2bjHskRYJZLJjuA2qfqksKk7FBOIh1VBanlfBmDUGemRB5Db5goql0OWGyA8t2GR0hbIjsjayoFNZ+koRTlnmbwsOt7WKNln/wWoxrxuWClmLw/RzL1tDywkjAtsuC9ynar5SOtYTJoyE38KMX7wIADsZhkuT4cih1++psT7d97vPXAUSJz4weTQ7oJWiMbRkPOOJkCoCojZoit0SD+Uyxr3gIsn8eq93/thxb6301n7QTYTVXEzlOLrT7VostdKR8pWtMj51h2XYkriH1PQd3lYFXVFRU7CjOlYH7tduoWfdl00Djj+6bimgTh5v3Puv2KBUJtg4RamAlJ0m8LYuojo5MUYV7TDglr4emSDBBFhd5iq27QUcM3qSEpQ68MOv12NEd0dSopCpkpnpFspl5nzAsKvGNd7FgbYJpA5c3uT/0vKRM0k6f16Nb/Zs7tmXj7CfLyA2swyS7jS18YFwZzXJ4n/EPD+0FJn5tcphs/+q0YeDTt4Vn6eV7+wCAu888BACY3GZ7UybeQErDUY+P+kifaV4bR3UciWWuEWgXibAulfh8CqN9K/R+pKOlJny//M2iCa7W6WhaW17QvG3iKgDwI9HNOfDdclqlMvCKioqKHcX5ulB8nmVbNt1r1nbRj3urFzNzXs4SY079N/2Vnsk+Vj/flBCLKI00lGkbxk1WPVRPd5riM7wnvl5l4GTe4iqZyau6TERjpN96HG63vxC8u6sLUapaFqEVfVJ94SzKwJSwUrBXWZNhkokXuqXvFuiFLV5sN1c/+Qa2XWLBVoeX9W6DT7lJ6WlSvnqy5UG6Xo5pI0uLmn5ogHk1/cjN6ELh5VE/jsqIDegMKZ8tAZO2TcSecm18DwCwJw/jtXHzXFyQB/DKJFT2uPntgW5SG/fP8yalTJzP+Yqfocjx1IwICqMoJsSi64rsWJ5fLRLRwxPfsPTU+dQg/0wqq4/noDQBlkShckqHlyHttSxa081K8jCybgBY7aWOFd1n0u9uVgZeUVFRsaM4ZwbuEk3YMu0cqy7m9+iLVXrM+NdxyCgsw9Jbv4bmkJaZ58CRRpGDcbacJI7Fg+kwOUrZdthGXCZHRusW5t0qqkDmvRd++tcHwbi6uCQMfNrcC2qH41eF4ZF52whLsiVltiOGIpoAACAASURBVIbpRnBdnmeyZi2AkEbNKSN3Rq+M29HyZssu+TM2sD7x2IXCY2r7SPk4bOI+1n9tzxHPBxQ0cH3dzKWsYyPZWvN3MH2syV9iXBPEVD5c+yLiPjF5BQCwivKfXpFq1jfHl8O2o/AcjL4+XOyXJoGJ40tk7fRdi5d7Gdo0iNxZqkfTIYRy3pQAJmspuHuiZc2jwhwupoByCaXcI7GmzriKCZgfKBx0xUGq5ESBlrKTtrDEmnyvrC5GUb/CtKdX09J5fVEZeEVFRcWO4nwZ+Dqvb9vCBJuiFPtGLJV8lIOcH2XFKLOw2JeZ57Tzkp7fNZJQPzij54R5s5RZOJYwbuvrXqYH9xMpBiFa9/JSoATzq2H9MuNtHYuTRdlRQc/1Jpl+i2XHGm5XuTLLfktRnFogIaJJBebddS5X0Jo3trXDHdMu9dVjPqB0/mGmH+PNTLRi7vwsvsD7rJGDwggZUTyWh/KShPReGrRZ4IEk2rk2DDr5/lBiC+SBnX5duGd/gsfDDsLEWSRiyM/DMmLg6kzJXmKRiet8gO2b+Lmg1q15U2QT65W3H4FCFsMma2GzkeZXMQdjhGgTpRreXe6H9ctroa9itm0LkNuSil2oDLyioqJiR3Ffc6H0Yd4lxl1a35RCKp612J6hEECdJTbMvPhrl3PWFK7NFkRVv/fK5DM5YlHhhpWqy4R5JchQVOsOv9preZ0/FKjX7KFwm+eXJLpMGAILGANNmTW3KGQdtAy2FNGY84GXYDIZqtuAdKivrSJpRt/IAN0hbUt2m4IGzpw4lkpy+1yUpem/4ohA4Gl1sO6K2FdNZiqsk1nzqMku9mW9MMHpSEZyMholmx5LgpA913ZZ7QsT5zZj+YBdHIkJ+uvCy+fmT4Y2yYeGo1kXTT7pfIssD1IberOdHVl2jE5ysPq/zRujIFOni0ZHNeXnoslXxJgNM98mrhNq3ldvhA+ZLZoONMz79q3gt9c5tEIciWl2RUVFRcWu4dx94H382zn23Ff77tpu0/sNezfuApKHGXXgbt3V5vfVCMvCq+b2nov7ZCaa9KxhQ/R3N04QYaz0dR+E1+NHwuvho6HhsyvCyPbTc44iyVOztS0KTgCrcVvNNocSu7THVmOvyQLYA52M27o/+rA3uiOYJdFEjrYiSrfITsn2dI5kTDu9zjWkbQQiPzS172nKvHnfmYVwKkPNqTwIZNwTeVipewMN017Ih4Pb8JXHWAjDXr4ttOtLsyfC5c1SXziQsnFgAxNnH6gbqD/zVgeOFnhmzpbwfimDo2M+cJPRMQduw1HGquO7h7p2rG/begF96wQQlYFXVFRU7CjuqwbepxrFSfPknqg9pQBLs76oo0VoZRnUWe7w2srhzbwmh8ynTE93ho1KRNpaIikXV0LuiuNHwvLdx8Pv8vGj4djz66Kdi299/GzQxv1LUXtVxyuwXzI+y7gNY0wi4Uw9R5tD3GqcRYaVyyxnvcDWI2zfL1XLyWnfpg9alYPIxEm5Wo6GE2RPtO3pykYY5eqgw4Iskxr4inmqmdrkUngO9kW3ZpQlGTd17qsRA9+TD+BK5o72jE6uDF0KRK7FGz/7prD80t3HwuUko9r8vVAmTt2XuXpynwEge69t9R72CZ0hK/Vm24hXOZTWpOQ9j+MD0vxENvPhwMxzSYArNI/57YutS7Bek646ARaVgVdUVFTsKOoXeEVFRcWO4lwlFIc0oMVKJ+cpl8SwYbSl4gonOZadxBwu0mIMk7sMj09tgzqZGKXBZIDOej+8zh4OY+Oj6+E2Hj4W+vPum8PJ3vD0iwCA/XEYMs9WYbsv3pGgi+j3uxRKXAowUXubkVZ8LF3YCTeVTkxZto5gnF7BOmaSdWs74UYboTkmJzc5AWlD/3tIbK3iEKWJXp2wlkUmrpo0H11O2NkCxExRykl3JmHTQB55OPlKWeRK9AGYmHbtu7m80k4olrg9ZLH8ztDwW7/zaLQ2DbfXS5Z+G98VKYLqHOWOHp/DpnSaT5Y32YeBqF9pG9R51ma/RmJNpRTKoE0DRcoSk8DwKL0/2bD+E1Lp3rs554bOud9zzn1clt/onPuEc+5zzrl/6ZybnKwJFRUVFRUnwTYM/KcAPAPgsiz/PIBf8N5/xDn3jwG8D8AvbTyCD6zbMu5OBhxh64TnJ2H1dpLCzrUVWHZ6XpnYMIE7NlmVLcZA5s3kRUyhCQBeJi1n1wPduXcjvHf3KZlg+o6XAQDfcvUWgGayaiQnP1xKiL2E/rtVj99vy7zZnhGta5xUy0Q7tSYaDQti8YjSxOmmycCOSb52sqiCbW8TOoo/OA1EklS7fMOmxd0Ey7Qz5e4SyPWtp02b1pKUjBN0aztBJyNdm+J4aAJ4LgkDP4gmfMdm8ncsH47JUFi9S71/KwYPiV/v9qXwrN76hgu6zfzTl9gyXpS5yJGci+0Xay1HbnZSMw5qoh1XJnaZkkILIbNUWiHla1MEWa4nCeQJ742OhIEz7cWCief4flhuTSpPhIlH37ocLel7ZvTU9X3Xi4E7554C8B8D+Cey7AB8H4CPyiYfBvBjfY5VUVFRUXE26MvAfxHA3wHAn86HAdzy3jMm9FkAT3YdxK2BYRQ8Yi12RR0WzS9kKwHOttpRLx1NXlf5ZVvuLA1SkG1E69bCDZoMXhi4MG+bGlYTVFFTjpjW7Fqw/5F533lD+NV+5Lu/CgB47CAUpX1Iku9PJWH/TH7yj0UDp51wHbF71eeorUpor4ZpsxjEVF7JSsnAKQ/HzNGUvFImpbJvQffVAgrr/PsxVIcuhLOXNHEbQh+/n0vMlVu2623xZtv+ZF1aBKKkhWv/c3c2O9LZra21WPJLgkXmhn6Sie8pI2+ei7HLU0Cy47F+IAMTX8kHcrEXjsFnb36jOeanb4bIosFCwsXXm5k400o4U3KtGQHF+6SBcINRGkoPDZVPz6RJrziQzKgDTUEVY/mdpaHx/AysLoT2M23zak/6Zj++X2Tn+XZ0pcHt/Ppzzv0IgJve+0+1zpoiO951zr3fOfdJ59wnl4f3cptUVFRUVJwAfRj4XwLwo865H0aYa76MwMivOudGwsKfAvBcbmfv/YcAfAgALjz2Oh8Hy5Q05hzsNpou9gQJj/qeq8S8ra6d/ErP0xBcMm7qZZqkSkqWtVLDknFJeDyDdADg8EbgPfceD7+fV7/zJgDg6ctB+746JvOWY7v0N5XuA7oRVpPm2GvqdaKzD8kIhTWTmWvYNpngOC0ikDLD5PRa+mswN8m4eM3LtA9aGniGJTdBNiZEvZS+1b7Pe5dj95adl4JsmJiKu2kyrjjlq3mAOcpwaQIvPbJpL0cvvKVxoYEmpFtOxeIghjyPb0uAl4jlK3OD9pSsNutHtuSYbLOSvpCBG67pLnfDOUTMfXovjBpvMZ4fwMtvDn+/cPdGetBCWbbGWSIl1VYypFi0P/wO1L7DszSi5s1NNW2zTVXQOpScO/pbNW9+pjmXlCZf04RwHDFQ2NbUtk2fMtWvRRfzJjo3895/0Hv/lPf+aQDvAfDvvPc/CeC3APy4bPZeAL/W75QVFRUVFWeB0/jAfxrAR5xzfw/A7wH45T47uXW3q+NBRct9QsNAUvZM2JAmpRK97Igh8iw4zGRVRj8TrZlFGBgeDwB3nwysYfpdgXG/+WqIhX9kGlgPS2OReTOseWGsOEwiv4x+/RcHZC6pU4Ez/2tq3eo64Yw6Z88zXECTPYUX6zZpFY8gqzTasWXZ8ToY10ALmtq1kAKAq+OCybakmj0ndfdS0QW2d0Mq0sZ9khZMVtdyyZ1CL33SXmnWjIwv9Vnz9nOe49VZGHktvNXCxYcd6d5Dm4JAG8h2h/enst01mXc5HoX5mEMfHrKnpq/oIV6+FBj4S286AAAsP8cQc8aFMCRdXpfyzM1MugQtxRbfp3QbSvQc6Q5n+RGjulC0EET73tJt4nqmStDRks5JILN/en4y8lwB5By2+gL33v82gN+Wv78A4Lu22b+ioqKi4uxwvpGYfkPCKEQ/6j2sumRcfbUiu198vi4MVumvYKONt1NOakm0EvPWNLFzOYZ1eYSLZ/mzezeaCzx6W7DwvPWhrwEoM+8S6Ae/ciEc56uXmveOVMSUdgiz5nXY5D/KUKjrjfJsFGj6xEbJFaMflTUbBrzJpdRV1LhUEHfdbosyb1PiTbcolZuz15NzodhRhl6reZ8aeSvVruwWsU4tA2aujTEH6l8Wy/ZzL1wFABxdz2vhg+6S0I1Obm7KGCkTvzYMz+hTk6/pNl/bC8z7lYcDE/+TW3tyTVLyj5cuDHwkKVYZ0cj5Fy3nF0+EGacKHSrsCb1S9vMgHUFq9b5MRTNl5/zuYeFk+cyoT50jOJfulysqwe869YPvMwGduNI2FE5PrqeioqKiYrdw/gUdTuA4AcqsvMTE7fabzmt93V3tUu1bizJEjoBlyspV6+Y55sLEtQyW/PIb18m9x8IF3H26adQ3Px2MPg9PA5XqYt5cz1wXl8eBeT9yQZwC4mIBgFd+7zoAYLkvmubtwBImd9LrSYu8NmyC+mrijtA+N/uU/NU2apIujhyTJTQPidnGZNf3qgsb3Z15TWK2LfdIIyxbxXVJEenIsddjWHPcnpZ+ynYOk2VtLxnlIo3UHYyaB16fW3VY5HNzsIDH4KXwrB2J0Lrw/b8GVBOXezKQdjOHCF0p+xL5eF2qNNwaNhGbj01vAwBe3A/a973Xh3Z89U7Il8IIYSclAFkUgvr1QJi6PvZJUeN0RGMjhMmKbYxCCbn3G3Y+iA+NdavUXnoOq7cDTXlDZeB74aJY+JjzVSVUBl5RUVGxozhfBu7yTPpUPvCO7fvo6V3nsn5v9XovUnYa1qUuAXVa0DNqixgY18m9x8NP8Z2nw9tv+LbGXn9jLxRFvToObIYMe2iGDixWy/VNzgthb/IrP4o05ivvCr/4X/raQwCAxTNBIJ8YJs4siqUcMzFjGZRcGGRDcu10XGhR40HKRlXH3FSzyjJu+sJt+wx71v0iBu7JwKllWm17JO0mm1aWR9Ezw7bl79Y1sJ1aHGKUbG9HCk2OnObB5jNnnRQa8SrXMdoL+4zuSkTgtomFtsBYmPlVGSVejRj4jVFg4F+dXAEAvDQNTPy5R8K26+PwWViJBr6UNCrLYzql5FUiOQdJgWfpZy0mIjo1X2WOqeWeyujTYbl9bVrsQRwijLRsXCrp9n3m6TQCcxqOSeadK4AcozLwioqKih3FA6mBbzxET9KwDfMu5j4xjLuV54TMO3a2WK+nYUGaK4RZ5Q7o9w464D0ph3b9O0J+kycPbumxybyZ42RsOpNMm5GYQ9Ulw3bHonXuD+fJ8QDgrkTMXRd9/PlrIenkF74QouUufj6dlrdMvHXd2HCvybQlv7mOSshsZTNPd4V1ZiDDig3IaNVRQi2Z/S+M23OEtGi0Rm996Qaql9vcLWTTmUyCbYdKqt3riIHnZIdabZ8+8Oh4mmPGuiSYgU8Y43BOti/s06dsc9XRpzGoha9UC0+jKFdgjvGw/PDgSPd9WRIiPSw1xx7ZC8/cEzfCs/7cnetyXeFDvDgQN4ocYnTELH8mHzsiJ4jAat66nn1FJs4iyK0shW0NvHFT0acucRe8h6YQck771vbq/JvcIxkd3b4VHDqMmi6hMvCKioqKHcW5FzW2nuoutHIbF7Tts4jmtAx7qDlPTA4E9eJyfaTBrVP25iyrIfO+SOYdXCd3nhLXydeHk37TpcBGrk/u6q5k3lbz1ooqwrwvCsOZuDxTJ1YRA6MT4eVp8OjemAZ98uCtga0/8/IbAQAjqZYyMR54m7ci/C1/KCMUtjMR7TJ9G4N7QrHYZ8vUBZKw2I5oOI/8Nasz2nq3T1CImHp2MdNhr4OUvOPWViX9vDQjC0ROlVUaXdg8Jua5la5ZeLJlyRciW6+juYuTquQa1SnXcWXQaLmXhI3fGAct/OYkzLe8NA3P7XNSfHl1l9G/0j6JUmR+bbfkqCVqpTpBUp+3PnujPPO21XJy0wPNvA8dQj7Zx5nnvA+0Uhfz1xzKvs+Hi51fzBjS4/17n6mioqKi4oHC+WvgWzLlopOhQ0u3zD177JVlj1wvr0brtrp2btZZq3Ms8xqm9XsfsqqO+L3f/rY/AwA8uRcY+MXRrDm26Qsy8UvCuPcHYdsDeW1qHqbMfSydN4mYOVnYYz6cl04B4ua3BqfA0fOPJtfM6iNW94th6xO2mDh14DndHXndN2bJJUeKI/vpeD68yfERH89ZBmXzgXC1+tdNvpWsbirn2dysqEHGhaKMUo63zDBwWTc0owk6LayHX98XCjnTxzvu/zwHX23y5kdgxOZeNCo5kLqafE6viLh9eRKeY6uFLw/lOdlPfeG8nvUi7u/UEaL6cyGSmMxbqxmN0+3izzZHJjpyHKcjnVZe9sJnIvm+kIHJYGFe+Tje3cyxKwOvqKio2FHUL/CKioqKHcX5JrNCPxthPEF50slJO4zMtseGxptiDCqdWAnFHicTsNEE7qQ2McoG8yuh61mc4Q3f9hUAwBMXQhpOSie5CUhKKZy0tNIJ1++59JVSyp68XtVaWw3ueRaUDed9aRqGs9cuBMvhnzM3PeUlk7RrI8zEEowk1cLASBQ94Pum+mzV5uuPlnRSKtuWA/fpSlXLYKZS2blFMynoRmnqVMUo7beuNKg6mRlNrK7AYLDTcb24OPIVeU4vDYN08sgoTNS/KJOZr06DvMjJzPVtBuGkgT0jBvZEUkUrZbG5ZpU/TGqI1dhKLOkr0EhrDHsvFaQZGKNFOzCwbbVlmgNO0A4kgVehol3reioqKioqdgznbiPsg22SWfXZF2gH54Rt02AUm7Cpi7HYtLLhGLR0mdBuCX2ePxTsQYePht9Opoh9+iLLogWmq2HvmWmvscx80C5YYt5k5g0TD8dkqs+DDKu6BAb9hHZcE3bECSabZrMp9Mrw8S2YLftvQcrCIBbDaCXAB+OoTy2Ll0m1IgO36Vt1dXt7rtPJzMK+TVvM5KVJ+JS8x2fFjirsxKcdfZj3NUUDALAoiLk3emUswqETerL5GVZSWRemZ2knjIOGLskH7tIgPFNXhiGg56rku90fhQnzR6+H0ehLLz0CAFjOUna6lIqAg0XUlyagzNlU0LLM51bXr9NJzVx6ZFvwuAvNpKYxS0T7axk8O4kpr77jXJWBV1RUVOwoHngboZrke/7qlcqeWbYdv2cZd6uNNtGNCVVONfC12Ub0u73Q1dS+D2+EYzFF7I1pYBtXRk14uwVD46fKtIOGbe2ClnkfcD0DfrR0Vvv3m4z/kmHx1yaH0n4m8DH2rGypr7QvopOEbWmFW7I0lrnJ1IMlNN1NIoop1jENa5cUntS2u7TwPlq53aalR9qRgjNsed3uX1cquqH72gg1l3/NHaKVUpd/SJEORp5LwqTpcCnNTfdbZyYl+toGS4gLJU/kGvT5lLkYpni4ImmPX5mE5ZuS5Gq5CKNXllpbim7MkHagYdIrlpPrGE03n/m8fTDWwG1gn25bHPWbACpjo023tcFXcv6qgVdUVFT8xcQDoYFvSr+4LWNvMfCCzh3eS9fZX9ZSSKzrE45hEsovD4R5PyJ65DeH1LBMEXtxSNZcTh9JptTSvIXBkNFMNJGQfQ3HGfYomTUUpshjXpPEQw9/64sAgNkXQ5DF5Ha4vuGhMOAoKZQy7FXhJpK1L40GbrRwZeJxAidbrJjJqxjeTuaiGrlhyRYRw2xp4ERr2TDuru2BdrpYuy3D4Kn7G+bNFLzZcnS2n037ljJqWlwJ212Q52a44Xluglfyz0xJ+96EsRyLI0M+vw+NwjP20jho4FcmwaVCLfzmnYcBAKtZmuQqLtO4WqTOFK8jQjJcM9pupYAoh9T7iUv20URu5pGyx6IGnvs+OUm66xiVgVdUVFTsKM6dgfdh1GeSmMow79wx+zJum6ymhUQDl32ENa73g247uxZej0J2VnzjYyFdrNW+qWcv5Kc59oFP1MctTJvatzLuRbLPGEz1GUBHwEpZVZs9zYSJMtERw+/ZvicuhhD7Z26EkPopGfgspAgY59g202wu0jSsLeZNWI2R7HMUPa5k2gPGQLM4RInt5z3o3qaERUZLJuSeOtXmTSGHkha+qT3G4eJsWD5L7o2kfBtT8MZttH1u+pOh9EsJRX/0TS8BAC6L+XhvAxNfm7JspfcH5n0u5/T0gWrg6XPLJFcsFbg/Eo1ctHCYJFech1nuNf3chKab9qjrJGXiytSHqQON3wXxUXQ0siGFcgyya84TbZrHU3eMXKo/TB1DJVQGXlFRUbGjeDA08B4pZm0ymr7HUu8m348IwaZE68kx7S9sxlOuoOdWmju/HBgTte8L3x783o9dCNo3mS1ZCNGUQWs0cWXchrnstQo45BnkymjLi4it8q+5bMOoPLL766PQ3tcfvAIAeO5doSDy3buBiQ+WfJT29Jiju4FOuEXaHhZ27g26PaJVWqy2talhw4XtdPsMAycrL6aJtR5usuE+EaPc1nEEYM5RYvUsgsFSavFDy9gDmzhNtl1eCK+zK+FYTxwEb/810Zz5HOVa3zwzm4fFOabdBZ7PjiiZNvmC2D7olrlyNXxWbt8Jnylq4cvocaJTZLEig5WRJOcWzHxXyydunGlpVLh1qqQ6ul1P2JF9+r4wfU2gJ6+8zR3dWhl4RUVFxY7iPpRUa7PtPpFNJ5ntTvbXX9Lo15AT/YVfuZKP077GWidznbDc0/xKeD0OwWR44+WgeR+I64R6H5n2mukwhdHEKV+bwg2p62SIdfI+mTidJLw8PZJ1eWRAfZKOFxalff00jCBefiiUfPq/3xaKIA8W7cTzJImje5LOVlOjip5rCvW2D2BcKRHauUNSzVgZ617Q5v1EvNBk8zz3XM5tPeiIdGfVpU0b6LKR9hc1/XgdveE8v32/5Pcepm3w0XPceJbTa2fsweISn8FwDjqfGGVrR3/xyExThPSpzItonqVHeTYee2xGlvvy2SAT3yMTZ4Ff0cI1MnPetG2xn/YbIytHo8Jn2eQt0QIPRr+O0cyvybPU6ppUZ2/PrZWjPAmmul53OMYqA6+oqKjYUTwQGrhFqlOH1y6WniuBBLR/QVcbJNFO50om90loY8TAZcafrOfomiTL/7ow488CrvR9k+GSLQ9BFp2yaqBh3tSlx6ZkmtW+tWSavCyU5UHO0QbXjRmRKec89sEh8MQ4aOC390NKuLtSgOIP7nxd2H8ecwIWaJDTsvAAWbDRjItMPAerR9OtsR80+JWUrFtcDgx8dSG9WrKjoRSkiMvi8Zlpym2lpb2IoWRgZCbGwXFghm4mDpl57ImnyFkYVRQYeHsUkFWqk/eofS/M/MuT7whRv09IsZBmBFdmyyt9b7MYS9fJNoWRib3WyDI8B4w4ngzl/VGqhd8SDXwdFT1grh46U4bS31p8QT/bhchHk4Uw5wLRotCdsn8hjiSTj8l+T2mG1I6I4crAKyoqKnYU58vAXfpLU3Kf9JTbAHQz71xe32LzTPYwekrbGrhpw7g5+OpC+Ht+UZh3kIjxxieD95Y5RVgGzeYxIYaa83ueWZcyp72CwVT1s1ZgGNl+0//ULptitHJsYXcsg3UsOZzfOA0RmYcXA8M9fkegPp9bvKE5P33TNsXJkeTgYLPo2VVWzXZvyP9h8qQwQnE9De1YSrvmV0UH3mdGvvQwo+PUDww0zHs1IROX9UbmHx2FNkzuSE70Q8mlfleu77h5OJlxsZj/xTBXMm8Y/d2aVoDotsozv7gUrn32kET/PhmO/c4r4Z69fvI1AI3v2uacX0TPxZjSPT8TfE4MuzyJC2Wor+KekmeNecLpQjkQc/T+WJ5BcTy5adh+NW2+xobHeQ3cou0c6W6v7rO5znALtpB7WoLRRH5ue+ztNq+oqKioeFBw7hq4H0Sz5tQajQYX690lhl08foF598k50M6jwvWpZ9TOLq+mze/g8kIa9bbaD9vSy2oxNMyl8XK3t9fixIx+K/m9QZaUzmRv0jrb7Urbsy+sf44wclgMw6PzlgsvpDt+d/Pn50A2Ho52UZYm8kpNnOxZNfCWAyMnRBY82gXwOVgFaVyLXjeMp9mf+infkyJFmn9aq6gc8Zjh4NPb1K2lv4+adg9FF9e86fRuk5mbKFUUtG/6mpNrk/5Z7QvzvhYafOepsO3T7/oyAOANFwLzpqNIc+psCBFcaNQuTxZeWp/ZPtWIBGuOAE1E5oHNXz9IfeB0o1ALn1wQN8qYT1SZcdvvAft90GLkmXmw1jxcB2vnvutVuW8GJiRitZcud2VhrQy8oqKiYkfR6wvcOXfVOfdR59wfO+eecc59j3PumnPuN5xzn5PXh17rxlZUVFRUNOgrofxDAP/We//jzrkJgH0AfxfAb3rvf8459wEAHwDw030O1p5Q7G/10z2slc/YcFpDpg0/VbbcWitxeyF0Xs8R2ct0AoylmYZ52WJlrrkJvlknr+Mm/KYlgXB5Ubo4Hku2o61wXCoqkAGPzMRYNvHQSob0iz2xdMWzbCKnlKQUTSgksgLlAQ0J3zQsL6X69UxKJNc+k+WpDaqwVtD235ROVsyXNWUSLrnHjONhQAfVEQmg4QRpaEe4dk6W0r6oE7rHnPCVvhibDwElFKZqiJ93uabFZSmU/WjY9+7Xh3v1+ovB+vnUJARh2cnLsaZtkOuNJlS1JJost6QT/mEeqVXrWS3fy2kpoEcm8Jn2lnbCoRTtuHoxXMcLlxrdoZnENJOZcu9Wez5Z9pO8DuLm7c+UFhpepOHvus9y84RpTg4RN3HTThYN59x2B8XuZODOucsA/kMAvwwA3vu59/4WgHcD+LBs9mEAP9Z1rIqKioqKs0MfBv4mAC8C+GfOuW8D8CkAPwXghvf+eQDw3j/vnHu080gu/4uyjW2wCRvuN1mxKkxqAI29wjISywAAIABJREFUp/mFtKHySJa3ad/ABAXNVlJSTTxpi3W+6xlCbxl5Dnaysm+R2lZoPdCysa3MtgQnnBaGifNJGu83Rx0I0x99TzjKZ8ZPyzvCNsnAZ4F2jGxY+6Z0rIad6ySgVKQjc9QJU+lvnWSepiwqTklKOrlgGlB5lsiw6Oy0DIzsSYNJLsTh7ky7G5bJzsd3QnvGEowykALF6ymDoNL7styXyc1o1OelSMS9x8J7t78xNOw7vuGLAJrJSxYR5mThgU6K5+890A7MaQ2OlaFv/ozkBtX82LPEmi3wwKLdDKmfyOtInvORMHHaCQFgLZPrtvwdzRBk3gzHn8pE6IVp/wRrR/K8zo/Cq58VEqsJix/eTb/g4ufGpppdywO73sDak2P1aO8IwDsA/JL3/u0A7iHIJb3gnHu/c+6TzrlPLo/u9d2toqKioqIDfRj4swCe9d5/QpY/ivAF/oJz7nFh348DuJnb2Xv/IQAfAoD9R1/nY6P6SQo3lOyATQkko4V32IViDMyvXsk+qMsmRSXQpKEcil42EWvZV16+AgB4fD8ks1pI0qt5pnBDjFU0PBkWtrHMu8suSOa+iNmVhtvnt7XHHhvrV26kMLwQ1imD+q7w+vt4MwBgsKIuHGjHQBj4gMmhbGM2QZNTSWpULmvxCLFeSmm7YSu0vulnju5s6SxlRRyZmUAvPnuaGCkTlDGkNVGLhFD3F4Yux2AKWGtZZYqG+cW27fHu68O27/i2PwUAvO1SsHi+fhKCyHivSqkXiLjb7QCWsn6T5KrfPYoHU0MdOabzEWMz78MCJuNB2t6p2Ag5qqWdEADmF9npMqLpkSgvBhNmkd3zNcaVC1JN+Wp4WWaKV8frZ4vQTsvcAWDwUnj2qavrej5rBV1dt9v4LgDv/VcB/Llz7q2y6vsBfAbAxwC8V9a9F8CvdR2roqKiouLs0NeF8t8A+BVxoHwBwF9H+PL/V8659wH4MoC/2udACUNmtHCPgg7Z/VF2mXB9zpBPWPdJsz7vPrFMnE6H5Nzy91hKIi3uhtfjLwTvxcvXQxrWV6dh5vx4En6BDyBlrRxLVLXTydrAHdXJewbo2ND6YeRGmRWY9yoXux2f06awjVw3mpxokJZ6G70rXMcn8fWyJR/D0Df0FAxeDfr6xjSthEkGpfschTYw0GREdq1zKZlDadBMWF5IX+iHRZ+H8DqcGw15Q/ERPus6YmTCrAlD/VOmzWeNmv2RJKaaXWuOOX86MMJ3vCkE7Cjzngbt+8CkH94z98x2Qcy6S4Mgru9SjnmseLxjB9Fk4mPzzFtXis6psP3CjmP9ejZhcBi1+cJcmejW8+y7wGhaeqc5b2lZjyEMnIFHB3LM5cWmx2/icvhDilTQ6YINwT/JOfps5L3/fQDvzLz1/b3OUlFRUVFx5rgPyazaq7uSlgNtpt1i3p1l0WSziO1r+aJFmtCo5D5pmLlsJ+uHs+YXmLPKXEcmTi385SNh4JKOdUahlLmZWgmrMtqy0QxzxYmBpl+tjk3ME319M4u396jRKwM05DoaJQxMPai37j0v55L17wovn7gUUtGupGDvlcEBAGAqRRiG94J2644aVtRi5dYzbopFONEhB+JSYQh7y28dYW3C1lfq/02fEz5HzTyM7JDRwEujPmXi4pJhClgdBYh5fvX2UIyBRbGBpjzfE9OQJpaJxqh57ztq33nXCZHtCTM30nfaqo87gqMihtaTrfMZ0pQR0l6dSxE/OEPstdADGkfKmg4Qqy3PyMylhbLdjE6Sq2kbDyImTj18tWaZtrQ3RuamjoZheenN9svma1fLxMnocy0PjXrNO0bXNZS+oqKiYkdxrgzcu5BMqKU59/gZsYx7bWbzLYZGnFNHQbReHSOGiReZt4Vh4vExvJRwot93JEz85hceBgDcuRKi4m6vAhO/PgrulMYHnvrBgZiZ9NO+G7fJIFnO+cbXHW4Cy+Jt9Oc4IypPmB5U/MfEm6dBoyW7OPjWwHL+6KnHAAAv/3YIKTj4imiIL4d5gsmtKLUuWTmLKNhiEKYcmy2kTHeKl3DK3AdhynMtqE9v7iO6QbQcVqRjWrZOMGUtS4HNroqj5E3ixHg0MLQ3XQ969tMXw3NzY/KqHuPxSWDeDw9DsRB689UhZBKSUQNnBKQmLstFvpoiIHau5CRopaRlOzg3Y5K1jen/FmuG9YHHThE6UuZ38nlZyWwtM1/JCGd2S2ZghInH7J7oYuKt7V3KxOP2kuEfXQjt5UigS8MnKgOvqKio2FGcuwa+Hre9mb0iMZkOlMy7IF2W0kIO1Z/dUIgR82RYDZyvBXeMpkHNpPZsNVuONT4Mr5OvhYa/chw0r0NJAbqSC6Q2Z1lTjMY9wGhNyfPg019tsuSF6awsX+gw5RfzrRhkvcUMfjNM/E3TEDpAvZ8J/D/3A2G7P/39pwAA+18JN33/heY69m6Ffhu/KrruYWAy6hSat5lTAqZzpV/4uOnn0Tp9Hlg0V6N/NVWx9LcphKvluzJdwZEjI4SZPnQewgTwyHcHbfs7r4a+uToODPzhcQiCe2IS8prEfUmmTebNMnh2hDYwrhPLvLN3uFCkuBQfcBpoUREzwtzrSKOc82pbdPrBJVqSTJxe7VnkcLHOFDJvq30XGTlXZzqaTpq5FCShht/1qasMvKKiomJHce4a+HrcsJBNHm3dp2ci9oZpy7IQMGrQmoMiYuBk48q4W5GXSJa1TT2YtwWJtBAp3LwbfupfvHgJAHBrGhj51WHYQPW/iC+XnCKWeR9LJ5F5l1wovapc8ByFY/RhXqrde+a8mHNnAMATsh2L2JJ13vjeoPN+5V4QJL/4x4/rMQ++HB6ivZfCIzx9NTBy3lMWHB4s7T2lOyXNgBhDM/6ZXCwaFQnDxA3zphYu0xsJVpIfZXEgK74hdZV84+Xw+ua9ME9g85eQZe9FBT/2mUPEMWNkek4bPVli3rmMgV05TvS6WvMr5W1tQQeLUqES+sA5yrN+8Ow+vSMa5d6KS2U12bKSTEc7kvfjzaTz1e0i2vut2SVpx+ZzVgZeUVFRsaM4Xw18EGUDi7Dp15FujtI+JeY9vmeYtzLxyNUxFx3UMG49BxmXjawzzCx+vyM1N4RI4c7nw0/tK9dCnopXloGSPTa6DQBYDCQ3RlTUmIWGm2yCaTtKzHvh09tMP3C8/6BjtnvddWGZ93n80r62iC0j7sgyb4wDA3/9haD7vvW7m3Q7z35L6L8/eeE6AODVz4URDf32o7tpTm4WqGbUpI6+TK6RGGTU1t/N+83ybHSQ0Kt9/Hi4jiuvu63HopuBUXmPXAiOkcf2AgN/635g3m8Sh85jw3DtV+X+XxqUdWoy54Gk4Buq/180ZGG8Nkd3e//Ul507XylCtyuO4CTQqGTNV54K2YPMOVVL7jh2O61QmpflNChp8suca0X+XMk6PifTq2HkFedNyaEy8IqKioodxflq4ENgcSWK1Jtt/6vHihtWPx+0mHZYpvtjJBVQyLrDNikDbwoi21fZYVR2FxCWrbdzjZMhhoO+Mgva9+1lEEwXyqLDrYmZTqmSjo24tMx7XtC648LJJZZc1M/5vhw7p5U27ckfe6I5OUQjH1DjlNwRwj7pkX912ojKT00DK3/LxcDKX3gq5JR4dRFsHTfvBTr8wrOh0t/oZWHkh+LFZUTmhpwoJecTR5F8lsm0X3cxsOrrwq4vjxunCHNZX5QHk95tXhtHXm+TSZJ9YdMDyWhu9WLrCsmBl7Q2UbNd1XLie1l61Fv+ZHq4nT122pYYbEdXDAJBxm2Zd+wCIYNlpR1G0xZqip8I1n0y3JC5MGnnhvenSBvIakOQ1y8V9qsMvKKiomJHcc4auNdKGACwDhOtrYoWm+rR6TbUvg3zHskP1/hQfhXJvIVtD5Lc3flfRPX3jlMm3lCa7G69oBGhItK9fC8w8HtXgqD6NTGiUhc+jPTriUuVPbJzq31b5r0AtVFqocwxEffz5osqsWi7f267Erunttm4IFIGvvKLpP17kSeeUYfH4pu9dUF89VLS5O7VwMRv3wis/Y4w83syrf/qPCwzp3QOzLVB5kQWvSfr6Vu/LA/dxVF4GB8ZhbbtD5qCh3saBSlOG3EbXRW9/3WjsP6iC9czdZs/mjn9l1jbe9nq/+0fYE4d8ZmzI7OunB2bQCbOUUVxvkXA/OC8L7GmbKv0MNeNN24UOyi1c23cP47EHPVk3qNC3v4cRpLXZTlIGzQ00Z4lVAZeUVFRsaOoX+AVFRUVO4pzlVCGo7WmT4zRKhIavUc5RdMrzpiMRo4p80TNpGUqnQwpoYhcwtJaQDsk3o8lnJ3SCUOkR0ZK4f6m+HG8rlR0mYmOmEzn1gtBR3r5kSABvDINdkJObt0bNE7+PZ8vhWUnC610smrqd4U2ML1l1NOl4ska4m8SYlkc+812p+w55JgDYxfjepaQY1KslWskFF7TAdIAl7XtA5GTjiV6jO28vdyX99sTvE1RDbHhifwxNTJIU6iCk66z9H3XToPAMPdLsg/tgftGOhl2ZXjzm2QQU0RXbplKK0aiaEkuEVZqQcynabDPYilMPxskRMlElhlw1FgV03ba54dSxl6Uue5QPi+aptUkteItaRWkNhPUcZk2PX9n0qq08MQ2GLGUtHwjDymddMQTVQZeUVFRsaM4VwbunM+mZyRypnVl3PKqRRjM5KW1C5J5D2fhl42h0/GPY6FaWCtJ0WrK0GpzPWvaCuOJUXOs0i+o/JgP74QNOKn2yiIww1vjwMQPookwMlGb4IrsmK9k3o0VkQ2XpEAuncwE7IRm+9jWmthlL8yBbNdOpubYWbxdLq1A6fR2xEAmTjuZXse4/OjH9spwXrE7moAS2h/Jqg9kv32GrEfWPxuuPhamzX4fu+1Dt0soB2WlI7GSFTG2GZKoliYvS0y8FCafPZ+0Y1GwndpJzYF5LmLG2yryIKYJhsZzRO+NKYLMm/ZDBgT1SZRVwkn2Hch3yahn/1UGXlFRUbGjOF8GDp/8KjG0lBo4QVYKNIE7tN1Z2yBDpLUYA1OA0iJInTpDNlT7luRFZNz8WbOh1Ey+byTlJCx3OEhZuernhUK3vL5XZ4GB3xIGfnMRAlMui7YLNExwpSwuXbbaodUQyZ5VS/Tdt39lWL09lj1HDrZQ80rXk9UbC5UWTJabq5r4ur2NoGHp9IuFl/1Cm1qsLnNsFj6waXv5PgsiTOQ6piaUvTSqCceyNjwbqHMKr+qWYDs3aeElkHkPNdGUPXYZah+UZZv+2L4SLOyQS11srX3Uwu08WylZFUPYyeBzLLqkhWvR5Y5SaxuxJaWuDLyioqJiR3G+gTwdYECPi8odWdfJwLw2TJzM26aGFaeJHDJJH6oBO8LEh3nXiSYxGuRfY/ZEVmFLNhG2qC2v77kXQnKmaxcCY2CQyP6gnZaHbFjZpllf0qnJHDW5Vaz1Fti4ZfX22F1BF/G2Q9gRgbTLMPRGo5WUsWIdyAUeWSZuy8V1Fb/IJWEaI2WT7ZJjMgIySaAs896kA1t2vtZ2bj+3cFqsdWSUukKA5h5Z2P5tXrc5bwCDhO7RMST3nVp4yZWyCSObHEpeWaDBMvISllEgjQ2u6VtKrZQeNwY/R1uxdVQGXlFRUbGzuK8MfLaQkG/5FeQMcezRVH3Z6M3UvpVpL/NUoZWwP/JnK/Mmox7l2U9Jv879WFp/absohHHT8PWl4F+9eV3SoppCrkDjZb4xDomPYodKDHVesFwYUp1yKPrqKvIaW48t9+ExVkaftOfaBDLvhS7nfey6nRYgCH1wjDZLYrugYfdpUi0e0+rYxMSE8cfabVepMeuaKbloci4PHrOsN5+eU5HF2wRjXRp336RS6bk4cgjoUyTCYt7Svkfp8nok7QvHWq57PHPCjpm+V5m0MHE778bRP8e7t+T1wrTtB2fq16HOU8hn1bF9wqaH8hky8Q459GHp2f1OtFdFRUVFxX3H+aaThUs0Jf4K8tePXu+4wENLMy4UGm6di26QwvpkXZFhC2OVn2W6UCyrTkYM63Tf6J3sObgv3Sg3XwzuEzKHGPO9cLtekShCpibdH+aZONHowpKgRyMKG329q1zbwuiTa8OabEmtGFONWDTpY41zpMwQ20zcOnJ0Pc/BMnPSTvXOkzWp4aj7eWKr+OS2CiMYx8hA3SqZe96h467Uc34aLXxzpKUmjWqNhML6ecTEF8rmT6fND6LrIdOfq/87PEP31lNZny6f5NzUqZfm9dbdkNxMo75nqT8c8rqpIMQmhwrQRIYue+janEvoWzTcojLwioqKih3FfdHAS9o33Sexr1qLknZlaLQOkQKrTsuf8Xxp/hLr7yZLK5Vc29S2kkRsf3DVbfN8YB1fvnMDAPDVRy/pNo9dDeW39seBH+yP0tcp/bHySh2djJfMcMq0qFFEJ69xrPukLJP6u/XmrpWhp8vx+QielyyZr125RpTdR8xw5dJrIzhSGGuh33CMQ2m/nlP94tQpo2g+XoLVhB3dEHS05LXmgTLc9jO4kZ1HsAO4TZ5yixW6PiwpFp7zHQFR1UFlhk0kbj7yUs/NPlNnTsA6YfU+OQ/vDZk4n7WZvFr3CeeFFkth6NEzx/TAZNz3ZmFu6fatMGq1jFtH/fLd48e8d9KGKNX1XFIXM08Kiy6M5FycU2JqWI2qHHbr26X+7EJl4BUVFRU7ivPVwL3DbDFqzQCTfVoHx8ZjKeM2nm1xlrh19y+azRyoujX1dgYC6qFM0vei3h21xzCtYm1gJiM7FI+xRKP6mw0D/+ow/M3k86s9eb0Udr56IzD0g6nk5hCmrjPyos1NJIn8wbBR+iw7nyr7pYZIl4cwMVmecb1c2HKDlkctkOeg1/2CtGNfXsmS6YG3zDxsE44x0QxwqS+ZuUUWknOE+9qoVTLxeMTR5GhJHRYw2fO4bK+48Y/H2R5ddp8uJk7tWLXxM/SJk3kvjPY9j+6hLRZC6KjIpXlMxsYPniukzPPQ933PB5ZMzftYlsnES9jEWm2Ud4t532073kKDLSOPtHvZl6ycThUtf2YwGkuxBunPSQ+WbUet61LCJm7fecSKioqKigcS58rA12uXsG9bSo32zkFmHQ0IK5MBkAVnmRmw+eUfJNs1RYW3b3dJ+86aJsxPIomLRnmycLLRxttuG3kjazBJIwLxgjCDL10DABxJCvEXJMPa6qJEo0qmNeZ7iJkDXS9k61NTBdaWdiKraK3fUAKKs/ZWw78ixX+PhqHhZOTHg3BzbRZAoK3Z77l05DAxGnijt8uoRPOdpDm94/carT4f9WnbQjCvdcK4DPO2LL3oOjH7ndYNEsOWMqMmvYgeYusyatpF3VdGz8IUZ9oXlok3uC0f6jtrw7yFcd9dhbxA654OmJi1lhwfGmMy23wsjbqmFj4tu5Q4hzczmQuHA45GjRbuyn7wUg7xrtzilYFXVFRU7Ch6MXDn3N8C8F8i/Kz+IYC/DuBxAB8BcA3A7wL4a977TfZJhc0/wF855g9Jf/VKv5hGWyazHRRyouT0avtDaHT1EhqPeaqhA00eFWYyXO6JhjmV98c8xsZTZGHdMfaHnIGZPMf4npxb9PS1ZGDzL4bb/tLeQdNukw9Zi8Jan6zBwMzib4KymkfCY/Lo9VB16M40MPCDsfjaR3SlBFZMFjIetBk4GTe36dLRbdUcImb3DeMX14zJB15k4vp+e7sWm1dmneZosbA6/Fi2m2zwiVuXTDnvd8ChKY59GGnPc6RzHApGyXIoKc2hZjs3Tpx7Ua6dQ2Hcr64D076zDt7s26sDeT8wc2X/hSjgXPY/G4HJSMrZJI0sVk+/XGrp+c9hmqnWk4NGZDJCs4cWPt5mIhA9GLhz7kkAfwPAO73334wwKnoPgJ8H8Ave+7cAeAXA+7Y6c0VFRUXFqdBXAx8BuOCcWyCkWH4ewPcB+E/l/Q8D+O8B/FKfg9FHSbpOfrC6KMuRTqW6OD3ZMzJceV+Y7iD8mGN5QbZjDU3mTMlETQ4K+VP6Q9oS5VBhtKakb9B2kokruWHOcaOFk+jY6L9kpW2F+dHWoEM5Nm2ozOhIHT7WA1WrZ270Yb9HQ336y7aHv+2Pl1HS7XCzviae9xeuhZtEF82VC4GRa25nstaIaZF10eu+x0osxuEyHaRs3nrR90yUKADsC0svVeBp9YHNzGcYfPze2KU++1IODMviLYOPqxPZDIvrDl5mNXtq3oembijQrq9KjGU9XUDH5jpsRaR4f2red1bhw/qyMG/WKZ2Z3CclkK3GbirI/E+jR4fXg9eHbegL51xcLtcJgI2VwyxGJgf5eaKTgXvvvwLg7wP4MsIX920AnwJwy3vPq3wWwJO5/Z1z73fOfdI598nVq/fOptUVFRUVFb0klIcAvBvAGwE8AeAAwA9lNs3SWe/9h7z37/Tev3N4+SC3SUVFRUXFCdBnnPyXAXzRe/8iADjnfhXA9wK46pwbCQt/CsBzXQcaDHx+yLJhUkBLIHHFHbGW3U1DYbXkGsPxVTqRc1NSiZJhcZ218PWFLewAtKWSLsmkdSx5X+ZxsM5IEpRCNODISCb2mBa5eRK/4qv0iT3WaLPcxPfjuhBxUrJNYAm929MwhO4a3sbgUJeTVlrUVpatxNJIK2m63lhCsTJLU3Ai3wc2/cCmwKOmLJtNgJUutyQX874t5gFEqX+7ikSbZGK2bN4iuokr3++YFo39UELaRTYBgJcWISDtrszsvyq6Z0k64T21/a8T2ZHllRObvO+0qs5XEqYv4fDW/roNNgWrAd1FGZIJ4ROG0BN9ruLLAN7lnNt3zjkA3w/gMwB+C8CPyzbvBfBrp2pJRUVFRcVW6GTg3vtPOOc+imAVXAL4PQAfAvB/AviIc+7vybpf7jqWcz6ZHLBpGbOTAFfTxeWNfJIaMnNNCnWcpqa1DD28F17JYFuTgT1T13LiEmjbBUvRwPZcTcAPj1M+98pM6HYm+jLnyC1bht2VM5+WwI6twrEK12IDi8i4mQqAz0MuOMiua9KGhueCSY3Izg7NM9YUzEgnSoGyfbEr9WxpwhSIJiELycLGJiWADTCyzD1m7NbiZwt6WNgCHwRZ8zxi4FyniaUKZfo02dXaFGOQV7JtALgnSajuyCvZsbZP2sVRExNoMVmbHT3Fo5mJBNFQrJ1Le/g8zNZpqtdNgWcWWlCiRxGT80Ivq4H3/mcB/KxZ/QUA33XmLaqoqKio6IVzDaV38AnLtlYfTXYUFTMYOSaECb96/MVkoiZazo6vyy+spKq16SOps5KZA1ESLVPejORmveoI6FHrXbNOAwMmfC/P2qztrjmWaMkbQnlps7QWS6s5d+nWMcvm+ZgYi4EMk55BC0ROt+6yZNkRmA3j3x9364QNk+43HNGAkxVLaTWdcexG2W3tM2iL2zJZGAORLkuKAKCc2pcYm3Zb1m91+HHE7rXkWKsAdZ4p8npKiZOoRcewSc1ax5Rzk+mSNXN0cLyKAnmW4cOhRRdM4YOpKWZCHZt9Ypl3PNKxYL+y/6ccIWgStjRN7iY0Cdvyz1iJzdtRXs46agN4+hQaCdtVVFRUVOwkzpmB58NeybhsulMg1iZT7YrMaaruA2Hgo/BKHVW1cnE4rO80orR1svBHmC6Pzh9leX8V6dyWSROWLTfvu2R5k/bsC+HAmuxnuF1gUqxjk+mTeV+5egigXD7KLueSYFm9uYQSQ9kmyX2L0RpGszAduylIxLJH1UuX4qwwzJESLBP5k6HdFaYJAGNh9SXWWyp+MTLXkQsmKqX8na3Sj7e9rhI2uSzIMm3/2dEJkZvHaPVfAdx3bEYflnnHfdcqzi0h/WOfuo0WvFfSZ1Oj7dvnBQDWkn53UGj3xKy2/dyncHFf5t1sX1FRUVGxkzjfkmrOhEO7VPvU5DTRL5X91dIGmzyVS5l9HpoCs2SQZJS3sa/vrWBM2uZXuJUsSs6lKSc3/PxZPdr+svb1SOdQYuLbItbXNYmP2aZLny75rYF2WHvONQBEbg91YqS6bx90MRerD28qBUfHhWWyfC6PB3m/MkeOqrdG7LmUpIhMz77Pc88zerRFiWkfRiOA+FhWw7cYZtxgdsTV5d6wcxKjaFSNwijTuk+60iLknpOWV1zOv2byL3Np9lpX+plqP0+cG5j2nmfpwbgLSczsyKu4f6+tKioqKioeOJy/CyX6tcz90gOpNmYbuK1/U5mDMPHYVcEUOGTig5WwM6QOEb6uCsUacrDuktMw7i6QSdtk9ZuS0W+LoXEM2fkKss7Lo6YCRalUGpmUTdTUrE8jBTdhUMrwZcDoQjKsmSZuGiXLQFNYQF0Zg3SbWSHRF1n0BU1h244QtNdUGhFsA/Y99VzJ56YjAJa925PURYfLcB2q2Rd0a6Bh0JYpUu+1oxDLonPzGSXWaZ03XYzbOnQ2gsWYeQ6fn4sgFizJl7kf2xbVyOnphL3mvsybqAy8oqKiYkdxvhq4oMS855oLofkVoj+3NHt/vEpzG+gM9zrP1HM+ZRYpXVyR9pmCp7lUqcBmBm5Rks1OE9SlurUUW+iKeOwDjlBaUbIuz7yZypM65eVRU6aNzJtFFS4Ogy+a5c5smlablrUPWq6DAiPXPCH0SA8YdSg5MnyjF7OkF5k4GeDCh2ssOVhKDLG0Dmi0WbbLMkPdzrhV4jaos8IksCkVpqY/3Xq2m+O12XJXNCpZqWWSm7zauWvJvd83J81G6LOF5Jjsdy1IwevgfYgfJ9m05IUvYdsiDdugMvCKioqKHcW5+8CHg3Vr9tsuz6Jmldi69ZJ2MW9GaObAXByzW4F52cISQhw14nLbiEfZK/xvfoyb5ZTBrAo5VHLoYti2PNqmbS60CrSm0XFW8ybztno3AFwZBjZ+SV5tgWFb+MBmy9sGXTqoauDCeMfURGX9JBr17bl5sg8LHFhfb5denRRhLrSPx7TFgxc93Cd6DOtP4PifAAAKv0lEQVSwKWi0K9N+FiKx15G2e3tHEFCOIN2EUrtz0adAfqRWyprYBRvNqu2Nu4xdsCXttYx9k4bObasLpaKiouIvOM6VgXukbNtGYmV9qR0/RCdh3ERLD5fMh8xBvkZKg1m4t6Vj9pDEmn36ZRBszhWdR5Ys4y4VYNXSdXI9mwq1lrRv+r7JuPl6cZQWC7Z6N9Bm3k35smWy3mrhJQ38JOyK+i+POVdbELcoR4lqBkDj57VM1p4re6xiPbx0XzpdhoPtdd4Se7fMlejD8kv7dqGUbTHbDjMCKGU8LB0r3n+b+ZPkHIP0u+A4l0a0CX0OLx0l3+x+ZNcn0vA3H7qioqKiYtdwvgzcuyRqrJTTuQ8sw2YVlxJOkiWPXJJM3OYe6ZcTO92ni4mrvt4jr4ll1GTRfSrZWJS0bxuJafNSaO5rYdV0mgBt5q3LJte1FhhWJr49A6eTgts0erXQJXarfd8xqjXDkKUZWrlGnoDGwWCZohlR9shwZ6G+aVm22vgmhqlFlQ2bLLHfveHJ2PUm9Mn3YTEtFETuOia3i69vk55/onbmNjMeeHtOy8x19HUCF0tx5JY2paKioqJi11C/wCsqKip2FOcqoazhcLxsn7LPhCNRkko4UWdBWWGbQrldsNLJppB1G97eOlaheLAmzopkA/7artIcRS3phNIQ+3Wb4sB28lKTEWmq1zTMmUEKlEkYpBO2TW2C7ddUOhmbUl+2XFd8h618od2kVroUHG6XZI3YutiSSnhwc5uHZgJyCCOtRE08iZySQ5+J3K6JvJPIHAT70R7DTkRvwqbJXgC9awRqbe9M31rppNTeIjJNHMuENyeaKZ0w6Gdt7nvLZupTKeUsUBl4RUVFxY7i/CcxF6POCcc+sIzbBqlwgo/b5UqDdTF/HrPEebZJFqUl0lqTmYVjbxGta5k3YZd5vbkiDaXJSzJuZdMMqeZ6k5AqZrI6qWa24bJl3hOdIE3Bc8Qciix9bq2oDGqhpU6CcWyh301MVictfWpBHBpGvtb300nOPsfsgp3MXPn0Wd1oATSFk8kE2f8lFn0SWCbbBO6Yicmob7S/OvqilPiLWGTy0nYya3uOwohBzx2dUpm+mR/X59OkReDEvk52sr2+Pdrr2y6LysArKioqdhTnysBXy4EWG86hTwFdMuoW456nQS7Kno3VLmb/ZK52RFDS008Cm+pViwfLKRiwU0Ku7NlJ0UpQlSlvp0U2qH0X7IOtBEOOLLrpb8vGbNKqZjuyecix8+1fRJdv+YktF7YyTLuLeSdsL3V6nli/jlnousCVLAPTxFRGP23NB2SKGp806KYPrM6sKQBkuYv55vqiKzy/lVLB3A+ecxa1rWQj7Bp1lNqyh+Y7aeXoH9QGhnMWwvCb+Stpr8yRJCMHn47e+jJvojLwioqKih3F+aaT9Slz3hTabVFixWTedtkycQblxCy/xLyVvcuxyJ7JlsmKuf5ULpQtgoFOC1sWKwebPGxkmEkpyc622iNw8rDnGGujeVt9uink0D8MX9nYGTHxk0CZOJf5hgnsidHSxV8DLbx0DGhw09np6ydBaQRTQkmzV8TdzPxWTK3MNAyGiWstRhMsZpk4AMzk+dyWeROVgVdUVFTsKO5LQQcLq33HvmWyZJuYibBFDU6CvsybsEz8LwIs0z4P5PzdZ33sk6YX3YRhxhXTe9+Ww2WzgyWn8wJ5F0qXw6nLG51DzmMNtJk4l7dNO5vDtumE4+vIhddvQteIIWmLPEpk0DPjUuKIp4uJr6PRQVdRiy5UBl5RUVGxo3C+UMLpNTmZcy8CuAfgpXM76cnxCGo7zwq70EagtvOsUdt5dniD9/66XXmuX+AA4Jz7pPf+ned60hOgtvPssAttBGo7zxq1na89qoRSUVFRsaOoX+AVFRUVO4r78QX+oftwzpOgtvPssAttBGo7zxq1na8xzl0Dr6ioqKg4G1QJpaKiomJHcW5f4M65H3TOfdY593nn3AfO67xdcM69zjn3W865Z5xzf+Sc+ylZf8059xvOuc/J60P3u60A4JwbOud+zzn3cVl+o3PuE9LOf+mcm3Qd4xzaeNU591Hn3B9Lv37Pg9ifzrm/Jff80865f+Gc23sQ+tM590+dczedc5+O1mX7zwX8T/K5+gPn3Dvuczv/R7nvf+Cc+9+dc1ej9z4o7fysc+4H7mc7o/f+W+ecd849Isv3rT9PgnP5AnfODQH8IwA/BOAbAfyEc+4bz+PcPbAE8Le9998A4F0A/itp2wcA/Kb3/i0AflOWHwT8FIBnouWfB/AL0s5XALzvvrQqxT8E8G+9928D8G0I7X2g+tM59ySAvwHgnd77bwYwBPAePBj9+c8B/KBZV+q/HwLwFvn3fgC/dE5tBPLt/A0A3+y9/1YAfwLggwAgn6n3APgm2ed/lu+F+9VOOOdeB+CvAPhytPp+9uf28N6/5v8AfA+AX4+WPwjgg+dx7hO09dcQbupnATwu6x4H8NkHoG1PIXx4vw/AxxGCe18CMMr1831q42UAX4TMr0TrH6j+BPAkgD8HcA0hpcTHAfzAg9KfAJ4G8Omu/gPwvwD4idx296Od5r3/BMCvyN/JZx7ArwP4nvvZTgAfRSAYfwbgkQehP7f9d14SCj8sxLOy7oGCc+5pAG8H8AkAN7z3zwOAvD56/1qm+EUAfwdNGo6HAdzy3jMR9IPQr28C8CKAfyZSzz9xzh3gAetP7/1XAPx9BPb1PIDbAD6FB68/iVL/Pcifrf8CwP8lfz9Q7XTO/SiAr3jv/71564FqZxfO6ws8l6nlgbK/OOcuAvjXAP6m9/7V+90eC+fcjwC46b3/VLw6s+n97tcRgHcA+CXv/dsRUic8KPKTQjTkdwN4I4AnABwgDJ8t7nd/duFBfAbgnPsZBHnyV7gqs9l9aadzbh/AzwD473JvZ9bd9/4s4by+wJ8F8Lpo+SkAz53TuTvhnBsjfHn/ivf+V2X1C865x+X9xwHcvF/tE/wlAD/qnPszAB9BkFF+EcBV5xxT0z0I/fosgGe995+Q5Y8ifKE/aP35lwF80Xv/ovd+AeBXAXwvHrz+JEr998B9tpxz7wXwIwB+0osOgQernV+H8MP97+Xz9BSA33XOPYYHq52dOK8v8N8B8BaZ4Z8gTGZ87JzOvRHOOQfglwE8473/B9FbHwPwXvn7vQja+H2D9/6D3vunvPdPI/Tfv/Pe/ySA3wLw47LZg9DOrwL4c+fcW2XV9wP4DB6w/kSQTt7lnNuXZ4DtfKD6M0Kp/z4G4D8T98S7ANym1HI/4Jz7QQA/DeBHvfeH0VsfA/Ae59zUOfdGhEnC//d+tNF7/4fe+0e990/L5+lZAO+QZ/eB6s9OnOMkwg8jzEr/KYCfud/if9Su/wBhiPQHAH5f/v0wgr78mwA+J6/X7ndbozb/RwA+Ln+/CeGD8HkA/xuA6QPQvm8H8Enp0/8DwEMPYn8C+B8A/DGATwP4XwFMH4T+BPAvEHT5BcKXy/tK/Ycw5P9H8rn6QwRXzf1s5+cRNGR+lv5xtP3PSDs/C+CH7mc7zft/hmYS877150n+1UjMioqKih1FjcSsqKio2FHUL/CKioqKHUX9Aq+oqKjYUdQv8IqKioodRf0Cr6ioqNhR1C/wioqKih1F/QKvqKio2FHUL/CKioqKHcX/BxyuzW92uDa1AAAAAElFTkSuQmCC\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 | --------------------------------------------------------------------------------