blog posts

JavaScript ve React ile yüz tanıma

JavaScript yüz tanıma “Yüz Algılama” ve “Yüz Tanıma” günümüzde birçok araştırmacının ve büyük, orta ve küçük ölçekli işletmelerin ilgisini çeken önemli ve sıcak konulardır. Bu yazıda “React” ve “face-api.js” kullanılarak yüz tanıma yöntemi incelenmiştir. JavaScript ve React ile yapılan yüz tanıma yazısında, muhtemelen insan gözüyle bile tanınması zor olan yüz tanıma görevini gerçekleştirmek için bir müzik grubunun üyelerinin görselleri kullanılıyor.

JavaScript ve React ile yüz tanıma

Devamında JavaScript ve React ile yüz tanıma konusu incelenmektedir. “face-api.js”, “TensorFlow.js” ile çalışan yüz algılama ve yüz tanıma için bir “Uygulama Programlama Arayüzü”dür (Uygulama Programlama Arayüzü) . Artık bu API kullanılarak tüm “Derin Öğrenme” işlemlerini arka uç koduna ihtiyaç duymadan tarayıcı üzerinde yapmak mümkün .

Artık herhangi bir arka uç kodu veya ortam yapılandırması olmadan, yalnızca statik bir web sunucusuna sahip olarak, React ve TensorFlow ile yüz tanımaya sahip olmak ve bunu herhangi bir cihaz veya tarayıcıda çalıştırmak mümkündür. Tabii ki, tarayıcı TensorFlow.js’yi çalıştırabilmelidir. Bu makalenin sonunda, bu React uygulamasının GitHub sayfasında nasıl dağıtılacağı öğretildi.

Daha önce bahsedildiği gibi, burada React ve ace-api.js yüz tanıma kitaplığı kullanılarak tek sayfalık bir yüz tanıma uygulamasının uygulanması yer almaktadır. Bu API, önceden eğitilmiş bir yüz tanıma sistemiyle Yüz İşaretlerini ve Yüz Hizalamasını algılar. Bu nedenle, TensorFlow’da derin bir öğrenme modeli yazmaya gerek yoktur .

JavaScript ve React ile yüz tanıma — pratik bir kılavuz

Aslında, kullanıcının derin öğrenmeye veya Konvolüsyonel Sinir Ağlarına gerçekten aşina olması gerekmez . Kullanıcının bilmesi gereken tek şey JavaScript ve React’in temel kavramlarıdır. JavaScript öğrenmek için ” JavaScript Eğitimi – Kapsamlı bir Faradar blog makaleleri koleksiyonu ” makalesini okumanız önerilir . Ayrıca React’i öğrenmek için aşağıdaki içeriği okumanız önerilir.

  • React : kapsamlı bir başlangıç ​​kılavuzu
  • Tepki eğitimi : Faradars dergisi makalelerinden oluşan bir koleksiyon

Bu makalede uygulanan kod çok basittir ve öğrenme konusunda endişelenmenize gerek yoktur. Ayrıca kodun farklı bölümleri hakkında gerekli açıklamalar eksiksiz olarak yapılmıştır.

Yüz tanımanın kısa bir açıklaması

JavaScript ve React ile yüz tanımanın bu bölümünde, yüz tanıma hakkında kısa açıklamalar yapılır. Bir kişinin bir devlet dairesine gittiği varsayılır. İlgili görevli, kişinin belgelerinin bir kopyasını alır. Kişinin kendisi olduğunu kanıtlamasını ister. Bu amaçla kişi, nüfus cüzdanı veya nüfus cüzdanı gibi kimlik kartını ibraz eder. Görevli, kişinin kimlik kartındaki adını ve resmini görür ve karşısında oturan kişiyle karşılaştırır. Ayrıca daha gelişmiş bir modda kimlik kartında yazan ismi sisteme girerek kimlik kartının doğru olduğundan emin oluyor ve ardından kişinin yüzünü kimlik kartındaki görüntü ile karşılaştırıyor.

Aynı şekilde yüz tanıma sisteminde de kişinin yüz bilgisi ile birlikte ismi de saklanmaktadır. Bu nedenle, kişinin başka bir görüntüsü sisteme verildiğinde, görüntüye sahip olan kişinin bilgilerinin kendi veritabanında olup olmadığını belirlemeye çalışır ve varsa kişinin adını veya tam profilini alır. Bu çalışma, Yüz Algılama Ağı tarafından yapılır. Bu projede yüz tanıma için kullanılan modelin adı Tiny Face Detector. Bu ismin alınmasının nedeni ise küçük boyutu ve mobil uyumlu olmasıdır. Bu projede kullanılan API ayrıca yüz tanıma için bir SSD mobileNet ve MTCNN kullanır; Ama şu anda tartışılmayacak.

Tıpkı bir parmak izi gibi, Yüz Tanımlayıcı da her yüz için benzersiz bir değerdir. Çeşitli görüntülerde belirli bir kişi için Yüz Tanımlayıcı çok yakın ve benzer değerlere sahiptir. Bu projede, karşılaştırma için Öklid Mesafesi kullanılmıştır. Aradaki mesafe belirlenen eşikten az ise iki görüntünün aynı kişiye ait olduğu anlaşılabilir. Mesafe ne kadar küçük olursa, güvenin o kadar yüksek olduğuna dikkat edilmelidir.

 Bu materyallerden bazıları, ilgilenenlerin okuması için aşağıda sunulmuştur:

  • OpenCV ve Dlib ile Python’da yüz tanıma — sıfırdan yüze
  • JavaScript API ile tarayıcıda yüz tanıma — basit terimlerle
  • MATLAB’da yüz tanıma sisteminin uygulanması – pratik rehber
  • Chrome Yüz Tanıma API’sı — Uygulama Kılavuzu
  • Flutter ile yüz tanıma — pratik bir kılavuz
  • Excel kullanarak Gelişmiş Yüz Tanıma — sade bir dille
  • Yüz Gülümsemesi Algılama—Uygulamalı Bir Kılavuz

Aşağıdaki makalede, yüz tanıma sistemini uygulamak için JavaScript ve React ile yüz tanıma kullanılacaktır.

JavaScript ve React ile yüz tanıma sisteminin uygulanması

JavaScript ve React ile yüz tanıma yazımızın bu bölümünde JavaScript ve React ile yüz tanıma sisteminin implementasyonu incelenmektedir. Bu programda uygulanması amaçlanan iki işlev vardır. Bu işlevlerden biri, bir giriş görüntüsünden bir yüzü tanımak için kullanılır ve diğeri, bir giriş canlı videosundan bir kişinin yüzünü tanır. Create-react-app ile başlar, react-router-dom’u kurar ve uygulamayı başlatır.

npx create-react-app react-face-recognition
cd react-face-recognition
npm i react-router-dom
npm start

Şimdi tarayıcıyı açın ve http://localhost:3000/ adresine gidin. Kullanıcı, sayfa açıldığında React logosunu görüyorsa bu, çalışmaya devam etmek için koşulların hazır olduğu anlamına gelir. Şimdi, kullanıcı proje klasörünü istediği herhangi bir editörle açmalıdır. Çıktı, aşağıdaki ağaç yapısı gibi görünmelidir.

tepki yüz tanıma
├── BENİOKU.md
├── düğüm_modülleri
├── package.json
├── .gitignore
├── herkese açık
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json
└── kaynak
    ├── Uygulama.css
    ├── Uygulama.js
    ├── Uygulama.test.js
    ├── index.css
    ├── index.js
    ├── logosu.svg
    └── serviceWorker.js

Şimdi src/App.js adresine gidin ve mevcut kodu aşağıdaki kodla değiştirin.

import React, { Component } from 'react';
import { Route, Router } from 'react-router-dom';
import createHistory from 'history/createBrowserHistory';
import './App.css';

import Home from './views/Home';

class App extends Component {
  render() {
    return (
      <div className="App">
        <Router history={createHistory()}>
          <div className="route">
            <Route exact path="/" component={Home} />
          </div>
        </Router>
      </div>
    );
  }
}

export default App;

Burada olan sadece Ana Sayfa bileşenini içe aktarmak ve açılış sayfası olarak “/” ye bir “Rota” oluşturmaktır. Bu bileşen hızlı bir şekilde oluşturulmuştur. Bu, yeni bir src/views klasörü oluşturarak ve bu klasör içinde yeni bir Home.js dosyası oluşturarak yapılır. Daha sonra aşağıdaki kodu dosyaya koyun ve dosyayı kaydedin.

import React, { Component } from 'react';
import { Link } from 'react-router-dom';

export default class Home extends Component {
  render() {
    return (
      <div>
        <h2>BNK48 Facial Recognition App</h2>
        <li>
          <Link to="/photo">Photo Input</Link>
        </li>
        <li>
          <Link to="/camera">Video Camera</Link>
        </li>
      </div>
    );
  }
}

Burada, “localhost:3000/photo” bağlantısı olan Fotoğraf Girişi için ve “localhost:3000/camera” bağlantısı olan Video Kamera için iki bağlantı oluşturulur. Her şey yolunda giderse, kullanıcı aşağıdakine benzer bir sayfa görmelidir.

JavaScript ve React ile yüz tanıma — pratik bir kılavuz

Yüz tanıma veya Yüz API’si için JavaScript uygulama programlama arabirimi

JavaScript ve React ile yüz tanımanın bu bölümünde ve yeni bir sayfa oluşturma çalışmasına devam etmeden önce, face-api.js’nin yüklenmesi ve API kullanılarak React’e bağlanmak için API dosyasının oluşturulması gerekir. Şimdi konsola geri dönelim ve kütüphane kurulacaktır.

npm i face-api.js

Kitaplık, TensorFlow.js ve model ağırlıkları dışında ihtiyaç duyduğu tüm bileşenlerle birlikte gelir. Model vızıltı kavramına aşina olmayan kullanıcılar için aşağıda açıklamalara yer verilmiştir. Modelin ağırlıkları aslında büyük bir veri seti ile eğitilmiş “sinir ağı” nın ağırlıklarıdır . Bu makalede yapılan örnek olay incelemesinde, veri kümesi aslında binlerce insan yüzü görüntüsüdür.

Halihazırda birçok kişinin modeli eğittiği göz önüne alındığında, burada ihtiyaç duyulan tek şey, kullanılacak ağırlıkları manuel olarak elde etmek ve projeye yerleştirmektir. Bu API için tüm ağırlıklar buradan [ + ] elde edilebilir.

Şimdi, tüm model ağırlıklarını içine koymak için yeni bir public/models klasörü oluşturulacak. Ardından, gerekli tüm ağırlıklar klasörden indirilir. Daha önce de bahsedildiği gibi burada Tiny Face Detector modeli kullanılmaktadır. Bu nedenle SSD MobileNet ve MTCNN modellerine gerek yoktur. Tüm ağırlıkların aşağıda gösterildiği gibi genel/modeller klasöründe olduğundan emin olun. Aksi takdirde modeller uygun ağırlıklar olmadan düzgün çalışmayacaktır.

tepki yüz tanıma
├── BENİOKU.md
├── düğüm_modülleri
├── package.json
├── .gitignore
├── herkese açık
│ ├── modeller
│ │ ├── face_landmark_68_tiny_model-shard1
│ │ ├── face_landmark_68_tiny_model-weights_manifest.json
│ │ ├── face_recognition_model-shard1
│ │ ├── face_recognition_model-shard2
│ │ ├── face_recognition_model-weights_manifest.json
│ │ ├── tiny_face_detector_model-shard1
│ │ └── tiny_face_detector_model-weights_manifest.json
│ ├── favicon.ico
│ ├── index.html
│ └── manifest.json

Şimdi geri dönün ve API için src/api olarak yeni bir klasör ve bu klasörün içinde yeni bir face.js dosyası oluşturun. Burada yapılacak olan, modeli yüklemek ve API’yi beslemek için bir işlev oluşturmak ve tüm yüz tanımlayıcıları döndürmenin yanı sıra yüz tanıma için tanımlayıcıları karşılaştırmaktır.

Bu işlevler dışa aktarılır ve daha sonra React Components’ta kullanılır:

import * as faceapi from 'face-api.js';

// Load models and weights
export async function loadModels() {
  const MODEL_URL = process.env.PUBLIC_URL + '/models';
  await faceapi.loadTinyFaceDetectorModel(MODEL_URL);
  await faceapi.loadFaceLandmarkTinyModel(MODEL_URL);
  await faceapi.loadFaceRecognitionModel(MODEL_URL);
}

export async function getFullFaceDescription(blob, inputSize = 512) {
  // tiny_face_detector options
  let scoreThreshold = 0.5;
  const OPTION = new faceapi.TinyFaceDetectorOptions({
    inputSize,
    scoreThreshold
  });
  const useTinyModel = true;

  // fetch image to api
  let img = await faceapi.fetchImage(blob);

  // detect all faces and generate full description from image
  // including landmark and descriptor of each face
  let fullDesc = await faceapi
    .detectAllFaces(img, OPTION)
    .withFaceLandmarks(useTinyModel)
    .withFaceDescriptors();
  return fullDesc;
}

Buradaki bu API dosyasında iki önemli bölüm var. İlki, loadModels() fonksiyonu ile modelleri ve ağırlıkları yüklemektir. Burada sadece Face Landmark Tiny Model, Tiny Face Detector ve Face Recognition modelleri yüklenir.

Diğer kısım, görüntü balonunu girdi olarak alan ve tam yüz açıklamasını döndüren getFullFaceDescription() işlevidir. Bu işlev, görüntü balonunu API’ye “getirmek” için faceapi.fetchImage() API işlevini kullanır.

Ardından, faceapi.detectAllFaces() bu görüntüyü alır ve içindeki tüm yüzleri bulur. Ardından, withFaceLandmarks(), yüz özelliğini Float 32 Dizisi olarak 128 değerden döndürmek için withFaceDescriptors() işlevini kullanmadan önce 68 yüz işaretini eşler .

Giriş görüntüsü için 512 piksel görüntünün, video girişi için daha sonra 160 piksel kullanılacağını belirtmekte fayda var. Bu, API tarafından önerilir. Şimdi, aşağıdaki görüntü yeni src/img klasörüne kaydedilmeli ve test.jpg olarak adlandırılmalıdır. Aslında test görüntüsü olan bu görüntü, uygulamayı test etmek içindir.

JavaScript ve React ile yüz tanıma — pratik bir kılavuz

Aşağıdaki metinde, yeni src/views/ImageInput.js dosyasında JavaScript ve React ile yüz tanıma oluşturulacaktır. Bu dosya, görüntü girdisine ve görüntü dosyasına giden bileşeni temsil eder.

import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import { loadModels, getFullFaceDescription } from '../api/face';

// Import image to test API
const testImg = require('../img/test.jpg');

// Initial State
const INIT_STATE = {
  imageURL: testImg,
  fullDesc: null
};

class ImageInput extends Component {
  constructor(props) {
    super(props);
    this.state = { ...INIT_STATE };
  }

  componentWillMount = async () => {
    await loadModels();
    await this.handleImage(this.state.imageURL);
  };

  handleImage = async (image = this.state.imageURL) => {
    await getFullFaceDescription(image).then(fullDesc => {
      console.log(fullDesc);
      this.setState({ fullDesc });
    });
  };

  render() {
    const { imageURL } = this.state;
    return (
      <div>
        <img src={imageURL} alt="imageURL" />
      </div>
    );
  }
}

export default withRouter(ImageInput);

Bu bileşen, şu anda yalnızca src/img/test.jpg test görüntüsünü görüntüler ve API modellerini tarayıcıya yüklemeye başlar, bu işlem birkaç saniye sürer. Bundan sonra görüntü, tam yüz açıklamasını alan bir API’ye beslenir. Duruma döndürülen fullDesc ileride kullanılmak üzere kaydedilebilir ve console.log’da detaylandırılabilir. Ancak bundan önce ImageInput bileşenini src/App.js dosyasına aktarmanız gerekir. Ayrıca, fotoğraf/ Bu, aşağıdaki kod parçası kullanılarak yapılabilir.

import React, { Component } from 'react';
import { Route, Router } from 'react-router-dom';
import createHistory from 'history/createBrowserHistory';
import './App.css';

import Home from './views/Home';
import ImageInput from './views/ImageInput';

class App extends Component {
  render() {
    return (
      <div className="App">
        <Router history={createHistory()}>
          <div className="route">
            <Route exact path="/" component={Home} />
            <Route exact path="/photo" component={ImageInput} />
          </div>
        </Router>
      </div>
    );
  }
}

export default App;

Şimdi, kullanıcı http://localhost:3000’i ziyaret edip Fotoğraf Girişi’ne tıklarsa, görüntü ekranını görmeleri gerekir. Tarayıcı konsolu işaretlenirse, bu görüntünün Tam Yüz Açıklaması aşağıdaki gibi görünmelidir.

JavaScript ve React ile yüz tanıma — pratik bir kılavuz

Aşağıdaki makalede, JavaScript ve React ile yüz tanıma, yüz tanıma kutusunun çizilmesi tartışılmaktadır.

Yüz tanıma kutusu

Görülebileceği gibi, açıklama, tanımlayıcı ve algılama dahil olmak üzere bu projede ihtiyaç duyulan tüm yüz tanıma bilgilerini içerir. Tespitin içinde koordinatlar gibi kutunun bilgileri xy, üst, alt, sol, sağ, yükseklik, genişlik içerir.

face-api.js kitaplığı, gerçekten kullanışlı olan HTML tuvalini kullanarak görüntü algılama kutusunu çizme işleviyle birlikte gelir. Fakat React kullanıldığını düşünürsek, görüntü algılama kutusu neden CSS ile çizilmiyor? Artık React kullanarak kutu ve ekran tespiti yapmak mümkün.

Kullanıcının şimdi yapacağı şey, yüz kutusunu görüntünün üzerine yerleştirmek için algılama kutusu bilgisini kullanmaktır. Ayrıca uygulama ile tespit edilen her bir yüzün adı üzerinde görüntülenebiliyor. Bu, DrawBox’ın ImageInput bileşenine eklendiği yöntemdir. Ardından giriş etiketi eklenir, böylece giriş görüntüsü değiştirilebilir.

import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import { loadModels, getFullFaceDescription } from '../api/face';

// Import image to test API
const testImg = require('../img/test.jpg');

// Initial State
const INIT_STATE = {
  imageURL: testImg,
  fullDesc: null,
  detections: null
};

class ImageInput extends Component {
  constructor(props) {
    super(props);
    this.state = { ...INIT_STATE };
  }

  componentWillMount = async () => {
    await loadModels();
    await this.handleImage(this.state.imageURL);
  };

  handleImage = async (image = this.state.imageURL) => {
    await getFullFaceDescription(image).then(fullDesc => {
      if (!!fullDesc) {
        this.setState({
          fullDesc,
          detections: fullDesc.map(fd => fd.detection)
        });
      }
    });
  };

  handleFileChange = async event => {
    this.resetState();
    await this.setState({
      imageURL: URL.createObjectURL(event.target.files[0]),
      loading: true
    });
    this.handleImage();
  };

  resetState = () => {
    this.setState({ ...INIT_STATE });
  };

  render() {
    const { imageURL, detections } = this.state;

    let drawBox = null;
    if (!!detections) {
      drawBox = detections.map((detection, i) => {
        let _H = detection.box.height;
        let _W = detection.box.width;
        let _X = detection.box._x;
        let _Y = detection.box._y;
        return (
          <div key={i}>
            <div
              style={{
                position: 'absolute',
                border: 'solid',
                borderColor: 'blue',
                height: _H,
                width: _W,
                transform: `translate(${_X}px,${_Y}px)`
              }}
            />
          </div>
        );
      });
    }

    return (
      <div>
        <input
          id="myFileUpload"
          type="file"
          onChange={this.handleFileChange}
          accept=".jpg, .jpeg, .png"
        />
        <div style={{ position: 'relative' }}>
          <div style={{ position: 'absolute' }}>
            <img src={imageURL} alt="imageURL" />
          </div>
          {!!drawBox ? drawBox : null}
        </div>
      </div>
    );
  }
}

export default withRouter(ImageInput);

React’te CSS kullanarak, tüm resim kutularını bunun gibi bir resme yerleştirmek mümkündür. Daha fazla yüze sahip bir resim kullanılırsa, resim üzerinde daha fazla kutu görülecektir.

JavaScript ve React ile yüz tanıma — pratik bir kılavuz

Yüz tanıma

Şimdi, JavaScript ve React ile yüz tanıma makalesinin bu bölümünde basit kısım geldi. Bir kişiyi tanımlamak için, görüntüden özellik vektöründen veya tanımlayıcıdan 128 değer çıkarmak için en az bir kaynak görüntüye ihtiyaç vardır. API, tanımlamaya çalıştığı her kişi için tanımlayıcılardan ve addan bir etiket çıkarmak için LabeledFaceDescriptors işlevini kullanır. Bu etiket, bireyi eşleştirmek için sorgu tanımlayıcısıyla birlikte API’yi besler. Ancak bundan önce, adların ve tanımlayıcıların bir profilini sağlamak gerekir.

Yüz profili

Şu anda, Cherprang karakteri için görsel bir referans var. Bu nedenle, tanımlayıcısı bir profil oluşturmak için kullanılabilir. Bu noktada yapmayı düşündüğümüz şey bir JSON dosyası ve src/descriptors/bnk48.json klasörü oluşturmak. Bu dosya, grup üye adlarını ve referans görüntülerinden tanımlayıcıları içerir. Aşağıda, yalnızca bir görüntü tanımlayıcısı olan ilk örnek dosya verilmektedir.

{
  "Cherprang": {
    "name": "เฌอปราง",
    "descriptors": [
      [-0.08113786578178406,0.05256778374314308,0.009473100304603577,-0.10561250895261765,-0.1783013790845871,-0.04459364339709282,-0.09838695079088211,-0.11281408369541168,0.15290355682373047,-0.12802188098430634,0.22490034997463226,-0.0876401960849762,-0.20344389975070953,-0.06546909362077713,-0.09518688917160034,0.21771210432052612,-0.1978156566619873,-0.20811164379119873,-0.005263347178697586,0.022171149030327797,0.08166252076625824,-0.024958046153187752,-0.008690833114087582,0.07264935970306396,-0.09877212345600128,-0.32639357447624207,-0.07010464370250702,-0.05077863112092018,-0.06450583040714264,-0.08223631232976913,0.03569770231842995,0.0591503381729126,-0.19877424836158752,0.005495572462677956,0.032966941595077515,0.10699400305747986,0.00043915724381804466,-0.10360816866159439,0.17986394464969635,-0.040484149008989334,-0.30697202682495117,0.03211132436990738,0.08842744678258896,0.19950658082962036,0.15933744609355927,-0.03205663338303566,0.0013319365680217743,-0.16289959847927094,0.14904619753360748,-0.15430817008018494,0.0096973218023777,0.14715969562530518,0.08346439152956009,0.031750328838825226,-0.016189731657505035,-0.1357622593641281,0.03173140063881874,0.1332130879163742,-0.1280241757631302,-0.03812456876039505,0.10302945971488953,-0.06710688769817352,-0.0045883068814873695,-0.18414227664470673,0.19671869277954102,0.05899167060852051,-0.13076898455619812,-0.2127394676208496,0.09676400572061539,-0.15055659413337708,-0.1203978881239891,0.0671667754650116,-0.15655417740345,-0.21337451040744781,-0.33455413579940796,0.0025228180456906557,0.32778817415237427,0.12706099450588226,-0.18636029958724976,0.077443927526474,0.04969285428524017,0.0199972465634346,0.04955039545893669,0.18967756628990173,-0.0021310225129127502,0.10583700984716415,-0.09680759161710739,-0.0061607323586940765,0.237107053399086,-0.07061111927032471,-0.0200827457010746,0.20259839296340942,-0.025431372225284576,0.097686767578125,0.024423770606517792,-0.0027051493525505066,-0.05065762251615524,0.05029483884572983,-0.18550457060337067,0.04197317361831665,-0.06792200356721878,0.0047242967411875725,-0.020428016781806946,0.061017416417598724,-0.0777672529220581,0.09362616389989853,-0.018073776736855507,0.00793382991105318,-0.11228518187999725,0.011685803532600403,-0.09283971041440964,-0.05933531001210213,0.12439746409654617,-0.177815243601799,0.20367340743541718,0.12916350364685059,0.16568998992443085,0.14472319185733795,0.18697629868984222,0.07876216620206833,-0.025242770090699196,-0.02333880588412285,-0.17500267922878265,0.011992575600743294,0.09926775842905045,-0.05089148133993149,0.1372077465057373,0.017258809879422188]
    ]
  }
}

Tüm üyelerin tüm görüntüleri mevcutsa, yüz profilini tamamlamak için tanımlayıcılar eklenebilir ve tek tek adlandırılabilir. Burada, bu tam resim profilini oluşturmak için her üyenin 5 ila 10 resmi kullanılır. Bu nedenle izleyiciler bu dosyayı buradan [ + ] kolayca indirebilir ve src/descriptors/bnk48.json dosyasını değiştirebilir.

Dosya boyutu, başvuru değerlendirmesi için makul görünen tüm üyeler için yaklaşık bir megabayttır. Ancak gerçek dünyada, tüm görüntü profillerini bir veritabanında saklamanız gerekebilir, bu nedenle dosya boyutu hakkında endişelenmenize gerek yoktur. Ancak bunun yerine, görüntü tanıma işlemini gerçekleştirmek için sunucu tarafı kullanılmalıdır.

Yüz ayarlayıcı

Bir sonraki adımda, görüntü tanıma görevi için labelDescriptors ve faceMatcher oluşturmamız gerekiyor. Şimdi src/api/face.js dosyasına geri dönelim ve aşağıdaki fonksiyonu dosyaya ekleyelim.

// face.js code...

const maxDescriptorDistance = 0.5;
export async function createMatcher(faceProfile) {
  // Create labeled descriptors of member from profile
  let members = Object.keys(faceProfile);
  let labeledDescriptors = members.map(
    member =>
      new faceapi.LabeledFaceDescriptors(
        faceProfile[member].name,
        faceProfile[member].descriptors.map(
          descriptor => new Float32Array(descriptor)
        )
      )
  );

  // Create face matcher (maximum descriptor distance is 0.5)
  let faceMatcher = new faceapi.FaceMatcher(
    labeledDescriptors,
    maxDescriptorDistance
  );
  return faceMatcher;
}

Bu işlev, bir yüz profilini (JSON dosyası) girdi olarak alır ve her üyenin tanımlayıcısından, adı etiket olarak etiketlenmişTanımlayıcılar oluşturur. Ardından, faceMatcher etiketle oluşturulabilir ve dışa aktarılabilir (Dışa Aktar). maxDescriptorDistance’ın 0.5 olarak yapılandırılması izleyicilerin dikkatini çekmiş olabilir. Bu, referans tanımlayıcının ve sorgu tanımlayıcının anlamlı olacak kadar birbirine yakın olduğunu belirlemek için “Öklid Mesafesi” eşiğidir. API varsayılan değeri, genel amaçlar için yeterince iyi olan 0,6’dır. Ancak bu örnekte 0,5 daha doğrudur ve daha az hata içerir çünkü bu örnekte görüntüleri kullanılan kişilerin yüzleri çok benzerdir. İşlev hazır olduğuna göre, kodu bitirmek için src/views/ImageInput.js’ye döner.

import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import { loadModels, getFullFaceDescription, createMatcher } from '../api/face';

// Import image to test API
const testImg = require('../img/test.jpg');

// Import face profile
const JSON_PROFILE = require('../descriptors/bnk48.json');

// Initial State
const INIT_STATE = {
  imageURL: testImg,
  fullDesc: null,
  detections: null,
  descriptors: null,
  match: null
};

class ImageInput extends Component {
  constructor(props) {
    super(props);
    this.state = { ...INIT_STATE, faceMatcher: null };
  }

  componentWillMount = async () => {
    await loadModels();
    this.setState({ faceMatcher: await createMatcher(JSON_PROFILE) });
    await this.handleImage(this.state.imageURL);
  };

  handleImage = async (image = this.state.imageURL) => {
    await getFullFaceDescription(image).then(fullDesc => {
      if (!!fullDesc) {
        this.setState({
          fullDesc,
          detections: fullDesc.map(fd => fd.detection),
          descriptors: fullDesc.map(fd => fd.descriptor)
        });
      }
    });

    if (!!this.state.descriptors && !!this.state.faceMatcher) {
      let match = await this.state.descriptors.map(descriptor =>
        this.state.faceMatcher.findBestMatch(descriptor)
      );
      this.setState({ match });
    }
  };

  handleFileChange = async event => {
    this.resetState();
    await this.setState({
      imageURL: URL.createObjectURL(event.target.files[0]),
      loading: true
    });
    this.handleImage();
  };

  resetState = () => {
    this.setState({ ...INIT_STATE });
  };

  render() {
    const { imageURL, detections, match } = this.state;

    let drawBox = null;
    if (!!detections) {
      drawBox = detections.map((detection, i) => {
        let _H = detection.box.height;
        let _W = detection.box.width;
        let _X = detection.box._x;
        let _Y = detection.box._y;
        return (
          <div key={i}>
            <div
              style={{
                position: 'absolute',
                border: 'solid',
                borderColor: 'blue',
                height: _H,
                width: _W,
                transform: `translate(${_X}px,${_Y}px)`
              }}
            >
              {!!match && !!match[i] ? (
                <p
                  style={{
                    backgroundColor: 'blue',
                    border: 'solid',
                    borderColor: 'blue',
                    width: _W,
                    marginTop: 0,
                    color: '#fff',
                    transform: `translate(-3px,${_H}px)`
                  }}
                >
                  {match[i]._label}
                </p>
              ) : null}
            </div>
          </div>
        );
      });
    }

    return (
      <div>
        <input
          id="myFileUpload"
          type="file"
          onChange={this.handleFileChange}
          accept=".jpg, .jpeg, .png"
        />
        <div style={{ position: 'relative' }}>
          <div style={{ position: 'absolute' }}>
            <img src={imageURL} alt="imageURL" />
          </div>
          {!!drawBox ? drawBox : null}
        </div>
      </div>
    );
  }
}

export default withRouter(ImageInput);

Bu son kodda face.js’den createMatcher fonksiyonu alınır ve hazırlanan yüz profili ile faceMatcher oluşturulur. handleImage() fonksiyonu içinde, resimden fullDesc alındıktan sonra, tanımlayıcılar eşlenir ve her resim için en iyi eşleşme bulunur. Ardından, her bir yüz algılama kutusunun altında en iyi eşleşmeyi görüntülemek için p etiketi ve CSS kullanılır. Bunun bir görünümü aşağıdaki resimde verilmiştir.

JavaScript ve React ile yüz tanıma — pratik bir kılavuz

Tam yüz profilini indiren kişiler [ + ] görseli aşağıdaki görsel ile değiştirebilir ve yüz tanıma sisteminin sonucunu görebilir.

JavaScript ve React ile yüz tanıma — pratik bir kılavuz

Aşağıdaki yazıda canlı video girişinde JavaScript ile yüz tanıma ve React yüz tanıma işlemi yapılmaktadır.

Canlı video girişi

JavaScript ve React ile yüz tanıma yazımızın bu bölümünde canlı video ile yüz tanıma yöntemi öğretilmektedir. Burada canlı video, React-Webcam kullanılarak face-api.js’ye beslenir. Daha sonra gerekli kütüphane kurularak iş yapılır.

npm i react-webcam

Yine yeni bir component oluşturmadan önce /src/App.js içindeki giriş videosu için bir “Route” eklememiz gerekiyor. VideoInput bileşeni yakında oluşturulacak.

import React, { Component } from 'react';
import { Route, Router } from 'react-router-dom';
import createHistory from 'history/createBrowserHistory';
import './App.css';

import Home from './views/Home';
import ImageInput from './views/ImageInput';
import VideoInput from './views/VideoInput';

class App extends Component {
  render() {
    return (
      <div className="App">
        <Router history={createHistory()}>
          <div className="route">
            <Route exact path="/" component={Home} />
            <Route exact path="/photo" component={ImageInput} />
            <Route exact path="/camera" component={VideoInput} />
          </div>
        </Router>
      </div>
    );
  }
}

export default App;

Giriş video bileşeni

Şimdi yeni dosya src/views/VideoInput.js oluşturulacak. Ardından, aşağıdaki kod kopyalanır ve o dosyaya kaydedilir. Bu bileşen için tam kod aşağıdadır.

import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import Webcam from 'react-webcam';
import { loadModels, getFullFaceDescription, createMatcher } from '../api/face';

// Import face profile
const JSON_PROFILE = require('../descriptors/bnk48.json');

const WIDTH = 420;
const HEIGHT = 420;
const inputSize = 160;

class VideoInput extends Component {
  constructor(props) {
    super(props);
    this.webcam = React.createRef();
    this.state = {
      fullDesc: null,
      detections: null,
      descriptors: null,
      faceMatcher: null,
      match: null,
      facingMode: null
    };
  }

  componentWillMount = async () => {
    await loadModels();
    this.setState({ faceMatcher: await createMatcher(JSON_PROFILE) });
    this.setInputDevice();
  };

  setInputDevice = () => {
    navigator.mediaDevices.enumerateDevices().then(async devices => {
      let inputDevice = await devices.filter(
        device => device.kind === 'videoinput'
      );
      if (inputDevice.length < 2) {
        await this.setState({
          facingMode: 'user'
        });
      } else {
        await this.setState({
          facingMode: { exact: 'environment' }
        });
      }
      this.startCapture();
    });
  };

  startCapture = () => {
    this.interval = setInterval(() => {
      this.capture();
    }, 1500);
  };

  componentWillUnmount() {
    clearInterval(this.interval);
  }

  capture = async () => {
    if (!!this.webcam.current) {
      await getFullFaceDescription(
        this.webcam.current.getScreenshot(),
        inputSize
      ).then(fullDesc => {
        if (!!fullDesc) {
          this.setState({
            detections: fullDesc.map(fd => fd.detection),
            descriptors: fullDesc.map(fd => fd.descriptor)
          });
        }
      });

      if (!!this.state.descriptors && !!this.state.faceMatcher) {
        let match = await this.state.descriptors.map(descriptor =>
          this.state.faceMatcher.findBestMatch(descriptor)
        );
        this.setState({ match });
      }
    }
  };

  render() {
    const { detections, match, facingMode } = this.state;
    let videoConstraints = null;
    let camera = '';
    if (!!facingMode) {
      videoConstraints = {
        width: WIDTH,
        height: HEIGHT,
        facingMode: facingMode
      };
      if (facingMode === 'user') {
        camera = 'Front';
      } else {
        camera = 'Back';
      }
    }

    let drawBox = null;
    if (!!detections) {
      drawBox = detections.map((detection, i) => {
        let _H = detection.box.height;
        let _W = detection.box.width;
        let _X = detection.box._x;
        let _Y = detection.box._y;
        return (
          <div key={i}>
            <div
              style={{
                position: 'absolute',
                border: 'solid',
                borderColor: 'blue',
                height: _H,
                width: _W,
                transform: `translate(${_X}px,${_Y}px)`
              }}
            >
              {!!match && !!match[i] ? (
                <p
                  style={{
                    backgroundColor: 'blue',
                    border: 'solid',
                    borderColor: 'blue',
                    width: _W,
                    marginTop: 0,
                    color: '#fff',
                    transform: `translate(-3px,${_H}px)`
                  }}
                >
                  {match[i]._label}
                </p>
              ) : null}
            </div>
          </div>
        );
      });
    }

    return (
      <div
        className="Camera"
        style={{
          display: 'flex',
          flexDirection: 'column',
          alignItems: 'center'
        }}
      >
        <p>Camera: {camera}</p>
        <div
          style={{
            width: WIDTH,
            height: HEIGHT
          }}
        >
          <div style={{ position: 'relative', width: WIDTH }}>
            {!!videoConstraints ? (
              <div style={{ position: 'absolute' }}>
                <Webcam
                  audio={false}
                  width={WIDTH}
                  height={HEIGHT}
                  ref={this.webcam}
                  screenshotFormat="image/jpeg"
                  videoConstraints={videoConstraints}
                />
              </div>
            ) : null}
            {!!drawBox ? drawBox : null}
          </div>
        </div>
      </div>
    );
  }
}

export default withRouter(VideoInput);

Girişin her 1500 milisaniyede bir web kamerasından alınan bir ekran görüntüsü olması dışında, tüm algılama ve tanıma mekanizmaları ImageInput bileşeniyle aynıdır. Görüntü boyutu 420 x 420 piksel olarak ayarlanmıştır, ancak daha küçük veya daha büyük boyutlu görüntüleri işleyebilir. Tabii ki, daha büyük görüntülerin kullanılmasının yüksek işlem süresine yol açtığını belirtmek gerekir. setInputDevice işlevinin içinde, cihazın 1 veya 2 (veya daha fazla) kamerası olup olmadığını kontrol eder. Yalnızca bir kamera varsa, uygulama bunun bir PC olduğunu varsayar ve ardından kameradan faceMode: user’ı kaydeder, ancak iki veya daha fazla kamera varsa bu bir akıllı telefon olabilir. Bu durumda, kamera arka ucundan faceMode: { exact: ‘environment’ } alabilirsiniz.

ImageInput bileşeninde olduğu gibi, görüntü algılama kutusunu çizmek için benzer bir işlev kullanılır. Aslında başka bir bileşen olarak hazırlanabilir. Bu nedenle, tekrar tekrar etmeye gerek yoktur. Artık uygulama hazır. Kullanıcılar, uygulamanın VideoInput modunu kendi yüzleriyle test edebilir. Ancak muhtemelen kullanıcı, modelin görüntüleriyle eğitildiği kişilerden birini bilinmeyen veya yanlışlıkla tanıyacaktır. Bunun nedeni, sistemin Öklid mesafesi 0,5’ten küçük olan tüm görüntüleri tanımaya çalışmasıdır.

Projeyi GitHub sayfasında dağıtma

JavaScript ve React ile yüz tanıma makalesinin bu bölümünde, projenin GitHub’da dağıtılma yöntemi incelenmektedir. Bu uygulama herhangi bir statik ana bilgisayarda konuşlandırılabilir. Ancak bu bölümde, bu React programını GitHub sayfalarında dağıtma yöntemi birkaç püf noktası kullanılarak öğretildi. Bu adımları gerçekleştirmek için bir GitHub hesabınızın olması gerekir. GitHub’ı olmayan kişiler, bu bölümdeki adımlara devam etmek için bir GitHub hesabı oluşturun. Öncelikle gh-pages kütüphanesinin kurulu olması gerekmektedir. Bunun için aşağıdaki kod parçacığını kullanabilirsiniz.

npm i ghpages

Ardından, src/App.js içindeki createHistory() içerisine { basename: process.env.PUBLIC_URL } aşağıdaki gibi eklememiz gerekiyor.

import React, { Component } from 'react';
import { Route, Router } from 'react-router-dom';
import createHistory from 'history/createBrowserHistory';
import './App.css';

import Home from './views/Home';
import ImageInput from './views/ImageInput';
import VideoInput from './views/VideoInput';

class App extends Component {
  render() {
    return (
      <div className="App">
        <Router history={createHistory({ basename: process.env.PUBLIC_URL })}>
          <div className="route">
            <Route exact path="/" component={Home} />
            <Route exact path="/photo" component={ImageInput} />
            <Route exact path="/camera" component={VideoInput} />
          </div>
        </Router>
      </div>
    );
  }
}

export default App;

Artık kullanıcı GitHub sayfasına gidebilir ve uygulama adlı bir havuz oluşturabilir. Buradaki uygulamanın adı tepki-yüz tanımadır. Ardından Git URL’si, projeye daha sonra eklenebilmesi için kopyalanabilir. Ardından, package.json dosyasını açmanız ve ana sayfayı GitHub hesabı ve uygulama adıyla aşağıdaki gibi eklemeniz gerekir:

"homepage": "http://YOUR_GITHUB_ACCOUNT.github.io/react-face-recognition"

Henüz package.json dosyasını kapatmamalısınız çünkü aşağıdaki gibi scriptler altında predeploy ve deploy komutlarını komut satırına eklemeniz gerekiyor.

"scripts": {
  "start": "react-scripts start",
  "build": "react-scripts build",
  "test": "react-scripts test",
  "eject": "react-scripts eject",
  "predeploy": "npm run build",
  "deploy": "gh-pages -d build"
}

Artık dosyayı kaydedebilir ve terminal konsoluna geri dönebilir, ardından kodu GitHub deposuna yüklemek için git komutunu çalıştırabilir ve npm run konuşlandırmayı çalıştırabilirsiniz. Sayfa, http://YOUR_GITHUB_ACCOUNT.github.io/react-face-recognition olarak ayarlanmış bir URL ile yayınlanmalıdır.