face-api 和 tensorflow.js 在浏览器中不工作
face-api and tensorflow.js not working in browser
我正尝试在浏览器中运行这个例子
https://justadudewhohacks.github.io/face-api.js/docs/index.html#getting-started-browser
这里具体是这段代码
<!DOCTYPE html>
<html>
<head>
<script src="assets/face-api.js"></script>
<script src="assets/commons.js"></script>
<script src="assets/faceDetectionControls.js"></script>
<link rel="stylesheet" href="assets/styles.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.css">
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
</head>
<body>
<div id="navbar"></div>
<div class="center-content page-container">
<div class="progress" id="loader">
<div class="indeterminate"></div>
</div>
<div style="position: relative" class="margin">
<video onloadedmetadata="onPlay(this)" id="inputVideo" autoplay muted playsinline></video>
<canvas id="overlay" />
</div>
<div class="row side-by-side">
<!-- face_detector_selection_control -->
<div id="face_detector_selection_control" class="row input-field" style="margin-right: 20px;">
<select id="selectFaceDetector">
<option value="ssd_mobilenetv1">SSD Mobilenet V1</option>
<option value="tiny_face_detector">Tiny Face Detector</option>
</select>
<label>Select Face Detector</label>
</div>
<!-- face_detector_selection_control -->
<!-- check boxes -->
<div class="row" style="width: 220px;">
<input type="checkbox" id="hideBoundingBoxesCheckbox" onchange="onChangeHideBoundingBoxes(event)" />
<label for="hideBoundingBoxesCheckbox">Hide Bounding Boxes</label>
</div>
<!-- check boxes -->
<!-- fps_meter -->
<div id="fps_meter" class="row side-by-side">
<div>
<label for="time">Time:</label>
<input disabled value="-" id="time" type="text" class="bold">
<label for="fps">Estimated Fps:</label>
<input disabled value="-" id="fps" type="text" class="bold">
</div>
</div>
<!-- fps_meter -->
</div>
<!-- ssd_mobilenetv1_controls -->
<span id="ssd_mobilenetv1_controls">
<div class="row side-by-side">
<div class="row">
<label for="minConfidence">Min Confidence:</label>
<input disabled value="0.5" id="minConfidence" type="text" class="bold">
</div>
<button
class="waves-effect waves-light btn"
onclick="onDecreaseMinConfidence()"
>
<i class="material-icons left">-</i>
</button>
<button
class="waves-effect waves-light btn"
onclick="onIncreaseMinConfidence()"
>
<i class="material-icons left">+</i>
</button>
</div>
</span>
<!-- ssd_mobilenetv1_controls -->
<!-- tiny_face_detector_controls -->
<span id="tiny_face_detector_controls">
<div class="row side-by-side">
<div class="row input-field" style="margin-right: 20px;">
<select id="inputSize">
<option value="" disabled selected>Input Size:</option>
<option value="128">128 x 128</option>
<option value="160">160 x 160</option>
<option value="224">224 x 224</option>
<option value="320">320 x 320</option>
<option value="416">416 x 416</option>
<option value="512">512 x 512</option>
<option value="608">608 x 608</option>
</select>
<label>Input Size</label>
</div>
<div class="row">
<label for="scoreThreshold">Score Threshold:</label>
<input disabled value="0.5" id="scoreThreshold" type="text" class="bold">
</div>
<button
class="waves-effect waves-light btn"
onclick="onDecreaseScoreThreshold()"
>
<i class="material-icons left">-</i>
</button>
<button
class="waves-effect waves-light btn"
onclick="onIncreaseScoreThreshold()"
>
<i class="material-icons left">+</i>
</button>
</div>
</span>
<!-- tiny_face_detector_controls -->
</body>
<script>
let forwardTimes = []
let withBoxes = true
function onChangeHideBoundingBoxes(e) {
withBoxes = !$(e.target).prop('checked')
}
function updateTimeStats(timeInMs) {
forwardTimes = [timeInMs].concat(forwardTimes).slice(0, 30)
const avgTimeInMs = forwardTimes.reduce((total, t) => total + t) / forwardTimes.length
$('#time').val(`${Math.round(avgTimeInMs)} ms`)
$('#fps').val(`${faceapi.utils.round(1000 / avgTimeInMs)}`)
}
async function onPlay() {
const videoEl = $('#inputVideo').get(0)
if(videoEl.paused || videoEl.ended || !isFaceDetectionModelLoaded())
return setTimeout(() => onPlay())
const options = getFaceDetectorOptions()
const ts = Date.now()
const result = await faceapi.detectSingleFace(videoEl, options).withFaceExpressions()
updateTimeStats(Date.now() - ts)
if (result) {
const canvas = $('#overlay').get(0)
const dims = faceapi.matchDimensions(canvas, videoEl, true)
const resizedResult = faceapi.resizeResults(result, dims)
const minConfidence = 0.05
if (withBoxes) {
faceapi.draw.drawDetections(canvas, resizedResult)
}
faceapi.draw.drawFaceExpressions(canvas, resizedResult, minConfidence)
}
setTimeout(() => onPlay())
}
async function run() {
// load face detection and face expression recognition models
await changeFaceDetector(TINY_FACE_DETECTOR)
await faceapi.loadFaceExpressionModel('/')
changeInputSize(224)
// try to access users webcam and stream the images
// to the video element
const stream = await navigator.mediaDevices.getUserMedia({ video: {} })
const videoEl = $('#inputVideo').get(0)
videoEl.srcObject = stream
}
function updateResults() {}
$(document).ready(function() {
renderNavBar('#navbar', 'webcam_face_expression_recognition')
initFaceDetectionControls()
run()
})
</script>
</body>
</html>
不幸的是,这不起作用(我已将关联的库加载到资产中,即 https://github.com/justadudewhohacks/face-api.js/tree/master/dist 并将此示例中的其他文件移至此处
https://github.com/justadudewhohacks/face-api.js/tree/master/examples/examples-browser
我做错了什么?我正在我网站的页面上加载这个
https://moodmap.app/webcamFaceExpressionRecognition.html 如果您想查看浏览器中发生的情况。
根据以下更改,
这是我设置内容存放位置的节点服务器 - 是否可以只更改它?因为在进行下面建议的更改时,模型中所需的分片也出现了一个单独的问题。
谢谢!
const config = require('../../config');
const express = require('express');
const app = express();
const server = require('http').createServer(app);
const io = require('socket.io')(server, { wsEngine: 'ws' });
const mysql = require('mysql');
const expressSession = require('express-session');
const ExpressMysqlSessionStore = require('express-mysql-session')(expressSession);
const sharedsession = require('express-socket.io-session');
const path = require('path');
const utils = require('./utils');
// remove from header "X-Powered-By: Express"
app.disable('x-powered-by');
server.listen(config.serverParams.port, config.serverParams.address, () => {
console.log(`Server running at http://${server.address().address}:${server.address().port}`);
});
/* DATABASE */
global.db = mysql.createConnection(config.db);
db.connect();
/* DATABASE */
/* SESSION */
const sessionStore = new ExpressMysqlSessionStore(config.sessionStore, db);
const session = expressSession({
...config.session,
store: sessionStore,
});
app.use(session);
/* SESSION */
app.use(express.static(config.frontendDir));
app.use(express.static(path.join(__dirname, './src/assets')))
app.use(express.static(path.join(__dirname, './src/assets/weights')))
app.use((req,res,next)=>{
//can reaplce * with website we want to allow access
res.header('Access-Control-Allow-Origin', '*');
next();
});
app.get([
'/signup',
'/stats',
'/pay',
], (req, res) => res.sendFile(path.join(`${config.frontendDir}${req.path}.html`)));
io.use(sharedsession(session, {
autoSave: true
}));
io.on('connection', socket => {
socket.use((packet, next) => {
if (packet[0]) {
console.log('METHOD:', packet[0]);
const sessionData = socket.handshake.session.user;
const noSessionNeed = [ 'login', 'signup', 'checkAuth' ].includes(packet[0]);
let error;
if ( ! sessionData && ! noSessionNeed) error = { code: -1, message: 'You need to login in extension!' };
if (error) return next(new Error(JSON.stringify(error)));
else next();
}
});
const auth = require('./auth')(socket);
socket.on('checkAuth', auth.checkAuth);
socket.on('login', auth.login);
socket.on('signup', auth.signup);
socket.on('logout', auth.logout);
const users = require('./users')(socket);
socket.on('users.get', users.get);
const sentiment = require('./sentiment')(socket);
socket.on('sentiment.get', sentiment.get);
socket.on('sentiment.set', sentiment.set);
socket.on('disconnect', () => {
});
});
由于某些原因仍然出现错误的原因如下,?
fetchOrThrow.ts:11 Uncaught (in promise) Error: failed to fetch: (404) , from url: https://moodmap.app/assets/tiny_face_detector_model-weights_manifest.json
at fetchOrThrow.ts:11
at step (drawContour.ts:28)
at Object.next (drawContour.ts:28)
at fulfilled (drawContour.ts:28)
(anonymous) @ fetchOrThrow.ts:11
step @ drawContour.ts:28
(anonymous) @ drawContour.ts:28
fulfilled @ drawContour.ts:28
async function (async)
run @ webcamFaceExpressionRecognition.html:142
(anonymous) @ webcamFaceExpressionRecognition.html:158
j @ jquery-2.1.1.min.js:2
fireWith @ jquery-2.1.1.min.js:2
ready @ jquery-2.1.1.min.js:2
I @ jquery-2.1.1.min.js:2
提前致谢!
所以,你在问题中所说的错误是:
Uncaught (in promise) Error: failed to fetch: (404) , from URL:
https://moodmap.app/tiny_face_detector_model-weights_manifest.json
所以,这个错误意味着找不到文件tiny_face_detector_model-weights_manifest.json
。正如我在您的网站上看到的那样,所有其他 manifest.json 文件也会发生这种情况。
您在问题中提到所有关联的库都在 assets 文件夹中。所以,你的 tiny_face_detector_model-weights_manifest.json
文件和其他 manifest.json 文件也在 assets
文件夹中,我根据那个给你解决方案但是如果你将文件的位置更改到另一个文件夹,只需替换 assets
与你的文件所在的任何文件夹。
face-api.js Line:1976
在这里,在 1976 年行 中,您会看到 defaultModelName
。这说明要加载的文件。
1. 因此,如果您的应用只有加载问题 tiny_face_detector_model-weights_manifest.json
[ 对于这种情况,它显示所有 manifest.json 所以跳到下面] 然后
face-api.js 行:5627
转到face-api.js中的第5627行并更改
"tiny_face_detector_model"
与
"./assets/tiny_face_detector_model"
2. 如果您所有的清单文件在加载时都显示 404 错误,对于这种情况是正确的,因为您的所有文件都在资产文件夹中。
所以,在这种情况下,请转到 face-api.js、
的 行号 1976
只需替换:
var defaultManifestFilename=defaultModelName+"-weights_manifest.json";
与:
var defaultManifestFilename="./assets/"+defaultModelName+"-weights_manifest.json";
这意味着仅将清单文件所在的文件夹名称或路径连接到上述变量。这将解决应用程序中所有 manifest.json 文件的路径问题。
注意:如果查找带有我提到的行号的代码时出现问题,请使用搜索。
我正尝试在浏览器中运行这个例子
https://justadudewhohacks.github.io/face-api.js/docs/index.html#getting-started-browser
这里具体是这段代码
<!DOCTYPE html>
<html>
<head>
<script src="assets/face-api.js"></script>
<script src="assets/commons.js"></script>
<script src="assets/faceDetectionControls.js"></script>
<link rel="stylesheet" href="assets/styles.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/css/materialize.css">
<script type="text/javascript" src="https://code.jquery.com/jquery-2.1.1.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.100.2/js/materialize.min.js"></script>
</head>
<body>
<div id="navbar"></div>
<div class="center-content page-container">
<div class="progress" id="loader">
<div class="indeterminate"></div>
</div>
<div style="position: relative" class="margin">
<video onloadedmetadata="onPlay(this)" id="inputVideo" autoplay muted playsinline></video>
<canvas id="overlay" />
</div>
<div class="row side-by-side">
<!-- face_detector_selection_control -->
<div id="face_detector_selection_control" class="row input-field" style="margin-right: 20px;">
<select id="selectFaceDetector">
<option value="ssd_mobilenetv1">SSD Mobilenet V1</option>
<option value="tiny_face_detector">Tiny Face Detector</option>
</select>
<label>Select Face Detector</label>
</div>
<!-- face_detector_selection_control -->
<!-- check boxes -->
<div class="row" style="width: 220px;">
<input type="checkbox" id="hideBoundingBoxesCheckbox" onchange="onChangeHideBoundingBoxes(event)" />
<label for="hideBoundingBoxesCheckbox">Hide Bounding Boxes</label>
</div>
<!-- check boxes -->
<!-- fps_meter -->
<div id="fps_meter" class="row side-by-side">
<div>
<label for="time">Time:</label>
<input disabled value="-" id="time" type="text" class="bold">
<label for="fps">Estimated Fps:</label>
<input disabled value="-" id="fps" type="text" class="bold">
</div>
</div>
<!-- fps_meter -->
</div>
<!-- ssd_mobilenetv1_controls -->
<span id="ssd_mobilenetv1_controls">
<div class="row side-by-side">
<div class="row">
<label for="minConfidence">Min Confidence:</label>
<input disabled value="0.5" id="minConfidence" type="text" class="bold">
</div>
<button
class="waves-effect waves-light btn"
onclick="onDecreaseMinConfidence()"
>
<i class="material-icons left">-</i>
</button>
<button
class="waves-effect waves-light btn"
onclick="onIncreaseMinConfidence()"
>
<i class="material-icons left">+</i>
</button>
</div>
</span>
<!-- ssd_mobilenetv1_controls -->
<!-- tiny_face_detector_controls -->
<span id="tiny_face_detector_controls">
<div class="row side-by-side">
<div class="row input-field" style="margin-right: 20px;">
<select id="inputSize">
<option value="" disabled selected>Input Size:</option>
<option value="128">128 x 128</option>
<option value="160">160 x 160</option>
<option value="224">224 x 224</option>
<option value="320">320 x 320</option>
<option value="416">416 x 416</option>
<option value="512">512 x 512</option>
<option value="608">608 x 608</option>
</select>
<label>Input Size</label>
</div>
<div class="row">
<label for="scoreThreshold">Score Threshold:</label>
<input disabled value="0.5" id="scoreThreshold" type="text" class="bold">
</div>
<button
class="waves-effect waves-light btn"
onclick="onDecreaseScoreThreshold()"
>
<i class="material-icons left">-</i>
</button>
<button
class="waves-effect waves-light btn"
onclick="onIncreaseScoreThreshold()"
>
<i class="material-icons left">+</i>
</button>
</div>
</span>
<!-- tiny_face_detector_controls -->
</body>
<script>
let forwardTimes = []
let withBoxes = true
function onChangeHideBoundingBoxes(e) {
withBoxes = !$(e.target).prop('checked')
}
function updateTimeStats(timeInMs) {
forwardTimes = [timeInMs].concat(forwardTimes).slice(0, 30)
const avgTimeInMs = forwardTimes.reduce((total, t) => total + t) / forwardTimes.length
$('#time').val(`${Math.round(avgTimeInMs)} ms`)
$('#fps').val(`${faceapi.utils.round(1000 / avgTimeInMs)}`)
}
async function onPlay() {
const videoEl = $('#inputVideo').get(0)
if(videoEl.paused || videoEl.ended || !isFaceDetectionModelLoaded())
return setTimeout(() => onPlay())
const options = getFaceDetectorOptions()
const ts = Date.now()
const result = await faceapi.detectSingleFace(videoEl, options).withFaceExpressions()
updateTimeStats(Date.now() - ts)
if (result) {
const canvas = $('#overlay').get(0)
const dims = faceapi.matchDimensions(canvas, videoEl, true)
const resizedResult = faceapi.resizeResults(result, dims)
const minConfidence = 0.05
if (withBoxes) {
faceapi.draw.drawDetections(canvas, resizedResult)
}
faceapi.draw.drawFaceExpressions(canvas, resizedResult, minConfidence)
}
setTimeout(() => onPlay())
}
async function run() {
// load face detection and face expression recognition models
await changeFaceDetector(TINY_FACE_DETECTOR)
await faceapi.loadFaceExpressionModel('/')
changeInputSize(224)
// try to access users webcam and stream the images
// to the video element
const stream = await navigator.mediaDevices.getUserMedia({ video: {} })
const videoEl = $('#inputVideo').get(0)
videoEl.srcObject = stream
}
function updateResults() {}
$(document).ready(function() {
renderNavBar('#navbar', 'webcam_face_expression_recognition')
initFaceDetectionControls()
run()
})
</script>
</body>
</html>
不幸的是,这不起作用(我已将关联的库加载到资产中,即 https://github.com/justadudewhohacks/face-api.js/tree/master/dist 并将此示例中的其他文件移至此处
https://github.com/justadudewhohacks/face-api.js/tree/master/examples/examples-browser
我做错了什么?我正在我网站的页面上加载这个
https://moodmap.app/webcamFaceExpressionRecognition.html 如果您想查看浏览器中发生的情况。
根据以下更改,
这是我设置内容存放位置的节点服务器 - 是否可以只更改它?因为在进行下面建议的更改时,模型中所需的分片也出现了一个单独的问题。
谢谢!
const config = require('../../config');
const express = require('express');
const app = express();
const server = require('http').createServer(app);
const io = require('socket.io')(server, { wsEngine: 'ws' });
const mysql = require('mysql');
const expressSession = require('express-session');
const ExpressMysqlSessionStore = require('express-mysql-session')(expressSession);
const sharedsession = require('express-socket.io-session');
const path = require('path');
const utils = require('./utils');
// remove from header "X-Powered-By: Express"
app.disable('x-powered-by');
server.listen(config.serverParams.port, config.serverParams.address, () => {
console.log(`Server running at http://${server.address().address}:${server.address().port}`);
});
/* DATABASE */
global.db = mysql.createConnection(config.db);
db.connect();
/* DATABASE */
/* SESSION */
const sessionStore = new ExpressMysqlSessionStore(config.sessionStore, db);
const session = expressSession({
...config.session,
store: sessionStore,
});
app.use(session);
/* SESSION */
app.use(express.static(config.frontendDir));
app.use(express.static(path.join(__dirname, './src/assets')))
app.use(express.static(path.join(__dirname, './src/assets/weights')))
app.use((req,res,next)=>{
//can reaplce * with website we want to allow access
res.header('Access-Control-Allow-Origin', '*');
next();
});
app.get([
'/signup',
'/stats',
'/pay',
], (req, res) => res.sendFile(path.join(`${config.frontendDir}${req.path}.html`)));
io.use(sharedsession(session, {
autoSave: true
}));
io.on('connection', socket => {
socket.use((packet, next) => {
if (packet[0]) {
console.log('METHOD:', packet[0]);
const sessionData = socket.handshake.session.user;
const noSessionNeed = [ 'login', 'signup', 'checkAuth' ].includes(packet[0]);
let error;
if ( ! sessionData && ! noSessionNeed) error = { code: -1, message: 'You need to login in extension!' };
if (error) return next(new Error(JSON.stringify(error)));
else next();
}
});
const auth = require('./auth')(socket);
socket.on('checkAuth', auth.checkAuth);
socket.on('login', auth.login);
socket.on('signup', auth.signup);
socket.on('logout', auth.logout);
const users = require('./users')(socket);
socket.on('users.get', users.get);
const sentiment = require('./sentiment')(socket);
socket.on('sentiment.get', sentiment.get);
socket.on('sentiment.set', sentiment.set);
socket.on('disconnect', () => {
});
});
由于某些原因仍然出现错误的原因如下,?
fetchOrThrow.ts:11 Uncaught (in promise) Error: failed to fetch: (404) , from url: https://moodmap.app/assets/tiny_face_detector_model-weights_manifest.json
at fetchOrThrow.ts:11
at step (drawContour.ts:28)
at Object.next (drawContour.ts:28)
at fulfilled (drawContour.ts:28)
(anonymous) @ fetchOrThrow.ts:11
step @ drawContour.ts:28
(anonymous) @ drawContour.ts:28
fulfilled @ drawContour.ts:28
async function (async)
run @ webcamFaceExpressionRecognition.html:142
(anonymous) @ webcamFaceExpressionRecognition.html:158
j @ jquery-2.1.1.min.js:2
fireWith @ jquery-2.1.1.min.js:2
ready @ jquery-2.1.1.min.js:2
I @ jquery-2.1.1.min.js:2
提前致谢!
所以,你在问题中所说的错误是:
Uncaught (in promise) Error: failed to fetch: (404) , from URL:
https://moodmap.app/tiny_face_detector_model-weights_manifest.json
所以,这个错误意味着找不到文件tiny_face_detector_model-weights_manifest.json
。正如我在您的网站上看到的那样,所有其他 manifest.json 文件也会发生这种情况。
您在问题中提到所有关联的库都在 assets 文件夹中。所以,你的 tiny_face_detector_model-weights_manifest.json
文件和其他 manifest.json 文件也在 assets
文件夹中,我根据那个给你解决方案但是如果你将文件的位置更改到另一个文件夹,只需替换 assets
与你的文件所在的任何文件夹。
face-api.js Line:1976
在这里,在 1976 年行 中,您会看到 defaultModelName
。这说明要加载的文件。
1. 因此,如果您的应用只有加载问题 tiny_face_detector_model-weights_manifest.json
[ 对于这种情况,它显示所有 manifest.json 所以跳到下面] 然后
face-api.js 行:5627
转到face-api.js中的第5627行并更改
"tiny_face_detector_model"
与
"./assets/tiny_face_detector_model"
2. 如果您所有的清单文件在加载时都显示 404 错误,对于这种情况是正确的,因为您的所有文件都在资产文件夹中。
所以,在这种情况下,请转到 face-api.js、
的 行号 1976只需替换:
var defaultManifestFilename=defaultModelName+"-weights_manifest.json";
与:
var defaultManifestFilename="./assets/"+defaultModelName+"-weights_manifest.json";
这意味着仅将清单文件所在的文件夹名称或路径连接到上述变量。这将解决应用程序中所有 manifest.json 文件的路径问题。
注意:如果查找带有我提到的行号的代码时出现问题,请使用搜索。