Мне всегда нравится применять новые инструменты к существующим рабочим процессам. Меня вдохновляет соединение идей из разных областей. Веселья мне как раз достаточно, чтобы тратить время на разработку. С этой точки зрения создание игры на основе распознавания лиц пришло мне в голову, когда я изучал JS-фреймворк.
Изучить язык программирования или фреймворк, как правило, несложно. Существуют хорошо структурированные онлайн-курсы, которые утверждают, что помогут вам с нуля стать героем. Но когда вы их выполните, у вас будет только цифровой сертификат или новый пункт в вашем резюме. Как насчет того, чтобы преобразовать свои знания в опыт?
Работая над найденной вами идеей, вы лучше понимаете то, чему научились, и применяете это, не следуя никаким инструкциям. В тот момент я решил создать мини-игру, когда изучал основы ReactJS. На самом деле React — это фреймворк общего назначения для создания пользовательских интерфейсов. Поэтому он явно не предназначен для приложений ИИ, но это нормально. Создание любой уникальной вещи с помощью изученного инструмента предпочтительнее.
Некоторые из вас могут знать серию Youtube под названием Soğuk Savaş. В которой два игрока по очереди задают друг другу неудобные вопросы. Если игрок не смеется, когда объявляется смешной ответ, он выигрывает. Я понял, когда мы смотрим ролики, мы тоже стараемся не смеяться. Если компьютер сможет распознать наши улыбающиеся лица, мы сможем играть без реального игрока.
Я начал искать API распознавания лиц с помощью Javascript и решил использовать face-api.js. Это модуль javascript, построенный поверх ядра tensorflow.js, который реализует несколько CNN (сверточных нейронных сетей) для решения проблем, связанных с лицами в Интернете.
Моя цель состояла в том, чтобы определить лицо через веб-камеру и понять, улыбается человек или нет во время игры. Этот API превзошел все мои ожидания. Он также обеспечивает процент улыбки.
В моем приложении React я импортировал face-api и другие библиотеки, связанные с дизайном.
import React, { useState } from ‘react’; import useInterval from ‘./customHooks/useInterval’; import * as faceapi from ‘face-api.js’ import stepsDB from ‘./data/steps.json’; import Button from ‘react-bootstrap/Button’; import ‘bootstrap/dist/css/bootstrap.min.css’; import ‘./App.css’; import ‘typeface-roboto’;
Включение моделей faceExpressionNet tinyFaceDetector достаточно для моей цели. Потоковая передача с веб-камеры включается после загрузки моделей.
Promise.all([ faceapi.nets.tinyFaceDetector.loadFromUri(‘./models’), faceapi.nets.faceExpressionNet.loadFromUri(‘./models’) ]).then(startVideo); function startVideo() { navigator.getUserMedia( { video: {} }, stream => video.srcObject = stream, err => console.error(err) ) }
В начале приложения определяются состояния.
const timeStep = 5000; //milliseconds const tickInterval = 250; const [gameStatus, setGameStatus] = useState(‘initial’); //’initial’, ‘playing, ‘win’, ‘fail’ const [smilePercent, setSmilePercent] = useState(0); //0–1 const [step, setStep] = useState({ id: 0, question: ‘’, answer: ‘’ }); const [answerVisibility, setAnswerVisibility] = useState(false); //true, false const [remainingTime, setRemainingTime] = useState(timeStep); const [remainingTimeStarted, setRemainingTimeStarted] = useState(false);
По сути, когда игроку показывают неудобные вопросы, он проверяет процент улыбающихся через веб-камеру каждые 250 миллисекунд. Когда частота улыбок достигла 0,3 порога, я решил, что игрок достаточно улыбается, и игрок терпит неудачу. Если он/она ответит на все вопросы без смеха, он/она выиграет игру.
useInterval(async () => { if (gameStatus === ‘initial’ || gameStatus === ‘playing’ ) { if (!video.srcObject) return; const detections = await faceapi.detectAllFaces(video, new faceapi.TinyFaceDetectorOptions()).withFaceExpressions(); if (detections.length) { detections.forEach(detection => { setSmilePercent(detection.expressions.happy); if (smilePercent > 0.3 && gameStatus === ‘initial’) start(); if (answerVisibility && smilePercent > 0.2 && remainingTimeStarted) { setAnswerVisibility(false); setRemainingTimeStarted(false); setRemainingTime(timeStep); setGameStatus(‘fail’); } }); } if (answerVisibility) { if (remainingTime <= 0) { setAnswerVisibility(false); setRemainingTimeStarted(false); setRemainingTime(timeStep); goNextStep(); } else setRemainingTime(remainingTime => remainingTime — tickInterval); } } }, tickInterval); function start() { steps = stepsDB.slice(0); const randomIndex = Math.floor(Math.random() * steps.length); const nextStep = steps.splice(randomIndex, 1).pop(); setStep(nextStep); setGameStatus(‘playing’); } function showAnswer() { setAnswerVisibility(true); setRemainingTimeStarted(true); } function goNextStep() { if (steps.length === 0) { setGameStatus(‘win’); return; } const randomIndex = Math.floor(Math.random() * steps.length); const nextStep = steps.splice(randomIndex, 1).pop(); setStep(nextStep); } return…
Это на самом деле так просто и около сотни строк кода. Но делать и тестировать интересно. Я собрал вопросы и ответы из видео, набрав их вручную. Хотя смотреть эти ролики тоже весело. Другой модуль может автоматически определять текст из видео для хранения базы данных вопросов и ответов.
Контент игры на турецком языке, так как у меня есть доступ только к турецкому набору данных. Это может быть добавлено к любому языку позже. Я поделился кодом из моего репозитория GitHub, и вы также можете воспроизвести его по демо-ссылке ниже.
Ссылка на демоверсию: https://try-not-to-laugh.netlify.app/
Код: https://github.com/ahmetbersoz/try-not-to-laugh
Я планирую поделиться проектами, которые я сделал просто для удовольствия, через свой блог. Подпишитесь на меня с моего адреса в Твиттере @ahmetbersoz или подпишитесь на блог из поля ниже. До следующего поста… Лучшее.
АБЕ.