<body> <div id="main"> <canvas id="myGrowCanvas" style="position:relative; left:0px; top:0px; width:3000px; height:2000px; " ></canvas> <br> <table border=1 style="position:absolute; left:800px; top:0px; "> <tr><td> Version 0.9.19 <br> <div id="description"> <div id="description-title" style="font-size:30px">Demo Edge Impulse WASM</div> Frequency ms <input type=text id="myText01" value=130 onChange="{ myFrequencyMs = this.value clearInterval(myTimer01) myTimer01 = setInterval(myPictureNow, myFrequencyMs); }"><br> (square) width/height: <input type=text value="96" size=5 id="myWidthHeight" READONLY> <br> <div id="myDiv01" style="font-size:30px">...</div> Stop Data Collection: <input type=checkbox id="myCheckbox01"><br> Stop All Sounds <input type=checkbox id="myCheckbox02sounds" ><br> Stop 0 (First) label sound: <input type=checkbox id="myCheckbox03lable0" checked=true><br> <input type=button value="Width -" onclick="{ document.getElementById('myGrowCanvas').style.width = parseInt(document.getElementById('myGrowCanvas').style.width) - 50 }"><input type=button value="Width +" onclick="{ document.getElementById('myGrowCanvas').style.width = parseInt(document.getElementById('myGrowCanvas').style.width) + 50 }"> <input type=button value="Height -" onclick="{ document.getElementById('myGrowCanvas').style.height = parseInt(document.getElementById('myGrowCanvas').style.height) - 50 }"><input type=button value="Height +" onclick="{ document.getElementById('myGrowCanvas').style.height = parseInt(document.getElementById('myGrowCanvas').style.height) + 50 }"> <br> Camera: <select id="mySelect" onChange="setupPage()"><option value="user">Front Camera<option selected="selected" value="environment">Rear Camera</select><br> Default is not mirrored: see canvas: scaleX(-1); transform: scaleX(-1);<br> Default GRAYSCALE, Check to use Color <input type=checkbox id="myCheckboxColor"><br><br> <textarea id="myTextArea01" style="display:none; " rows=10 cols=70>...</textarea> <br> <br> <br> </td></tr></table> <video id="video" playsinline="" style="display:none; -webkit-transform: scaleX(-1); transform: scaleX(-1); width: auto; height: auto;"></video> <canvas id="myOnTopOutput" style="display:none; background-color:white; border:black 3px solid;" ></canvas> <!-- position:absolute; top:0; left:0; --> <canvas id="output" style="display:none; " ></canvas> <canvas id="myColorCanvas" style="display:none; " ></canvas> <br> </div> </body> <script src="edge-impulse-standalone.js"></script> <!-- Link to short internet sounds, load your own sound if uploaded to the same folder with the below code. .wav, .a4u, mp3 sound files should work --> <!-- <audio preload="auto" id="mySound8" src="mySound01.mp3"></audio> --> <audio preload="auto" id="mySound0" src="https://raw.githubusercontent.com/wesbos/JavaScript30/master/01%20-%20JavaScript%20Drum%20Kit/sounds/clap.wav"></audio> <audio preload="auto" id="mySound1" src="https://raw.githubusercontent.com/wesbos/JavaScript30/master/01%20-%20JavaScript%20Drum%20Kit/sounds/boom.wav"></audio> <audio preload="auto" id="mySound2" src="https://raw.githubusercontent.com/wesbos/JavaScript30/master/01%20-%20JavaScript%20Drum%20Kit/sounds/kick.wav"></audio> <audio preload="auto" id="mySound3" src="https://raw.githubusercontent.com/wesbos/JavaScript30/master/01%20-%20JavaScript%20Drum%20Kit/sounds/openhat.wav"></audio> <audio preload="auto" id="mySound4" src="https://raw.githubusercontent.com/wesbos/JavaScript30/master/01%20-%20JavaScript%20Drum%20Kit/sounds/ride.wav"></audio> <audio preload="auto" id="mySound5" src="https://raw.githubusercontent.com/wesbos/JavaScript30/master/01%20-%20JavaScript%20Drum%20Kit/sounds/snare.wav"></audio> <audio preload="auto" id="mySound6" src="https://raw.githubusercontent.com/wesbos/JavaScript30/master/01%20-%20JavaScript%20Drum%20Kit/sounds/tom.wav"></audio> <audio preload="auto" id="mySound7" src="https://raw.githubusercontent.com/wesbos/JavaScript30/master/01%20-%20JavaScript%20Drum%20Kit/sounds/tink.wav"></audio> <audio preload="auto" id="mySound8" src="https://raw.githubusercontent.com/wesbos/JavaScript30/master/01%20-%20JavaScript%20Drum%20Kit/sounds/hihat.wav"></audio> <script> let myTimer01 = 0; let myOutputString = '' let myFrequencyMs = document.getElementById('myText01').value let myWidthHeightSquare = document.getElementById('myWidthHeight').value function RGBAToHex(r,g,b,a) { r = r.toString(16); g = g.toString(16); b = b.toString(16); if (r.length == 1) r = "0" + r; if (g.length == 1) g = "0" + g; if (b.length == 1) b = "0" + b; // return "#" + r + g + b + ", " ; return "0x" + r + g + b + ", " ; } const setupCamera = async function(){ video = document.getElementById('video'); // stop it if running video.pause() video.srcObject = null const stream = await navigator.mediaDevices.getUserMedia({ 'audio': false, 'video': { facingMode: document.getElementById('mySelect').value }, }); video.srcObject = stream; return new Promise((resolve) => { video.onloadedmetadata = () => { resolve(video); }; }); } const renderPrediction = async function(){ document.ctx.clearRect(0, 0, document.ctx.canvas.width, document.ctx.canvas.width); document.ctx.drawImage(video, 0, 0, videoWidth, videoHeight); ctxColor.drawImage(video, 0, 0, videoWidth, videoHeight); let imgData = document.ctx.getImageData(0, 0, document.ctx.canvas.width, document.ctx.canvas.height); let pixels = imgData.data; for (var i = 0; i < pixels.length; i += 4) { let lightness = parseInt((pixels[i] + pixels[i + 1] + pixels[i + 2]) / 3); pixels[i] = lightness; pixels[i + 1] = lightness; pixels[i + 2] = lightness; } document.ctx.scale(-1, 1); // mirror image document.ctx.putImageData(imgData, 0, 0); requestAnimationFrame(renderPrediction); }; const myPictureNow = async function(){ var classifier = new EdgeImpulseClassifier(); await classifier.init(); let props = classifier.getProperties(); myWidthHeightSquare = props.input_width document.getElementById('myWidthHeight').value = props.input_width // console.log(props.input_width) // props.sensor props.frequency props.frame_sample_count props.input_width props.input_height ctxOnTop.clearRect(0, 0, canvasOnTop.width, canvasOnTop.height); let myX = (640-myWidthHeightSquare)/2 let myY = (480-myWidthHeightSquare)/2 let ImageData2; if (document.getElementById('myCheckboxColor').checked ) { ImageData2 = ctxColor.getImageData(myX, myY, myWidthHeightSquare, myWidthHeightSquare); // grab COLOR image x,y,width,height } else { ImageData2 = document.ctx.getImageData(myX, myY, myWidthHeightSquare, myWidthHeightSquare); // grab GRAYSCALE image x,y,width,height } ctxOnTop.putImageData(ImageData2, myX, myY ); //put image near center ctxGrow.putImageData(ImageData2, 0, 0); // try to grow the image // alert(RGBAToHex(ImageData2.data[0], ImageData2.data[1], ImageData2.data[2], ImageData2.data[3]) ) let pixels2 = ImageData2.data myOutputString = '' if (document.getElementById('myCheckbox01').checked ) { //console.log('checked') //console.log(document.getElementById('myCheckbox01').checked) myOutputString = document.getElementById('myTextArea01').value document.getElementById('myTextArea01').style.display = 'inline' } else { document.getElementById('myTextArea01').style.display = 'none' for (var i = 0; i < pixels2.length; i += 4) { myOutputString += RGBAToHex(ImageData2.data[i], ImageData2.data[i+1], ImageData2.data[i+2], ImageData2.data[i+3]) } // console.log('myOutputString') // console.log(myOutputString) // document.getElementById('myTextArea01').value= JSON.stringify(myOutputString, 2, '\n') // myOutputString = myOutputString.substring(1); // remove first " myOutputString = myOutputString.substring(0, myOutputString.length - 2); // remove last ," document.getElementById('myTextArea01').value = myOutputString } results = await classifier.classify( myOutputString.split(', ') ); //, true can set debug true auto shows in console let myTemp = '' myTemp = '<table border=1 style="font-size:30px">' let myBestClassificationNumber = -1 let myBestClassificationValue = 0.25 // lowest best allowable value for (let j = 0; j < results.results.length; j++){ if (results.results[j].value > myBestClassificationValue ){ myBestClassificationNumber = j; // find the biggest array value myBestClassificationValue = results.results[j].value } } //////////////////////////////////////////// Where the magic happens ////////////////////////////////////////////////////////////////////////////// for (let i = 0; i < results.results.length; i++){ if (myBestClassificationNumber == i){ // check if this is the best one if (! document.getElementById('myCheckbox02sounds').checked){ if (! document.getElementById('myCheckbox03lable0').checked){ if (i==0) { document.getElementById('mySound0').currentTime = 0; document.getElementById('mySound0').play() } } if (i==1) { document.getElementById('mySound1').currentTime = 0; document.getElementById('mySound1').play() } if (i==2) { document.getElementById('mySound2').currentTime = 0; document.getElementById('mySound2').play() } if (i==3) { document.getElementById('mySound3').currentTime = 0; document.getElementById('mySound3').play() } if (i==4) { document.getElementById('mySound4').currentTime = 0; document.getElementById('mySound4').play() } if (i==5) { document.getElementById('mySound5').currentTime = 0; document.getElementById('mySound5').play() } if (i==6) { document.getElementById('mySound6').currentTime = 0; document.getElementById('mySound6').play() } if (i==7) { document.getElementById('mySound7').currentTime = 0; document.getElementById('mySound7').play() } if (i==8) { document.getElementById('mySound8').currentTime = 0; document.getElementById('mySound8').play() } } myTemp += '<tr><td>'+ results.results[i].label + '</td><td><font style=\'color:yellow; background-color:blue;\'>' + results.results[i].value.toFixed(3) +'</font></td></tr>' } else { myTemp += '<tr><td>'+ results.results[i].label + '</td><td>' + results.results[i].value.toFixed(3) +'</td></tr>' } } myTemp += '</table>' //console.log(results) document.getElementById('myDiv01').innerHTML = ' results.anomaly: '+ results.anomaly + '<br>' + myTemp } const setupPage = async function(){ await setupCamera(); video.play(); videoWidth = video.videoWidth; videoHeight = video.videoHeight; console.log('videoWidth') console.log(videoWidth) console.log('videoHeight') console.log(videoHeight) video.width = videoWidth; video.height = videoHeight; canvasOnTop = document.getElementById('myOnTopOutput'); canvasOnTop.width = videoWidth; canvasOnTop.height = videoHeight; ctxOnTop = canvasOnTop.getContext('2d'); canvasColor = document.getElementById('myColorCanvas'); canvasColor.width = videoWidth; canvasColor.height = videoHeight; ctxColor = canvasColor.getContext('2d'); canvasGrow = document.getElementById('myGrowCanvas'); canvasGrow.width = videoWidth; canvasGrow.height = videoHeight; ctxGrow = canvasGrow.getContext('2d'); canvas = document.getElementById('output'); canvas.width = videoWidth; canvas.height = videoHeight; document.ctx = canvas.getContext('2d'); // setInterval(function(){ alert("Hello"); }, 3000); myTimer01 = setInterval(myPictureNow, myFrequencyMs); // myTimer01 = setInterval('myPictureNow', 3000); renderPrediction(); }; // main program! setupPage(); </script> <script> // From the old run_impulse.js file // Classifier module let classifierInitialized = false; Module.onRuntimeInitialized = function() { classifierInitialized = true; }; class EdgeImpulseClassifier { _initialized = false; // https://forum.edgeimpulse.com/t/wasm-sound-acceleration-camera-demos/1611/7 getProperties() { return Module.get_properties(); } init() { if (classifierInitialized === true) return Promise.resolve(); return new Promise((resolve) => { Module.onRuntimeInitialized = () => { resolve(); classifierInitialized = true; }; }); } classify(rawData, debug = false) { if (!classifierInitialized) throw new Error('Module is not initialized'); const obj = this._arrayToHeap(rawData); let ret = Module.run_classifier(obj.buffer.byteOffset, rawData.length, debug); Module._free(obj.ptr); if (ret.result !== 0) { throw new Error('Classification failed (err code: ' + ret.result + ')'); } let jsResult = { anomaly: ret.anomaly, results: [] }; // if ret.size is a function, then this is a new module. Use this API call to prevent leaks. // the old API (calling via ret.classification) is still there for backwards compatibility, but leaks some memory if (typeof ret.size === 'function') { for (let cx = 0; cx < ret.size(); cx++) { let c = ret.get(cx); jsResult.results.push({ label: c.label, value: c.value }); c.delete(); } } else { for (let cx = 0; cx < ret.classification.size(); cx++) { let c = ret.classification.get(cx); jsResult.results.push({ label: c.label, value: c.value }); c.delete(); } } ret.delete(); return jsResult; } _arrayToHeap(data) { let typedArray = new Float32Array(data); let numBytes = typedArray.length * typedArray.BYTES_PER_ELEMENT; let ptr = Module._malloc(numBytes); let heapBytes = new Uint8Array(Module.HEAPU8.buffer, ptr, numBytes); heapBytes.set(new Uint8Array(typedArray.buffer)); return { ptr: ptr, buffer: heapBytes }; } } </script>