HuggingFace-SK commited on
Commit
5ad985e
·
1 Parent(s): 7b3c42a

added keyboard functionality

Browse files
Files changed (2) hide show
  1. main.py +1 -1
  2. templates/browser-detect.html +440 -340
main.py CHANGED
@@ -8,7 +8,7 @@ def index():
8
 
9
  @app.route('/exported')
10
  def send_report():
11
- return send_from_directory("exported", "model.tflite")
12
 
13
  if (__name__ == '__main__'):
14
  app.run( host='0.0.0.0', port=7860)
 
8
 
9
  @app.route('/exported')
10
  def send_report():
11
+ return send_from_directory("better_exported", "model.tflite")
12
 
13
  if (__name__ == '__main__'):
14
  app.run( host='0.0.0.0', port=7860)
templates/browser-detect.html CHANGED
@@ -1,368 +1,468 @@
1
  <!DOCTYPE html>
2
- <html lang="en"><head></head>
3
- <meta charset="UTF-8">
4
 
 
 
5
 
6
- <title>Sign Language Interpreter</title>
7
- <style>
8
 
 
 
 
 
 
9
 
10
- body {
11
- font-family: roboto;
12
- color: #3d3d3d;
13
- --mdc-theme-primary: #007f8b;
14
- --mdc-theme-on-primary: #f1f3f4;
15
- box-sizing: border-box;
16
- }
17
 
18
- canvas {
19
- background-color: lightgray; /* Just for visibility */
20
- }
21
 
 
 
 
 
22
  </style>
23
 
24
- <script>
25
- window.console = window.console || function(t) {};
26
  </script>
27
 
28
-
29
-
30
- </head>
31
 
32
- <body translate="no">
33
- <script src="https://cdn.jsdelivr.net/npm/@mediapipe/drawing_utils/drawing_utils.js" crossorigin="anonymous"></script>
34
- <script src="https://cdn.jsdelivr.net/npm/@mediapipe/hands/hands.js" crossorigin="anonymous"></script>
35
- <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-core"></script>
36
- <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-cpu"></script>
37
- <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-tflite/dist/tf-tflite.min.js"></script>
38
 
 
39
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  <center>
41
- <img id="output_image" style="display:none"></img>
42
- <button id="webcamButton">
43
- <span>ENABLE WEBCAM</span>
44
- </button>
45
- <span id="predicted_result"></span>
46
-
47
- </center>
48
- <video id="webcam" style="display:none" autoplay="" playsinline=""></video>
49
- <canvas class="output_canvas" id="output_canvas" style="display:block; position:absolute; left:0px" width="100%" height="30%"></canvas>
50
-
51
-
52
-
53
-
54
- <script type="module">
55
-
56
- import { HandLandmarker, FilesetResolver } from "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.0";
57
- let handLandmarker = undefined;
58
- let runningMode = "IMAGE";
59
- let enableWebcamButton;
60
- let webcamRunning = false;
61
- // Before we can use HandLandmarker class we must wait for it to finish
62
- // loading. Machine Learning models can be large and take a moment to
63
- // get everything needed to run.
64
- const createHandLandmarker = async () => {
65
- const vision = await FilesetResolver.forVisionTasks("https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.0/wasm");
66
- handLandmarker = await HandLandmarker.createFromOptions(vision, {
67
- baseOptions: {
68
- modelAssetPath: `https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task`,
69
- delegate: "GPU"
70
- },
71
- runningMode: runningMode,
72
- numHands: 1
73
- });
74
- };
75
- createHandLandmarker();
76
-
77
- const MODEL_PATH = "/exported"
78
- var objectDetector = tflite.loadTFLiteModel(MODEL_PATH);
79
-
80
- /********************************************************************
81
- // Demo 2: Continuously grab image from webcam stream and detect it.
82
- ********************************************************************/
83
- var global_res = 0;
84
- const video = document.getElementById("webcam");
85
- const canvasElement = document.getElementById("output_canvas");
86
- const canvasCtx = canvasElement.getContext("2d");
87
- var x_array=[]
88
- var y_array=[]
89
- // Check if webcam access is supported.
90
- const hasGetUserMedia = () => { var _a; return !!((_a = navigator.mediaDevices) === null || _a === void 0 ? void 0 : _a.getUserMedia); };
91
- // If webcam supported, add event listener to button for when user
92
- // wants to activate it.
93
- if (hasGetUserMedia()) {
94
- enableWebcamButton = document.getElementById("webcamButton");
95
- enableWebcamButton.addEventListener("click", enableCam);
96
- }
97
- else {
98
- console.warn("getUserMedia() is not supported by your browser");
99
- }
100
- // Enable the live webcam view and start detection.
101
- function enableCam(event) {
102
- if (!handLandmarker) {
103
- console.log("Wait! objectDetector not loaded yet.");
104
- return;
105
- }
106
- if (webcamRunning === true) {
107
- webcamRunning = false;
108
- enableWebcamButton.innerText = "ENABLE PREDICTIONS";
109
- }
110
- else {
111
- webcamRunning = true;
112
- enableWebcamButton.innerText = "DISABLE PREDICTIONS";
113
- }
114
- // getUsermedia parameters.
115
- const constraints = {
116
- video: true
117
- };
118
- // Activate the webcam stream.
119
- navigator.mediaDevices.getUserMedia(constraints).then((stream) => {
120
- video.srcObject = stream;
121
- video.addEventListener("loadeddata", predictWebcam);
122
- });
123
- }
124
- let lastVideoTime = -1;
125
- let results = undefined;
126
- console.log(video);
127
- async function predictWebcam() {
128
- canvasElement.width = window.innerWidth;
129
- // Now let's start detecting the stream.
130
- if (runningMode === "IMAGE") {
131
- runningMode = "VIDEO";
132
- await handLandmarker.setOptions({ runningMode: "VIDEO" });
133
- }
134
- let startTimeMs = performance.now();
135
- if (lastVideoTime !== video.currentTime) {
136
- lastVideoTime = video.currentTime;
137
- results = handLandmarker.detectForVideo(video, startTimeMs);
138
- }
139
- canvasCtx.save();
140
- canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);
141
- canvasCtx.drawImage(video, 0, 0, canvasElement.width, (video.videoHeight/video.videoWidth)*canvasElement.width)
142
- if (results.landmarks) {
143
- annotateImage()
144
- //detectSign()
145
- }
146
- canvasCtx.restore();
147
- // Call this function again to keep predicting when the browser is ready.
148
- if (webcamRunning === true) {
149
- window.requestAnimationFrame(predictWebcam);
150
- }
151
- }
152
- function annotateImage(){
153
-
154
- //console.log(results.landmarks)
155
- if(results.landmarks[0]){
156
- x_array=[]
157
- y_array=[]
158
- results.landmarks[0].forEach(iterate)
159
- //console.log(x_array)
160
- var image_height = (video.videoHeight/video.videoWidth)*canvasElement.width
161
- var image_width= canvasElement.width
162
- var min_x = Math.min(...x_array)*image_width
163
- var min_y = Math.min(...y_array)*image_height
164
- var max_x = Math.max(...x_array)*image_width
165
- var max_y = Math.max(...y_array)*image_height
166
-
167
- var sect_height = max_y-(min_y)
168
- var sect_width = max_x-(min_x)
169
- var center_x=(min_x+max_x)/2
170
- var center_y=(min_y+max_y)/2
171
-
172
- var sect_diameter=50
173
- if(sect_height>sect_width){
174
- sect_diameter = sect_height
175
- //console.log("sect_height", sect_diameter)
176
- }
177
- if(sect_height<sect_width){
178
- sect_diameter = sect_width
179
- // console.log("sect_width", sect_diameter)
180
- }
181
-
182
- sect_diameter=sect_diameter+50
183
- var sect_radius=sect_diameter/2
184
- var crop_top=center_y-sect_radius
185
- var crop_bottom=center_y+sect_radius
186
- var crop_left=center_x-sect_radius
187
- var crop_right=center_x+sect_radius
188
- if(crop_top<0){
189
- crop_top=0
190
- }
191
- if(crop_left<0){
192
- crop_left=0
193
- }
194
- if(crop_right>image_width){
195
- crop_right=image_width
196
- }
197
- if(crop_bottom>image_height){
198
- crop_bottom=image_height
199
- }
200
-
201
- canvasCtx.beginPath();
202
- canvasCtx.rect(crop_left, crop_top, crop_right-crop_left, crop_bottom-crop_top);
203
- canvasCtx.stroke();
204
-
205
-
206
- }
207
- /* for (const landmarks of results.multiHandLandmarks) {
208
- drawConnectors(canvasCtx, landmarks, HAND_CONNECTIONS, {
209
- color: "#00FF00",
210
- lineWidth: 5
211
- });
212
- drawLandmarks(canvasCtx, landmarks, { color: "#FF0000", lineWidth: 2 });
213
- }*/
214
- console.log(results)
215
- const landmarks = results.landmarks;
216
- if(landmarks[0]){
217
- var hand=landmarks[0]
218
-
219
- // Thumb connections
220
- drawConnection(hand[4], hand[3], '#ffe5b4', 5); // 4-3
221
- drawConnection(hand[3], hand[2], '#ffe5b4', 5); // 3-2
222
- drawConnection(hand[2], hand[1], '#ffe5b4', 5); // 2-1
223
-
224
- // Index connections
225
- drawConnection(hand[8], hand[7], '#804080', 5); // 8-7
226
- drawConnection(hand[7], hand[6], '#804080', 5); // 7-6
227
- drawConnection(hand[6], hand[5], '#804080', 5); // 6-5
228
-
229
- // Middle connections
230
- drawConnection(hand[12], hand[11], '#ffcc00', 5); // 12-11
231
- drawConnection(hand[11], hand[10], '#ffcc00', 5); // 11-10
232
- drawConnection(hand[10], hand[9], '#ffcc00', 5); // 10-9
233
-
234
- // Ring connections
235
- drawConnection(hand[16], hand[15], '#30ff30', 5); // 16-15
236
- drawConnection(hand[15], hand[14], '#30ff30', 5); // 15-14
237
- drawConnection(hand[14], hand[13], '#30ff30', 5); // 14-13
238
-
239
- // Pinky connections
240
- drawConnection(hand[20], hand[19], '#1565c0', 5); // 20-19
241
- drawConnection(hand[19], hand[18], '#1565c0', 5); // 19-18
242
- drawConnection(hand[18], hand[17], '#1565c0', 5); // 18-17
243
-
244
- drawConnection(hand[0], hand[1], '#808080', 5); // 0-1
245
- drawConnection(hand[0], hand[5], '#808080', 5); // 0-5
246
- drawConnection(hand[0], hand[17], '#808080', 5); // 0-17
247
- drawConnection(hand[5], hand[9], '#808080', 5); // 5-9
248
- drawConnection(hand[9], hand[13], '#808080', 5); // 9-13
249
- drawConnection(hand[13], hand[17], '#808080', 5); // 13-17
250
-
251
- // Thumb
252
- drawLandmarks(canvasCtx, hand[2], '#ffe5b4'); // Thumb tip (2)
253
- drawLandmarks(canvasCtx, hand[3], '#ffe5b4'); // Thumb base (3)
254
- drawLandmarks(canvasCtx, hand[4], '#ffe5b4'); // Thumb base (4)
255
-
256
- // Index
257
- drawLandmarks(canvasCtx, hand[6], '#804080'); // Index tip (6)
258
- drawLandmarks(canvasCtx, hand[7], '#804080'); // Index base (7)
259
- drawLandmarks(canvasCtx, hand[8], '#804080'); // Index base (8)
260
-
261
- // Middle
262
- drawLandmarks(canvasCtx, hand[10], '#ffcc00'); // Middle tip (10)
263
- drawLandmarks(canvasCtx, hand[11], '#ffcc00'); // Middle base (11)
264
- drawLandmarks(canvasCtx, hand[12], '#ffcc00'); // Middle base (12)
265
-
266
- // Ring
267
- drawLandmarks(canvasCtx, hand[14], '#30ff30'); // Ring tip (14)
268
- drawLandmarks(canvasCtx, hand[15], '#30ff30'); // Ring base (15)
269
- drawLandmarks(canvasCtx, hand[16], '#30ff30'); // Ring base (16)
270
-
271
- // Pinky
272
- drawLandmarks(canvasCtx, hand[18], '#1565c0'); // Pinky tip (18)
273
- drawLandmarks(canvasCtx, hand[19], '#1565c0'); // Pinky base (19)
274
- drawLandmarks(canvasCtx, hand[20], '#1565c0'); // Pinky base (20)
275
-
276
- drawLandmarks(canvasCtx, hand[0], '#ff3030'); // Wrist (0)
277
-
278
- drawLandmarks(canvasCtx, hand[1], '#ff3030'); // Palm base (1)
279
-
280
- drawLandmarks(canvasCtx, hand[5], '#ff3030'); // Index palm (5)
281
-
282
- drawLandmarks(canvasCtx, hand[9], '#ff3030'); // Middle palm (9)
283
-
284
- drawLandmarks(canvasCtx, hand[13], '#ff3030'); // Ring palm (13)
285
-
286
- drawLandmarks(canvasCtx, hand[17], '#ff3030'); // Pinky palm (17)
287
- }
288
- // Add more drawing calls for each landmark collection as needed
289
-
290
- var dataurl=cropCanvas(canvasElement,crop_left,crop_top,crop_right-crop_left, crop_bottom-crop_top).toDataURL("image/jpeg", 0.2);
291
-
292
-
293
- //# sourceURL=pen.js
294
- }
295
 
296
 
297
- function iterate(x,y){
298
- x_array.push(x.x)
299
- y_array.push(x.y)
300
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
 
302
- const cropCanvas = (sourceCanvas,left,top,width,height) => {
303
- let destCanvas = document.createElement('canvas');
304
- destCanvas.width = 224;
305
- var cropAspectRatio = width / height;
306
 
307
- destCanvas.height = 224 / cropAspectRatio
308
- destCanvas.getContext("2d").drawImage(
309
- sourceCanvas,
310
- left,top,width,height, // source rect with content to crop
311
- 0,0,224,destCanvas.height); // newCanvas, same size as source
312
- var predictionInput=tf.browser.fromPixels(destCanvas.getContext("2d").getImageData(0, 0, 224, 224))
 
313
 
314
- predict(tf.expandDims(predictionInput,0))
315
- return destCanvas;
316
- }
317
- async function predict(inputTensor){
318
- //console.log("in predict")
319
- var letter_list=["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","#"]
320
- objectDetector.then(function (res) {
321
- var prediction = res.predict(inputTensor);
322
- var outputArray = prediction.dataSync(); // Get the output as an array
323
- var predictedClass = outputArray.indexOf(Math.max(...outputArray)); // Get the index
324
- document.getElementById("predicted_result").innerText=letter_list[predictedClass]
325
- console.log(letter_list[predictedClass]);
326
- }, function (err) {
327
- console.log(err);
328
- });
329
 
330
- }
331
 
332
- function drawLandmarks(canvasCtx, landmarks, color) {
333
- var image_height = (video.videoHeight/video.videoWidth)*canvasElement.width
334
- var image_width= canvasElement.width
335
 
336
- canvasCtx.fillStyle = color;
337
- canvasCtx.strokeStyle = 'white';
338
- canvasCtx.lineWidth = 1;
339
- canvasCtx.beginPath();
340
- canvasCtx.arc(landmarks.x * image_width, landmarks.y*image_height, 6, 0, 2 * Math.PI);
341
- canvasCtx.fill();
342
- canvasCtx.stroke();
 
 
343
 
344
- }
 
 
345
 
346
- function drawConnection(startNode, endNode, strokeColor, strokeWidth) {
 
347
 
348
- var image_height = (video.videoHeight/video.videoWidth)*canvasElement.width
349
- var image_width= canvasElement.width
350
-
351
- canvasCtx.strokeStyle = strokeColor;
352
- canvasCtx.lineWidth = strokeWidth;
353
- canvasCtx.beginPath();
354
- canvasCtx.moveTo(startNode.x * image_width, startNode.y*image_height);
355
- canvasCtx.lineTo(endNode.x * image_width, endNode.y*image_height);
356
- canvasCtx.stroke();
357
- }
358
-
359
-
360
- </script>
361
-
362
-
363
-
364
-
365
-
366
- <script src="https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.0/wasm/vision_wasm_internal.js" crossorigin="anonymous"></script>
 
 
 
 
 
 
367
  </body>
 
368
  </html>
 
1
  <!DOCTYPE html>
2
+ <html lang="en">
 
3
 
4
+ <head></head>
5
+ <meta charset="UTF-8">
6
 
 
 
7
 
8
+ <title>Sign Language Interpreter</title>
9
+ <style>
10
+ * {
11
+ box-sizing: border-box;
12
+ }
13
 
14
+ body {
15
+ font-family: roboto;
16
+ color: #3d3d3d;
17
+ --mdc-theme-primary: #007f8b;
18
+ --mdc-theme-on-primary: #f1f3f4;
19
+ margin-left: 0px;
20
+ }
21
 
22
+ .container {
23
+ position: relative;
24
+ }
25
 
26
+ canvas {
27
+ background-color: lightgray;
28
+ /* Just for visibility */
29
+ }
30
  </style>
31
 
32
+ <script>
33
+ window.console = window.console || function (t) { };
34
  </script>
35
 
 
 
 
36
 
 
 
 
 
 
 
37
 
38
+ </head>
39
 
40
+ <body translate="no">
41
+ <script src="https://cdn.jsdelivr.net/npm/@mediapipe/drawing_utils/drawing_utils.js"
42
+ crossorigin="anonymous"></script>
43
+ <script src="https://cdn.jsdelivr.net/npm/@mediapipe/hands/hands.js" crossorigin="anonymous"></script>
44
+ <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-core"></script>
45
+ <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-cpu"></script>
46
+ <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-tflite/dist/tf-tflite.min.js"></script>
47
+
48
+
49
+ <div class="container">
50
+ <video id="webcam" style="display:none" autoplay="" playsinline=""></video>
51
+ <canvas class="output_canvas" id="output_canvas" style="display:block; position:relative;" width="100%"
52
+ height="300%"></canvas>
53
+ </div>
54
+ <center>
55
+ <img id="output_image" style="display:none"></img>
56
+ <button id="webcamButton">
57
+ <span>ENABLE WEBCAM</span>
58
+ </button>
59
+ <div style="position:relative" id="predicted_result"></div>
60
+ <div style="position:relative" id="text"></div>
61
  <center>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
 
63
 
64
+ <script type="module">
65
+
66
+ import { HandLandmarker, FilesetResolver } from "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.0";
67
+ let handLandmarker = undefined;
68
+ let runningMode = "IMAGE";
69
+ let enableWebcamButton;
70
+ let webcamRunning = false;
71
+ var time_since_letter = 0
72
+ var last_letter_time = 0
73
+ var word_list = []
74
+ // Before we can use HandLandmarker class we must wait for it to finish
75
+ // loading. Machine Learning models can be large and take a moment to
76
+ // get everything needed to run.
77
+ const createHandLandmarker = async () => {
78
+ const vision = await FilesetResolver.forVisionTasks("https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.0/wasm");
79
+ handLandmarker = await HandLandmarker.createFromOptions(vision, {
80
+ baseOptions: {
81
+ modelAssetPath: `https://storage.googleapis.com/mediapipe-models/hand_landmarker/hand_landmarker/float16/1/hand_landmarker.task`,
82
+ delegate: "GPU"
83
+ },
84
+ runningMode: runningMode,
85
+ numHands: 1
86
+ });
87
+ };
88
+ createHandLandmarker();
89
+
90
+ const MODEL_PATH = "/exported"
91
+ var objectDetector = tflite.loadTFLiteModel(MODEL_PATH);
92
+
93
+ /********************************************************************
94
+ // Demo 2: Continuously grab image from webcam stream and detect it.
95
+ ********************************************************************/
96
+ var global_res = 0;
97
+ const video = document.getElementById("webcam");
98
+ const canvasElement = document.getElementById("output_canvas");
99
+ const canvasCtx = canvasElement.getContext("2d");
100
+ var x_array = []
101
+ var y_array = []
102
+ // Check if webcam access is supported.
103
+ const hasGetUserMedia = () => { var _a; return !!((_a = navigator.mediaDevices) === null || _a === void 0 ? void 0 : _a.getUserMedia); };
104
+ // If webcam supported, add event listener to button for when user
105
+ // wants to activate it.
106
+ if (hasGetUserMedia()) {
107
+ enableWebcamButton = document.getElementById("webcamButton");
108
+ enableWebcamButton.addEventListener("click", enableCam);
109
+ }
110
+ else {
111
+ console.warn("getUserMedia() is not supported by your browser");
112
+ }
113
+ // Enable the live webcam view and start detection.
114
+ function enableCam(event) {
115
+ if (!handLandmarker) {
116
+ console.log("Wait! objectDetector not loaded yet.");
117
+ return;
118
+ }
119
+ if (webcamRunning === true) {
120
+ webcamRunning = false;
121
+ enableWebcamButton.innerText = "ENABLE PREDICTIONS";
122
+ }
123
+ else {
124
+ webcamRunning = true;
125
+ enableWebcamButton.style = "display:none"
126
+ }
127
+ // getUsermedia parameters.
128
+ const constraints = {
129
+ video: true
130
+ };
131
+ // Activate the webcam stream.
132
+ navigator.mediaDevices.getUserMedia(constraints).then((stream) => {
133
+ video.srcObject = stream;
134
+ video.addEventListener("loadeddata", predictWebcam);
135
+ });
136
+ }
137
+ let lastVideoTime = -1;
138
+ let results = undefined;
139
+ console.log(video);
140
+ async function predictWebcam() {
141
+ canvasElement.width = window.innerWidth;
142
+ // Now let's start detecting the stream.
143
+ if (runningMode === "IMAGE") {
144
+ runningMode = "VIDEO";
145
+ await handLandmarker.setOptions({ runningMode: "VIDEO" });
146
+ }
147
+ let startTimeMs = performance.now();
148
+ if (lastVideoTime !== video.currentTime) {
149
+ lastVideoTime = video.currentTime;
150
+ results = handLandmarker.detectForVideo(video, startTimeMs);
151
+ }
152
+ canvasCtx.save();
153
+ canvasCtx.clearRect(0, 0, canvasElement.width, canvasElement.height);
154
+ canvasCtx.drawImage(video, 0, 0, canvasElement.width, (video.videoHeight / video.videoWidth) * canvasElement.width)
155
+
156
+ if (results.landmarks && results.handednesses[0]) {
157
+ if (results.handednesses[0][0].categoryName == "Left") {
158
+ annotateImage()
159
+ console.log("LEFT")
160
+ //detectSign()
161
+ } else {
162
+ console.log("RIGHT")
163
+ var current_result = " "
164
+ var previous_result = document.getElementById("predicted_result").innerText
165
+ document.getElementById("predicted_result").innerText = current_result
166
+ var current_time = Math.round(Date.now())
167
+
168
+ if (previous_result == current_result) {
169
+ if (current_time - last_letter_time > 1000) {
170
+ last_letter_time = current_time
171
+ word_list.push(current_result)
172
+ console.log(word_list)
173
+ document.getElementById("text").innerText=word_list.join('')
174
+ }
175
+ }
176
+ else {
177
+ last_letter_time = current_time
178
+ }
179
+ }
180
+ }
181
+ else {
182
+ if (30 > calculateCanvasBrightness(canvasElement)){
183
+
184
+ var current_result = "<"
185
+ var previous_result = document.getElementById("predicted_result").innerText
186
+ document.getElementById("predicted_result").innerText = current_result
187
+ var current_time = Math.round(Date.now())
188
+ console.log(current_time-last_letter_time)
189
+ if (previous_result == current_result) {
190
+ if (current_time - last_letter_time > 1000) {
191
+ last_letter_time = current_time
192
+ word_list.pop()
193
+ console.log(word_list)
194
+ document.getElementById("text").innerText=word_list.join('')
195
+ }
196
+ }
197
+ else {
198
+ last_letter_time = current_time
199
+ }
200
+ }else{last_letter_time = Math.round(Date.now())}
201
+ }
202
+
203
+ canvasCtx.restore();
204
+ // Call this function again to keep predicting when the browser is ready.
205
+ if (webcamRunning === true) {
206
+ window.requestAnimationFrame(predictWebcam);
207
+ }
208
+ }
209
+ function annotateImage() {
210
+
211
+ //console.log(results.landmarks)
212
+ if (results.landmarks[0]) {
213
+ x_array = []
214
+ y_array = []
215
+ results.landmarks[0].forEach(iterate)
216
+ //console.log(x_array)
217
+ var image_height = (video.videoHeight / video.videoWidth) * canvasElement.width
218
+ var image_width = canvasElement.width
219
+ var min_x = Math.min(...x_array) * image_width
220
+ var min_y = Math.min(...y_array) * image_height
221
+ var max_x = Math.max(...x_array) * image_width
222
+ var max_y = Math.max(...y_array) * image_height
223
+
224
+ var sect_height = max_y - (min_y)
225
+ var sect_width = max_x - (min_x)
226
+ var center_x = (min_x + max_x) / 2
227
+ var center_y = (min_y + max_y) / 2
228
+
229
+ var sect_diameter = 50
230
+ if (sect_height > sect_width) {
231
+ sect_diameter = sect_height
232
+ //console.log("sect_height", sect_diameter)
233
+ }
234
+ if (sect_height < sect_width) {
235
+ sect_diameter = sect_width
236
+ // console.log("sect_width", sect_diameter)
237
+ }
238
+
239
+ sect_diameter = sect_diameter + 50
240
+ var sect_radius = sect_diameter / 2
241
+ var crop_top = center_y - sect_radius
242
+ var crop_bottom = center_y + sect_radius
243
+ var crop_left = center_x - sect_radius
244
+ var crop_right = center_x + sect_radius
245
+ if (crop_top < 0) {
246
+ crop_top = 0
247
+ }
248
+ if (crop_left < 0) {
249
+ crop_left = 0
250
+ }
251
+ if (crop_right > image_width) {
252
+ crop_right = image_width
253
+ }
254
+ if (crop_bottom > image_height) {
255
+ crop_bottom = image_height
256
+ }
257
+
258
+ canvasCtx.beginPath();
259
+ canvasCtx.rect(crop_left, crop_top, crop_right - crop_left, crop_bottom - crop_top);
260
+ canvasCtx.stroke();
261
+
262
+
263
+ }
264
+ /* for (const landmarks of results.multiHandLandmarks) {
265
+ drawConnectors(canvasCtx, landmarks, HAND_CONNECTIONS, {
266
+ color: "#00FF00",
267
+ lineWidth: 5
268
+ });
269
+ drawLandmarks(canvasCtx, landmarks, { color: "#FF0000", lineWidth: 2 });
270
+ }*/
271
+ // console.log(results)
272
+ const landmarks = results.landmarks;
273
+ if (landmarks[0]) {
274
+ var hand = landmarks[0]
275
+
276
+ // Thumb connections
277
+ drawConnection(hand[4], hand[3], '#ffe5b4', 5); // 4-3
278
+ drawConnection(hand[3], hand[2], '#ffe5b4', 5); // 3-2
279
+ drawConnection(hand[2], hand[1], '#ffe5b4', 5); // 2-1
280
+
281
+ // Index connections
282
+ drawConnection(hand[8], hand[7], '#804080', 5); // 8-7
283
+ drawConnection(hand[7], hand[6], '#804080', 5); // 7-6
284
+ drawConnection(hand[6], hand[5], '#804080', 5); // 6-5
285
+
286
+ // Middle connections
287
+ drawConnection(hand[12], hand[11], '#ffcc00', 5); // 12-11
288
+ drawConnection(hand[11], hand[10], '#ffcc00', 5); // 11-10
289
+ drawConnection(hand[10], hand[9], '#ffcc00', 5); // 10-9
290
+
291
+ // Ring connections
292
+ drawConnection(hand[16], hand[15], '#30ff30', 5); // 16-15
293
+ drawConnection(hand[15], hand[14], '#30ff30', 5); // 15-14
294
+ drawConnection(hand[14], hand[13], '#30ff30', 5); // 14-13
295
+
296
+ // Pinky connections
297
+ drawConnection(hand[20], hand[19], '#1565c0', 5); // 20-19
298
+ drawConnection(hand[19], hand[18], '#1565c0', 5); // 19-18
299
+ drawConnection(hand[18], hand[17], '#1565c0', 5); // 18-17
300
+
301
+ drawConnection(hand[0], hand[1], '#808080', 5); // 0-1
302
+ drawConnection(hand[0], hand[5], '#808080', 5); // 0-5
303
+ drawConnection(hand[0], hand[17], '#808080', 5); // 0-17
304
+ drawConnection(hand[5], hand[9], '#808080', 5); // 5-9
305
+ drawConnection(hand[9], hand[13], '#808080', 5); // 9-13
306
+ drawConnection(hand[13], hand[17], '#808080', 5); // 13-17
307
+
308
+ // Thumb
309
+ drawLandmarks(canvasCtx, hand[2], '#ffe5b4'); // Thumb tip (2)
310
+ drawLandmarks(canvasCtx, hand[3], '#ffe5b4'); // Thumb base (3)
311
+ drawLandmarks(canvasCtx, hand[4], '#ffe5b4'); // Thumb base (4)
312
+
313
+ // Index
314
+ drawLandmarks(canvasCtx, hand[6], '#804080'); // Index tip (6)
315
+ drawLandmarks(canvasCtx, hand[7], '#804080'); // Index base (7)
316
+ drawLandmarks(canvasCtx, hand[8], '#804080'); // Index base (8)
317
+
318
+ // Middle
319
+ drawLandmarks(canvasCtx, hand[10], '#ffcc00'); // Middle tip (10)
320
+ drawLandmarks(canvasCtx, hand[11], '#ffcc00'); // Middle base (11)
321
+ drawLandmarks(canvasCtx, hand[12], '#ffcc00'); // Middle base (12)
322
+
323
+ // Ring
324
+ drawLandmarks(canvasCtx, hand[14], '#30ff30'); // Ring tip (14)
325
+ drawLandmarks(canvasCtx, hand[15], '#30ff30'); // Ring base (15)
326
+ drawLandmarks(canvasCtx, hand[16], '#30ff30'); // Ring base (16)
327
+
328
+ // Pinky
329
+ drawLandmarks(canvasCtx, hand[18], '#1565c0'); // Pinky tip (18)
330
+ drawLandmarks(canvasCtx, hand[19], '#1565c0'); // Pinky base (19)
331
+ drawLandmarks(canvasCtx, hand[20], '#1565c0'); // Pinky base (20)
332
+
333
+ drawLandmarks(canvasCtx, hand[0], '#ff3030'); // Wrist (0)
334
+
335
+ drawLandmarks(canvasCtx, hand[1], '#ff3030'); // Palm base (1)
336
+
337
+ drawLandmarks(canvasCtx, hand[5], '#ff3030'); // Index palm (5)
338
+
339
+ drawLandmarks(canvasCtx, hand[9], '#ff3030'); // Middle palm (9)
340
+
341
+ drawLandmarks(canvasCtx, hand[13], '#ff3030'); // Ring palm (13)
342
+
343
+ drawLandmarks(canvasCtx, hand[17], '#ff3030'); // Pinky palm (17)
344
+ cropCanvas(canvasElement, crop_left, crop_top, crop_right - crop_left, crop_bottom - crop_top)
345
+ }
346
+ // Add more drawing calls for each landmark collection as needed
347
+
348
+
349
+
350
+
351
+ //# sourceURL=pen.js
352
+ }
353
+
354
+
355
+ function iterate(x, y) {
356
+ x_array.push(x.x)
357
+ y_array.push(x.y)
358
+ }
359
+
360
+ const cropCanvas = (sourceCanvas, left, top, width, height) => {
361
+ let destCanvas = document.createElement('canvas');
362
+ destCanvas.width = 224;
363
+ var cropAspectRatio = width / height;
364
+
365
+ destCanvas.height = 224 / cropAspectRatio
366
+ destCanvas.getContext("2d").drawImage(
367
+ sourceCanvas,
368
+ left, top, width, height, // source rect with content to crop
369
+ 0, 0, 224, destCanvas.height); // newCanvas, same size as source
370
+ var predictionInput = tf.browser.fromPixels(destCanvas.getContext("2d").getImageData(0, 0, 224, 224))
371
+
372
+ predict(tf.expandDims(predictionInput, 0));
373
+ }
374
+ async function predict(inputTensor) {
375
+
376
+ //console.log("in predict")
377
+ var letter_list = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "#"]
378
+ objectDetector.then(function (res) {
379
+ var prediction = res.predict(inputTensor);
380
+ var outputArray = prediction.dataSync(); // Get the output as an array
381
+ var predictedClass = outputArray.indexOf(Math.max(...outputArray)); // Get the index
382
+ var current_result = letter_list[predictedClass]
383
+ var previous_result = document.getElementById("predicted_result").innerText
384
+ document.getElementById("predicted_result").innerText = current_result
385
+ var current_time = Math.round(Date.now())
386
+
387
+ if (previous_result == current_result) {
388
+ if (current_time - last_letter_time > 1000) {
389
+ last_letter_time = current_time
390
+ word_list.push(current_result)
391
+ console.log(word_list)
392
+ document.getElementById("text").innerText=word_list.join('')
393
+ }
394
+ }
395
+ else {
396
+ last_letter_time = current_time
397
+ }
398
+ console.log(letter_list[predictedClass]);
399
+ }, function (err) {
400
+ console.log(err);
401
+ });
402
+
403
+ }
404
 
405
+ function drawLandmarks(canvasCtx, landmarks, color) {
406
+ var image_height = (video.videoHeight / video.videoWidth) * canvasElement.width
407
+ var image_width = canvasElement.width
 
408
 
409
+ canvasCtx.fillStyle = color;
410
+ canvasCtx.strokeStyle = 'white';
411
+ canvasCtx.lineWidth = 1;
412
+ canvasCtx.beginPath();
413
+ canvasCtx.arc(landmarks.x * image_width, landmarks.y * image_height, 6, 0, 2 * Math.PI);
414
+ canvasCtx.fill();
415
+ canvasCtx.stroke();
416
 
417
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
418
 
419
+ function drawConnection(startNode, endNode, strokeColor, strokeWidth) {
420
 
421
+ var image_height = (video.videoHeight / video.videoWidth) * canvasElement.width
422
+ var image_width = canvasElement.width
 
423
 
424
+ canvasCtx.strokeStyle = strokeColor;
425
+ canvasCtx.lineWidth = strokeWidth;
426
+ canvasCtx.beginPath();
427
+ canvasCtx.moveTo(startNode.x * image_width, startNode.y * image_height);
428
+ canvasCtx.lineTo(endNode.x * image_width, endNode.y * image_height);
429
+ canvasCtx.stroke();
430
+ }
431
+ function calculateCanvasBrightness(canvas) {
432
+ const context = canvas.getContext('2d');
433
 
434
+ // Get the image data from the canvas
435
+ const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
436
+ const data = imageData.data;
437
 
438
+ let totalBrightness = 0;
439
+ let pixelCount = 0;
440
 
441
+ // Loop through each pixel
442
+ for (let i = 0; i < data.length; i += 4) {
443
+ const r = data[i]; // Red
444
+ const g = data[i + 1]; // Green
445
+ const b = data[i + 2]; // Blue
446
+
447
+ // Calculate brightness for this pixel
448
+ const brightness = 0.299 * r + 0.587 * g + 0.114 * b;
449
+ totalBrightness += brightness;
450
+ pixelCount++;
451
+ }
452
+
453
+ // Calculate average brightness
454
+ const averageBrightness = totalBrightness / pixelCount;
455
+
456
+ return averageBrightness;
457
+ }
458
+ </script>
459
+
460
+
461
+
462
+
463
+
464
+ <script src="https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.0/wasm/vision_wasm_internal.js"
465
+ crossorigin="anonymous"></script>
466
  </body>
467
+
468
  </html>