camera exception handling

pull/50/head
Vladimir Mandic 2020-11-20 07:52:50 -05:00
parent 12ab61bb0a
commit e537a7dce7
21 changed files with 109 additions and 86 deletions

View File

@ -134,10 +134,10 @@ async function drawResults(input) {
const avgDetect = Math.trunc(10 * ui.detectFPS.reduce((a, b) => a + b, 0) / ui.detectFPS.length) / 10;
const avgDraw = Math.trunc(10 * ui.drawFPS.reduce((a, b) => a + b, 0) / ui.drawFPS.length) / 10;
const warning = (ui.detectFPS.length > 5) && (avgDetect < 5) ? '<font color="lightcoral">warning: your performance is low: try switching to higher performance backend, lowering resolution or disabling some models</font>' : '';
document.getElementById('log').innerHTML = `
video: ${ui.camera.name} | facing: ${ui.camera.facing} | screen: ${window.innerWidth} x ${window.innerHeight} camera: ${ui.camera.width} x ${ui.camera.height} ${processing}<br>
backend: ${human.tf.getBackend()} | ${memory}<br>
performance: ${str(result.performance)} FPS process:${avgDetect} refresh:${avgDraw}<br>
document.getElementById('log').innerText = `
video: ${ui.camera.name} | facing: ${ui.camera.facing} | screen: ${window.innerWidth} x ${window.innerHeight} camera: ${ui.camera.width} x ${ui.camera.height} ${processing}
backend: ${human.tf.getBackend()} | ${memory}
performance: ${str(result.performance)}ms FPS process:${avgDetect} refresh:${avgDraw}
${warning}
`;
@ -169,7 +169,8 @@ async function setupCamera() {
output.innerText += `\n${msg}`;
log(msg);
status(msg);
return null;
ui.busy = false;
return msg;
}
let stream;
const constraints = {
@ -181,15 +182,20 @@ async function setupCamera() {
try {
stream = await navigator.mediaDevices.getUserMedia(constraints);
} catch (err) {
if (err.name === 'PermissionDeniedError') msg = 'camera permission denied';
if (err.name === 'PermissionDeniedError' || err.name === 'NotAllowedError') msg = 'camera permission denied';
else if (err.name === 'SourceUnavailableError') msg = 'camera not available';
else msg = 'camera error';
else msg = `camera error: ${err.message || err}`;
output.innerText += `\n${msg}`;
status(msg);
log(err);
log('camera error:', err);
ui.busy = false;
return msg;
}
if (stream) video.srcObject = stream;
else return null;
else {
ui.busy = false;
return 'camera stream empty';
}
const track = stream.getVideoTracks()[0];
const settings = track.getSettings();
// log('camera constraints:', constraints, 'window:', { width: window.innerWidth, height: window.innerHeight }, 'settings:', settings, 'track:', track);
@ -215,7 +221,7 @@ async function setupCamera() {
// do once more because onresize events can be delayed or skipped
// if (video.width > window.innerWidth) await setupCamera();
status('');
resolve(video);
resolve();
};
});
}
@ -299,8 +305,10 @@ function runHumanDetect(input, canvas, timestamp) {
bench.nextFrame(timestamp);
}
if (document.getElementById('gl-bench')) document.getElementById('gl-bench').style.display = ui.bench ? 'block' : 'none';
if (result.error) log(result.error);
else {
if (result.error) {
log(result.error);
document.getElementById('log').innerText += `\nHuman error: ${result.error}`;
} else {
lastDetectedResult = result;
if (!ui.drawThread) drawResults(input);
ui.framesDetect++;
@ -352,15 +360,19 @@ async function detectVideo() {
status('paused');
video.pause();
} else {
await setupCamera();
document.getElementById('play').style.display = 'none';
for (const m of Object.values(menu)) m.hide();
status('');
document.getElementById('btnStart').className = 'button button-stop';
document.getElementById('btnStart').innerHTML = 'pause<br>video';
video.play();
const cameraError = await setupCamera();
if (!cameraError) {
document.getElementById('play').style.display = 'none';
for (const m of Object.values(menu)) m.hide();
status('');
document.getElementById('btnStart').className = 'button button-stop';
document.getElementById('btnStart').innerHTML = 'pause<br>video';
await video.play();
if (!ui.detectThread) runHumanDetect(video, canvas);
} else {
status(cameraError);
}
}
if (!ui.detectThread) runHumanDetect(video, canvas);
}
// just initialize everything and call main function

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,7 @@
{
"inputs": {
"demo/browser.js": {
"bytes": 24811,
"bytes": 25185,
"imports": [
{
"path": "dist/human.esm.js"
@ -30,7 +30,7 @@
"imports": []
},
"dist/human.esm.js": {
"bytes": 1783426,
"bytes": 1783650,
"imports": []
}
},
@ -38,14 +38,14 @@
"dist/demo-browser-index.js.map": {
"imports": [],
"inputs": {},
"bytes": 2675999
"bytes": 2677420
},
"dist/demo-browser-index.js": {
"imports": [],
"exports": [],
"inputs": {
"dist/human.esm.js": {
"bytesInOutput": 1776302
"bytesInOutput": 1776526
},
"demo/draw.js": {
"bytesInOutput": 7668
@ -57,10 +57,10 @@
"bytesInOutput": 7436
},
"demo/browser.js": {
"bytesInOutput": 19152
"bytesInOutput": 19406
}
},
"bytes": 1829661
"bytes": 1830139
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -290,7 +290,7 @@
"imports": []
},
"src/human.js": {
"bytes": 15657,
"bytes": 15842,
"imports": [
{
"path": "dist/tfjs.esm.js"
@ -334,7 +334,7 @@
]
},
"src/image.js": {
"bytes": 5701,
"bytes": 5862,
"imports": [
{
"path": "dist/tfjs.esm.js"
@ -357,7 +357,7 @@
"dist/human.esm-nobundle.js.map": {
"imports": [],
"inputs": {},
"bytes": 2581163
"bytes": 2582027
},
"dist/human.esm-nobundle.js": {
"imports": [],
@ -450,13 +450,13 @@
"bytesInOutput": 13638
},
"src/image.js": {
"bytesInOutput": 3993
"bytesInOutput": 4079
},
"dist/tfjs.esm.js": {
"bytesInOutput": 1529550
},
"src/human.js": {
"bytesInOutput": 10345
"bytesInOutput": 10483
},
"src/hand/box.js": {
"bytesInOutput": 1880
@ -471,7 +471,7 @@
"bytesInOutput": 21
}
},
"bytes": 1783435
"bytes": 1783659
}
}
}

4
dist/human.esm.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

12
dist/human.esm.json vendored
View File

@ -290,7 +290,7 @@
"imports": []
},
"src/human.js": {
"bytes": 15657,
"bytes": 15842,
"imports": [
{
"path": "dist/tfjs.esm.js"
@ -334,7 +334,7 @@
]
},
"src/image.js": {
"bytes": 5701,
"bytes": 5862,
"imports": [
{
"path": "dist/tfjs.esm.js"
@ -357,7 +357,7 @@
"dist/human.esm.js.map": {
"imports": [],
"inputs": {},
"bytes": 2581163
"bytes": 2582027
},
"dist/human.esm.js": {
"imports": [],
@ -450,13 +450,13 @@
"bytesInOutput": 13638
},
"src/image.js": {
"bytesInOutput": 3993
"bytesInOutput": 4079
},
"dist/tfjs.esm.js": {
"bytesInOutput": 1529550
},
"src/human.js": {
"bytesInOutput": 10345
"bytesInOutput": 10483
},
"src/hand/box.js": {
"bytesInOutput": 1880
@ -471,7 +471,7 @@
"bytesInOutput": 21
}
},
"bytes": 1783426
"bytes": 1783650
}
}
}

4
dist/human.js vendored

File diff suppressed because one or more lines are too long

4
dist/human.js.map vendored

File diff suppressed because one or more lines are too long

12
dist/human.json vendored
View File

@ -290,7 +290,7 @@
"imports": []
},
"src/human.js": {
"bytes": 15657,
"bytes": 15842,
"imports": [
{
"path": "dist/tfjs.esm.js"
@ -334,7 +334,7 @@
]
},
"src/image.js": {
"bytes": 5701,
"bytes": 5862,
"imports": [
{
"path": "dist/tfjs.esm.js"
@ -357,7 +357,7 @@
"dist/human.js.map": {
"imports": [],
"inputs": {},
"bytes": 2548927
"bytes": 2549411
},
"dist/human.js": {
"imports": [],
@ -448,10 +448,10 @@
"bytesInOutput": 13638
},
"src/image.js": {
"bytesInOutput": 3958
"bytesInOutput": 4044
},
"src/human.js": {
"bytesInOutput": 10409
"bytesInOutput": 10547
},
"dist/tfjs.esm.js": {
"bytesInOutput": 1529041
@ -469,7 +469,7 @@
"bytesInOutput": 21
}
},
"bytes": 1782737
"bytes": 1782961
}
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -290,7 +290,7 @@
"imports": []
},
"src/human.js": {
"bytes": 15657,
"bytes": 15842,
"imports": [
{
"path": "dist/tfjs.esm.js"
@ -334,7 +334,7 @@
]
},
"src/image.js": {
"bytes": 5701,
"bytes": 5862,
"imports": [
{
"path": "dist/tfjs.esm.js"
@ -357,7 +357,7 @@
"dist/human.node-nobundle.js.map": {
"imports": [],
"inputs": {},
"bytes": 2597270
"bytes": 2598324
},
"dist/human.node-nobundle.js": {
"imports": [],
@ -448,10 +448,10 @@
"bytesInOutput": 13640
},
"src/image.js": {
"bytesInOutput": 3995
"bytesInOutput": 4081
},
"src/human.js": {
"bytesInOutput": 10383
"bytesInOutput": 10521
},
"dist/tfjs.esm.js": {
"bytesInOutput": 1529722
@ -469,7 +469,7 @@
"bytesInOutput": 21
}
},
"bytes": 1783767
"bytes": 1783991
}
}
}

4
dist/human.node.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

12
dist/human.node.json vendored
View File

@ -290,7 +290,7 @@
"imports": []
},
"src/human.js": {
"bytes": 15657,
"bytes": 15842,
"imports": [
{
"path": "dist/tfjs.esm.js"
@ -334,7 +334,7 @@
]
},
"src/image.js": {
"bytes": 5701,
"bytes": 5862,
"imports": [
{
"path": "dist/tfjs.esm.js"
@ -357,7 +357,7 @@
"dist/human.node.js.map": {
"imports": [],
"inputs": {},
"bytes": 2597270
"bytes": 2598324
},
"dist/human.node.js": {
"imports": [],
@ -448,10 +448,10 @@
"bytesInOutput": 13640
},
"src/image.js": {
"bytesInOutput": 3995
"bytesInOutput": 4081
},
"src/human.js": {
"bytesInOutput": 10383
"bytesInOutput": 10521
},
"dist/tfjs.esm.js": {
"bytesInOutput": 1529722
@ -469,7 +469,7 @@
"bytesInOutput": 21
}
},
"bytes": 1783758
"bytes": 1783982
}
}
}

View File

@ -348,6 +348,11 @@ class Human {
timeStamp = now();
const process = image.process(input, this.config);
if (!process || !process.tensor) {
this.log('could not convert input to tensor');
resolve({ error: 'could not convert input to tensor' });
return;
}
this.perf.image = Math.trunc(now() - timeStamp);
this.analyze('Get Image:');

View File

@ -21,6 +21,11 @@ function process(input, config) {
else if (config.filter.height > 0) targetWidth = originalWidth * (config.filter.height / originalHeight);
if (config.filter.height > 0) targetHeight = config.filter.height;
else if (config.filter.width > 0) targetHeight = originalHeight * (config.filter.width / originalWidth);
if (!targetWidth || !targetHeight) {
// eslint-disable-next-line no-console
console.log('Human: invalid input', input);
return null;
}
if (!inCanvas || (inCanvas.width !== targetWidth) || (inCanvas.height !== targetHeight)) {
inCanvas = (typeof OffscreenCanvas !== 'undefined') ? new OffscreenCanvas(targetWidth, targetHeight) : document.createElement('canvas');
if (inCanvas.width !== targetWidth) inCanvas.width = targetWidth;