Мне всегда нравится применять новые инструменты к существующим рабочим процессам. Меня вдохновляет соединение идей из разных областей. Веселья мне как раз достаточно, чтобы тратить время на разработку. С этой точки зрения создание игры на основе распознавания лиц пришло мне в голову, когда я изучал 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 или подпишитесь на блог из поля ниже. До следующего поста… Лучшее.

АБЕ.