IT/AI

TensorFlow.js - Face Detection for React App

루벤초이 2021. 5. 6. 21:41

★Sample Code(Github)

 

인공지능, 딥러닝 하면 떠오르는 텐서플로우(TensorFlow)를 웹앱에서도 개발 및 사용할 수 있는 TensorFlow.js 자바스크립트 머신러닝 라이브러리에 대해 알아봅시다.

 

TensorFlow.js | 자바스크립트 개발자를 위한 머신러닝

브라우저, Node.js 또는 Google Cloud Platform에서 모델을 학습시키고 배포합니다. TensorFlow.js는 자바스크립트 및 웹 개발을 위한 오픈소스 ML 플랫폼입니다.

www.tensorflow.org

 

 

인공지능 서비스는 특히 영상(Vision)과 음성(Speech) 서비스에 특화되어 있는데요,

AWS AI, Google Cloud AI 등 세계적인 클라우드 기반 AI 서비스를 들여다 보면

얼굴, 포즈, 사물 인식 등의 비전 기술과 음성 인식, Text-to-speech, 자연어 처리 등 음성 기술이 주를 이루고 있어요.

 

AWS나 Google Cloud는 유료 서비스라서 배우는 입장에서는 부담스러울 수 있는데요,

Tensorflow 같은 오픈 소스 프로젝트를 활용해서 유사한 기술들을 무료로 사용할 수 있습니다.

특히 Tensorflow.js는 브라우저에서 돌아가기 때문에 User Interface와 맞물려 있어 간단한 웹앱을 짜서 쉽게 연동해 볼 수 있지요.

 

Face Detection 얼굴 인식

웹앱에서 얼굴 인식을 할 수 있는 몇몇 오픈 소스 프로젝트가 있는데요, Github에서 별을 12.4k개나 받은 가장 유명한 face-api.js가 있었어요. 얼굴을 찾기는 물론, 정확도는 조금 떨어지지만, 얼굴 인증(face recognition), 감성/연령 추출 등의 기능도 제공하는데 MIT 라이선스로 무료입니다.

 

그런데 어느 날 Tensorflow.js 버전 1.x 대에서 업데이트가 중단됩니다. 그래서 지금 face-api.js를 그대로 갖다 쓰면, 다른 Tensorflow.js 버전과 함께 동작할 때 이상한 에러들을 보게 됩니다.

TypeError: t.toFloat is not a function

그래서 Tensorflow.js 버전 2.x 및 3.x에서도 가능하도록 업데이트한 것을 역시나 MIT 라이선스로 배포하기도 했습니다.

이 face-api.js 외에도 Blazeface라는 가볍고 빠른 알고리즘이 있는데요, Tensorflow.js 모델에 포함되어 Apache 라이선스 2.0으로 공개되어 있네요.

출처: Tensorflow.js 홈페이지

오늘은 이 Blazeface를 사용해서 React 앱을 만들어보겠습니다.

 

React Face Detection

★Sample Code(Github)

오늘 만들어 볼 앱은 웹캠 영상을 받아 face detection을 수행하는 앱인데요, 지난 번에 다룬 React 웹캠 앱(아래 튜토리얼 참고)에코드를 추가합니다. React 웹캠 앱에서는 영상을 받아 Draw to Canvas 버튼을 클릭하면 웹캠 영상을 캔버스에 그리는 예제였습니다.

React 웹캠 앱 실행화면


먼저 npm으로 텐서플로우 라이브러리들을 설치합니다. 우리가 사용할 blazeface도 설치합니다. 

npm i --save @tensorflow/tfjs-backend-webgl @tensorflow/tfjs-converter @tensorflow/tfjs-core
npm i --save @tensorflow-models/blazeface

참고로 공식사이트 안내대로 실행하면 React에서는 오류가 나는데요, @tensorflow/tfjs-backend-webgl을 import하고 tf.setBackend('webgl')을 호출해주면 됩니다.

import * as tf from '@tensorflow/tfjs-core';
import '@tensorflow/tfjs-backend-webgl';
import * as blazeface from '@tensorflow-models/blazeface';

이제 모델을 초기화합니다.

  React.useEffect(() => {
    const initFD = async () => {
      await tf.setBackend('webgl');
      g_var.model = await blazeface.load();
      console.log("model", g_var.model);

      getWebcam((stream => {
        videoRef.current.srcObject = stream;
      }));
    }
    initFD();
  }, []);

React.useEffect(() => {}, []) 구문은 componentDidMount()와 같아서 최초 1회 실행됩니다.

그 안에서 initFD() async 함수를 정의했는데 이 안에서 tf.setBackend()와 blazeface.load()를 await를 사용해서 순차적으로 호출합니다. 전역 변수 g_var.model에 초기화된 모델을 저장하고 웹캠을 엽니다.

 

웹캠 앱 예제에서 Draw to Canvas 버튼을 누르면 호출되는 drawToCanvas() 함수에서 얼굴 찾기를 수행합니다.

const estimateCanvas = async (canvasRef) => {
  const predictions = await g_var.model.estimateFaces(canvasRef, false);
  return predictions;
}

const drawToCanvas = async () => {
    try {
      const ctx = canvasRef.current.getContext('2d');

      canvasRef.current.width = videoRef.current.videoWidth;
      canvasRef.current.height = videoRef.current.videoHeight;

      if (ctx && ctx !== null) {
        if (videoRef.current) {
          ctx.translate(canvasRef.current.width, 0);
          ctx.scale(-1, 1);
          ctx.drawImage(videoRef.current, 0, 0, canvasRef.current.width, canvasRef.current.height);
          ctx.setTransform(1, 0, 0, 1, 0, 0);
        }

        const preds = await estimateCanvas(canvasRef.current);
        for (let i = 0; i < preds.length; i++) {
          let p = preds[i];
          ctx.strokeStyle = "#FF0000";
          ctx.lineWidth = 5;
          ctx.strokeRect(p.topLeft[0], p.topLeft[1], p.bottomRight[0] - p.topLeft[0], p.bottomRight[1] - p.topLeft[1]);
        }
      }
    } catch (err) {
      console.log(err);
    }
  }

중간에 estimateCanvas()에 캔버스 엘리먼트를 넘겨주는데 이 캔버스를 그대로 blazeface.estimateFaces 파라미터로 넣어주면 됩니다. 간단하죠?

 

캔버스에 결과를 그리는 drawToCanvas()에서는 먼저 웹캠 영상을 그리고 얼굴을 찾은 뒤, 찾은 얼굴을 빨강 사각형으로 표시합니다. Face detection 결과값 구성은 사이트에도 소개되어 있지만, 간단하게는 개발자도구(F12) 로그로 확인해 볼 수 있습니다.

결과 값 콘솔 로그

위와 같이 face detection 결과로 배열(찾은 얼굴의 수)이 올라오고 bottomRight[x, y], topLeft[x, y] 값을 이용하여 사각형을 그립니다. 랜드마크는 얼굴의 눈, 코, 입 등을 표시해주는데, 오늘 우리 앱에서는 다루지 않으므로 자세한 내용은 사이트를 참고하세요.

 

결과 화면을 볼까요? 얼굴은 부끄러워서 가렸습니다.

실행 결과 - 빨간 사각형으로 얼굴을 찾음

 

Repeat 버튼을 누르면 주기적으로 얼굴을 찾고 화면에 (사람이든 사진이든) 얼굴이 여러 개면 그만큼 배열이 올라옵니다.

여러 명을 찾는 경우


오늘은 간단한 얼굴 찾기 웹앱을 만들어봤습니다.

이처럼 Tensorflow.js는 웹앱에서 바로 돌아가기 때문에 사용성에 있어서는 아주 훌륭한 기술이네요!

728x90
반응형