Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GSoC 2024: Eye Tracking Algorithm Optimization Based on Low-Resolution Cameras (Final Project Submission) #26

Open
wants to merge 78 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
78 commits
Select commit Hold shift + click to select a range
37fdf67
data visualization notebook added
sitamgithub-MSIT Jul 2, 2024
3bcc3a1
old data visualization file removed and reproduced under calib_valida…
sitamgithub-MSIT Jul 2, 2024
fb98e56
separate test folder made for all model testing
sitamgithub-MSIT Jul 2, 2024
7430e37
linear regression model test added
sitamgithub-MSIT Jul 2, 2024
47b5e9a
old test notebook removed
sitamgithub-MSIT Jul 2, 2024
90ae9bb
ridge regression model added under test folder
sitamgithub-MSIT Jul 2, 2024
cea7499
lasso model added to the test folder
sitamgithub-MSIT Jul 2, 2024
bbb1e9d
ridge CV model added to the test folder
sitamgithub-MSIT Jul 2, 2024
af861e1
small comment fix in ridge model notebook
sitamgithub-MSIT Jul 2, 2024
e4b59f8
ridge cv model comment fix
sitamgithub-MSIT Jul 2, 2024
ffc5e41
comment fix in linear regression notebook
sitamgithub-MSIT Jul 2, 2024
8f99d43
comment fix in lasso notebook
sitamgithub-MSIT Jul 2, 2024
c978574
comment fix in ridge model notebook
sitamgithub-MSIT Jul 2, 2024
19f8aca
move the data exploration notebook under calib_validation
sitamgithub-MSIT Jul 2, 2024
2befb13
separate folders for models added
sitamgithub-MSIT Jul 2, 2024
4d2fba5
ridge regression model folder added
sitamgithub-MSIT Jul 2, 2024
0d96874
ridge model grid search added
sitamgithub-MSIT Jul 2, 2024
39e4c8f
minor change in ridge grid search notebook
sitamgithub-MSIT Jul 2, 2024
e634a42
ridge cv grid search notebook added
sitamgithub-MSIT Jul 2, 2024
c9c623e
lasso notebook added to lasso_regression folder
sitamgithub-MSIT Jul 2, 2024
ee10a30
lasso cv model notebook added
sitamgithub-MSIT Jul 3, 2024
9ff80d1
small comment fix in ridge cv notebook
sitamgithub-MSIT Jul 3, 2024
1779984
scoring metric change in grid search
sitamgithub-MSIT Jul 4, 2024
093ed62
ridge cv grid search also updated
sitamgithub-MSIT Jul 4, 2024
e50ee6f
lasso grid search added
sitamgithub-MSIT Jul 5, 2024
c30fb6d
lasso CV grid search added
sitamgithub-MSIT Jul 5, 2024
6ed7da1
elastic net notebook added
sitamgithub-MSIT Jul 5, 2024
618300d
elastic net grid search added
sitamgithub-MSIT Jul 5, 2024
1b7cc82
minor changes in cv grid search notebooks
sitamgithub-MSIT Jul 5, 2024
84e1c42
elastic net CV model added
sitamgithub-MSIT Jul 8, 2024
dd013a5
elastic net cv grid search added
sitamgithub-MSIT Jul 8, 2024
869aab3
comments updated
sitamgithub-MSIT Jul 8, 2024
ea0405a
bayesian ridge model added
sitamgithub-MSIT Jul 9, 2024
106416c
sgd regression model added
sitamgithub-MSIT Jul 11, 2024
51c5e94
models/session file formatted
sitamgithub-MSIT Aug 1, 2024
43f583e
eyeinfo file docs added
sitamgithub-MSIT Aug 1, 2024
2932a84
minor change to doc string
sitamgithub-MSIT Aug 6, 2024
05c901d
parameters to args
sitamgithub-MSIT Aug 6, 2024
6677662
mix notebook added
sitamgithub-MSIT Aug 6, 2024
7dcb250
database docs added
sitamgithub-MSIT Aug 6, 2024
b5099d8
heatmap to do for later
sitamgithub-MSIT Aug 6, 2024
5d41c9e
storage file docs added
sitamgithub-MSIT Aug 6, 2024
49b76d0
mix notebook docs modified
sitamgithub-MSIT Aug 6, 2024
7f9d0e5
data viz docs updated
sitamgithub-MSIT Aug 6, 2024
feb72b2
wsgi file docs added
sitamgithub-MSIT Aug 6, 2024
5482515
docs change little
sitamgithub-MSIT Aug 7, 2024
e37ae48
notebooks doc strings modified
sitamgithub-MSIT Aug 7, 2024
45b0470
main file docs added
sitamgithub-MSIT Aug 7, 2024
fb67f97
yaml file formatted
sitamgithub-MSIT Aug 7, 2024
68fa335
minor doc strings change
sitamgithub-MSIT Aug 7, 2024
8f8be61
remove not used import
sitamgithub-MSIT Aug 7, 2024
ad09e75
linear reg docs strings update
sitamgithub-MSIT Aug 7, 2024
01c5ad7
lasso reg doc fixes
sitamgithub-MSIT Aug 8, 2024
ab84525
ridge reg doc strings fix
sitamgithub-MSIT Aug 8, 2024
5235cec
elastic net doc strings added
sitamgithub-MSIT Aug 10, 2024
065438e
bayesian ridge grid search added
sitamgithub-MSIT Aug 10, 2024
dbd442f
repeat code removed
sitamgithub-MSIT Aug 10, 2024
8460ac6
repeated code removed
sitamgithub-MSIT Aug 10, 2024
9200a99
new metrics file added
sitamgithub-MSIT Aug 10, 2024
395af41
docs strings updated
sitamgithub-MSIT Aug 10, 2024
4b0a6c2
sgd grid search added
sitamgithub-MSIT Aug 10, 2024
5eafcab
SVR model added
sitamgithub-MSIT Aug 11, 2024
b49049c
warning ignore added to some notebooks
sitamgithub-MSIT Aug 11, 2024
dc1203b
warnings removed
sitamgithub-MSIT Aug 11, 2024
6c99356
warnings handling completed
sitamgithub-MSIT Aug 11, 2024
384d31f
legend box fixed
sitamgithub-MSIT Aug 11, 2024
45215db
SVR model grid search added
sitamgithub-MSIT Aug 11, 2024
fe10832
minor fix in linear regression notebook
sitamgithub-MSIT Aug 13, 2024
2cdce47
config file grid search updated
sitamgithub-MSIT Aug 24, 2024
1811310
session file updated
sitamgithub-MSIT Aug 24, 2024
47773ec
minor update
sitamgithub-MSIT Aug 24, 2024
53d9bcc
requirements are updated
sitamgithub-MSIT Aug 24, 2024
05a2875
streamlit dashboard code added
sitamgithub-MSIT Aug 24, 2024
9bf5c6d
readme update
sitamgithub-MSIT Aug 25, 2024
1d12e49
Update README.md
sitamgithub-MSIT Aug 25, 2024
b818e5a
readme minor change
sitamgithub-MSIT Aug 25, 2024
5b9f361
minor change
sitamgithub-MSIT Aug 25, 2024
9e13df9
gaze_tracker file predict function updated
sitamgithub-MSIT Aug 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 4 additions & 6 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

name: CI

# Controls when the action will run.
# Controls when the action will run.
on:
# Triggers the workflow on push or pull request events but only for the main branch
push:
branches: [ main ]
branches: [main]
pull_request:
branches: [ main ]
branches: [main]

# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
Expand All @@ -19,7 +19,7 @@ jobs:
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
Expand All @@ -29,5 +29,3 @@ jobs:
heroku_api_key: ${{secrets.HEROKU_API_KEY}} # Located in GitHub secrets
heroku_app_name: "web-eye-tracker-1204" # Must be unique in Heroku
heroku_email: "[email protected]"


22 changes: 14 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
# 👁️ Eye Lab: Gaze Tracker API

Eye Lab is an open source tool to create eye tracking usability tests. It started as a final undergraduation work for Computer Engineering of student [Karine Pistili](https://www.linkedin.com/in/karine-pistili/) that created the first prototype. The idea is to evolve it to a more complete and useful tool with the help of the community.
Eye Lab is an open-source tool to create eye-tracking usability tests. It started as a final undergraduate work for the Computer Engineering student [Karine Pistili](https://www.linkedin.com/in/karine-pistili/) who made the prototype. The idea is to evolve it into a more complete and useful tool with the community's help.

The current version of the software allows users to create their usability sessions of an website, recording the webcam, screen and mouse movements and use this information to find out where the user has been looking into the screen by using heatmaps.
The current version of the software allows users to create their usability sessions of a website, recording the webcam, screen, and mouse movements and use this information to find out where the user has been looking into the screen by using heatmaps.

## 👩‍💻 Setting up project locally

The project consists of two parts, this repository contains the backend of the application and the frontend can be found [here](https://github.com/uramakilab/web-eye-tracker-front). Install it as well.
The project consists of two parts, this repository contains the backend of the application, and the frontend can be found [here](https://github.com/uramakilab/web-eye-tracker-front). Install it as well to have the full application running.

### Prerequisites

* [Python 3x](https://www.python.org/downloads/)
- [Python 3x](https://www.python.org/downloads/)

### 1. Create virtual environment

Before installing all dependencies and starting your Flask Server, it is better to create a python virtual environment. You can use the [venv package](https://docs.python.org/3/library/venv.html)
Before installing all dependencies and starting your Flask Server, it is better to create a Python virtual environment. You can use the [venv package](https://docs.python.org/3/library/venv.html) to create a virtual environment. To create a new virtual environment, run the following command:

```
python -m venv /path/to/new/virtual/environment
```

Then activate your env. On windows for example you can activate with the script:
Then activate your environment. On Windows for example you can activate with the script:

```
name-of-event/Scripts/activate
Expand All @@ -40,12 +40,18 @@ pip install -r requirements.txt
flask run
```

## Contributors ✨

The project is selected to be part of the [Google Summer of Code 2024](https://summerofcode.withgoogle.com/programs/2024/organizations/uramaki-lab) program, and [Vinícius Cavalcanti](https://github.com/hvini) is the main mentor of the project along with [Marc Gonzalez Capdevila](https://github.com/marcgc21), [Karine Pistili Rodrigues](https://github.com/KarinePistili). The active development of the project is being done by [Sitam Meur](https://github.com/sitamgithub-MSIT), selected as a GSoC'24 student for the project. Here are the project details in the [GSoC'24 website](https://summerofcode.withgoogle.com/programs/2024/projects/lEPzZg7S).

To see the full list of contributions, check out the ahead commits of the "develop" branch concerning the "main" branch. Full logs of the project development can be found in the [Daily Work Progress](https://docs.google.com/document/d/1RjCnGjYYgPKvFUrN8hSjPX29aayWr6eEopeCN3QZwEQ/edit?usp=sharing) file. Hoping to see your name in the list of contributors soon! 🚀

## 🧑‍🤝‍🧑 Contributing

Anyone is free to contribute to this project. Just do a pull request with your code and if it is all good we will accept it. You can also help us look for bugs, if you find anything create and issue.
Anyone is free to contribute to this project. Just do a pull request with your code and if it is all good we will accept it. You can also help us look for bugs if you find anything that creates an issue.

## 📃 License

This software is under the [MIT License](https://opensource.org/licenses/MIT).
This software is under the [MIT License](https://opensource.org/licenses/MIT).

Copyright 2021 Uramaki Lab
23 changes: 19 additions & 4 deletions app/main.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
# Necessary imports
from flask import Flask, request, Response
from flask_cors import CORS

# Local imports from app
from app.routes import session as session_route
import os


# Initialize Flask app and enable CORS
app = Flask(__name__)
CORS(app)


# @app.route('/', methods=['GET'])
# def welcome():
# return Response(f'Welcome to EyeLab!', status=200, mimetype='application/json')
Expand Down Expand Up @@ -51,8 +56,18 @@
# return Response('Invalid request method for route', status=405, mimetype='application/json')


@app.route('/api/session/calib_validation', methods=['POST'])
# Route for validating calibration
@app.route("/api/session/calib_validation", methods=["POST"])
def calib_validation():
if request.method == 'POST':
"""
Validates the calibration request.

Returns:
If the request method is 'POST', it calls the `calib_results` function from the `session_route` module.
Otherwise, it returns a `Response` object with an error message and status code 405.
"""
if request.method == "POST":
return session_route.calib_results()
return Response('Invalid request method for route', status=405, mimetype='application/json')
return Response(
"Invalid request method for route", status=405, mimetype="application/json"
)
62 changes: 49 additions & 13 deletions app/models/session.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
class Session:
def __init__(self, id, title, description, user_id, created_date, website_url, screen_record_url, webcam_record_url, heatmap_url, calib_points, iris_points):
"""
Represents a session in the eye tracking application.

Attributes:
- id (int): The unique identifier of the session.
- title (str): The title of the session.
- description (str): The description of the session.
- user_id (int): The user ID associated with the session.
- created_date (datetime): The date and time when the session was created.
- website_url (str): The URL of the website being tracked.
- screen_record_url (str): The URL of the screen recording for the session.
- webcam_record_url (str): The URL of the webcam recording for the session.
- heatmap_url (str): The URL of the heatmap image for the session.
- calib_points (list): The calibration points used in the session.
- iris_points (list): The iris tracking points recorded in the session.
"""

def __init__(
self,
id,
title,
description,
user_id,
created_date,
website_url,
screen_record_url,
webcam_record_url,
heatmap_url,
calib_points,
iris_points,
):
self.id = id
self.title = title
self.description = description
Expand All @@ -13,16 +43,22 @@ def __init__(self, id, title, description, user_id, created_date, website_url, s
self.iris_points = iris_points

def to_dict(self):
"""
Converts the session object to a dictionary.

Returns:
dict: A dictionary representation of the session object.
"""
return {
u'id': self.id,
u'title': self.title,
u'description': self.description,
u'user_id': self.user_id,
u'created_date': self.created_date,
u'website_url': self.website_url,
u'screen_record_url': self.screen_record_url,
u'webcam_record_url': self.webcam_record_url,
u'heatmap_url': self.heatmap_url,
u'callib_points': self.calib_points,
u'iris_points': self.iris_points
}
"id": self.id,
"title": self.title,
"description": self.description,
"user_id": self.user_id,
"created_date": self.created_date,
"website_url": self.website_url,
"screen_record_url": self.screen_record_url,
"webcam_record_url": self.webcam_record_url,
"heatmap_url": self.heatmap_url,
"callib_points": self.calib_points,
"iris_points": self.iris_points,
}
102 changes: 73 additions & 29 deletions app/routes/session.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,26 @@
from flask import Flask, request, Response, send_file
from app.services.storage import save_file_locally
from app.models.session import Session
#from app.services import database as db
from app.services import gaze_tracker
# Necesary imports
import os
import re
import time
import json
import csv

from pathlib import Path
import os
import re
from flask import Flask, request, Response, send_file

# Local imports from app
from app.services.storage import save_file_locally
from app.models.session import Session

# from app.services import database as db
from app.services import gaze_tracker

ALLOWED_EXTENSIONS = {'txt', 'webm'}
COLLECTION_NAME = u'session'

# Constants
ALLOWED_EXTENSIONS = {"txt", "webm"}
COLLECTION_NAME = "session"

# Initialize Flask app
app = Flask(__name__)


Expand Down Expand Up @@ -139,49 +147,85 @@


def calib_results():
file_name = json.loads(request.form['file_name'])
fixed_points = json.loads(request.form['fixed_circle_iris_points'])
calib_points = json.loads(request.form['calib_circle_iris_points'])
screen_height = json.loads(request.form['screen_height'])
screen_width = json.loads(request.form['screen_width'])
k = json.loads(request.form['k'])
"""
Generate calibration results.

This function generates calibration results based on the provided form data.
It saves the calibration points to a CSV file. Then, it uses the gaze_tracker module to predict the calibration results.

Returns:
Response: A JSON response containing the calibration results.

Raises:
IOError: If there is an error while writing to the CSV files.
"""
# Get form data from request
file_name = json.loads(request.form["file_name"])
fixed_points = json.loads(request.form["fixed_circle_iris_points"])
calib_points = json.loads(request.form["calib_circle_iris_points"])
screen_height = json.loads(request.form["screen_height"])
screen_width = json.loads(request.form["screen_width"])
k = json.loads(request.form["k"])
model = json.loads(request.form["model"])

# Generate csv dataset of calibration points
os.makedirs(
f'{Path().absolute()}/app/services/calib_validation/csv/data/', exist_ok=True)
calib_csv_file = f'{Path().absolute()}/app/services/calib_validation/csv/data/{file_name}_fixed_train_data.csv'
csv_columns = ['left_iris_x', 'left_iris_y',
'right_iris_x', 'right_iris_y', 'point_x', 'point_y', 'screen_height', 'screen_width']
f"{Path().absolute()}/app/services/calib_validation/csv/data/", exist_ok=True
)

# Generate csv of calibration points with following columns
calib_csv_file = f"{Path().absolute()}/app/services/calib_validation/csv/data/{file_name}_fixed_train_data.csv"
csv_columns = [
"left_iris_x",
"left_iris_y",
"right_iris_x",
"right_iris_y",
"point_x",
"point_y",
"screen_height",
"screen_width",
]

# Save calibration points to CSV file
try:
with open(calib_csv_file, 'w') as csvfile:
# Open CSV file
with open(calib_csv_file, "w") as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=csv_columns)
writer.writeheader()

# Write calibration points to CSV file
for data in fixed_points:
data['screen_height'] = screen_height
data['screen_width'] = screen_width
data["screen_height"] = screen_height
data["screen_width"] = screen_width
writer.writerow(data)

# Handle I/O error
except IOError:
print("I/O error")

# Generate csv of iris points of session
os.makedirs(
f'{Path().absolute()}/app/services/calib_validation/csv/data/', exist_ok=True)
predict_csv_file = f'{Path().absolute()}/app/services/calib_validation/csv/data/{file_name}_predict_train_data.csv'
csv_columns = ['left_iris_x', 'left_iris_y',
'right_iris_x', 'right_iris_y']
f"{Path().absolute()}/app/services/calib_validation/csv/data/", exist_ok=True
)
predict_csv_file = f"{Path().absolute()}/app/services/calib_validation/csv/data/{file_name}_predict_train_data.csv"
csv_columns = ["left_iris_x", "left_iris_y", "right_iris_x", "right_iris_y"]
try:
with open(predict_csv_file, 'w') as csvfile:
with open(predict_csv_file, "w") as csvfile:
writer = csv.DictWriter(csvfile, fieldnames=csv_columns)
writer.writeheader()
for data in calib_points:
# print(data)
writer.writerow(data)
except IOError:
print("I/O error")

# data = gaze_tracker.train_to_validate_calib(calib_csv_file, predict_csv_file)
data = gaze_tracker.predict(calib_csv_file, calib_csv_file, k)

return Response(json.dumps(data), status=200, mimetype='application/json')
# Predict calibration results
data = gaze_tracker.predict(calib_csv_file, k, model_X=model, model_Y=model)

# Return calibration results
return Response(json.dumps(data), status=200, mimetype="application/json")


# def session_results():
Expand Down
Loading
Loading