-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdisplay.js
More file actions
78 lines (70 loc) · 2.78 KB
/
Copy pathdisplay.js
File metadata and controls
78 lines (70 loc) · 2.78 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
import { gazeData, calibrationModel } from "./dotCalibration.js";
import { leastSquares } from "./mathUtils.js";
/**
* Calculates the prediction model based on collected gaze data.
* It builds matrices from the gaze points and iris positions, performs a least-squares fit,
* validates the model accuracy, and updates the global calibrationModel object.
*
* @returns {Object} An object containing success flags, RMSE values, and accuracy scores for both eyes.
*/
export function displayPredictionModel() {
const buildMatrices = (eye) => {
const A = [], bx = [], by = [];
gazeData.forEach(d => {
const iris = eye==="left"?d.iris_left:d.iris_right;
if (!iris) return;
const x = iris.x, y = iris.y;
A.push([1, x, y, x*x, y*y, x*y]);
bx.push(d.targetX);
by.push(d.targetY);
});
return { A, bx, by };
};
const fitAndValidate = ({A,bx,by}) => {
if(A.length<6) return {success:false, reason:"not enough samples"};
const px = leastSquares(A,bx);
const py = leastSquares(A,by);
if(!px || !py) return {success:false, reason:"matrix failure"};
let errSum=0;
for(let i=0;i<A.length;i++){
const [_,ix,iy] = A[i];
const predX = px[0]+px[1]*ix+px[2]*iy+px[3]*ix*ix+px[4]*iy*iy+px[5]*ix*iy;
const predY = py[0]+py[1]*ix+py[2]*iy+py[3]*ix*ix+py[4]*iy*iy+py[5]*ix*iy;
const dx = predX-bx[i], dy = predY-by[i];
errSum += dx*dx+dy*dy;
}
const rmse = Math.sqrt(errSum/A.length);
const accuracy = Math.max(0,1-rmse);
return {success:true, px, py, rmse, accuracy, samples:A.length};
};
const leftRes = fitAndValidate(buildMatrices("left"));
const rightRes = fitAndValidate(buildMatrices("right"));
if(leftRes.success){
calibrationModel.left.coefX = leftRes.px;
calibrationModel.left.coefY = leftRes.py;
}
if(rightRes.success){
calibrationModel.right.coefX = rightRes.px;
calibrationModel.right.coefY = rightRes.py;
}
// debug: Store calibration metadata
calibrationModel.metadata = {
coordinateSystem: 'normalized', // Model outputs 0-1 range
irisExtractionMethod: '9point', // Uses 5-point average
irisIndices: {
left: { start: 474, end: 479 },
right: { start: 469, end: 474 }
},
screenDimensions: {
width: window.innerWidth,
height: window.innerHeight
},
timestamp: Date.now(),
version: '1.0'
};
return {
sucess: {left: leftRes.success, right: rightRes.success },
rmse: {left: leftRes.rmse, right: rightRes.rmse },
accuracy: { left: leftRes.accuracy, right: rightRes.accuracy }
};
}