- 本次就使用PaddleInference將PaddleHub上的兩個模型串聯起來,并部署在CPU桌面平臺上,搭建一個簡單的人臉識別系統
先展示一下效果
部署方案
- PaddleHub本身其實包含一個可直接調用的預測端口,但是使用起來不夠靈活
- 所以本次使用的大概方案是:
- 將兩個模型導出為推理模型
- 使用PaddleInference重寫預測端口,優化預測效率
- 串聯兩個模型,實現人臉識別
- 使用預測結果實現一些小功能
導出推理模型
- 對于人臉檢測模型這類PaddleHub的預置模型來講,導出推理模型是非常簡單的,通過直接調用模型的save_inference_model函數即可一鍵導出推理模型
- 對于人臉驗證模型這類經過Finetune的模型來講,導出推理模型需要先搭建配置模型,然后加載訓練結束的模型參數,然后再調用save_inference_model函數即可導出推理模型
In [ ]
# 安裝新版PaddleHub
!pip install paddlehub==1.8.1
In [ ]
# 人臉檢測模型導出
import paddlehub as hub
# 加載模型
face_detector = hub.Module(name="pyramidbox_lite_mobile")
# 導出推理模型
face_detector.save_inference_model(
dirname='inference/face_detection',
model_filename='__model__',
params_filename='__params__')
In [ ]
# 人臉驗證模型導出
import paddlehub as hub
from paddlehub.dataset.base_cv_dataset import BaseCVDataset
# 新建臨時train.txt
with open('data/train.txt', 'w', encoding='UTF-8') as f:
for x in range(100):
f.write('test 0\\n')
import paddlehub as hub
from paddlehub.dataset.base_cv_dataset import BaseCVDataset
# 自定義數據集
class FaceDataset(BaseCVDataset):
def __init__(self):
# 數據集存放位置
self.dataset_dir = "/home/aistudio/data/"
super(FaceDataset, self).__init__(
base_path=self.dataset_dir,
train_list_file="train.txt",
label_list=['0','1']
)
dataset = FaceDataset()
# 使用mobilenet_v3_large_imagenet_ssld預訓練模型進行finetune
module = hub.Module(name="mobilenet_v3_large_imagenet_ssld")
# 數據讀取器
data_reader = hub.reader.ImageClassificationReader(
image_width=module.get_expected_image_width(),
image_height=module.get_expected_image_height(),
images_mean=module.get_pretrained_images_mean(),
images_std=module.get_pretrained_images_std(),
dataset=dataset)
# 優化器配置
strategy = hub.AdamWeightDecayStrategy(
learning_rate=1e-3,
lr_scheduler="linear_decay",
warmup_proportion=0.1,
weight_decay=0.0001,
optimizer_name="adam")
# 總體配置
config = hub.RunConfig(
use_cuda=False,
num_epoch=10,
checkpoint_dir="mobilenet_v3",
batch_size=100,
eval_interval=100,
strategy=strategy)
# 任務構建
input_dict, output_dict, program = module.context(trainable=True)
img = input_dict["image"]
feature_map = output_dict["feature_map"]
feed_list = [img.name]
task = hub.ImageClassifierTask(
data_reader=data_reader,
feed_list=feed_list,
feature=feature_map,
num_classes=dataset.num_labels,
config=config)
# 加載best_model
task.init_if_load_best_model()
# 導出推理模型
task.save_inference_model(
dirname='inference/face_verification',
model_filename='__model__',
params_filename='__params__')
使用推理模型進行預測
- 使用推理模型部署一般分為如下5步:
- 讀取數據
- 數據預處理
- 模型預測
- 結果后處理
- 結果展示
- 上述模型預測階段也分為5步:
- 配置推理選項
- 創建Predictor
- 準備模型輸入
- 模型推理
- 獲取模型輸出
- 下面就來演示一下如何使用剛剛導出的推理模型完成人臉的檢測和驗證
- 代碼上有詳細的注釋,更多更詳細的使用方法請參考[PaddleInference]
In [1]
# 檢測模型預測
%matplotlib inline
import cv2
import numpy as np
from PIL import Image
from matplotlib import pyplot as plt
from paddle.fluid.core import AnalysisConfig, PaddleTensor
from paddle.fluid.core import create_paddle_predictor
# 數據預處理
def pre_det(org_im, shrink):
image = org_im.copy()
image_height, image_width, image_channel = image.shape
# 圖像縮放
if shrink != 1:
image_height, image_width = int(image_height * shrink), int(
image_width * shrink)
image = cv2.resize(image, (image_width, image_height),
cv2.INTER_NEAREST)
# HWC to CHW
if len(image.shape) == 3:
image = np.swapaxes(image, 1, 2)
image = np.swapaxes(image, 1, 0)
# 歸一化
mean = [104., 117., 123.]
scale = 0.007843
image = image.astype('float32')
image -= np.array(mean)[:, np.newaxis, np.newaxis].astype('float32')
image = image * scale
image = np.expand_dims(image, axis=0).astype('float32')
return image
# 數據后處理
# 輸入原始圖像,根據預測結果繪制人臉預測框,并裁剪人臉圖像
def post_det(img, output_datas):
img_h, img_w = img.shape[:2]
new_img = img.copy()
crops = []
for data in output_datas:
label, score, x1, y1, x2, y2 = data
if score>0.8:
x1, y1, x2, y2 = [int(_) for _ in [x1*img_w, y1*img_h, x2*img_w, y2*img_h]]
crop = img[max(0, y1-50):min(y2+50,img_h),max(0, x1-50):min(x2+50,img_w),:]
h, w = crop.shape[:2]
crop = cv2.resize(crop, (200, int(h/w*200))) if w>h else cv2.resize(crop, (int(w/h*200), 200))
row_nums = 200-crop.shape[0]
line_nums = 200-crop.shape[1]
if row_nums%2 ==0:
crop= np.pad(crop,((row_nums//2,row_nums//2),(0,0),(0,0)),'constant')
else:
crop= np.pad(crop,((row_nums//2,row_nums//2+1),(0,0),(0,0)),'constant')
if line_nums%2 ==0:
crop= np.pad(crop,((0,0),(line_nums//2,line_nums//2),(0,0)),'constant')
else:
crop= np.pad(crop,((0,0),(line_nums//2,line_nums//2+1),(0,0)),'constant')
crops.append(crop)
cv2.rectangle(new_img, (x1, y1), (x2, y2), (255, 0, 0), 2)
return new_img, crops
# 創建預測器
def create_predictor(model_file, params_file):
# 創建配置
config = AnalysisConfig(model_file, params_file)
# 關閉GPU
config.disable_gpu()
# 開啟mkldnn加速intel平臺的CPU推理速度
config.enable_mkldnn()
# 關閉log顯示
config.disable_glog_info()
# 開啟ir優化
config.switch_ir_optim(True)
# 使用feed和fetch的算子
config.switch_use_feed_fetch_ops(True)
# 根據配置創建預測器
predictor = create_paddle_predictor(config)
return predictor
# 模型預測
def predict_det(predictor, inputs):
# 轉換輸入數據為PaddleTensor
inputs = PaddleTensor(inputs.copy())
# 執行前向計算
result = predictor.run([inputs])
# 轉換輸出數據為ndarray
output_data = result[0].as_ndarray()
return output_data
# 實例化檢測模型預測器
predictor = create_predictor('inference/face_detection/__model__', 'inference/face_detection/__params__')
# 讀取圖片
img = cv2.imread('img/test.jpg')
# 原始圖片展示
plt.imshow(img[:,:,::-1])
plt.show()
# 圖像預處理
img1 = pre_det(img, 0.5)
# 模型預測
output_data = predict_det(predictor, img1)
# 結果后處理
img, crops = post_det(img, output_data)
# 結果圖片展示
plt.imshow(img[:,:,::-1])
plt.show()
In [3]
# 驗證模型預測
%matplotlib inline
import cv2
import numpy as np
from PIL import Image
from matplotlib import pyplot as plt
from paddle.fluid.core import AnalysisConfig
from paddle.fluid.core import create_paddle_predictor
# 圖片拼接
def concatenate(true_img, crop):
new = np.concatenate([true_img,crop],1)
return new
# 數據預處理
def pre_val(img):
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = Image.fromarray(img)
# 圖像縮放
image = img.resize((224, 224), Image.LANCZOS)
# HWC to CHW
mean = np.array([0.485,0.456,0.406]).reshape(3, 1, 1)
std = np.array([0.229,0.224,0.225]).reshape(3, 1, 1)
image = np.array(image).astype('float32')
if len(image.shape) == 3:
image = np.swapaxes(image, 1, 2)
image = np.swapaxes(image, 1, 0)
# 歸一化
image /= 255
image -= mean
image /= std
image = image[[0, 1, 2], :, :]
image = np.expand_dims(image, axis=0).astype('float32')
return image
# 創建預測器
def create_predictor(model_file, params_file):
# 創建配置
config = AnalysisConfig(model_file, params_file)
# 關閉GPU
config.disable_gpu()
# 開啟mkldnn加速intel平臺的CPU推理速度
config.enable_mkldnn()
# 關閉log顯示
config.disable_glog_info()
# 開啟ir優化
config.switch_ir_optim(True)
# 不使用feed和fetch的算子
config.switch_use_feed_fetch_ops(False)
# 根據配置創建預測器
predictor = create_paddle_predictor(config)
return predictor
# 模型預測
def predict_val(predictor, inputs):
# 獲取輸入向量名
input_names = predictor.get_input_names()
# 根據輸入向量名獲取輸入向量
input_tensor = predictor.get_input_tensor(input_names[0])
# 將輸入數據拷貝進輸入向量
input_tensor.copy_from_cpu(inputs)
# 執行前向計算
predictor.zero_copy_run()
# 獲取輸出向量名
output_names = predictor.get_output_names()
# 根據輸出向量名獲取輸出向量
output_tensor = predictor.get_output_tensor(output_names[0])
# 從輸出向量中拷貝輸出數據到輸出變量上
output_data = output_tensor.copy_to_cpu()
return output_data
# 實例化檢測模型預測器
predictor = create_predictor('inference/face_verification/__model__', 'inference/face_verification/__params__')
# 讀取圖片
img1 = cv2.imread('img/crop_0.jpg')
img2 = cv2.imread('img/crop_1.jpg')
# 圖像拼接
img_true = concatenate(img1, img1)
img_false = concatenate(img1, img2)
# 輸入圖片展示
plt.imshow(img_true[:,:,::-1])
plt.show()
plt.imshow(img_false[:,:,::-1])
plt.show()
# 數據預處理
img_true = pre_val(img_true)
img_false = pre_val(img_false)
# 數據拼接
imgs = np.concatenate([img_true, img_false], 0)
# 模型預測
output_data = predict_val(predictor, imgs)
# 結果后處理
results = np.argmax(output_data, 1)
for i, result in enumerate(results):
if result:
print('第%d個樣本匹配' % (i+1))
else:
print('第%d個樣本不匹配' % (i+1))
第1個樣本匹配
第2個樣本不匹配
完整程序
- 只需要將上面的兩個代碼稍微封裝,串聯起來,就能實現一個簡單的實時人臉識別系統
- 完整程序存放在face_recognition目錄下,目錄結構如下:
- inference -- 存放推理模型
- preprocess.py -- 數據預處理
- postprocess.py -- 數據后處理
- inference.py -- 模型推理
- main.py -- 主程序
- 僅作為測試使用,未封裝GUI界面
- 使用下面的代碼即可啟動程序
- 將按鈕窗口關閉,并使用Esc鍵退出視頻窗口,即可退出程序
In [ ]
# 請下載代碼并在有攝像頭的系統環境中執行
!python face_recognition/main.py
程序流程
- 通過main.py來介紹一下大致的程序流程
- 具體細節請參考源碼
# 導入所需的包
import cv2, threading
import numpy as np
from inference import AnalysisModel
from preprocess import pre_det, pre_val
from postprocess import post_det
from tkinter import Tk, Button
# 按鈕點擊函數,用于切換人臉
def change_face():
global change_flag
change_flag = True
# 主線程
def main():
global change_flag
# 開啟攝像頭
cap = cv2.VideoCapture(0)
# 初始化兩個模型
model_det = AnalysisModel('inference/face_detection/__model__',
'inference/face_detection/__params__',
True,
False)
model_val = AnalysisModel('inference/face_verification/__model__',
'inference/face_verification/__params__',
False,
True)
tmp = None
font = cv2.FONT_HERSHEY_SIMPLEX
while True:
# 讀取當前幀
sucess, img = cap.read()
# 檢測數據預處理
img_det = pre_det(img, 0.3)
# 檢測模型預測
result_det = model_det.predict_det(img_det)
# 檢測結果后處理
img, crops, bboxes = post_det(img, result_det)
# 如果當前人臉信息不為空,則啟動人臉驗證
if type(tmp) is np.ndarray:
for crop, bbox in zip(crops, bboxes):
# 驗證數據預處理
img_val = pre_val(tmp, crop)
x1, y1 = bbox[:2]
# 驗證模型預測
result_val = model_val.predict_val(img_val)
# 驗證結果后處理
if np.argmax(result_val[0]):
img = cv2.putText(img, 'Success', (x1, y1-4), font, 0.6, (0, 255, 0), 2)
else:
img = cv2.putText(img, 'Faild', (x1, y1-4), font, 0.6, (0, 0, 255), 2)
# 若更換人臉的標識為真,則切換人臉信息
if (len(crops)>0) and change_flag:
tmp = crops[0]
crop = crops[0]
cv2.imshow('Face', crop)
change_flag=False
# 使用窗口顯示結果圖片
cv2.imshow('Face recognition', img)
k = cv2.waitKey(1)
if k == 27:
#通過esc鍵退出攝像
cv2.destroyAllWindows()
break
if __name__=='__main__':
global change_flag
change_flag = False
# 初始化按鈕界面
root = Tk()
root.title('Button')
button = Button(root, text ="點擊抓取人臉圖片", command = change_face)
button.pack()
# 初始化主線程
main_thread = threading.Thread(target=main)
# 啟動主線程
main_thread.start()
# 啟動按鈕界面線程
root.mainloop()
總結
- 這個人臉識別系統實測可用,效果也還能夠接受
- 如果項目有任何錯誤的地方,歡迎大家在評論區中評論指正
關于作者
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。
舉報投訴
-
人臉識別技術
+關注
關注
0文章
125瀏覽量
14511 -
人臉識別
+關注
關注
76文章
4012瀏覽量
81956
發布評論請先 登錄
相關推薦
基于OpenCV的人臉識別系統設計
基于OpenCV的人臉識別系統是一個復雜但功能強大的系統,廣泛應用于安全監控、人機交互、智能家居等多個領域。下面將詳細介紹基于OpenCV的
人臉檢測和人臉識別的區別是什么
人臉檢測和人臉識別是計算機視覺領域的兩個重要技術,它們在許多應用場景中都有廣泛的應用,如安全監控、身份驗證、社交媒體等。盡管它們在某些方面有
人臉檢測與識別的方法有哪些
人臉檢測與識別是計算機視覺領域中的一個重要研究方向,具有廣泛的應用前景,如安全監控、身份認證、智能視頻分析等。本文將詳細介紹人臉檢測與
評論