mirror of https://github.com/vladmandic/human
optimized camera and mobile layout
parent
8d91c9237d
commit
b669277223
|
@ -135,7 +135,7 @@ function drawResults(input, result, canvas) {
|
|||
const avg = Math.trunc(10 * fps.reduce((a, b) => a + b) / fps.length) / 10;
|
||||
document.getElementById('log').innerText = `
|
||||
video: ${camera.name} | facing: ${camera.facing} | resolution: ${camera.width} x ${camera.height} ${processing}
|
||||
backend: ${human.tf.getBackend()} | ${memory} | object size: ${(str(result)).length.toLocaleString()} bytes
|
||||
backend: ${human.tf.getBackend()} | ${memory}
|
||||
performance: ${str(result.performance)} FPS:${avg}
|
||||
`;
|
||||
}
|
||||
|
@ -159,26 +159,27 @@ async function setupCamera() {
|
|||
return null;
|
||||
}
|
||||
let stream;
|
||||
const constraints = {
|
||||
audio: false,
|
||||
video: { facingMode: (ui.facing ? 'user' : 'environment'), resizeMode: 'none' },
|
||||
};
|
||||
try {
|
||||
stream = await navigator.mediaDevices.getUserMedia({
|
||||
audio: false,
|
||||
video: {
|
||||
facingMode: (ui.facing ? 'user' : 'environment'),
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
resizeMode: 'none',
|
||||
contrast: 75,
|
||||
},
|
||||
});
|
||||
if (window.innerWidth > window.innerHeight) constraints.video.width = { ideal: window.innerWidth };
|
||||
else constraints.video.height = { ideal: window.innerHeight };
|
||||
stream = await navigator.mediaDevices.getUserMedia(constraints);
|
||||
} catch (err) {
|
||||
output.innerText += '\nCamera permission denied';
|
||||
status('camera permission denied');
|
||||
if (err.name === 'PermissionDeniedError') msg = 'camera permission denied';
|
||||
else if (err.name === 'SourceUnavailableError') msg = 'camera not available';
|
||||
else msg = 'camera error';
|
||||
output.innerText += `\n${msg}`;
|
||||
status(msg);
|
||||
log(err);
|
||||
}
|
||||
if (stream) video.srcObject = stream;
|
||||
else return null;
|
||||
const track = stream.getVideoTracks()[0];
|
||||
const settings = track.getSettings();
|
||||
log('camera constraints:', constraints, 'window:', { width: window.innerWidth, height: window.innerHeight });
|
||||
log('camera settings:', settings);
|
||||
log('camera track:', track);
|
||||
camera = { name: track.label, width: settings.width, height: settings.height, facing: settings.facingMode === 'user' ? 'front' : 'back' };
|
||||
|
@ -402,11 +403,11 @@ async function main() {
|
|||
setupMenu();
|
||||
document.getElementById('log').innerText = `Human: version ${human.version} TensorFlow/JS: version ${human.tf.version_core}`;
|
||||
// this is not required, just pre-warms the library
|
||||
if (!ui.modelsPreload) {
|
||||
if (ui.modelsPreload) {
|
||||
status('loading');
|
||||
await human.load();
|
||||
}
|
||||
if (!ui.modelsWarmup) {
|
||||
if (ui.modelsWarmup) {
|
||||
status('initializing');
|
||||
const warmup = new ImageData(50, 50);
|
||||
await human.detect(warmup);
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<meta content="text/html">
|
||||
<meta charset="UTF-8">
|
||||
<meta name="description" content="3D Face Detection, Body Pose, Hand & Finger Tracking, Iris Tracking, Age & Gender Prediction & Emotion Prediction; Author: Vladimir Mandic <mandic00@live.com>">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=0.5, minimum-scale=0.1, maximum-scale=4.0, shrink-to-fit=yes, user-scalable=yes">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=0.6, minimum-scale=0.1, maximum-scale=4.0, shrink-to-fit=yes, user-scalable=yes">
|
||||
<meta name="theme-color" content="#000000"/>
|
||||
<meta name="application-name" content="Human">
|
||||
<meta name="msapplication-tooltip" content="Human: AI-powered 3D Human Detection">
|
||||
|
@ -22,20 +22,21 @@
|
|||
<!-- alternatively load demo sources directly -->
|
||||
<!-- <script src="browser.js" type="module"></script> -->
|
||||
<style>
|
||||
body { margin: 0; background: black; color: white; font-family: 'Segoe UI'; font-size: 16px; font-variant: small-caps; overflow-x: hidden; scrollbar-width: none; }
|
||||
html { font-family: 'Segoe UI'; font-size: 16px; font-variant: small-caps; }
|
||||
body { margin: 0; background: black; color: white; overflow-x: hidden; scrollbar-width: none; }
|
||||
body::-webkit-scrollbar { display: none; }
|
||||
.play { position: absolute; width: 300px; height: 300px; z-index: 25; top: 30%; left: 50%; margin-left: -150px; display: none; }
|
||||
.play { position: absolute; width: 300px; height: 300px; z-index: 9; top: 30%; left: 50%; margin-left: -150px; display: none; }
|
||||
.play-background { fill:darkslategray; cursor:pointer; opacity: 0.6; }
|
||||
.play-foreground { fill:white; cursor:pointer; opacity: 0.8; }
|
||||
.play-foreground:hover { opacity: 1; }
|
||||
.status { position: absolute; width: 100vw; top: 100px; text-align: center; font-size: 4rem; font-weight: 100; text-shadow: 2px 2px darkslategrey; }
|
||||
.status { position: absolute; width: 100vw; bottom: 15%; text-align: center; font-size: 4rem; font-weight: 100; text-shadow: 2px 2px darkslategrey; }
|
||||
.thumbnail { margin: 8px; box-shadow: 0 0 4px 4px dimgrey; }
|
||||
.thumbnail:hover { box-shadow: 0 0 8px 8px dimgrey; filter: grayscale(1); }
|
||||
.log { position: fixed; bottom: 0; margin: 0.4rem; }
|
||||
.log { position: fixed; bottom: 0; margin: 0.4rem; font-size: 0.9rem; }
|
||||
.samples-container { display: flex; flex-wrap: wrap; }
|
||||
.video { display: none; }
|
||||
.canvas { margin: 0 auto; width: 100%; }
|
||||
.loader { width: 300px; height: 300px; border: 3px solid transparent; border-radius: 50%; border-top: 4px solid #f15e41; animation: spin 4s linear infinite; position: absolute; top: 30%; left: 50%; margin-left: -150px; }
|
||||
.canvas { margin: 0 auto; height: 100%; }
|
||||
.loader { width: 300px; height: 300px; border: 3px solid transparent; border-radius: 50%; border-top: 4px solid #f15e41; animation: spin 4s linear infinite; position: absolute; top: 30%; left: 50%; margin-left: -150px; z-index: 15; }
|
||||
.loader::before, .loader::after { content: ""; position: absolute; top: 6px; bottom: 6px; left: 6px; right: 6px; border-radius: 50%; border: 4px solid transparent; }
|
||||
.loader::before { border-top-color: #bad375; animation: 3s spin linear infinite; }
|
||||
.loader::after { border-top-color: #26a9e0; animation: spin 1.5s linear infinite; }
|
||||
|
|
|
@ -18,7 +18,7 @@ let theme = {
|
|||
function createCSS() {
|
||||
if (CSScreated) return;
|
||||
const css = `
|
||||
.menu { position: fixed; top: 0rem; right: 0; width: fit-content; padding: 0 0.8rem 0 0.8rem; line-height: 1.8rem; z-index: 10; max-height: calc(100% - 4rem);
|
||||
.menu { position: absolute; top: 0rem; right: 0; width: fit-content; padding: 0 0.8rem 0 0.8rem; line-height: 1.8rem; z-index: 10; max-height: calc(100% - 4rem);
|
||||
box-shadow: 0 0 8px dimgrey; background: ${theme.background}; border-radius: 1rem; border-color: black; border-style: solid; border-width: thin; }
|
||||
|
||||
.menu:hover { box-shadow: 0 0 8px ${theme.hover}; }
|
||||
|
|
|
@ -33646,7 +33646,7 @@ function createCSS() {
|
|||
if (CSScreated)
|
||||
return;
|
||||
const css = `
|
||||
.menu { position: fixed; top: 0rem; right: 0; width: fit-content; padding: 0 0.8rem 0 0.8rem; line-height: 1.8rem; z-index: 10; max-height: calc(100% - 4rem);
|
||||
.menu { position: absolute; top: 0rem; right: 0; width: fit-content; padding: 0 0.8rem 0 0.8rem; line-height: 1.8rem; z-index: 10; max-height: calc(100% - 4rem);
|
||||
box-shadow: 0 0 8px dimgrey; background: ${theme.background}; border-radius: 1rem; border-color: black; border-style: solid; border-width: thin; }
|
||||
|
||||
.menu:hover { box-shadow: 0 0 8px ${theme.hover}; }
|
||||
|
@ -34040,7 +34040,7 @@ function drawResults(input, result, canvas) {
|
|||
const avg = Math.trunc(10 * fps.reduce((a, b) => a + b) / fps.length) / 10;
|
||||
document.getElementById("log").innerText = `
|
||||
video: ${camera.name} | facing: ${camera.facing} | resolution: ${camera.width} x ${camera.height} ${processing}
|
||||
backend: ${human.tf.getBackend()} | ${memory} | object size: ${str(result).length.toLocaleString()} bytes
|
||||
backend: ${human.tf.getBackend()} | ${memory}
|
||||
performance: ${str(result.performance)} FPS:${avg}
|
||||
`;
|
||||
}
|
||||
|
@ -34063,20 +34063,26 @@ ${msg}`;
|
|||
return null;
|
||||
}
|
||||
let stream;
|
||||
const constraints = {
|
||||
audio: false,
|
||||
video: {facingMode: ui.facing ? "user" : "environment", resizeMode: "none"}
|
||||
};
|
||||
try {
|
||||
stream = await navigator.mediaDevices.getUserMedia({
|
||||
audio: false,
|
||||
video: {
|
||||
facingMode: ui.facing ? "user" : "environment",
|
||||
width: window.innerWidth,
|
||||
height: window.innerHeight,
|
||||
resizeMode: "none",
|
||||
contrast: 75
|
||||
}
|
||||
});
|
||||
if (window.innerWidth > window.innerHeight)
|
||||
constraints.video.width = {ideal: window.innerWidth};
|
||||
else
|
||||
constraints.video.height = {ideal: window.innerHeight};
|
||||
stream = await navigator.mediaDevices.getUserMedia(constraints);
|
||||
} catch (err) {
|
||||
output.innerText += "\nCamera permission denied";
|
||||
status("camera permission denied");
|
||||
if (err.name === "PermissionDeniedError")
|
||||
msg = "camera permission denied";
|
||||
else if (err.name === "SourceUnavailableError")
|
||||
msg = "camera not available";
|
||||
else
|
||||
msg = "camera error";
|
||||
output.innerText += `
|
||||
${msg}`;
|
||||
status(msg);
|
||||
log(err);
|
||||
}
|
||||
if (stream)
|
||||
|
@ -34085,6 +34091,7 @@ ${msg}`;
|
|||
return null;
|
||||
const track = stream.getVideoTracks()[0];
|
||||
const settings = track.getSettings();
|
||||
log("camera constraints:", constraints, "window:", {width: window.innerWidth, height: window.innerHeight});
|
||||
log("camera settings:", settings);
|
||||
log("camera track:", track);
|
||||
camera = {name: track.label, width: settings.width, height: settings.height, facing: settings.facingMode === "user" ? "front" : "back"};
|
||||
|
@ -34287,11 +34294,11 @@ async function main() {
|
|||
log("Human: demo starting ...");
|
||||
setupMenu();
|
||||
document.getElementById("log").innerText = `Human: version ${human.version} TensorFlow/JS: version ${human.tf.version_core}`;
|
||||
if (!ui.modelsPreload) {
|
||||
if (ui.modelsPreload) {
|
||||
status("loading");
|
||||
await human.load();
|
||||
}
|
||||
if (!ui.modelsWarmup) {
|
||||
if (ui.modelsWarmup) {
|
||||
status("initializing");
|
||||
const warmup = new ImageData(50, 50);
|
||||
await human.detect(warmup);
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"inputs": {
|
||||
"demo/browser.js": {
|
||||
"bytes": 17419,
|
||||
"bytes": 17704,
|
||||
"imports": [
|
||||
{
|
||||
"path": "dist/human.esm.js"
|
||||
|
@ -19,7 +19,7 @@
|
|||
"imports": []
|
||||
},
|
||||
"demo/menu.js": {
|
||||
"bytes": 12354,
|
||||
"bytes": 12357,
|
||||
"imports": []
|
||||
},
|
||||
"dist/human.esm.js": {
|
||||
|
@ -31,7 +31,7 @@
|
|||
"dist/demo-browser-index.js.map": {
|
||||
"imports": [],
|
||||
"inputs": {},
|
||||
"bytes": 5520028
|
||||
"bytes": 5520480
|
||||
},
|
||||
"dist/demo-browser-index.js": {
|
||||
"imports": [],
|
||||
|
@ -46,13 +46,13 @@
|
|||
"bytesInOutput": 7389
|
||||
},
|
||||
"demo/menu.js": {
|
||||
"bytesInOutput": 12356
|
||||
"bytesInOutput": 12359
|
||||
},
|
||||
"demo/browser.js": {
|
||||
"bytesInOutput": 15580
|
||||
"bytesInOutput": 15889
|
||||
}
|
||||
},
|
||||
"bytes": 1704669
|
||||
"bytes": 1704981
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue