SSD,全稱Single Shot MultiBox Detector,是Wei Liu在ECCV 2016上提出的一種目標檢測算法,截至目前是主要的檢測框架之一,相比Faster RCNN有明顯的速度優(yōu)勢,相比YOLO又有明顯的mAP優(yōu)勢(不過已經(jīng)被CVPR 2017的YOLO9000超越)。
論文:https://arxiv.org/abs/1512.02325
code:
目標檢測主流算法分成兩個類型:
(1)two-stage方法:RCNN系列
通過算法產(chǎn)生候選框,然后再對這些候選框進行分類和回歸
(2)one-stage方法:yolo和SSD
直接通過主干網(wǎng)絡(luò)給出類別位置信息,不需要區(qū)域生成
兩類算法在精度和速度上有一定的差異
(1)采用多尺度特征圖用于檢測
CNN網(wǎng)絡(luò)一般前面的特征圖比較大,后面會逐漸采用stride=2的卷積或者pool來降低特征圖大小,這正如圖3所示,一個比較大的特征圖和一個比較小的特征圖,它們都用來做檢測。這樣做的好處是比較大的特征圖來用來檢測相對較小的目標,而小的特征圖負責檢測大目標。
(2)采用卷積進行檢測
SSD直接采用卷積對不同的特征圖來進行提取檢測結(jié)果。對于形狀為
的特征圖,只需要采用
這樣比較小的卷積核得到檢測值。(每個添加的特征層使用一系列卷積濾波器可以產(chǎn)生一系列固定的預(yù)測。
(3)設(shè)置先驗框
SSD借鑒faster rcnn中ancho理念,每個單元設(shè)置尺度或者長寬比不同的先驗框,預(yù)測的是對于該單元格先驗框的偏移量,以及每個類被預(yù)測反映框中該物體類別的置信度。
SSD的模型框架主要由三部分組成,以SSD300為例,有VGG-Base Extra-Layers,Pred-Layers。
VGG-Base作為基礎(chǔ)框架用來提取圖像的feature,Extra-Layers對VGG的feature做進一步處理,增加模型對圖像的感受野,使得extra-layers得到的特征圖承載更多抽象信息。待預(yù)測的特征圖由六種特征圖組成,6中特征圖最終通過pred-layer得到預(yù)測框的坐標,置信度,類別信息。
造:
import torch.nn.init as init
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.autograd import Variable
from math import sqrt as sqrt
from itertools import product as product
base={
'300': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'C', 512, 512, 512, 'M',
512, 512, 512],
'512': [],
}
def vgg(cfg, i, batch_norm=False):
layers=[]
in_channels=i
for v in cfg:
if v=='M':
layers +=[nn.MaxPool2d(kernel_size=2, stride=2)]
elif v=='C':
layers +=[nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)]
else:
conv2d=nn.Conv2d(in_channels, v, kernel_size=3, padding=1)
if batch_norm:
layers +=[conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)]
else:
layers +=[conv2d, nn.ReLU(inplace=True)]
in_channels=v
pool5=nn.MaxPool2d(kernel_size=3, stride=1, padding=1)
conv6=nn.Conv2d(512, 1024, kernel_size=3, padding=6, dilation=6)
conv7=nn.Conv2d(1024, 1024, kernel_size=1)
layers +=[pool5, conv6,
nn.ReLU(inplace=True), conv7, nn.ReLU(inplace=True)]
return layers
layers=vgg(base[str(300)], 3)
print(nn.Sequential(*layers))
Sequential(
(0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU(inplace)
(2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(3): ReLU(inplace)
(4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(6): ReLU(inplace)
(7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(8): ReLU(inplace)
(9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(11): ReLU(inplace)
(12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(13): ReLU(inplace)
(14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(15): ReLU(inplace)
(16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=True)
(17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(18): ReLU(inplace)
(19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(20): ReLU(inplace)
(21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(22): ReLU(inplace)
(23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(25): ReLU(inplace)
(26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(27): ReLU(inplace)
(28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(29): ReLU(inplace)
(30): MaxPool2d(kernel_size=3, stride=1, padding=1, dilation=1, ceil_mode=False)
(31): Conv2d(512, 1024, kernel_size=(3, 3), stride=(1, 1), padding=(6, 6), dilation=(6, 6))
(32): ReLU(inplace)
(33): Conv2d(1024, 1024, kernel_size=(1, 1), stride=(1, 1))
(34): ReLU(inplace)
)
?
第一次的特征圖輸出是在(22)處,一共經(jīng)歷3次池化,所以特征圖大小是38*38,之后用進行二次maxpool2d 特征圖在最后輸出應(yīng)該是10x10的大小,但最后一層的maxpool2d的stride=1所以特征圖大小還是19x19
SSD中還額外構(gòu)造了7個卷積,通過1,3,5,7卷積之后的特征圖用于輸出,這里提取了4個特征圖,加上從vgg網(wǎng)絡(luò)里面提取的2個特征圖一共6個特征圖。
Sequential(
(0): Conv2d(1024, 256, kernel_size=(1, 1), stride=(1, 1))
(1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))
(2): Conv2d(512, 128, kernel_size=(1, 1), stride=(1, 1))
(3): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1))
(4): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1))
(5): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1))
(6): Conv2d(256, 128, kernel_size=(1, 1), stride=(1, 1))
(7): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1))
)
?
從上圖可以看到六個特征圖的尺寸:[38, 19, 10, 5, 3, 1],在Predict Layers中可以看到每個特征圖中的每個像素點對應(yīng)的先驗框個數(shù)為:[4, 6, 6, 6, 4, 4] 。
下載VOC2007,VOC2012數(shù)據(jù)集進行訓(xùn)練。
數(shù)據(jù)size為300x300,一共有21個類。
查看官方的mAP為77.7,基本保持了一致。
使用訓(xùn)練后的模型進行推理,推理速度達到了38FPS
優(yōu)點:
缺點:
者|Victor Dibia
譯者|薛命燈
近日,GitHub 上開源了一個名為 Handtrack.js 的項目,有了它,你只需要 3 行代碼就能用來檢測圖片中手的動作。
演示地址:https://victordibia.github.io/handtrack.js/#/
運行時:22 FPS,Macbook Pro 2018(2.5 Ghz),Chrome 瀏覽器。13FPS,Macbook Pro 2014(2.2GHz)。
不久之前,一個使用 TensorFlow 對象檢測 API 跟蹤圖片中手部動作的實驗結(jié)果把我震驚到了。我把訓(xùn)練模型和源代碼開放了出來:
https://github.com/victordibia/handtracking
從那時起,它就被用來開發(fā)一些非常有趣的東西,比如:
一個可以幫助孩子進行拼寫練習(xí)的工具:
https://medium.com/@drewgillson/alphabot-a-screen-less-interactive-spelling-primer-powered-by-computer-vision-cc1095bce90
一個可以識別手勢的插件:
https://github.com/MrEliptik/HandPose
一個乒乓球游戲:
https://github.com/alvinwan/hand-tracking-pong
有很多人想要嘗試我提供的訓(xùn)練模型,但無法設(shè)置好 Tensorflow(安裝問題、TF 版本問題、導(dǎo)出圖表,等等)。幸運的是,Tensorflow.js 解決了其中的一些安裝和發(fā)行問題,因為它經(jīng)過優(yōu)化,可以在瀏覽器的標準化環(huán)境中運行。為此,我創(chuàng)建了 Handtrack.js 庫:
https://github.com/victordibia/handtrack.js/
它可以讓開發(fā)人員使用經(jīng)過訓(xùn)練的手部檢測模型快速創(chuàng)建手勢交互原型。
這個庫的目標是隱藏與加載模型文件相關(guān)的步驟,為用戶提供有用的函數(shù),并允許用戶在沒有任何 ML 經(jīng)驗的情況下檢測圖像中的手,你不需要自己訓(xùn)練模型。
你也無需導(dǎo)出任何圖或已保存的模型。你可以直接在 Web 應(yīng)用程序中包含 handtrack.js(詳情如下),然后調(diào)用這個庫提供的方法。
你可以直接在 script 標簽中包含這個庫的 URL 地址,或者使用構(gòu)建工具從 npm 中導(dǎo)入它。
使用 script 標簽
Handtrack.js 的最小化 js 文件目前托管在 jsdelivr 上,jsdelivr 是一個免費的開源 CDN,讓你可以在 Web 應(yīng)用程序中包含任何的 npm 包。
<script src="https://cdn.jsdelivr.net/npm/handtrackjs/dist/handtrack.min.js"> </script>
在將上面的 script 標簽添加到 html 頁面后,就可以使用 handTrack 變量引用 handtrack.js,如下所示。
const img=document.getElementById('img'); handTrack.load().then(model=> { model.detect(img).then(predictions=> { console.log('Predictions: ', predictions) // bbox predictions }); });
上面的代碼段將打印出通過 img 標簽傳入的圖像的預(yù)測邊框,如果換了視頻或通過攝像頭提交圖像幀,那么就可以“跟蹤”在每一幀中出現(xiàn)的手。
使用 handtrack.js 跟蹤圖像中的手,你可以調(diào)用 renderPredictions() 方法在 canvas 對象中繪制檢測到的邊框和源圖像。
你可以使用以下命令將 handtrack.js 作為 npm 包來安裝:
npm install --save handtrackjs
下面給出了如何在 React 應(yīng)用程序中導(dǎo)入和使用它的示例。
import * as handTrack from 'handtrackjs'; const img=document.getElementById('img'); // Load the model. handTrack.load().then(model=> { // detect objects in the image. console.log("model loaded") model.detect(img).then(predictions=> { console.log('Predictions: ', predictions); }); });
Handtrack.js 提供了幾種方法。兩個主要的方法是 load() 和 detect(),分別用于加載手部檢測模型和獲取預(yù)測結(jié)果。
load() 方法接受可選的模型參數(shù),允許你控制模型的性能。這個方法以 webmodel 格式(也托管在 jsdelivr 上)加載預(yù)訓(xùn)練的手部檢測模型。
detect() 方法接受輸入源參數(shù)(img、video 或 canvas 對象)并返回圖像中手部位置的邊框預(yù)測結(jié)果。
const modelParams={ flipHorizontal: true, // flip e.g for video imageScaleFactor: 0.7, // reduce input image size . maxNumBoxes: 20, // maximum number of boxes to detect iouThreshold: 0.5, // ioU threshold for non-max suppression scoreThreshold: 0.79, // confidence threshold for predictions. } const img=document.getElementById('img'); handTrack.load(modelParams).then(model=> { model.detect(img).then(predictions=> { console.log('Predictions: ', predictions); }); });
預(yù)測結(jié)果格式如下:
[{ bbox: [x, y, width, height], class: "hand", score: 0.8380282521247864 }, { bbox: [x, y, width, height], class: "hand", score: 0.74644153267145157 }]
Handtrack.js 還提供了其他輔助方法:
庫大小和模型大小
庫大小為 810 KB,主要是因為它與 tensorflow.js 庫捆綁在一起(最新版本存在一些未解決的問題)。
模型大小為 18.5 MB,在初始加載頁面時需要等待一會兒。TF.js 模型通常分為多個文件(在本例中為四個 4.2 MB 的文件和一個 1.7 MB 的文件)。
工作原理
Handtrack.js 使用了 Tensorflow.js 庫,一個靈活而直觀的 API,用于在瀏覽器中從頭開始構(gòu)建和訓(xùn)練模型。它提供了一個低級的 JavaScript 線性代數(shù)庫和一個高級的層 API。
創(chuàng)建基于 Tensorflow.js 的 JavaScript 庫的步驟
數(shù)據(jù)匯編
這個項目中使用的數(shù)據(jù)主要來自 Egohands 數(shù)據(jù)集(http://vision.soic.indiana.edu/projects/egohands/)。其中包括 4800 張人手的圖像,帶有邊框,使用谷歌眼鏡捕獲。
模型訓(xùn)練
使用 Tensorflow 對象檢測 API 訓(xùn)練模型。對于這個項目,我們使用了 Single Shot MultiBox Detector(https://arxiv.org/abs/1512.02325)和 MobileNetV2 架構(gòu)(https://arxiv.org/abs/1801.04381)。然后將訓(xùn)練好的模型導(dǎo)出為 savedmodel。
模型轉(zhuǎn)換
Tensorflow.js 提供了一個模型轉(zhuǎn)換工具,可以用它將 savedmodel 轉(zhuǎn)換為可以在瀏覽器中加載的 webmodel 格式。最后,在轉(zhuǎn)換過程中刪除了對象檢測模型圖的后處理部分。這個優(yōu)化可以讓檢測和預(yù)測操作的速度加倍。
庫的包裝和托管
這個庫由一個主類組成,這個類提供了一些用于加載模型、檢測圖像的方法以及一組其他有用的函數(shù),例如 startVideo、stopVideo、getFPS()、renderPredictions()、getModelParameters()、setModelParameters(),等等。方法的完整描述可以在 Github 上找到:
https://github.com/victordibia/handtrack.js/#other-helper-methods
然后使用 rollup.js 捆綁源文件,并在 npm 上發(fā)布(包括 webmodel 文件)。目前 Handtrack.js 與 Tensorflow.js(v0.13.5)捆綁在一起,主要是因為在編寫這個庫的時候,Tensorflow.js(v0.15)在加載圖像 / 視頻標簽為張量時會發(fā)生類型錯誤。如果新版本修復(fù)了這個問題,我也將更新到最新版本。
什么時候應(yīng)該使用 Handtrack.js?
如果你對基于手勢的交互式體驗感興趣,Handtrack.js 可能會很有用。用戶不需要使用任何額外的傳感器或硬件就可以立即獲得基于手勢的交互體驗。
下面列出了一些(并非所有)相關(guān)的場景:
瀏覽器是單線程的:所以必須確保預(yù)測操作不會阻塞 UI 線程。每個預(yù)測可能需要 50 到 150 毫秒,所以用戶會注意到這個延遲。在將 Handtrack.js 集成到每秒需要多次渲染整個屏幕的應(yīng)用程序中時(例如游戲),我發(fā)現(xiàn)有必要減少每秒的預(yù)測數(shù)量。
逐幀跟蹤手部動作:如果想要跨幀識別手勢,需要編寫額外的代碼來推斷手在進入、移動和離開連續(xù)幀時的 ID。
不正確的預(yù)測:偶爾會出現(xiàn)不正確的預(yù)測(有時候會將臉檢測為手)。我發(fā)現(xiàn),不同的攝像頭和光線條件都需要不同的模型參數(shù)設(shè)置(尤其是置信度閾值)才能獲得良好的檢測效果。更重要的是,這個可以通過額外的數(shù)據(jù)進行改進。
Handtrack.js 代表了新形式 AI 人機交互的早期階段。在瀏覽器方面已經(jīng)有一些很好的想法,例如用于人體姿勢檢測的 posenet:
https://github.com/tensorflow/tfjs-models/tree/master/posenet
以及用于在瀏覽器中檢測面部表情的 handsfree.js:
https://handsfree.js.org/
與此同時,我將在以下這些方面花更多的時間:
創(chuàng)建更好的模型:創(chuàng)建一個強大的基準來評估底層的手部模型。收集更多可提高準確性和穩(wěn)定性的數(shù)據(jù)。
額外的詞匯表:在構(gòu)建樣本時,我發(fā)現(xiàn)這種交互方法的詞匯表很有限。最起碼還需要支持更多的狀態(tài),比如拳頭和攤開的手掌。這意味著需要重新標記數(shù)據(jù)集(或使用一些半監(jiān)督方法)。
額外的模型量化:現(xiàn)在,我們使用的是 MobilenetV2。是否還有更快的解決方案?
英文原文:
https://hackernoon.com/handtrackjs-677c29c1d585
在,終于有可能在瀏覽器中運行人臉識別了!通過本文,我將介紹face-api,它是一個構(gòu)建在tensorflow.js core的JavaScript模塊,它實現(xiàn)了人臉檢測、人臉識別和人臉地標檢測三種類型的CNN。
我們首先研究一個簡單的代碼示例,以用幾行代碼立即開始使用該包。
第一個face-recognition.js,現(xiàn)在又是一個包?
如果你讀過關(guān)于人臉識別與其他的NodeJS文章:(https://medium.com/@muehler.v/node-js-face-recognition-js-simple-and-robust-face-recognition-using-deep-learning-ea5ba8e852),你可能知道,不久前,我組裝了一個類似的包(face-recognition.js)。
起初,我沒有想到在javascript社區(qū)中對臉部識別軟件包的需求如此之高。對于很多人來說,face-recognition.js似乎是一個不錯的免費使用且開源的替代付費服務(wù)的人臉識別服務(wù),就像微軟或亞馬遜提供的一樣。其中很多人問,是否可以在瀏覽器中完全運行完整的人臉識別管道。
在這里,我應(yīng)該感謝tensorflow.js!我設(shè)法使用tfjs-core實現(xiàn)了部分類似的工具,這使你可以在瀏覽器中獲得與face-recognition.js幾乎相同的結(jié)果!最好的部分是,不需要設(shè)置任何外部依賴關(guān)系,可以直接使用。并且,它是GPU加速的,在WebGL上運行操作。
這使我相信,JavaScript社區(qū)需要這樣的瀏覽器包!你可以用這個來構(gòu)建自己的各種各樣的應(yīng)用程序。;)
如何用深度學(xué)習(xí)解決人臉識別問題
如果你希望盡快開始,也可以直接去編碼。但想要更好地理解face-api.js中用于實現(xiàn)人臉識別的方法,我強烈建議你看一看,這里有很多我經(jīng)常被問到的問題。
簡單地說,我們真正想要實現(xiàn)的是,識別一個人的面部圖像(input image)。我們這樣做的方式是為每個我們想要識別的人提供一個(或多個)圖像,并標注人名(reference data)?,F(xiàn)在我們將它們進行比較,并找到最相似的參考圖像。如果兩張圖片足夠相似,我們輸出該人的姓名,否則我們輸出“unknown”。
聽起來不錯吧!然而,還是存在兩個問題。首先,如果我們有一張顯示多個人的圖片,我們想要識別所有的人,該怎么辦?其次,我們需要能夠獲得這種類型的兩張人臉圖像的相似性度量,以便比較它們......
人臉檢測
第一個問題的答案是人臉檢測。簡而言之,我們將首先找到輸入圖像中的所有人臉。對于人臉檢測,face-api.js實現(xiàn)了SSD(Single Shot Multibox Detector),它基本上是基于MobileNetV1的CNN,只是在網(wǎng)絡(luò)頂部疊加了一些額外的盒預(yù)測層。
網(wǎng)絡(luò)返回每個人臉的邊界框及其相應(yīng)的分數(shù),即每個邊界框顯示一個人臉的可能性。分數(shù)用于過濾邊界框,因為圖像中可能根本不包含任何人臉。請注意,即使只有一個人檢索邊界框,也應(yīng)執(zhí)行人臉檢測。
人臉標志檢測和人臉對齊
第一個問題解決了!但是,我們希望對齊邊界框,這樣我們就可以在每個框的人臉中心提取出圖像,然后將它們傳遞給人臉識別網(wǎng)絡(luò),這會使人臉識別更加準確!
為此,face-api.js實現(xiàn)了一個簡單的CNN,它返回給定人臉圖像的68個點的人臉標志:
從地標位置,邊界框可以準確的包圍人臉。在下圖,你可以看到人臉檢測的結(jié)果(左)與對齊的人臉圖像(右)的比較:
人臉識別
現(xiàn)在我們可以將提取并對齊的人臉圖像提供給人臉識別網(wǎng)絡(luò),這個網(wǎng)絡(luò)基于類似ResNet-34的架構(gòu)并且基本上與dlib中實現(xiàn)的架構(gòu)相對應(yīng)。該網(wǎng)絡(luò)已經(jīng)被訓(xùn)練學(xué)習(xí)將人臉的特征映射到人臉描述符(descriptor ,具有128個值的特征矢量),這通常也被稱為人臉嵌入。
現(xiàn)在回到我們最初的比較兩個人臉的問題:我們將使用每個提取的人臉圖像的人臉描述符并將它們與參考數(shù)據(jù)的人臉描述符進行比較。也就是說,我們可以計算兩個人臉描述符之間的歐氏距離,并根據(jù)閾值判斷兩個人臉是否相似(對于150 x 150大小的人臉圖像,0.6是一個很好的閾值)。使用歐幾里德距離的方法非常有效,當然,你也可以使用任何你選擇的分類器。以下gif通過歐幾里德距離將兩幅人臉圖像進行比較:
學(xué)完了人臉識別的理論,我們可以開始編寫一個示例。
編碼
在這個簡短的例子中,我們將逐步了解如何在以下顯示多人的輸入圖像上進行人臉識別:
包括腳本
首先,從 dist/face-api.js或者dist/face-api.min.js的minifed版本中獲取最新的構(gòu)建且包括腳本:
<script src=“face-api.js”> </ script>
鏈接:https://github.com/justadudewhohacks/face-api.js/tree/master/dist
如果你使用npm:
npm i face-api.js
加載模型數(shù)據(jù)
根據(jù)應(yīng)用程序的要求,你可以專門加載所需的模型,但要運行完整的端到端示例,我們需要加載人臉檢測,人臉標識和人臉識別模型。模型文件在repo上可用,下方鏈接中找到。
https://github.com/justadudewhohacks/face-api.js/tree/master/weights
已經(jīng)量化了模型權(quán)重,將模型文件大小減少了75%,以便使你的客戶端僅加載所需的最小數(shù)據(jù)。此外,模型權(quán)重被分割成最大4MB的塊,以允許瀏覽器緩存這些文件,使得它們只需加載一次。
模型文件可以簡單地作為靜態(tài)資源(static asset)提供給你的Web應(yīng)用程序,可以在其他地方托管它們,可以通過指定文件的路徑或url來加載它們。假設(shè)你在models目錄中提供它們并且資源在public/models下:
const MODEL_URL='/models' await faceapi.loadModels(MODEL_URL)
或者,如果你只想加載特定模型:
const MODEL_URL='/models' await faceapi.loadFaceDetectionModel(MODEL_URL) await faceapi.loadFaceLandmarkModel(MODEL_URL) await faceapi.loadFaceRecognitionModel(MODEL_URL)
從輸入圖像接收所有面孔的完整描述
神經(jīng)網(wǎng)絡(luò)接受HTML圖像,畫布或視頻元素或張量作為輸入。要使用score> minScore檢測輸入的人臉邊界框,我們只需聲明:
const minConfidence=0.8 const fullFaceDescriptions=await faceapi.allFaces(input, minConfidence)
完整的人臉描述檢測結(jié)果(邊界框+分數(shù))、人臉標志以及計算出的描述符。正如你所看到的,faceapi.allFaces在前面討論過的所有內(nèi)容都適用于我們。但是,你也可以手動獲取人臉位置和標志。如果這是你的目標,github repo上有幾個示例。
請注意,邊界框和標志位置是相對于原始圖像/媒體大小。如果顯示的圖像尺寸與原始圖像尺寸不一致,則可以調(diào)整它們的尺寸:
const resized=fullFaceDescriptions.map(fd=> fd.forSize(width, height))
我們可以通過將邊界框繪制到畫布中來可視化檢測結(jié)果:
fullFaceDescription.forEach((fd, i)=> { faceapi.drawDetection(canvas, fd.detection, { withScore: true }) })
臉部可 以顯示如下:
fullFaceDescription.forEach((fd, i)=> { faceapi.drawLandmarks(canvas, fd.landmarks, { drawLines: true }) })
通常,我所做的可視化工作是在img元素的頂部覆蓋一個絕對定位的畫布,其寬度和高度相同(參閱github示例以獲取更多信息)。
人臉識別
現(xiàn)在我們知道如何在給定輸入圖像的情況下檢索所有人臉的位置和描述符,即,我們將得到一些圖像,分別顯示每個人并計算他們的人臉描述符。這些描述符將成為我們的參考數(shù)據(jù)。
假設(shè)我們有一些可用的示例圖像,我們首先從url獲取圖像,然后使用faceapi.bufferToImage從其數(shù)據(jù)緩沖區(qū)創(chuàng)建HTML圖像元素:
// fetch images from url as blobs const blobs=await Promise.all( ['sheldon.png' 'raj.png', 'leonard.png', 'howard.png'].map( uri=> (await fetch(uri)).blob() ) ) // convert blobs (buffers) to HTMLImage elements const images=await Promise.all(blobs.map( blob=> await faceapi.bufferToImage(blob) ))
接下來,對于每個圖像,我們定位主體的面部并計算人臉描述符,就像我們之前在輸入圖像時所做的那樣:
const refDescriptions=await Promsie.all(images.map( img=> (await faceapi.allFaces(img))[0] )) const refDescriptors=refDescriptions.map(fd=> fd.descriptor)
現(xiàn)在,我們要做的一切就是遍歷輸入圖像的人臉描述,并在參考數(shù)據(jù)中找到距離最近的描述符:
const sortAsc=(a, b)=> a - b const labels=['sheldon', 'raj', 'leonard', 'howard'] const results=fullFaceDescription.map((fd, i)=> { const bestMatch=refDescriptors.map( refDesc=> ({ label: labels[i], distance: faceapi.euclideanDistance(fd.descriptor, refDesc) }) ).sort(sortAsc)[0] return { detection: fd.detection, label: bestMatch.label, distance: bestMatch.distance } })
如前所述,我們在此使用歐氏距離作為相似性度量,結(jié)果表明工作得很好。我們最終得到了在輸入圖像中檢測到的每個人臉的最佳匹配。
最后,我們可以將邊界框與標簽一起繪制到畫布中以顯示結(jié)果:
// 0.6 is a good distance threshold value to judge // whether the descriptors match or not const maxDistance=0.6 results.forEach(result=> { faceapi.drawDetection(canvas, result.detection, { withScore: false }) const text=`${result.distance < maxDistance ? result.className : 'unkown'} (${result.distance})` const { x, y, height: boxHeight }=detection.getBox() faceapi.drawText( canvas.getContext('2d'), x, y + boxHeight, text ) })
以上我希望你首先了解如何使用api。另外,我建議查看repo中的其他示例。
來自:ATYUN
*請認真填寫需求信息,我們會在24小時內(nèi)與您取得聯(lián)系。