remote-calibrator 0.2.1 → 0.2.2-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +2 -0
  3. package/homepage/example.js +11 -13
  4. package/lib/RemoteCalibrator.min.js +1 -1
  5. package/lib/RemoteCalibrator.min.js.LICENSE.txt +1 -1
  6. package/lib/RemoteCalibrator.min.js.map +1 -1
  7. package/package.json +8 -8
  8. package/src/WebGazer4RC/.gitattributes +10 -0
  9. package/src/WebGazer4RC/LICENSE.md +15 -0
  10. package/src/WebGazer4RC/README.md +142 -0
  11. package/src/WebGazer4RC/gnu-lgpl-v3.0.md +163 -0
  12. package/src/WebGazer4RC/gplv3.md +636 -0
  13. package/src/WebGazer4RC/package-lock.json +1133 -0
  14. package/src/WebGazer4RC/package.json +28 -0
  15. package/src/WebGazer4RC/src/dom_util.mjs +27 -0
  16. package/src/WebGazer4RC/src/facemesh.mjs +150 -0
  17. package/src/WebGazer4RC/src/index.mjs +1213 -0
  18. package/src/WebGazer4RC/src/mat.mjs +301 -0
  19. package/src/WebGazer4RC/src/params.mjs +29 -0
  20. package/src/WebGazer4RC/src/pupil.mjs +109 -0
  21. package/src/WebGazer4RC/src/ridgeReg.mjs +104 -0
  22. package/src/WebGazer4RC/src/ridgeRegThreaded.mjs +161 -0
  23. package/src/WebGazer4RC/src/ridgeWeightedReg.mjs +125 -0
  24. package/src/WebGazer4RC/src/ridgeWorker.mjs +135 -0
  25. package/src/WebGazer4RC/src/util.mjs +348 -0
  26. package/src/WebGazer4RC/src/util_regression.mjs +240 -0
  27. package/src/WebGazer4RC/src/worker_scripts/mat.js +306 -0
  28. package/src/WebGazer4RC/src/worker_scripts/util.js +398 -0
  29. package/src/WebGazer4RC/test/regression_test.js +182 -0
  30. package/src/WebGazer4RC/test/run_tests_and_server.sh +24 -0
  31. package/src/WebGazer4RC/test/util_test.js +60 -0
  32. package/src/WebGazer4RC/test/webgazerExtract_test.js +40 -0
  33. package/src/WebGazer4RC/test/webgazer_test.js +160 -0
  34. package/src/WebGazer4RC/test/www_page_test.js +41 -0
  35. package/src/components/onCanvas.js +1 -2
  36. package/src/core.js +18 -0
  37. package/src/css/distance.scss +1 -0
  38. package/src/distance/distance.js +4 -1
  39. package/src/distance/distanceTrack.js +2 -2
  40. package/src/panel/panel.js +14 -5
  41. package/src/text.json +4 -2
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "webgazer",
3
+ "version": "2.1.0",
4
+ "private": "true",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/brownhci/WebGazer.git"
8
+ },
9
+ "license": "GPL-3.0-or-later",
10
+ "main": "dist/webgazer.js",
11
+ "module": "src/index.mjs",
12
+ "files": [
13
+ "/dist",
14
+ "/src"
15
+ ],
16
+ "keywords": [
17
+ "webgazer",
18
+ "eyetracking",
19
+ "webcam"
20
+ ],
21
+ "dependencies": {
22
+ "@tensorflow-models/facemesh": "^0.0.5",
23
+ "@tensorflow/tfjs": "^3.8.0",
24
+ "localforage": "^1.9.0",
25
+ "numeric": "1.2.6",
26
+ "regression": "2.0.1"
27
+ }
28
+ }
@@ -0,0 +1,27 @@
1
+ // helper functions
2
+
3
+ /**
4
+ * Provides requestAnimationFrame in a cross browser way.
5
+ */
6
+ window.requestAnimFrame = (function() {
7
+ return window.requestAnimationFrame ||
8
+ window.webkitRequestAnimationFrame ||
9
+ window.mozRequestAnimationFrame ||
10
+ window.oRequestAnimationFrame ||
11
+ window.msRequestAnimationFrame ||
12
+ function(/* function FrameRequestCallback */ callback, /* DOMElement Element */ element) {
13
+ return window.setTimeout(callback, 1000/60);
14
+ };
15
+ })();
16
+
17
+ /**
18
+ * Provides cancelRequestAnimationFrame in a cross browser way.
19
+ */
20
+ window.cancelRequestAnimFrame = (function() {
21
+ return window.cancelCancelRequestAnimationFrame ||
22
+ window.webkitCancelRequestAnimationFrame ||
23
+ window.mozCancelRequestAnimationFrame ||
24
+ window.oCancelRequestAnimationFrame ||
25
+ window.msCancelRequestAnimationFrame ||
26
+ window.clearTimeout;
27
+ })();
@@ -0,0 +1,150 @@
1
+ const FacemeshModel = require('@tensorflow-models/facemesh');
2
+ /**
3
+ * Constructor of TFFaceMesh object
4
+ * @constructor
5
+ * */
6
+ const TFFaceMesh = function() {
7
+ //Backend options are webgl, wasm, and CPU.
8
+ //For recent laptops WASM is better than WebGL.
9
+ //TODO: This hack makes loading the model block the UI. We should fix that
10
+ // this.model = (async () => { return await facemesh.load({"maxFaces":1}) })();
11
+ this.model = FacemeshModel.load({ "maxFaces": 1 });
12
+ this.predictionReady = false;
13
+ };
14
+
15
+ // Global variable for face landmark positions array
16
+ TFFaceMesh.prototype.positionsArray = null;
17
+
18
+ /**
19
+ * Isolates the two patches that correspond to the user's eyes
20
+ * @param {Canvas} imageCanvas - canvas corresponding to the webcam stream
21
+ * @param {Number} width - of imageCanvas
22
+ * @param {Number} height - of imageCanvas
23
+ * @return {Object} the two eye-patches, first left, then right eye
24
+ */
25
+ TFFaceMesh.prototype.getEyePatches = async function(imageCanvas, width, height) {
26
+
27
+ if (imageCanvas.width === 0) {
28
+ return null;
29
+ }
30
+
31
+ // Load the MediaPipe facemesh model.
32
+ const model = await this.model;
33
+
34
+ // Pass in a video stream (or an image, canvas, or 3D tensor) to obtain an
35
+ // array of detected faces from the MediaPipe graph.
36
+ const predictions = await model.estimateFaces(imageCanvas);
37
+
38
+ if (predictions.length == 0){
39
+ return false;
40
+ }
41
+
42
+ // Save positions to global variable
43
+ this.positionsArray = predictions[0].scaledMesh;
44
+ const positions = this.positionsArray;
45
+
46
+ // Fit the detected eye in a rectangle. [20200626 xk] not clear which approach is better
47
+ // https://raw.githubusercontent.com/tensorflow/tfjs-models/master/facemesh/mesh_map.jpg
48
+
49
+ // // Maintains a relatively stable shape of the bounding box at the cost of cutting off parts of
50
+ // // the eye when the eye is tilted.
51
+ // var leftOriginX = Math.round(positions[130][0]);
52
+ // var leftOriginY = Math.round(positions[27][1]);
53
+ // var leftWidth = Math.round(positions[243][0] - leftOriginX);
54
+ // var leftHeight = Math.round(positions[23][1] - leftOriginY);
55
+ // var rightOriginX = Math.round(positions[463][0]);
56
+ // var rightOriginY = Math.round(positions[257][1]);
57
+ // var rightWidth = Math.round(positions[359][0] - rightOriginX);
58
+ // var rightHeight = Math.round(positions[253][1] - rightOriginY);
59
+
60
+ // Won't really cut off any parts of the eye, at the cost of warping the shape (i.e. height/
61
+ // width ratio) of the bounding box.
62
+ var leftOriginX = Math.round(Math.min(positions[247][0], positions[130][0], positions[25][0]));
63
+ var leftOriginY = Math.round(Math.min(positions[247][1], positions[27][1], positions[190][1]));
64
+ var leftWidth = Math.round(Math.max(positions[190][0], positions[243][0], positions[233][0]) - leftOriginX);
65
+ var leftHeight = Math.round(Math.max(positions[25][1], positions[23][1], positions[112][1]) - leftOriginY);
66
+ var rightOriginX = Math.round(Math.min(positions[414][0], positions[463][0], positions[453][0]));
67
+ var rightOriginY = Math.round(Math.min(positions[414][1], positions[257][1], positions[467][1]));
68
+ var rightWidth = Math.round(Math.max(positions[467][0], positions[359][0], positions[255][0]) - rightOriginX);
69
+ var rightHeight = Math.round(Math.max(positions[341][1], positions[253][1], positions[255][1]) - rightOriginY);
70
+
71
+ if (leftWidth === 0 || rightWidth === 0){
72
+ console.log('an eye patch had zero width');
73
+ return null;
74
+ }
75
+
76
+ if (leftHeight === 0 || rightHeight === 0){
77
+ console.log('an eye patch had zero height');
78
+ return null;
79
+ }
80
+
81
+ // Start building object to be returned
82
+ var eyeObjs = {};
83
+
84
+ var leftImageData = imageCanvas.getContext('2d').getImageData(leftOriginX, leftOriginY, leftWidth, leftHeight);
85
+ eyeObjs.left = {
86
+ patch: leftImageData,
87
+ imagex: leftOriginX,
88
+ imagey: leftOriginY,
89
+ width: leftWidth,
90
+ height: leftHeight
91
+ };
92
+
93
+ var rightImageData = imageCanvas.getContext('2d').getImageData(rightOriginX, rightOriginY, rightWidth, rightHeight);
94
+ eyeObjs.right = {
95
+ patch: rightImageData,
96
+ imagex: rightOriginX,
97
+ imagey: rightOriginY,
98
+ width: rightWidth,
99
+ height: rightHeight
100
+ };
101
+
102
+ this.predictionReady = true;
103
+
104
+ return eyeObjs;
105
+ };
106
+
107
+ /**
108
+ * Returns the positions array corresponding to the last call to getEyePatches.
109
+ * Requires that getEyePatches() was called previously, else returns null.
110
+ */
111
+ TFFaceMesh.prototype.getPositions = function () {
112
+ return this.positionsArray;
113
+ }
114
+
115
+ /**
116
+ * Reset the tracker to default values
117
+ */
118
+ TFFaceMesh.prototype.reset = function(){
119
+ console.log( "Unimplemented; Tracking.js has no obvious reset function" );
120
+ }
121
+
122
+ /**
123
+ * Draw TF_FaceMesh_Overlay
124
+ */
125
+ TFFaceMesh.prototype.drawFaceOverlay= function(ctx, keypoints){
126
+ // If keypoints is falsy, don't do anything
127
+ if (keypoints) {
128
+ ctx.fillStyle = '#32EEDB';
129
+ ctx.strokeStyle = '#32EEDB';
130
+ ctx.lineWidth = 0.5;
131
+
132
+ for (let i = 0; i < keypoints.length; i++) {
133
+ const x = keypoints[i][0];
134
+ const y = keypoints[i][1];
135
+
136
+ ctx.beginPath();
137
+ ctx.arc(x, y, 1 /* radius */, 0, 2 * Math.PI);
138
+ ctx.closePath();
139
+ ctx.fill();
140
+ }
141
+ }
142
+ }
143
+
144
+ /**
145
+ * The TFFaceMesh object name
146
+ * @type {string}
147
+ */
148
+ TFFaceMesh.prototype.name = 'TFFaceMesh';
149
+
150
+ export default TFFaceMesh;