[JavaScript, Программирование, HTML, TensorFlow] Отслеживание лиц в реальном времени в браузере с использованием TensorFlow.js. Часть 1 (перевод)

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
02-Мар-2021 00:30


Такие приложения, как Snapchat, предлагают удивительное разнообразие фильтров для лиц и объективов, которые позволяют накладывать интересные эффекты на фотографии и видео. Если вы когда-либо дарили себе виртуальные собачьи уши или праздничную шляпу, вы знаете, насколько это может быть весело! Задумывались ли вы о возможности создания таких фильтров с нуля? Что ж, теперь у вас есть возможность научиться всему, используя только веб-браузер! В этой серии статей мы узнаем, как создавать в браузере фильтры в стиле Snapchat, обучать модель искусственного интеллекта (ИИ) понимать выражения лиц и добиваться ещё большего, используя библиотеку Tensorflow.js и отслеживание лиц. Вы можете загрузить демоверсию этого проекта. Для обеспечения необходимой производительности может потребоваться включить в веб-браузере поддержку интерфейса WebGL. Вы также можете загрузить код и файлы для этой серии. Предполагается, что вы знакомы с JavaScript и HTML и имеете хотя бы базовое представление о нейронных сетях. Первый шаг к созданию фильтра для лиц с нуля – это обнаружение и локализация лиц на изображениях. Поэтому мы можем начать отсюда.Лица можно отслеживать с помощью библиотеки TensorFlow.js и модели обнаружения ориентиров лиц, которая за пару миллисекунд может дать нам 486 различных ключевых точек в пространстве для каждого лица на изображении или в видеокадре. Особенно замечательно то, что эта модель может работать в рамках веб-страницы, поэтому вы также сможете отслеживать лица на мобильных устройствах, используя тот же код.Давайте настроим проект, чтобы загрузить модель и запустить отслеживание лиц в видеопотоке с веб-камеры.Отправная точкаВот начальный шаблон веб-страницы, который мы будем использовать для отслеживания лиц.Этот шаблон содержит:
  • библиотеки TensorFlow.js, необходимые для этого проекта;
  • индекс эталонной сетки для лица, заданный в файле triangles.js (включён в код проекта);
  • элемент canvas для визуализированных выходных данных;
  • скрытый элемент video для веб-камеры;
  • текстовый элемент статуса и служебная функция setText;
  • служебные функции drawLine и drawTriangle для элементов canvas.
<html>
    <head>
        <title>Real-Time Face Tracking in the Browser with TensorFlow.js</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>
        <script src="web/triangles.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>
        <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();
        }
        function drawTriangle( ctx, x1, y1, x2, y2, x3, y3 ) {
            ctx.beginPath();
            ctx.moveTo( x1, y1 );
            ctx.lineTo( x2, y2 );
            ctx.lineTo( x3, y3 );
            ctx.lineTo( x1, y1 );
            ctx.stroke();
        }
        (async () => {
            // TODO: Add code here
        })();
        </script>
    </body>
</html>
Использование API веб-камеры в HTML5 с TensorFlow.jsВ JavaScript довольно просто запустить веб-камеру, если у вас есть для неё фрагмент кода. Вот служебная функция запуска веб-камеры и запроса доступа у пользователя:
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();
        }
    });
}
Мы можем вызвать функцию setupWebcam в блоке async в нижней части нашего кода и заставить её воспроизводить видео веб-камеры после загрузки.
(async () => {
    await setupWebcam();
    const video = document.getElementById( "webcam" );
    video.play();
})();
Затем давайте настроим выходной элемент canvas и подготовимся к рисованию линий и треугольников для ограничивающего прямоугольника и каркаса лица.Контекст canvas будет использоваться для вывода результатов отслеживания лиц, поэтому мы можем сохранить их глобально за пределами блока async. Обратите внимание, что мы зеркально отразили изображение веб-камеры по горизонтали, чтобы поведение было более естественным, как в настоящем зеркале.
let output = null;
(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;
})();
Давайте отследим некоторые лицаТеперь мы готовы! Всё, что нам нужно, это загрузить модель обнаружения ориентиров лица TensorFlow и применить её к кадрам нашей веб-камеры, чтобы показать результаты.Во-первых, нам нужна глобальная переменная model для сохранения загруженной модели:
let model = null;
Затем мы можем загрузить модель в конец блока async и задать текст статуса, чтобы указать на готовность нашего приложения для отслеживания лиц:
// Load Face Landmarks Detection
model = await faceLandmarksDetection.load(
    faceLandmarksDetection.SupportedPackages.mediapipeFacemesh
);
setText( "Loaded!" );
Теперь давайте создадим функцию trackFace, которая принимает видеокадры веб-камеры, применяет модель отслеживания лиц, копирует изображение веб-камеры в выходной элемент canvas, а затем рисует ограничивающий прямоугольник вокруг лица и треугольники сетки каркаса поверх лица.
async function trackFace() {
    const video = document.getElementById( "webcam" );
    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
    );
    faces.forEach( face => {
        setText( `Face Tracking Confidence: ${face.faceInViewConfidence.toFixed( 3 )}` );
        // Draw the bounding box
        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;
        drawLine( output, x1, y1, x2, y1 );
        drawLine( output, x2, y1, x2, y2 );
        drawLine( output, x1, y2, x2, y2 );
        drawLine( output, x1, y1, x1, y2 );
        // Draw the face mesh
        const keypoints = face.scaledMesh;
        for( let i = 0; i < FaceTriangles.length / 3; i++ ) {
            let pointA = keypoints[ FaceTriangles[ i * 3 ] ];
            let pointB = keypoints[ FaceTriangles[ i * 3 + 1 ] ];
            let pointC = keypoints[ FaceTriangles[ i * 3 + 2 ] ];
            drawTriangle( output, pointA[ 0 ], pointA[ 1 ], pointB[ 0 ], pointB[ 1 ], pointC[ 0 ], pointC[ 1 ] );
        }
    });
    requestAnimationFrame( trackFace );
}
Наконец, мы можем запустить первый кадр для отслеживания, вызвав эту функцию в конце нашего блока async:
(async () => {
    ...
    trackFace();
})();
Финишная прямаяПолный код должен выглядеть так:
<html>
    <head>
        <title>Real-Time Face Tracking in the Browser with TensorFlow.js</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>
        <script src="web/triangles.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>
        <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();
        }
        function drawTriangle( ctx, x1, y1, x2, y2, x3, y3 ) {
            ctx.beginPath();
            ctx.moveTo( x1, y1 );
            ctx.lineTo( x2, y2 );
            ctx.lineTo( x3, y3 );
            ctx.lineTo( x1, y1 );
            ctx.stroke();
        }
        let output = null;
        let model = null;
        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();
                }
            });
        }
        async function trackFace() {
            const video = document.getElementById( "webcam" );
            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
            );
            faces.forEach( face => {
                setText( `Face Tracking Confidence: ${face.faceInViewConfidence.toFixed( 3 )}` );
                // Draw the bounding box
                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;
                drawLine( output, x1, y1, x2, y1 );
                drawLine( output, x2, y1, x2, y2 );
                drawLine( output, x1, y2, x2, y2 );
                drawLine( output, x1, y1, x1, y2 );
                // Draw the face mesh
                const keypoints = face.scaledMesh;
                for( let i = 0; i < FaceTriangles.length / 3; i++ ) {
                    let pointA = keypoints[ FaceTriangles[ i * 3 ] ];
                    let pointB = keypoints[ FaceTriangles[ i * 3 + 1 ] ];
                    let pointC = keypoints[ FaceTriangles[ i * 3 + 2 ] ];
                    drawTriangle( output, pointA[ 0 ], pointA[ 1 ], pointB[ 0 ], pointB[ 1 ], pointC[ 0 ], pointC[ 1 ] );
                }
            });
            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
            );
            setText( "Loaded!" );
            trackFace();
        })();
        </script>
    </body>
</html>
Можно ли с помощью отслеживания лиц добиться большего?Объединив модель обнаружения ориентиров лица TensorFlow с видео с веб-камеры, мы смогли отслеживать лица в режиме реального времени прямо в браузере. Наш код отслеживания лиц также работает с изображениями, а ключевые моменты могли бы сказать нам больше, чем мы могли бы ожидать. Может быть, нам следует попробовать применить этот код к набору данных лиц, например FER+ Facial Expression Recognition (распознавание выражений лиц)?В следующей статье этой серии мы используем глубокое обучение на отслеженных лицах из набора данных FER+ и попытаемся точно определить эмоции человека по точкам лица в браузере с помощью TensorFlow.js. До встречи завтра, в это же время.

Узнайте подробности, как получить Level Up по навыкам и зарплате или востребованную профессию с нуля, пройдя онлайн-курсы SkillFactory со скидкой 40% и промокодом HABR, который даст еще +10% скидки на обучение. Другие профессии и курсыПРОФЕССИИ КУРСЫ
===========
Источник:
habr.com
===========

===========
Автор оригинала: Raphael Mun
===========
Похожие новости: Теги для поиска: #_javascript, #_programmirovanie (Программирование), #_html, #_tensorflow, #_skillfactory, #_html, #_javascript, #_raspoznavanie_lits (распознавание лиц), #_tensorflow, #_lajfhaki (лайфхаки), #_programmirovanie (программирование), #_blog_kompanii_skillfactory (
Блог компании SkillFactory
)
, #_javascript, #_programmirovanie (
Программирование
)
, #_html, #_tensorflow
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 25-Ноя 07:17
Часовой пояс: UTC + 5