От автора: когда мы смотрим фильмы, действие которых происходит в будущем, мы часто видим, как персонажи смотрят на экран компьютера, пытаясь отсканировать лица людей, таких как преступники, или тех, кого они хотят преследовать. Прямо сейчас технология распознавания лиц настолько развита, что это стало реальностью. Мы можем создавать приложения, которые могут распознавать лица с большой точностью. Это больше не что-то из области научной фантастики.
Чтобы создать приложение для распознавания лиц, мы можем использовать такую библиотеку, как, face-api.js, расположенную по адресу https://github.com/justadudewhohacks/face-api.js/. Работает как в браузере, так и на Node.js. Вы используете его, обучая Tensorflow с помощью изображений, чтобы генерировать тестовые данные, которые загружаете в приложение, а затем оно сможет распознавать лица. Генерация данных выходит за рамки этой статьи, но вы можете загрузить предустановленные данные. По ссылке выше есть папка weights, которую вы можете использовать в своем приложении.
В этой статье мы создадим простое приложение для распознавания лиц, которое пользователи могут использовать для определения эмоций лица, пола и возраста человека. Мы будем использовать для сборки приложения Vue.js вместе с библиотекой face-api.js. Чтобы начать, мы запускаем Vue CLI, выполнив npx @vue/cli create facial-recognition-app. В мастере мы выбираем «Выбор объектов вручную», затем выбираем Babel, препроцессоры CSS, Vuex и Vue Router.
Теперь нам нужно установить библиотеки. В дополнение к face-api.js нам также требуется Axios для выполнения запросов к бэк-энд и BootstrapVue для стилизации. Чтобы установить их, мы запускаем:
npm i axios bootstrap-vue face-api.js
Теперь мы переходим к разработке приложения. Создайте папку mixins в каталоге src, а затем создайте файл с именем requestsMixin.js. В него добавьте:
const APIURL = "http://localhost:3000"; const axios = require("axios");export const requestsMixin = { methods: { getImages() { return axios.get(`${APIURL}/images`); }, addImage(data) { return axios.post(`${APIURL}/images`, data); }, editImage(data) { return axios.put(`${APIURL}/images/${data.id}`, data); }, deleteImage(id) { return axios.delete(`${APIURL}/images/${id}`); } } };
Здесь у нас есть функции для отправки запросов к бэк-энд для сохранения изображений, которые мы настроим позже. Затем Home.vue замените существующий код на:
<template> <div class="page"> <h1 class="text-center">Images</h1> <div class="clearfix"> <b-button-toolbar class="button-toolbar float-left"> <input type="file" style="display: none" ref="file" @change="onChangeFileUpload($event)" /> <b-button variant="primary" @click="$refs.file.click()">Upload Images</b-button> </b-button-toolbar> <img ref="image" :src="form.image" class="photo float-left" /> </div> <div v-if="loaded"> <b-card v-for="(img, index) in images" :key="img.id"> <div class="row"> <div class="col-md-6"> <img :src="img.image" img-alt="Image" class="photo" :ref="`photo-${index}`" /> </div> <div class="col-md-6"> <h3>Faces</h3> <b-list-group> <b-list-group-item v-for="(d, i) of img.detections" :key="i"> <h4>Face {{i + 1}}</h4> <ul class="detection"> <li>Age: {{d.age.toFixed(0)}}</li> <li>Gender: {{d.gender}}</li> <li>Gender Probability: {{(d.genderProbability*100).toFixed(2)}}%</li> <li> Expressions: <ul> <li v-for="key of Object.keys(d.expressions)" :key="key" >{{key}}: {{(d.expressions[key]*100).toFixed(2)}}%</li> </ul> </li> </ul> </b-list-group-item> </b-list-group> </div> </div> <br /> <b-button variant="primary" @click="detectFace(index)">Detect Face</b-button> <b-button variant="danger" @click="deleteOneImage(img.id)">Delete</b-button> </b-card> </div> <div v-else> <p>Loading image data...</p> </div> </div> </template><script> import { requestsMixin } from "@/mixins/requestsMixin"; import * as faceapi from "face-api.js"; const axios = require("axios"); const WEIGHTS_URL = "http://localhost:8081/weights";export default { name: "home", mixins: [requestsMixin], computed: { images() { return this.$store.state.images; } }, async beforeMount() { await faceapi.loadTinyFaceDetectorModel(WEIGHTS_URL); await faceapi.loadFaceLandmarkTinyModel(WEIGHTS_URL); await faceapi.loadFaceLandmarkModel(WEIGHTS_URL); await faceapi.loadFaceRecognitionModel(WEIGHTS_URL); await faceapi.loadFaceExpressionModel(WEIGHTS_URL); await faceapi.loadAgeGenderModel(WEIGHTS_URL); await faceapi.loadFaceDetectionModel(WEIGHTS_URL); await this.getAllImages(); this.loaded = true; }, data() { return { form: {}, loaded: false }; }, methods: { async deleteOneImage(id) { await this.deleteImage(id); this.getAllImages(); }, async getAllImages() { const { data } = await this.getImages(); this.$store.commit("setImages", data); if (this.$refs.file) { this.$refs.file.value = ""; } }, onChangeFileUpload($event) { const file = $event.target.files[0]; const reader = new FileReader(); reader.onload = async () => { this.$refs.image.src = reader.result; this.form.image = reader.result; await this.addImage(this.form); this.getAllImages(); this.form.image = ""; }; reader.readAsDataURL(file); }, async detectFace(index) { const input = this.$refs[`photo-${index}`][0]; const options = new faceapi.TinyFaceDetectorOptions({ inputSize: 128, scoreThreshold: 0.3 }); const detections = await faceapi .detectAllFaces(input, options) .withFaceLandmarks() .withFaceExpressions() .withAgeAndGender() .withFaceDescriptors(); this.images[index].detections = detections; await this.editImage(this.images[index]); this.getAllImages(); } } }; </script><style> .photo { max-width: 200px; margin-bottom: 10px; } </style>
Вот где происходит магия распознавания изображений. В хук beforeMount мы загружаем все данные, необходимые для face-api.js для распознавания лиц. WEIGHTS_URL — это просто папка weights из репозитория https://github.com/justadudewhohacks/face-api.js/, обслуживаемая HTTP-сервером. С помощью этой ссылки мы можем загрузить весь репозиторий в Zip-файл и извлечь из него папку weights. Затем загрузите http-server, запустив npm i -g http-server. Перейдите в папку weights и запустите http-server —cors, чтобы мы не получали ошибки CORS. Обратите внимание, что загрузка файлов может занять несколько секунд.
В шаблоне у нас есть кнопка «Загрузить изображения» для загрузки изображения. При нажатии откроется диалоговое окно загрузки файла, а затем будет вызвано onChangeFileUpload для преобразования его в строку base64, которая затем сохраняется на сервере. Обратите внимание, что это сделано только для того, чтобы приложение было простым. В производственных целях его, вероятно, следует сохранить в файл с внутренним приложением.
Когда изображение будет загружено, оно будет отображаться на карточках. Каждая карточка будет иметь кнопку «Определить лицо». При нажатии вызывается функция detectFace, которая запускает вызывающую функцию распознавания лица face-api.js detectAllFaces. Обратите внимание, что, прежде чем выполнять распознавание лиц, мы использовали TinyFaceDetectorOptions для сжатия изображений, чтобы ускорить его. Мы объединяем функции, начинающиеся с with, чтобы получить представление, понятное человеку. Когда это будет сделано, будут загружены карточки с результатами.
Затем App.vue заменит существующий код на:
<template> <div id="app"> <b-navbar toggleable="lg" type="dark" variant="info"> <b-navbar-brand to="/">Facial Recognition App</b-navbar-brand><b-navbar-toggle target="nav-collapse"></b-navbar-toggle><b-collapse id="nav-collapse" is-nav> <b-navbar-nav> <b-nav-item to="/" :active="path == '/'">Home</b-nav-item> </b-navbar-nav> </b-collapse> </b-navbar> <router-view /> </div> </template><script> export default { data() { return { path: this.$route && this.$route.path }; }, watch: { $route(route) { this.path = route.path; } } }; </script><style lang="scss"> .page { padding: 20px; margin: 0 auto; }button, .btn.btn-primary { margin-right: 10px !important; }.button-toolbar { margin-bottom: 10px; } </style>
Это добавляет панель навигации Bootstrap вверху страниц, и отображение router-view маршрутов, которые мы определили. Далее в main.js замените код на:
import Vue from 'vue' import App from './App.vue' import router from './router' import store from './store' import BootstrapVue from "bootstrap-vue"; import "bootstrap/dist/css/bootstrap.css"; import "bootstrap-vue/dist/bootstrap-vue.css"; Vue.use(BootstrapVue);Vue.config.productionTip = falsenew Vue({ router, store, render: h => h(App) }).$mount('#app')
Это добавляет библиотеки, которые мы установили в приложении, чтобы мы могли использовать их в компонентах. В router.js, мы заменим существующий код на:
import Vue from "vue"; import Router from "vue-router"; import Home from "./views/Home.vue";Vue.use(Router);export default new Router({ mode: "history", base: process.env.BASE_URL, routes: [ { path: "/", name: "home", component: Home } ] });
Это включает в себя главную страницу и страницы поисков. Затем в store.js мы заменим существующий код на:
import Vue from "vue"; import Vuex from "vuex";Vue.use(Vuex);export default new Vuex.Store({ state: { images: [] }, mutations: { setImages(state, payload) { state.images = payload; } }, actions: {} });
Это добавляет состояние images в хранилище, чтобы мы могли наблюдать его в блоке computed HomePage. У нас есть функция setImages для обновления состояния passwords, мы используем ее в компонентах, вызывая, this.$store.commit(“setImages”, data); как мы это делали для HomePage.
Наконец, в index.html замените существующий код на:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width,initial-scale=1.0" /> <link rel="icon" href="<%= BASE_URL %>favicon.ico" /> <title>Facial Detection App</title> </head> <body> <noscript> <strong >We're sorry but vue-face-api-tutorial-app doesn't work properly without JavaScript enabled. Please enable it to continue.</strong > </noscript> <div id="app"></div> <!-- built files will be auto injected --> </body> </html>
Это меняет заголовок.
Теперь мы можем запустить приложение, выполнив npm run serve. Чтобы запустить серверную часть, мы сначала устанавливаем пакет json-server, выполнив npm i json-server. Затем перейдите в папку проекта и запустите:
json-server --watch db.json
В db.json измените текст на:
{ "images": [ ] }
Таким образом, у нас есть конечные точки images, определенные в requests.js. И мы получаем следующее:
Как вы можете видеть, face-api.js довольно точно определяет пол и выражение лица — как мужского, так и женского. Возраст также определился довольно близко к тому, чего вы ожидаете. Это интересно, учитывая, что для создания этого приложения была проделана не такая уж большая работа. Спасибо разработчикам face-api.js.
Автор: John Au-Yeung
Источник: https://levelup.gitconnected.com
Редакция: Команда webformyself.