近期百度開源了口罩模型,包括端上和服務(wù)器上的蚕脏,目前已經(jīng)在北京地鐵等實(shí)際上線具钥。我們這里寫一篇教程,教大家如何使用Paddle Inference 部署該口罩模型驯用。
主要內(nèi)容
- 準(zhǔn)備環(huán)境
- 使用Paddle Python API進(jìn)行預(yù)測(cè)
- 構(gòu)建人臉檢測(cè)模型
- 構(gòu)建人臉口罩分類模型
- 結(jié)果可視化
- 總結(jié)
NOTE: 如果大家已經(jīng)有Paddle1.7.0的python環(huán)境脸秽,可通過鏈接 下載整個(gè)程序,解壓后即可運(yùn)行python cam_video.py
實(shí)時(shí)進(jìn)行人臉口罩檢測(cè)蝴乔。(此程序可以在已安裝Paddle1.7.0的Mac os记餐, Linux,Windows 的Server服務(wù)器以及NV Jetson 硬件上運(yùn)行)
一 :準(zhǔn)備環(huán)境
1) 準(zhǔn)備python環(huán)境
sudo apt-get install python3.6-dev liblapack-dev gfortran libfreetype6-dev libpng-dev libjpeg-dev zlib1g-dev patchelf
sudo apt-get install python3-pip
sudo apt-get install python3-opencv
pip install virtualenv -i https://mirror.baidu.com/pypi/simple
2)準(zhǔn)備Paddle環(huán)境
Mac,Windows疑务,Linux可以通過https://www.paddlepaddle.org.cn/ 中的提示進(jìn)行pip 安裝(需要至少1.7的Paddle安裝)葬毫,NV Jetson上可以通過此鏈接下載已有的whl包然后pip安裝。
# 可選:創(chuàng)建Python虛擬環(huán)境雕沿,避免對(duì)全局的環(huán)境造成影響。
virtualenv pd_env --python=python3.6
# 進(jìn)入Python虛擬環(huán)境
source pd_env/bin/activate
# 安裝1.7 Paddle
# 這一步會(huì)同步安裝numpy猴仑,scipy审轮,cv2等依賴,會(huì)消耗較長(zhǎng)的時(shí)間,請(qǐng)耐心等待疾渣。
# 如果為nv jetson 硬件篡诽,先wget https://paddle-inference-dist.cdn.bcebos.com/temp_data/paddlepaddle_gpu-0.0.0-cp36-cp36m-linux_aarch64.whl 獲取whl包,
# 然后使用 pip install -U paddlepaddle_gpu-0.0.0-cp36-cp36m-linux_aarch64.whl 安裝
python3 -m pip install paddlepaddle-gpu==1.7.1.post107 -i https://mirror.baidu.com/pypi/simple
安裝后可以shell中運(yùn)行python榴捡, 通過import paddle
測(cè)試是否安裝成功杈女。
3)準(zhǔn)備usb攝像頭
如果想使用攝像頭實(shí)時(shí)獲取視頻流并進(jìn)行口罩檢測(cè)的話,準(zhǔn)備一個(gè)usb攝像頭吊圾,并插入到自己的機(jī)器上达椰。
二:使用Paddle Inference Python API預(yù)測(cè)。
這個(gè)部分主要通過一段簡(jiǎn)單的程序介紹如何使用Paddle Inference Python API進(jìn)行模型預(yù)測(cè)项乒。
整個(gè)預(yù)測(cè)流程主要包含以下幾個(gè)部分:
1) 創(chuàng)建AnalysisConfig并進(jìn)行配置砰碴,包括設(shè)置模型的路徑,是否開啟gpu板丽, 是否開始顯存優(yōu)化等呈枉。
2) 根據(jù)AnalysisConfig創(chuàng)建predictor。
3) 獲取模型的所有輸入tensor埃碱,并將數(shù)據(jù)設(shè)置到tensor中猖辫。
4) 模型運(yùn)行。
5) 獲取模型的所有輸出tensor砚殿,并將tensor中的數(shù)值獲取保存
代碼如下:
# -*- coding: UTF-8 -*-
import numpy as np
from paddle.fluid.core import AnalysisConfig
from paddle.fluid.core import create_paddle_predictor
class Model:
def __init__(self, model_file, params_file, use_mkldnn=True, use_gpu = False, device_id = 0):
# 通過AnalysisConfig對(duì)配置預(yù)測(cè)引擎啃憎。
config = AnalysisConfig(model_file, params_file)
config.switch_use_feed_fetch_ops(False)
config.switch_specify_input_names(True)
config.enable_memory_optim() # 打開顯存優(yōu)化
if use_gpu:
print ("ENABLE_GPU")
# 設(shè)置使用GPU
config.enable_use_gpu(100, device_id)
# 創(chuàng)建predictor
self.predictor = create_paddle_predictor(config)
def run(self, img_list):
input_names = self.predictor.get_input_names() # 獲取輸入tensor的name
for i, name in enumerate(input_names): # 對(duì)每個(gè)輸入進(jìn)行設(shè)置
input_tensor = self.predictor.get_input_tensor(input_names[i])
input_tensor.reshape(img_list[i].shape)
input_tensor.copy_from_cpu(img_list[i].copy())
self.predictor.zero_copy_run() # 預(yù)測(cè)
results = []
output_names = self.predictor.get_output_names()
# 獲取所有的輸出并放入results中
for i, name in enumerate(output_names):
output_tensor = self.predictor.get_output_tensor(output_names[i])
output_data = output_tensor.copy_to_cpu()
results.append(output_data)
return results
三:構(gòu)建人臉檢測(cè)模型
在整個(gè)口罩檢測(cè)流任務(wù)中,首要做的一件事是對(duì)圖像中的人臉進(jìn)行檢測(cè)似炎。上一節(jié)中我們通過Paddle Inference Python API構(gòu)建了模型預(yù)測(cè)模塊辛萍,在這一節(jié)中,我們將用該模塊來構(gòu)建人臉檢測(cè)模型羡藐。
- 下載人臉檢測(cè)預(yù)測(cè)模型并解壓:
$ wget https://paddle-inference-dist.cdn.bcebos.com/temp_data/nano_mask_detection/pyramidbox_lite.zip
- 創(chuàng)建人臉檢測(cè)的Model對(duì)象贩毕,其中
model
文件表示模型結(jié)構(gòu)文件,params
表示模型參數(shù)文件仆嗦。
face_detector = Model('./pyramidbox_lite/model', './pyramidbox_lite/params')
- 人臉檢測(cè)圖像預(yù)處理
import cv2
import numpy as np
from PIL import Image
import math
def face_detect_preprocess(img, shrink=1.0):
# BGR
img_shape = img.shape
img = cv2.resize(img, (int(img_shape[1] * shrink), int(img_shape[0] * shrink)), interpolation=cv2.INTER_CUBIC)
# HWC -> CHW
img = np.swapaxes(img, 1, 2)
img = np.swapaxes(img, 1, 0)
# RBG to BGR
mean = [104., 117., 123.]
scale = 0.007843
img = img.astype('float32')
img -= np.array(mean)[:, np.newaxis, np.newaxis].astype('float32')
img = img * scale
img = img[np.newaxis, :]
return img
- 讀取圖片并進(jìn)行人臉檢測(cè)模型預(yù)測(cè)辉阶。
下載人臉圖片,wget https://paddle-inference-dist.cdn.bcebos.com/temp_data/nano_mask_detection/test_mask_detection.jpg
人臉圖片
# 讀取圖片
ori_img = cv2.imread('test_mask_detection.jpg')
print (ori_img.shape) # 該圖片為高1050(y軸)瘩扼, 長(zhǎng)1682(x軸)的圖片
# (1050, 1682, 3)
img_h, img_w, c = img
# 人臉檢測(cè)圖像預(yù)處理
img = face_detect_preprocess(ori_img, 0.3) # 0.3表示將讀取的圖片長(zhǎng)谆甜,寬的大小縮小至原來的0.3倍。
# 運(yùn)行人臉檢測(cè)集绰, result中存放檢測(cè)的結(jié)果
result = face_detector.run([img])
print (result[0])
# [[1. 0.99998796 0.27059144 0.18095288 0.39210612 0.43089798]
# [1. 0.99998593 0.5600477 0.32936218 0.66750807 0.55742574]
# [1. 0.9999182 0.693954 0.28346226 0.7878771 0.47385922]
# [1. 0.01414413 0.89871734 0.6311271 0.96674687 0.9164002 ]]
可以看到规辱,該模型的輸出結(jié)果共有四行,每一行的第二個(gè)數(shù)字代表人臉的置信度栽燕,后四個(gè)數(shù)字表示人臉區(qū)域左上角以及右下角的位置信息罕袋。
我們拿輸出結(jié)果的第一行來詳細(xì)說明下每個(gè)數(shù)字的含義:
第一行結(jié)果:[1. 0.99998796 0.27059144 0.18095288 0.39210612 0.43089798] :
0.99998796表示該區(qū)域是人臉的置信度改淑。
0.27059144表示該區(qū)域在原圖中左上角的x軸信息,x軸的坐標(biāo)可以通過 (0.27059144 * 1682) 得到炫贤。
0.18095288 表示該區(qū)域在原圖中左上角的y軸信息,y軸的坐標(biāo)可以通過 (0.18095288 * 1050) 得到付秕。
右下角的信息也可以通過類似上述方式求得兰珍。
- 獲取人臉的坐標(biāo)信息
通過上一節(jié)我們知道,模型輸出的坐標(biāo)信息是一個(gè)小數(shù)询吴,我們通過以下代碼來獲取人臉在原圖中坐標(biāo)的真實(shí)值掠河。
# 該函數(shù)的將檢測(cè)模型的輸出,原圖的高度以及長(zhǎng)度信息作為輸入猛计,輸出所有人臉的左上角坐標(biāo)以及人臉區(qū)域的高度唠摹,長(zhǎng)度信息。
def get_faces(data, h, w):
faces_loc = []
for d in data:
if d[1] >= 0.5:
x_min = max(d[2] * w, 0)
y_min = max(d[3] * h, 0)
x_h = min((d[4] - d[2]) * w, w)
y_w = min((d[5] - d[3]) * h, h)
faces_loc.append([int(x_min), int(y_min), int(x_h), int(y_w)])
return faces_loc
faces = get_faces(result[0], img_h, img_w)
print (faces)
# [[455, 190, 204, 262], [942, 345, 180, 239], [1167, 297, 157, 199]]
四:構(gòu)建人臉口罩分類模型
- 下載口罩人臉檢測(cè)預(yù)測(cè)模型并解壓:
$ wget https://paddle-inference-dist.cdn.bcebos.com/temp_data/nano_mask_detection/mask_detector.zip
- 根據(jù)第二節(jié)中的描述創(chuàng)建口罩分類的Model對(duì)象奉瘤。
mask_classify = Model('./mask_detector/model', './mask_detector/params')
- 口罩分類模型圖像預(yù)處理
同樣勾拉,進(jìn)行口罩分類模型預(yù)測(cè)前,需要對(duì)人臉的圖片進(jìn)行預(yù)處理盗温。
import cv2
import numpy as np
from PIL import Image
import math
# img 為原始圖片藕赞,pts為單個(gè)人臉的坐標(biāo)信息(x1, y1, x2, y1, x1, y2, x2, y2)。
def mask_classify_preprocess(img, pts):
# BGR
img_face, _ = crop(img, pts)
t_img_face = img_face.copy()
img_face = img_face / 256.
# HWC -> CHW
img_face = np.swapaxes(img_face, 1, 2)
img_face = np.swapaxes(img_face, 1, 0)
# RBG to BGR
mean = [0.5, 0.5, 0.5]
img_face = img_face.astype('float32')
img_face -= np.array(mean)[:, np.newaxis, np.newaxis].astype('float32')
img_face = img_face.reshape(-1, 3, 128, 128)
return img_face, t_img_face
# crop函數(shù)會(huì)微調(diào)人臉的框
def crop(image, pts, shift=0, scale=1.5, rotate=0, res_width=128, res_height=128):
res = (res_width, res_height)
idx1 = 0
idx2 = 1
# angle
alpha = 0
if pts[idx2, 0] != -1 and pts[idx2, 1] != -1 and pts[idx1, 0] != -1 and pts[idx1, 1] != -1:
alpha = math.atan2(pts[idx2, 1] - pts[idx1, 1], pts[idx2, 0] - pts[idx1, 0]) * 180 / math.pi
pts[pts == -1] = np.inf
coord_min = np.min(pts, 0)
pts[pts == np.inf] = -1
coord_max = np.max(pts, 0)
# coordinates of center point
c = np.array([coord_max[0] - (coord_max[0] - coord_min[0]) / 2,
coord_max[1] - (coord_max[1] - coord_min[1]) / 2]) # center
max_wh = max((coord_max[0] - coord_min[0]) / 2, (coord_max[1] - coord_min[1]) / 2)
# Shift the center point, rot add eyes angle
c = c + shift * max_wh
rotate = rotate + alpha
M = cv2.getRotationMatrix2D((c[0], c[1]), rotate, res[0] / (2 * max_wh * scale))
M[0, 2] = M[0, 2] - (c[0] - res[0] / 2.0)
M[1, 2] = M[1, 2] - (c[1] - res[0] / 2.0)
image_out = cv2.warpAffine(image, M, res)
return image_out, M
- 人臉口罩分類
在人臉檢測(cè)章節(jié)中卖局,我們進(jìn)行了人臉檢測(cè)斧蜕,通過模型輸出結(jié)果了解到,模型檢測(cè)到了三張人臉砚偶,我們并通過get_faces 函數(shù)獲取到了人臉的真實(shí)坐標(biāo)信息并保存在faces變量中批销。在這一部分中,我們將使用口罩分類模型染坯, 對(duì)這些人臉是否戴有口罩進(jìn)行分析判斷均芽。
faces_with_mask_conf = []
# 遍歷所有的人臉
for loc in faces:
pts = np.array([loc[0], loc[1], loc[2] + loc[0], loc[1], loc[0], loc[1] + loc[3], loc[2] + loc[0], loc[1] + loc[3]]).reshape(4, 2).astype(np.float32)
# 人臉預(yù)處理,并將人臉大小resize到(128单鹿,128)
face_img_t, temp_face = mask_classify_preprocess(ori_img, pts)
mask_results = mask_classify.run([face_img_t])
mask_conf = mask_results[0][0][1] # 獲取戴口罩的置信度
temp_loc = loc
temp_loc.append(mask_conf)
faces_with_mask_conf.append(temp_loc)
print (faces_with_mask_conf)
# [[455, 190, 204, 262, 0.993429], [942, 345, 180, 239, 0.9189134], [1167, 297, 157, 199, 0.28184703]]
我們遍歷每一張人臉的坐標(biāo)骡技,并從原圖中將人臉截取出來,經(jīng)過圖像預(yù)處理后并通過口罩分類模型獲取到該人臉是否帶有口罩的置信度(置信度的值越大說明戴口罩的概率越大)
五: 結(jié)果可視化
到這一步羞反,我們已經(jīng)完成了對(duì)圖片中的人臉進(jìn)行檢測(cè)布朦,并對(duì)每個(gè)人臉進(jìn)行是否戴有口罩的判斷,接下來我們將檢測(cè)的結(jié)果可視化看一下效果昼窗。
from PIL import Image
from PIL import ImageDraw, ImageFont
# 傳入原始圖片是趴,人臉的坐標(biāo)位置以及戴有口罩置信度信息, 該函數(shù)會(huì)將戴口罩人臉畫上藍(lán)框澄惊,不戴口罩的人臉畫上紅框唆途。
def draw_boxes(img, boxes):
h, w, _ = img.shape
image = Image.fromarray(img)
draw = ImageDraw.Draw(image)
for box in boxes:
x_min = box[0]
y_min = box[1]
x_max = box[0] + box[2]
y_max = box[1] + box[3]
(left, right, top, bottom) = (x_min, x_max, y_min, y_max)
color = "red"
if box[4] < 0.6:
color = "blue"
draw.line(
[(left - 10, top - 10), (left - 10, bottom + 10), (right + 10, bottom + 10), (right + 10, top - 10),
(left - 10, top - 10)],
width=10,
fill=color)
conf_text = str(box[4])
img = np.asarray(image)
return img
drawed_img = draw_boxes(ori_img, faces_with_mask_conf)
cv2.imshow("mask_faces", drawed_img)
cv2.waitKey(0)
運(yùn)行上述程序會(huì)在桌面上彈出帶有畫框的圖片富雅。
六: 總結(jié)
在這一章節(jié)中,我們介紹了如何使用Paddle Inference Python api進(jìn)行預(yù)測(cè)模型預(yù)測(cè)肛搬,并且通過代碼一步步的展示了如何在自己的機(jī)器上搭建自己的人臉口罩檢測(cè)任務(wù)没佑。 除此之外,我們還提供了整個(gè)代碼服務(wù)温赔,大家可以通過以下的鏈接下載:https://paddle-inference-dist.cdn.bcebos.com/temp_data/nano_mask_detection/nano_face_detection.tar
解壓后運(yùn)行python cam_video.py
, 程序會(huì)從攝像頭讀取圖像蛤奢,然后實(shí)時(shí)進(jìn)行人臉口罩檢測(cè)。
講到這里陶贼,大家有沒有感覺部署AI應(yīng)用也是非常簡(jiǎn)單的呢啤贩,那還等什么,趕緊在自己的機(jī)器上測(cè)試下吧拜秧!