【ATU Book-i.MX8系列 - TFLite 進階】 面網偵測應用

一.   概述

邊緣運算的重點技術之中,模組輕量化網路架構 是不可或缺的一環,如何高效的利用硬體資源來達到最佳目標,特別是在效能與準確度的衡量上,是個非常有趣的議題。此章節再來探討深度學習熱門的研究項目之一 人臉關鍵點偵測(Facial KeyPoints Detection) ,主要用於預測人的臉部特徵點位置,可衍伸應用至分析表情、人臉輪廓偵測、人臉替換等等。而具代表性的研究項目為 Dlib、DAN、Facemesh 等等,本範例採用 Google 發佈的 FaceMesh 結合 輕量化網路架構 MobileNet 作為應用主軸 ,後續將介紹演算法的基本概念。

 

若新讀者欲理解更多人工智慧、機器學習以及深度學習的資訊,可點選查閱下方博文
 大大通精彩博文   【ATU Book-i.MX8系列】博文索引

TensorFlow Lite 進階系列博文-文章架構示意圖

 

二.  算法介紹

神經網路架構探討 :

人臉關鍵點偵測並非著重於架構的改變,更重要的是如何運用特徵。如下圖所示,左側為 Facial keypoint 的典型做法,以 68 點來描述面部的特徵。右側則是 FaceMesh的新穎做法,以 468 點來描述面部的特徵。此外 FaceMesh 也是利用 MobileNet 架構來預測這 468 個特徵點的位置資訊。FaceMesh 於一般的 Facial keypoint 概念不同的地方是引入的 3D 特徵點,取得原本偵測熱圖的概念 (可查看後續 Pose Estimation 章節)。故預測後得到參數應為特徵點的像素坐標 (x,y),網格重心的深度值為 z ,共三個維度。

Facial keypoint 與 FaceMesh 特徵點概念示意圖

圖片來源 - MediaPipe

 

 

三.  算法實現

Google 官方有提供效果極佳的 facemesh.tflite 模組,故利用 TensorFlow Lite 與 ONNX 的轉換,將 MediaPipe 團隊提供的模組應用至 i.MX8M Plus 平台來實現所謂的 面網偵測(FaceMesh)
範例連結 : https://google.github.io/mediapipe/solutions/face_mesh.html 

實現步驟如下:

第一步 : 開啟 Colab 設定環境

%tensorflow_version 2.x

 第二步 : 下載轉換套件

! pip install tf2onnx
! pip install onnx-tf

第三步下載 MediaPipe FaceMesh 模組

! cd /root
! git clone https://github.com/google/mediapipe
! cp /root/mediapipe/mediapipe/modules/face_landmark/face_landmark.tflite /root/facemesh.tflite

第四步 :  TensorFlow Lite 轉為 ONNX 格式

! python -m tf2onnx.convert --opset 9 --tflite /root/facemesh.tflite --output /root/facemesh.onnx

第五步 :  ONNX 轉為 SavedModel 格式

! onnx-tf convert -i /root/facemesh.onnx -o /root/facemesh

第六步 :  TensorFlow  Lite 轉換

import tensorflow as tf
import numpy as np
def representative_dataset_gen():
for _ in range(250):
yield [np.random.uniform(0.0, 1.0, size=(1, 192, 192, 3)).astype(np.float32)]
converter = tf.lite.TFLiteConverter.from_saved_model("/root/facemesh")
converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS,tf.lite.OpsSet.SELECT_TF_OPS]
converter.inference_input_type = tf.uint8
converter.inference_output_type = tf.float32
converter.representative_dataset = representative_dataset_gen
tflite_model = converter.convert()
with open('/root/facemesh_uint8.tflite','wb') as f:
f.write(tflite_model)

第七步 : FaceMesh 範例實現 (於 i.MX8M Plus 撰寫運行)

需搭配人臉偵測找出人臉位置,若相關模型請查看 ”人臉偵測(face Detection) ” 章節

import cv2
import numpy as np
from tflite_runtime.interpreter import Interpreter

# 載入人臉檢測器(face detector) , 解析 tensorflow lite 檔案
interpreterFaceExtractor = Interpreter(model_path='mobilenetssd_uint8_face.tflite')
interpreterFaceExtractor.allocate_tensors()
input_details = interpreterFaceExtractor.get_input_details()

output_details = interpreterFaceExtractor.get_output_details()
width = input_details[0]['shape'][2]
height = input_details[0]['shape'][1]

# 載入面網檢測器(facemesh detector) , 解析 tensorflow lite 檔案
interpreterFaceMesh = Interpreter(model_path='/root/facemesh_uint8.tflite')
interpreterFaceMesh.allocate_tensors()
facemesh_input_details = interpreterFaceMesh.get_input_details()
facemesh_output_details = interpreterFaceMesh.get_output_details()
facemesh_width = facemesh_input_details[0]['shape'][1]
facemesh_height = facemesh_input_details[0]['shape'][2]

# 載入影像資訊,並設置張量 Tensor
frame = cv2.imread("/root/YangMi.jpg")
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
frame_resized = cv2.resize(frame_rgb/255, (width, height))
input_data = np.expand_dims(frame_resized, axis=0)

# 檢測出人臉位置資訊
interpreterFaceExtractor.set_tensor(input_details[0]['index'], input_data)
interpreterFaceExtractor.invoke()
detection_boxes = interpreterFaceExtractor.get_tensor(output_details[0]['index'])
detection_classes = interpreterFaceExtractor.get_tensor(output_details[1]['index'])
detection_scores = interpreterFaceExtractor.get_tensor(output_details[2]['index'])
num_boxes = interpreterFaceExtractor.get_tensor(output_details[3]['index'])

# 檢測每一個人臉
for i in range(1):
if detection_scores[0, i] > .5:

# 人臉位置
x = detection_boxes[0, i, [1, 3]] * frame_rgb.shape[1]
y = detection_boxes[0, i, [0, 2]] * frame_rgb.shape[0]
y[1] = y[1] + 15 # offset, 因人臉偵測給予的框架之下巴範圍過少
cv2.rectangle(frame, (x[0], y[0]), (x[1], y[1]), (0, 255, 0), 2)

# 人臉位置資訊整合
roi_x0 = max(0, np.floor(x[0] + 0.5).astype('int32'))
roi_y0 = max(0, np.floor(y[0] + 0.5).astype('int32'))
roi_x1 = min(frame.shape[1], np.floor(x[1] + 0.5).astype('int32'))
roi_y1 = min(frame.shape[0], np.floor(y[1] + 0.5).astype('int32'))

# 感興趣區域 (擷取人臉)
roi = frame_rgb[ roi_y0 : roi_y1, roi_x0 : roi_x1, :]

# 設置來源資料至解譯器
roi_resized = cv2.resize(roi, (facemesh_width, facemesh_height))
facemesh_input_data = np.expand_dims(roi_resized.astype("uint8"), axis=0)
interpreterFaceMesh.set_tensor(facemesh_input_details[0]['index'], facemesh_input_data)

# 面網偵測
interpreterFaceMesh.invoke()

# 畫出面網
mesh = interpreterFaceMesh.get_tensor(facemesh_output_details[1]['index']).reshape(468, 3) # 特徵點
size_rate = [roi.shape[1]/facemesh_width, roi.shape[0]/facemesh_height]
for pt in mesh:
x = int(roi_x0 + pt[0]*size_rate[0])
y = int(roi_y0 + pt[1]*size_rate[1])
cv2.circle(frame, ( x ,y ), 1, (0, 0, 255), 1)

cv2.imshow('facemesh',frame)
cv2.waitKey(0)

 

 Face mesh 實現結果呈現 

如下圖所示,成功檢測出臉部面網資訊。
在 i.MX8M Plus 的 NPU 處理器 推理時間(Inference Time) 約 2.91  ms。

 

 

四.  結語

面網偵測應用 (FaceMesh) 通常需要搭配 人臉偵測(Face Detection) 來作應用。也就是偵測到人臉的位置後,將局部會特徵交付給面網偵測模組進行特徵提取,才能將準確度應用最大化。最後利用所檢測到的 68 個臉部特徵點來作後續的判斷機制,即可以實現疲勞駕駛或是閉眼、張口檢測等等應用。目前運行在 i.MX8MP 的 Vivante VIP8000 NPU,其推理時間可達每秒 2.91 ms 的處理速度,約 330 張 FPS,以及在正面臉部檢測時,有不錯的檢測率 。由於此範例屬於複合式的應用,故實際花費時間應該為人臉與面網偵測的花費時間,粗估計算為 10 ms + N * ( 3 ms ) ,其中 N 為偵測到的人臉數量。下一章節將會介紹熱門應用之一的 “肢體識別(Pose Estimation)” ,敬請期待 !!。

 

五.  參考文件

[1] SSD: Single Shot MultiBox Detector
[2] SSD-Tensorflow
[3] Single Shot MultiBox Detector (SSD) 論文閱讀
[4] ssd-mobilenet v1 演算法結構及程式碼介紹
[5] Get models for TensorFlow Lite
[6] widerface-to-tfrecord
[7] Real-time Facial Surface Geometry from Monocular Video on Mobile GPUs
[8] MobileNets: Efficient Convolutional Neural Networks for Mobile Vision
[9] MediaPipe Face Mesh

如有任何相關 TensorFlow Lite 進階技術問題,歡迎至博文底下留言提問 !!
接下來還會分享更多 TensorFlow Lite 進階文章 !!敬請期待 【ATU Book-i.MX8系列 – TFLite 進階】 !!

★博文內容均由個人提供,與平台無關,如有違法或侵權,請與網站管理員聯繫。

★文明上網,請理性發言。內容一周內被舉報5次,發文人進小黑屋喔~

參考來源

評論