| --- |
| license: mit |
| tags: |
| - eye-tracking |
| - gaze-estimation |
| - computer-vision |
| - onnx |
| - ux-research |
| library_name: onnx |
| pipeline_tag: image-classification |
| --- |
| |
| # InsightUX β Webcam Eye-Tracking UX Research Browser |
|
|
| A webcam-based gaze tracking system that turns any consumer laptop into a UX |
| research tool. Browse a website, and get back a heatmap, an attention timeline, |
| and a ranked list of which page elements actually held your gaze. |
|
|
| No specialist hardware β just a webcam. |
|
|
| **This is a local desktop app, not a hosted demo.** It needs a physical |
| webcam, a native window, and full-screen capture β none of which exist on a |
| server, so it cannot run as a Hugging Face Space. Clone it and run it on your |
| own machine. |
|
|
| ## Requirements before you start |
|
|
| - **Windows** (uses WebView2 via pywebview's WinForms backend) |
| - **Python 3.11 exactly** β mediapipe's legacy face-mesh API this project |
| depends on does not exist on Python 3.12+ |
| - A working webcam |
|
|
| ## How to run β step by step |
|
|
| ### 1. Clone the repo |
|
|
| ```bash |
| git clone https://huggingface.co/<your-username>/insightux |
| cd insightux |
| ``` |
|
|
| ### 2. Create and activate a virtual environment |
|
|
| ```bash |
| python -m venv venv |
| venv\Scripts\activate |
| ``` |
|
|
| ### 3. Install dependencies β use the pinned versions |
|
|
| ```bash |
| pip install -r requirements.txt |
| ``` |
|
|
| This includes `onnx`, which `calibrate.py` needs when it exports the |
| fine-tuned model after training. |
|
|
| **Do not `pip install --upgrade` pywebview or pythonnet.** `requirements.txt` |
| pins `pywebview==4.4.1` and `pythonnet==3.0.3` deliberately β newer versions |
| have a bug in their Windows backend that freezes the app window and floods |
| the console with: |
| ``` |
| AccessibilityObject.Bounds.Empty.Empty.Empty.Empty... |
| ``` |
| If you already have a newer version installed globally, this install step |
| will replace it with the working one. |
|
|
| ### 4. Calibrate β required, per person, per setup |
|
|
| ```bash |
| python calibrate.py |
| ``` |
| Sit normally at your usual distance from the screen, look at each of the 16 |
| dots as they appear. Takes about a minute. This is **per-person and |
| per-setup** β your eyes, your camera, your screen size. Everyone using this |
| must run it themselves; it is not something you can copy from someone else. |
|
|
| Re-run it if your lighting, seating position, or camera position changes |
| noticeably. |
|
|
| At the end it prints an honest quality readout, including whether the model |
| can actually see where you're looking on each axis: |
| ``` |
| HORIZONTAL yaw vs screen-X : r = +0.995 |
| VERTICAL pitch vs screen-Y: r = +0.883 |
| ``` |
| If either number is low, the report will say so plainly and explain why β |
| that means the model isn't seeing that axis, and no amount of recalibrating |
| will fix it. |
|
|
| ### 5. (Optional) Check your accuracy |
|
|
| ```bash |
| python validate.py |
| ``` |
| Flashes 9 test dots and reports your real error in pixels. Good for knowing |
| what to expect before relying on a session. |
|
|
| ### 6. Run the browser |
|
|
| ```bash |
| python browser_session.py |
| ``` |
| - Opens on an InsightUX-branded search page. Type a search term (goes to |
| real Google results) or a URL (goes straight there). |
| - Land on the page you want to study, **click on blank space on the page** |
| (not a text field), then press **S** to start eye-tracking. |
| - Press **E** to stop. A full report β heatmap over real screenshots, |
| ranked attention list, dwell timeline β generates and opens automatically. |
|
|
| ## What's in this repo |
|
|
| | File | Purpose | |
| |---|---| |
| | `models/gaze_cnn_v4.onnx` (+ `.onnx.data`) | Binocular gaze CNN (EfficientNet-B0 backbone, dual eye patches + head pose) | |
| | `models/model_v4.py` | Model architecture definition, used during calibration fine-tuning | |
| | `checkpoints/best_model_v4.pt` | PyTorch checkpoint for fine-tuning | |
| | `calibrate.py` | Per-user calibration β 16-point, live blink/lighting rejection, honest quality report | |
| | `validate.py` | Measures real accuracy in pixels after calibration | |
| | `browser_session.py` | The research browser β search, track, auto-report | |
| | `analysis.py` | Builds the session report (heatmaps over real screenshots) | |
| | `inference_pipeline.py` | ONNX inference + RBF gazeβscreen calibration mapping | |
| | `preprocessing/preprocessing_pipeline.py` | Eye patch normalization, head pose estimation, illumination correction | |
|
|
| ## Calibration is per-person and per-setup β not included in this repo |
|
|
| `calibration.pkl` (generated by `calibrate.py`) encodes *your* eye geometry, |
| *your* camera characteristics, and *your* screen size. It is deliberately |
| **not** in this repo β it would be useless to anyone else and it's personal |
| data. Run `calibrate.py` yourself; it takes about a minute. |
|
|
| ## Accuracy β honest numbers |
|
|
| This is a webcam system, not a Tobii. Expect roughly **5β10% of screen |
| diagonal** mean error after a good calibration. That's enough for coarse AOI |
| attribution (navbar vs hero vs footer) and heatmaps. It is **not** enough for |
| reading-level analysis (which word you're on). |
|
|
| Vertical accuracy is typically a bit looser than horizontal β looking down |
| partially occludes the iris under the eyelid, a physical limit of webcam |
| gaze estimation, not a bug. Calibration automatically checks whether eye |
| aperture (eyelid closing as you look down) tracks vertical position better |
| than the model's raw output, and uses whichever signal is actually stronger. |
|
|
| ## Known limitations |
|
|
| - Windows-only (pywebview + WebView2 backend). Other platforms untested. |
| - Head movement during a session degrades accuracy β the calibration assumes |
| a roughly stable head pose. |
| - No lens distortion correction β `solvePnP` assumes zero distortion, which |
| costs some accuracy near frame edges. |
|
|
| ## Troubleshooting |
|
|
| **Window freezes with `AccessibilityObject.Bounds.Empty.Empty.Empty...` |
| spamming the console:** |
| Confirm you actually have the pinned versions installed, not newer ones: |
| ```bash |
| pip uninstall pywebview pythonnet -y |
| pip install pywebview==4.4.1 pythonnet==3.0.3 |
| ``` |
| If it persists after that, turn off **Xbox Game Bar** (Settings β Gaming β |
| Xbox Game Bar) and any overlay software (Discord overlay, GeForce |
| Experience, OBS), then **restart your PC** β those hooks stay loaded until a |
| real reboot. Last resort: install `PyQt5` + `PyQtWebEngine` (see |
| `requirements.txt`) and switch the GUI backend as described there. |
|
|
| **"No calibration.pkl found" when pressing S:** |
| Run `python calibrate.py` first β it must exist before `browser_session.py` |
| can track anything. |
|
|
| **Can't type in the search box:** |
| Click directly into the search field first β this can happen if the window |
| just opened and hasn't fully grabbed keyboard focus yet. |
|
|
| ## License |
|
|
| MIT. |