前端人臉檢測指南

發表於2018-04-26

前端人臉檢測指南

Shape Detection API 的釋出已經有一些時日,其主要的提供的能力是給予前端直接可用的特徵檢測的介面(包括條形碼、人臉、文字檢測)。本文將簡單的對其進行介紹,對前端進行人臉檢測進行普適性的講解。(本文不講演算法~望輕拍)


前端人臉檢測指南


1 背景與場景

人臉檢測(Face Detection)算是老生常談的課題了,在諸多行業應用廣泛,例如金融、安防、電子商務、智慧手機、娛樂圖片等行業。其中涉及的技術也在不斷的演變,下面簡要介紹幾種思路:

a. 基於特徵的人臉檢測

例如opencv中內建了基於Viola-Jones目標檢測框架的Harr分類器(實際上大多數分類器都是基於學習得到的),只需要載入對應的配置檔案(haarcascade_frontalface_alt.xml)就能直接呼叫detectObject去完成檢測過程,同時也支援其他特徵的檢測(如鼻子、嘴巴等)。

b. 基於學習的人臉檢測,其實也是需要通過運算元提取的影像中的區域性特徵,通過對其進行分類、統計、迴歸等方式得到的具備更精確和快響應的分類器。


2 套路集錦

2.1 後端處理

前端通過網路將資源傳輸到後端,後端統一處理需要檢測的影像或視訊流,對後端的架構有一定的挑戰,同時網路的延時往往不能給使用者帶來實時的互動效果。

2.2 客戶端處理

得益於OpenCV在跨語言和跨平臺的優勢,客戶端也能以較低的開發成本的提供人臉檢測的能力,並且可以通過JsBridge等方式向web容器提供服務,然而一旦脫離這個容器,孤立的頁面將失去這種能力。直到有一天……

2.3 開放服務

不知道從啥時候開始,雲端計算等概念拔地而起,計算的成本日益降低。各大研發團隊(如阿里雲、Face++)都蠢蠢欲動又不緊不慢的上架了人臉檢測服務,甚至還帶上了各種特!殊!服!務!,人臉識別、活體識別、證件OCR及人臉對比等等等。


前端人臉檢測指南


儘管不僅提供了客戶端的SDK以及前後端的API,但是,怎麼說也要講講我純前端的方案吧。


3 時代帶來了什麼

好吧,人臉識別在前端依然是在刀耕火種的遠古時代,然而,我們的基礎建設已經起步,希望後續的一些相關介紹能為各位看官帶來一定的啟發。

3.1 Shape Detection API

隨著客戶端硬體的計算能力逐漸提高,瀏覽器層面得到的許可權也越來越多,由於影像處理需要耗費大量的計算資源,實際上瀏覽器上也能承擔影像檢測的一些工作,因此就搞出了個Shape Detection API。


以下幾個簡單的例子介紹了基本的用法,在嘗試編輯並執行這些程式碼之前,請確保在你的Chrome版本以及該新特性已經被啟用,另外該API受同源策略所限制:

chrome://flags/#enable-experimental-web-platform-features


條形碼檢測:Barcode Detection (For Chrome 56+)

var barcodeDetector = new BarcodeDetector();
barcodeDetector.detect(image)
  .then(barcodes => {
    barcodes.forEach(barcode => console.log(barcodes.rawValue))
  })
  .catch(err => console.error(err));複製程式碼


    人臉檢測:Face Detection (For Chrome 56+)

    var faceDetector = new FaceDetector();
    faceDetector.detect(image)
      .then(faces => faces.forEach(face => console.log(face)))
      .catch(err => console.error(err));複製程式碼


    文字檢測:Text Detection (For Chrome 58+)

    var textDetector = new TextDetector();
    textDetector.detect(image)
      .then(boundingBoxes => {
        for(let box of boundingBoxes) {
          speechSynthesis.speak(new SpeechSynthesisUtterance(box.rawValue));
        }
      })
      .catch(err => console.error(err));
    複製程式碼

    3.2 影像中的人臉檢測

    影像的人臉檢測比較簡單,只需要傳入一個圖片的元素,就能直接調起該API進行人臉識別了。然後接住canvas我們可以將檢測的結果展示出來。


    核心程式碼:

    var image = document.querySelector('#image');
    var canvas = document.querySelector('#canvas');
    var ctx = canvas.getContext("2d");
    var scale = 1;
    
    image.onload = function () {
      ctx.drawImage(image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height);
      scale = canvas.width / image.width;
    };
    
    function detect() {  
      if (window.FaceDetector == undefined) {
        console.error('Face Detection not supported');
        return;
      } 
      var faceDetector = new FaceDetector();
      console.time('detect');
      return faceDetector.detect(image)
        .then(faces => {
          console.log(faces)      // Draw the faces on the <canvas>.
          var ctx = canvas.getContext("2d");
          ctx.lineWidth = 2;
          ctx.strokeStyle = "red";
          for (var i = 0; i < faces.length; i++) {
            var item = faces[i].boundingBox;
            ctx.rect(Math.floor(item.x * scale), Math.floor(item.y * scale), Math.floor(item.width * scale), Math.floor(item.height * scale));
            ctx.stroke();
          }
          console.timeEnd('detect');
        })
        .catch((e) => console.error("Boo, Face Detection failed: " + e));
    }複製程式碼

    處理效果:

    前端人臉檢測指南


    3.3 視訊中的人臉檢測

    視訊中的人臉檢測跟影像相差不大,通過getUserMedia 可以開啟攝像頭獲取視訊/麥克風的資訊,通過將視訊幀進行檢測和展示,即可實現視訊中的人臉檢測。

    核心程式碼如下:

    navigator.mediaDevices.getUserMedia({
      video: true,    // audio: true
    })
      .then(function (mediaStream) {
        video.src = window.URL.createObjectURL(mediaStream);
        video.onloadedmetadata = function (e) {
          // Do something with the video here.
        };
      })
      .catch(function (error) {
        console.log(error.name);
      });
    
    setInterval(function () {
      ctx.clearRect(0, 0, canvas.width, canvas.height);
      ctx.drawImage(video, 0, 0);
      image.src = canvas.toDataURL('image/png');
      image.onload = function() {
        detect();
      }
    }, 60);複製程式碼

    處理效果:

    前端人臉檢測指南


    3.4 時光倒流到沒有API的日子

    實際上,在很久很久以前,也有不少解決方案存在。由於硬體條件以及沒有硬體加速等限制的情況,一直沒有被廣泛地投入生產。

    a. tracking.js

    tracking.js 是一款js封裝的影像處理的庫,為瀏覽器帶來豐富的計算視覺相關的演算法和技術,通過它可以實現顏色追蹤、人臉檢測等功能,具體特性如下:

    前端人臉檢測指南

    b. jquery.facedetection

    jquery.facedetection 是一款jquery / zepto 人臉檢測外掛,基於跨終端能力超強的ccv中的影像分類器和檢測器。


    3.5 Node.js & OpenCV

    node-opencv 模組已經發布了有些年頭,儘管目前還不能完美相容v3.x,提供的API也比較有限,但能完美相容opencv v2.4.x。N-API的到來可能會帶來更多的驚喜。

    設想一下在一個Electron或者Node-Webkit容器中,我們是否可以通過本地開啟websocket服務來實現實時的人臉檢測呢?實現的思路程式碼如下:


    後端處理邏輯

    import cv from 'opencv';
    
    const detectConfigFile = './node_modules/opencv/data/haarcascade_frontalface_alt2.xml';// camera propertiesconst camWidth = 320;const camHeight = 240;const camFps = 10;const camInterval = 1000 / camFps;// face detection propertiesconst rectColor = [0, 255, 0];const rectThickness = 2;// initialize cameraconst camera = new cv.VideoCapture(0);
    
    camera.setWidth(camWidth);
    camera.setHeight(camHeight);
    const frameHandler = (err, im) => {
      return new Promise((resolve, reject) => {
        if (err) {
          return reject(err);
        }
        im.detectObject(detectConfigFile, {}, (error, faces) => {
          if (error) {
            return reject(error);
          }
          let face;
          for (let i = 0; i < faces.length; i++) {
            face = faces[i];
            im.rectangle([face.x, face.y], [face.width, face.height], rectColor, rectThickness);
          }
          return resolve(im);
        });
      });
    };
    
    module.exports = function (socket) {
      const frameSocketHanlder = (err, im) => {
        return frameHandler(err, im)
          .then((img) => {
            socket.emit('frame', {
              buffer: img.toBuffer(),
            });
          });
      };
      const handler = () => {
        camera.read(frameSocketHanlder);
      };
      setInterval(handler, camInterval);
    };複製程式碼


    前端呼叫介面

    socket.on('frame', function (data) {
    
      var unit8Arr = new Uint8Array(data.buffer);
      var str = String.fromCharCode.apply(null, unit8Arr);
      var base64String = btoa(str);
    
      img.onload = function () {
        ctx.drawImage(this, 0, 0, canvas.width, canvas.height);
      }
      img.src = 'data:image/png;base64,' + base64String;
    });複製程式碼

    4.1 未來的發展

    這些前沿的技術將會在前端得到更為廣泛的應用和支援是毋庸置疑的,未來的影像在前端也會隨著傳統影像處理->學習+影像處理的方式前進,這一切的功勞離不開基礎設施(硬體、瀏覽器、工具、庫等)的逐漸增強和完善,其中包括但不僅限於:

    • getUserMedia/Canvas => 影像 / 視訊的操作

    • Shape Detection API => 影像檢測

    • Web Workers => 平行計算能力

    • ConvNetJS => 深度學習框架

    • Tensorflow (原 DeeplearnJS) => 正大力支援 JS


    4.2 實際上並沒有那麼樂觀

    4.2.1 準確率

    對於正臉(多個)的識別率還是比較高的,但是在側臉已經有障礙物的情況下,檢測的效果並不理想。


    4.2.2 處理速度

    對於影像中人臉檢測的例子2.2,耗費時間300ms+(實際上無法滿足大解析度視訊實時處理),是呼叫Opencv的檢測速度100ms的三倍之多。


    4.2.3 特性

    還有很多需要完善的地方:如不支援眼鏡狀態、性別、年齡估計、表情識別、人種、笑容、模糊檢測等主流服務提供商提供的服務。


    4.3 想說又說不完的

    a. 本文中所有樣例的原始碼,歡迎 Fork / Star:

    https://github.com/x-cold/face-detection-browser

    https://github.com/x-cold/face-detection-nodejs

    b. 關於人臉檢測在不同場景的適應性,以及檢測消耗的時間暫時沒有資料支撐,後面考慮引入PASCAL VOC、AT&T提供的樣本進行小規模的測試。


    5 參考

    1. 人臉識別技術大總結(1):Face Detection & Alignment: http://blog.jobbole.com/85783/

    2. 阿里巴巴直播防控中的實人認證技術: https://xianzhi.aliyun.com/forum/mobile/read/635.html

    3. 前端在人工智慧時代能做些什麼?:https://yq.aliyun.com/articles/153198

    4. ConvNetJS Deep Learning in your browser:http://cs.stanford.edu/people/karpathy/convnetjs/

    5. Face detection using Shape Detection API:https://paul.kinlan.me/face-detection/


    前端人臉檢測指南




    相關文章