[JavaScript, Программирование, HTML, TensorFlow] Отслеживание лиц в реальном времени в браузере с использованием TensorFlow.js. Часть 5 (перевод)
Автор
Сообщение
news_bot ®
Стаж: 6 лет 9 месяцев
Сообщений: 27286
Носить виртуальные аксессуары – это весело, но до их ношения в реальной жизни всего один шаг. Мы могли бы легко создать приложение, которое позволяет виртуально примерять шляпы – именно такое приложение вы могли бы захотеть создать для веб-сайта электронной коммерции. Но, если мы собираемся это сделать, почему бы при этом не получить немного больше удовольствия? Программное обеспечение замечательно тем, что мы можем воплотить в жизнь своё воображение.
В этой статье мы собираемся соединить все предыдущие части, чтобы создать волшебную шляпу для обнаружения эмоций, которая распознаёт и реагирует на выражения лиц, когда мы носим её виртуально. Вы можете загрузить демоверсию этого проекта. Для обеспечения необходимой производительности может потребоваться включить в веб-браузере поддержку интерфейса WebGL. Вы также можете загрузить код и файлы для этой серии. Предполагается, что вы знакомы с JavaScript и HTML и имеете хотя бы базовое представление о нейронных сетях. Создание волшебной шляпыПомните, как мы ранее в этой серии статей создавали функцию обнаружения эмоций на лице в реальном времени? Теперь давайте добавим немного графики в этот проект – придадим ему, так сказать, «лицо». Чтобы создать нашу виртуальную шляпу, мы собираемся добавить графические ресурсы на веб-страницу как скрытые элементы img:
<img id="hat-angry" src="web/hats/angry.png" style="visibility: hidden;" />
<img id="hat-disgust" src="web/hats/disgust.png" style="visibility: hidden;" />
<img id="hat-fear" src="web/hats/fear.png" style="visibility: hidden;" />
<img id="hat-happy" src="web/hats/happy.png" style="visibility: hidden;" />
<img id="hat-neutral" src="web/hats/neutral.png" style="visibility: hidden;" />
<img id="hat-sad" src="web/hats/sad.png" style="visibility: hidden;" />
<img id="hat-surprise" src="web/hats/surprise.png" style="visibility: hidden;" />
Ключевое свойство этого проекта заключается в том, что шляпа должна отображаться всё время, в правильном положении и с правильным размером, поэтому мы сохраним «состояния» шляпы в глобальной переменной:
let currentEmotion = "neutral";
let hat = { scale: { x: 0, y: 0 }, position: { x: 0, y: 0 } };
Рисовать шляпу этого размера и в этом положении мы будем с помощью 2D-преобразования полотна в каждом кадре.
async function trackFace() {
...
output.drawImage(
video,
0, 0, video.width, video.height,
0, 0, video.width, video.height
);
let hatImage = document.getElementById( `hat-${currentEmotion}` );
output.save();
output.translate( -hatImage.width / 2, -hatImage.height / 2 );
output.translate( hat.position.x, hat.position.y );
output.drawImage(
hatImage,
0, 0, hatImage.width, hatImage.height,
0, 0, hatImage.width * hat.scale, hatImage.height * hat.scale
);
output.restore();
...
}
По ключевым точкам лица, предоставляемым TensorFlow, мы можем рассчитать размер и положение шляпы относительно лица, чтобы задать указанные выше значения.
Размер головы можно оценить по расстоянию между глазами. Вектор «вверх» аппроксимируем по точке midwayBetweenEyes и точке noseBottom, которые можно использовать для перемещения шляпы вверх ближе к верхней части лица (в отличие от виртуальных очков из предыдущей статьи).
const eyeDist = Math.sqrt(
( face.annotations.leftEyeUpper1[ 3 ][ 0 ] - face.annotations.rightEyeUpper1[ 3 ][ 0 ] ) ** 2 +
( face.annotations.leftEyeUpper1[ 3 ][ 1 ] - face.annotations.rightEyeUpper1[ 3 ][ 1 ] ) ** 2 +
( face.annotations.leftEyeUpper1[ 3 ][ 2 ] - face.annotations.rightEyeUpper1[ 3 ][ 2 ] ) ** 2
);
const faceScale = eyeDist / 80;
let upX = face.annotations.midwayBetweenEyes[ 0 ][ 0 ] - face.annotations.noseBottom[ 0 ][ 0 ];
let upY = face.annotations.midwayBetweenEyes[ 0 ][ 1 ] - face.annotations.noseBottom[ 0 ][ 1 ];
const length = Math.sqrt( upX ** 2 + upY ** 2 );
upX /= length;
upY /= length;
hat = {
scale: faceScale,
position: {
x: face.annotations.midwayBetweenEyes[ 0 ][ 0 ] + upX * 100 * faceScale,
y: face.annotations.midwayBetweenEyes[ 0 ][ 1 ] + upY * 100 * faceScale,
}
};
После сохранения названия спрогнозированной эмоции в currentEmotion отображается соответствующее изображение шляпы, и мы готовы её примерить!
if( points ) {
let emotion = await predictEmotion( points );
setText( `Detected: ${emotion}` );
currentEmotion = emotion;
}
else {
setText( "No Face" );
}
Вот полный код этого проекта
<html>
<head>
<title>Building a Magical Emotion Detection Hat</title>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@2.4.0/dist/tf.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/face-landmarks-detection@0.0.1/dist/face-landmarks-detection.js"></script>
</head>
<body>
<canvas id="output"></canvas>
<video id="webcam" playsinline style="
visibility: hidden;
width: auto;
height: auto;
">
</video>
<h1 id="status">Loading...</h1>
<img id="hat-angry" src="web/hats/angry.png" style="visibility: hidden;" />
<img id="hat-disgust" src="web/hats/disgust.png" style="visibility: hidden;" />
<img id="hat-fear" src="web/hats/fear.png" style="visibility: hidden;" />
<img id="hat-happy" src="web/hats/happy.png" style="visibility: hidden;" />
<img id="hat-neutral" src="web/hats/neutral.png" style="visibility: hidden;" />
<img id="hat-sad" src="web/hats/sad.png" style="visibility: hidden;" />
<img id="hat-surprise" src="web/hats/surprise.png" style="visibility: hidden;" />
<script>
function setText( text ) {
document.getElementById( "status" ).innerText = text;
}
function drawLine( ctx, x1, y1, x2, y2 ) {
ctx.beginPath();
ctx.moveTo( x1, y1 );
ctx.lineTo( x2, y2 );
ctx.stroke();
}
async function setupWebcam() {
return new Promise( ( resolve, reject ) => {
const webcamElement = document.getElementById( "webcam" );
const navigatorAny = navigator;
navigator.getUserMedia = navigator.getUserMedia ||
navigatorAny.webkitGetUserMedia || navigatorAny.mozGetUserMedia ||
navigatorAny.msGetUserMedia;
if( navigator.getUserMedia ) {
navigator.getUserMedia( { video: true },
stream => {
webcamElement.srcObject = stream;
webcamElement.addEventListener( "loadeddata", resolve, false );
},
error => reject());
}
else {
reject();
}
});
}
const emotions = [ "angry", "disgust", "fear", "happy", "neutral", "sad", "surprise" ];
let emotionModel = null;
let output = null;
let model = null;
let currentEmotion = "neutral";
let hat = { scale: { x: 0, y: 0 }, position: { x: 0, y: 0 } };
async function predictEmotion( points ) {
let result = tf.tidy( () => {
const xs = tf.stack( [ tf.tensor1d( points ) ] );
return emotionModel.predict( xs );
});
let prediction = await result.data();
result.dispose();
// Get the index of the maximum value
let id = prediction.indexOf( Math.max( ...prediction ) );
return emotions[ id ];
}
async function trackFace() {
const video = document.querySelector( "video" );
const faces = await model.estimateFaces( {
input: video,
returnTensors: false,
flipHorizontal: false,
});
output.drawImage(
video,
0, 0, video.width, video.height,
0, 0, video.width, video.height
);
let hatImage = document.getElementById( `hat-${currentEmotion}` );
output.save();
output.translate( -hatImage.width / 2, -hatImage.height / 2 );
output.translate( hat.position.x, hat.position.y );
output.drawImage(
hatImage,
0, 0, hatImage.width, hatImage.height,
0, 0, hatImage.width * hat.scale, hatImage.height * hat.scale
);
output.restore();
let points = null;
faces.forEach( face => {
const x1 = face.boundingBox.topLeft[ 0 ];
const y1 = face.boundingBox.topLeft[ 1 ];
const x2 = face.boundingBox.bottomRight[ 0 ];
const y2 = face.boundingBox.bottomRight[ 1 ];
const bWidth = x2 - x1;
const bHeight = y2 - y1;
// Add just the nose, cheeks, eyes, eyebrows & mouth
const features = [
"noseTip",
"leftCheek",
"rightCheek",
"leftEyeLower1", "leftEyeUpper1",
"rightEyeLower1", "rightEyeUpper1",
"leftEyebrowLower", //"leftEyebrowUpper",
"rightEyebrowLower", //"rightEyebrowUpper",
"lipsLowerInner", //"lipsLowerOuter",
"lipsUpperInner", //"lipsUpperOuter",
];
points = [];
features.forEach( feature => {
face.annotations[ feature ].forEach( x => {
points.push( ( x[ 0 ] - x1 ) / bWidth );
points.push( ( x[ 1 ] - y1 ) / bHeight );
});
});
const eyeDist = Math.sqrt(
( face.annotations.leftEyeUpper1[ 3 ][ 0 ] - face.annotations.rightEyeUpper1[ 3 ][ 0 ] ) ** 2 +
( face.annotations.leftEyeUpper1[ 3 ][ 1 ] - face.annotations.rightEyeUpper1[ 3 ][ 1 ] ) ** 2 +
( face.annotations.leftEyeUpper1[ 3 ][ 2 ] - face.annotations.rightEyeUpper1[ 3 ][ 2 ] ) ** 2
);
const faceScale = eyeDist / 80;
let upX = face.annotations.midwayBetweenEyes[ 0 ][ 0 ] - face.annotations.noseBottom[ 0 ][ 0 ];
let upY = face.annotations.midwayBetweenEyes[ 0 ][ 1 ] - face.annotations.noseBottom[ 0 ][ 1 ];
const length = Math.sqrt( upX ** 2 + upY ** 2 );
upX /= length;
upY /= length;
hat = {
scale: faceScale,
position: {
x: face.annotations.midwayBetweenEyes[ 0 ][ 0 ] + upX * 100 * faceScale,
y: face.annotations.midwayBetweenEyes[ 0 ][ 1 ] + upY * 100 * faceScale,
}
};
});
if( points ) {
let emotion = await predictEmotion( points );
setText( `Detected: ${emotion}` );
currentEmotion = emotion;
}
else {
setText( "No Face" );
}
requestAnimationFrame( trackFace );
}
(async () => {
await setupWebcam();
const video = document.getElementById( "webcam" );
video.play();
let videoWidth = video.videoWidth;
let videoHeight = video.videoHeight;
video.width = videoWidth;
video.height = videoHeight;
let canvas = document.getElementById( "output" );
canvas.width = video.width;
canvas.height = video.height;
output = canvas.getContext( "2d" );
output.translate( canvas.width, 0 );
output.scale( -1, 1 ); // Mirror cam
output.fillStyle = "#fdffb6";
output.strokeStyle = "#fdffb6";
output.lineWidth = 2;
// Load Face Landmarks Detection
model = await faceLandmarksDetection.load(
faceLandmarksDetection.SupportedPackages.mediapipeFacemesh
);
// Load Emotion Detection
emotionModel = await tf.loadLayersModel( 'web/model/facemo.json' );
setText( "Loaded!" );
trackFace();
})();
</script>
</body>
</html>
Что дальше? Возможен ли контроль по состоянию глаз и рта?В этом проекте собраны воедино все куски, созданные ранее в этой серии статей в целях развлечения с визуальными образами. А что, если бы можно было реализовать в нём взаимодействие с лицом?В следующей, заключительной статье этой серии мы реализуем обнаружение моргания глаз и открывания рта, чтобы получить интерактивную сцену. Оставайтесь с нами и до встречи завтра, в это же время.
- Отслеживание лиц в реальном времени в браузере. Часть 1
- Отслеживание лиц в реальном времени в браузере. Часть 2
- Отслеживание лиц в реальном времени в браузере. Часть 3
- Отслеживание лиц в реальном времени в браузере. Часть 4
Узнайте подробности, как получить Level Up по навыкам и зарплате или востребованную профессию с нуля, пройдя онлайн-курсы SkillFactory со скидкой 40% и промокодом HABR, который даст еще +10% скидки на обучение.
Другие профессии и курсыПРОФЕССИИ
- Профессия Java-разработчик
- Профессия QA-инженер на JAVA
- Профессия Frontend-разработчик
- Профессия Этичный хакер
- Профессия C++ разработчик
- Профессия Разработчик игр на Unity
- Профессия Веб-разработчик
- Профессия iOS-разработчик с нуля
- Профессия Android-разработчик с нуля
КУРСЫ
- Курс по Machine Learning
- Курс "Математика и Machine Learning для Data Science"
- Курс "Machine Learning и Deep Learning"
- Курс "Python для веб-разработки"
- Курс "Алгоритмы и структуры данных"
- Курс по аналитике данных
- Курс по DevOps
===========
Источник:
habr.com
===========
===========
Автор оригинала: Raphael Mun
===========Похожие новости:
- [Open source, Программирование, Системное программирование, Компиляторы, Rust] Планирование редакции Rust 2021 (перевод)
- [Информационная безопасность, Программирование, C++] С++: безопасность для новичков
- [Разработка веб-сайтов, JavaScript, Программирование, ReactJS] 20 основных частей любого крупномасштабного React-приложения (перевод)
- [Open source, Алгоритмы, Lua, Параллельное программирование] Параллелизм и плотность кода
- [Высокая производительность, Разработка мобильных приложений, IT-инфраструктура, Разработка под Android] Как мы ускорили запуск приложения Dropbox для Android на 30 % (перевод)
- [Python, Программирование, Машинное обучение] Поиск нарушений на видео с помощью компьютерного зрения
- [Анализ и проектирование систем, Промышленное программирование, Распределённые системы] Устройство гетерогенного кластера выполнения задач. Доклад Яндекса
- [Разработка веб-сайтов, Python, Django, Функциональное программирование] Делаем тесты частью приложения (перевод)
- [JavaScript, Монетизация мобильных приложений, Natural Language Processing, Голосовые интерфейсы] Аккредитация разработчиков навыков для ассистентов Салют и первый аккредитованный партнёр
- [Программирование, Java] REST API с использованием Spring Security и JWT
Теги для поиска: #_javascript, #_programmirovanie (Программирование), #_html, #_tensorflow, #_skillfactory, #_programmirovanie (программирование), #_glubokoe_obuchenie (глубокое обучение), #_lajfhaki (лайфхаки), #_raspoznavanie_lits (распознавание лиц), #_html, #_tensorflowjs, #_tensorflow, #_javascript, #_blog_kompanii_skillfactory (
Блог компании SkillFactory
), #_javascript, #_programmirovanie (
Программирование
), #_html, #_tensorflow
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 02:02
Часовой пояс: UTC + 5
Автор | Сообщение |
---|---|
news_bot ®
Стаж: 6 лет 9 месяцев |
|
Носить виртуальные аксессуары – это весело, но до их ношения в реальной жизни всего один шаг. Мы могли бы легко создать приложение, которое позволяет виртуально примерять шляпы – именно такое приложение вы могли бы захотеть создать для веб-сайта электронной коммерции. Но, если мы собираемся это сделать, почему бы при этом не получить немного больше удовольствия? Программное обеспечение замечательно тем, что мы можем воплотить в жизнь своё воображение. В этой статье мы собираемся соединить все предыдущие части, чтобы создать волшебную шляпу для обнаружения эмоций, которая распознаёт и реагирует на выражения лиц, когда мы носим её виртуально. Вы можете загрузить демоверсию этого проекта. Для обеспечения необходимой производительности может потребоваться включить в веб-браузере поддержку интерфейса WebGL. Вы также можете загрузить код и файлы для этой серии. Предполагается, что вы знакомы с JavaScript и HTML и имеете хотя бы базовое представление о нейронных сетях. Создание волшебной шляпыПомните, как мы ранее в этой серии статей создавали функцию обнаружения эмоций на лице в реальном времени? Теперь давайте добавим немного графики в этот проект – придадим ему, так сказать, «лицо». Чтобы создать нашу виртуальную шляпу, мы собираемся добавить графические ресурсы на веб-страницу как скрытые элементы img: <img id="hat-angry" src="web/hats/angry.png" style="visibility: hidden;" />
<img id="hat-disgust" src="web/hats/disgust.png" style="visibility: hidden;" /> <img id="hat-fear" src="web/hats/fear.png" style="visibility: hidden;" /> <img id="hat-happy" src="web/hats/happy.png" style="visibility: hidden;" /> <img id="hat-neutral" src="web/hats/neutral.png" style="visibility: hidden;" /> <img id="hat-sad" src="web/hats/sad.png" style="visibility: hidden;" /> <img id="hat-surprise" src="web/hats/surprise.png" style="visibility: hidden;" /> let currentEmotion = "neutral";
let hat = { scale: { x: 0, y: 0 }, position: { x: 0, y: 0 } }; async function trackFace() {
... output.drawImage( video, 0, 0, video.width, video.height, 0, 0, video.width, video.height ); let hatImage = document.getElementById( `hat-${currentEmotion}` ); output.save(); output.translate( -hatImage.width / 2, -hatImage.height / 2 ); output.translate( hat.position.x, hat.position.y ); output.drawImage( hatImage, 0, 0, hatImage.width, hatImage.height, 0, 0, hatImage.width * hat.scale, hatImage.height * hat.scale ); output.restore(); ... } Размер головы можно оценить по расстоянию между глазами. Вектор «вверх» аппроксимируем по точке midwayBetweenEyes и точке noseBottom, которые можно использовать для перемещения шляпы вверх ближе к верхней части лица (в отличие от виртуальных очков из предыдущей статьи). const eyeDist = Math.sqrt(
( face.annotations.leftEyeUpper1[ 3 ][ 0 ] - face.annotations.rightEyeUpper1[ 3 ][ 0 ] ) ** 2 + ( face.annotations.leftEyeUpper1[ 3 ][ 1 ] - face.annotations.rightEyeUpper1[ 3 ][ 1 ] ) ** 2 + ( face.annotations.leftEyeUpper1[ 3 ][ 2 ] - face.annotations.rightEyeUpper1[ 3 ][ 2 ] ) ** 2 ); const faceScale = eyeDist / 80; let upX = face.annotations.midwayBetweenEyes[ 0 ][ 0 ] - face.annotations.noseBottom[ 0 ][ 0 ]; let upY = face.annotations.midwayBetweenEyes[ 0 ][ 1 ] - face.annotations.noseBottom[ 0 ][ 1 ]; const length = Math.sqrt( upX ** 2 + upY ** 2 ); upX /= length; upY /= length; hat = { scale: faceScale, position: { x: face.annotations.midwayBetweenEyes[ 0 ][ 0 ] + upX * 100 * faceScale, y: face.annotations.midwayBetweenEyes[ 0 ][ 1 ] + upY * 100 * faceScale, } }; if( points ) {
let emotion = await predictEmotion( points ); setText( `Detected: ${emotion}` ); currentEmotion = emotion; } else { setText( "No Face" ); } <html>
<head> <title>Building a Magical Emotion Detection Hat</title> <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@2.4.0/dist/tf.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/face-landmarks-detection@0.0.1/dist/face-landmarks-detection.js"></script> </head> <body> <canvas id="output"></canvas> <video id="webcam" playsinline style=" visibility: hidden; width: auto; height: auto; "> </video> <h1 id="status">Loading...</h1> <img id="hat-angry" src="web/hats/angry.png" style="visibility: hidden;" /> <img id="hat-disgust" src="web/hats/disgust.png" style="visibility: hidden;" /> <img id="hat-fear" src="web/hats/fear.png" style="visibility: hidden;" /> <img id="hat-happy" src="web/hats/happy.png" style="visibility: hidden;" /> <img id="hat-neutral" src="web/hats/neutral.png" style="visibility: hidden;" /> <img id="hat-sad" src="web/hats/sad.png" style="visibility: hidden;" /> <img id="hat-surprise" src="web/hats/surprise.png" style="visibility: hidden;" /> <script> function setText( text ) { document.getElementById( "status" ).innerText = text; } function drawLine( ctx, x1, y1, x2, y2 ) { ctx.beginPath(); ctx.moveTo( x1, y1 ); ctx.lineTo( x2, y2 ); ctx.stroke(); } async function setupWebcam() { return new Promise( ( resolve, reject ) => { const webcamElement = document.getElementById( "webcam" ); const navigatorAny = navigator; navigator.getUserMedia = navigator.getUserMedia || navigatorAny.webkitGetUserMedia || navigatorAny.mozGetUserMedia || navigatorAny.msGetUserMedia; if( navigator.getUserMedia ) { navigator.getUserMedia( { video: true }, stream => { webcamElement.srcObject = stream; webcamElement.addEventListener( "loadeddata", resolve, false ); }, error => reject()); } else { reject(); } }); } const emotions = [ "angry", "disgust", "fear", "happy", "neutral", "sad", "surprise" ]; let emotionModel = null; let output = null; let model = null; let currentEmotion = "neutral"; let hat = { scale: { x: 0, y: 0 }, position: { x: 0, y: 0 } }; async function predictEmotion( points ) { let result = tf.tidy( () => { const xs = tf.stack( [ tf.tensor1d( points ) ] ); return emotionModel.predict( xs ); }); let prediction = await result.data(); result.dispose(); // Get the index of the maximum value let id = prediction.indexOf( Math.max( ...prediction ) ); return emotions[ id ]; } async function trackFace() { const video = document.querySelector( "video" ); const faces = await model.estimateFaces( { input: video, returnTensors: false, flipHorizontal: false, }); output.drawImage( video, 0, 0, video.width, video.height, 0, 0, video.width, video.height ); let hatImage = document.getElementById( `hat-${currentEmotion}` ); output.save(); output.translate( -hatImage.width / 2, -hatImage.height / 2 ); output.translate( hat.position.x, hat.position.y ); output.drawImage( hatImage, 0, 0, hatImage.width, hatImage.height, 0, 0, hatImage.width * hat.scale, hatImage.height * hat.scale ); output.restore(); let points = null; faces.forEach( face => { const x1 = face.boundingBox.topLeft[ 0 ]; const y1 = face.boundingBox.topLeft[ 1 ]; const x2 = face.boundingBox.bottomRight[ 0 ]; const y2 = face.boundingBox.bottomRight[ 1 ]; const bWidth = x2 - x1; const bHeight = y2 - y1; // Add just the nose, cheeks, eyes, eyebrows & mouth const features = [ "noseTip", "leftCheek", "rightCheek", "leftEyeLower1", "leftEyeUpper1", "rightEyeLower1", "rightEyeUpper1", "leftEyebrowLower", //"leftEyebrowUpper", "rightEyebrowLower", //"rightEyebrowUpper", "lipsLowerInner", //"lipsLowerOuter", "lipsUpperInner", //"lipsUpperOuter", ]; points = []; features.forEach( feature => { face.annotations[ feature ].forEach( x => { points.push( ( x[ 0 ] - x1 ) / bWidth ); points.push( ( x[ 1 ] - y1 ) / bHeight ); }); }); const eyeDist = Math.sqrt( ( face.annotations.leftEyeUpper1[ 3 ][ 0 ] - face.annotations.rightEyeUpper1[ 3 ][ 0 ] ) ** 2 + ( face.annotations.leftEyeUpper1[ 3 ][ 1 ] - face.annotations.rightEyeUpper1[ 3 ][ 1 ] ) ** 2 + ( face.annotations.leftEyeUpper1[ 3 ][ 2 ] - face.annotations.rightEyeUpper1[ 3 ][ 2 ] ) ** 2 ); const faceScale = eyeDist / 80; let upX = face.annotations.midwayBetweenEyes[ 0 ][ 0 ] - face.annotations.noseBottom[ 0 ][ 0 ]; let upY = face.annotations.midwayBetweenEyes[ 0 ][ 1 ] - face.annotations.noseBottom[ 0 ][ 1 ]; const length = Math.sqrt( upX ** 2 + upY ** 2 ); upX /= length; upY /= length; hat = { scale: faceScale, position: { x: face.annotations.midwayBetweenEyes[ 0 ][ 0 ] + upX * 100 * faceScale, y: face.annotations.midwayBetweenEyes[ 0 ][ 1 ] + upY * 100 * faceScale, } }; }); if( points ) { let emotion = await predictEmotion( points ); setText( `Detected: ${emotion}` ); currentEmotion = emotion; } else { setText( "No Face" ); } requestAnimationFrame( trackFace ); } (async () => { await setupWebcam(); const video = document.getElementById( "webcam" ); video.play(); let videoWidth = video.videoWidth; let videoHeight = video.videoHeight; video.width = videoWidth; video.height = videoHeight; let canvas = document.getElementById( "output" ); canvas.width = video.width; canvas.height = video.height; output = canvas.getContext( "2d" ); output.translate( canvas.width, 0 ); output.scale( -1, 1 ); // Mirror cam output.fillStyle = "#fdffb6"; output.strokeStyle = "#fdffb6"; output.lineWidth = 2; // Load Face Landmarks Detection model = await faceLandmarksDetection.load( faceLandmarksDetection.SupportedPackages.mediapipeFacemesh ); // Load Emotion Detection emotionModel = await tf.loadLayersModel( 'web/model/facemo.json' ); setText( "Loaded!" ); trackFace(); })(); </script> </body> </html>
=========== Источник: habr.com =========== =========== Автор оригинала: Raphael Mun ===========Похожие новости:
Блог компании SkillFactory ), #_javascript, #_programmirovanie ( Программирование ), #_html, #_tensorflow |
|
Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы
Текущее время: 22-Ноя 02:02
Часовой пояс: UTC + 5