Jetson Nano搭建人脸检测系统: (二)人脸检测算法

1、人脸检测算法的原理

  人脸检测算法目前以深度学习方向更为准确,本文不进行算法的原理解析,直接以开源的训练好的模型介绍和比较为主。主要介绍MTCNN、Resnet10_SSD、RFBNet三个开源的模型。

2、MTCNN算法

MTCNN原理介绍:https://zhuanlan.zhihu.com/p/38520597
Github上参考来源:https://github.com/LeslieZhoa/tensorflow-MTCNN

MTCNN

import cv2
import sys

from MtcnnDetector import MtcnnDetector
from detector import Detector
from fcn_detector import FcnDetector
from model import P_Net,R_Net,O_Net
from utils import *
import testconfig as config

# 加载MTCNN的三个模型
def load_align():
    thresh=config.thresh
    min_face_size=config.min_face
    stride=config.stride
    test_mode=config.test_mode
    detectors=[None,None,None]
    # 模型放置位置
    model_path=['./model/PNet/','./model/RNet/','./model/ONet']
    batch_size=config.batches
    PNet=FcnDetector(P_Net,model_path[0])
    detectors[0]=PNet


    if test_mode in ["RNet", "ONet"]:
        RNet = Detector(R_Net, 24, batch_size[1], model_path[1])
        detectors[1] = RNet


    if test_mode == "ONet":
        ONet = Detector(O_Net, 48, batch_size[2], model_path[2])
        detectors[2] = ONet

    mtcnn_detector = MtcnnDetector(detectors=detectors, min_face_size=min_face_size,
                                   stride=stride, threshold=thresh)
    return mtcnn_detector

# 检测部分
def align_face(img, mtcnn_detector):
    try:
        boxes_c, _ = mtcnn_detector.detect(img)
    except:
        print('找不到脸')
        return [], [], []
    # 人脸框数量
    num_box = boxes_c.shape[0]
    # 位置坐标
    bb_arr = []

    if num_box > 0:
        det = boxes_c[:, :4]
        det_arr = []
        img_size = np.asarray(img.shape)[:2]
        for i in range(num_box):
            det_arr.append(np.squeeze(det[i]))

        for i, det in enumerate(det_arr):
            det = np.squeeze(det)
            bb = [int(max(det[0], 0)), int(max(det[1], 0)), int(min(det[2], img_size[1])),
                  int(min(det[3], img_size[0]))]
            cv2.rectangle(img, (bb[0], bb[1]), (bb[2], bb[3]), (0, 255, 0), 2)
        return  bb_arr
    else:
        print('找不到脸 ')
        return [], [], []

if __name__ == '__main__':
        mtcnn = load_align()
        img_path = '../1.jpg'
        image = cv2.imread(img_path)
        align_face(image, mtcnn)
        cv2.imshow('main', image)
        cv2.waitKey()

MTCNN的模型过于复杂,运行速度较慢。我减少了PNet前做图像金字塔的次数,同时提高了检测阈值,也没有得到较好地结果。在我的MAC上测得结果如下:
MTCNN检测结果

3、Resnet10_SSD算法

  在这推荐一个工具,能够脱离深度学习框架直接运行已经训练好的模型opencv_dnn模块,能够直接解析caffe、tensorflow、pytorch、onnx的预训练模型。
这次的人脸检测算法参考:https://github.com/thegopieffect/computer_vision/tree/master/CAFFE_DNN

import numpy as np
import cv2

net = cv2.dnn.readNetFromCaffe("./deploy.prototxt",
                               "./res10_300x300_ssd_iter_140000.caffemodel")
def find_face(frame):
    h, w = frame.shape[:2]
    blob = cv2.dnn.blobFromImage(cv2.resize(frame, (320, 240)), 1.0, (320, 240), (104.0, 177.0, 123.0))
    net.setInput(blob)
    detections = net.forward()
    scaled_arr = []
    bb_arr = []
    # loop over the detections
    if detections.shape[2]>0:
        for i in range(0, detections.shape[2]):
            # extract the confidence (i.e., probability) associated with the
            # prediction
            confidence = detections[0, 0, i, 2]

            # filter out weak detections by ensuring the `confidence` is
            # greater than the minimum confidence
            if confidence < 0.8:
                continue
            # compute the (x, y)-coordinates of the bounding box for the object
            box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
            (startX, startY, endX, endY) = box.astype("int")
            cv2.rectangle(frame, (startX, startY), (endX, endY), (0, 255, 0), 2)
            bb_arr.append(box)
            cv2.imshow('main',frame)
            cv2.waitKey(0)
           
        return  bb_arr
    else:
        print('find no face!!!')
        return [],[],[]

if __name__ == '__main__':
    img = cv2.imread('../1.jpg')
    for _ in range(10):
        find_face(img)

这里直接输出了boundingbox的坐标相对真实尺寸的比值,可以通过Netron在线看模型的结构图。可以得出,其比MTCNN模型更加快速,占用内存更少,运行更为简单。同样其测试结果如下:
Resnet_SSD测试结果

4、RFBnet

  RFBnet使用了github上的一个厉害的项目:https://github.com/Linzaer/Ultra-Light-Fast-Generic-Face-Detector-1MB,模型仅有1MB大小但效果却非常好。作者提供了pytorch、caffe、MNN、ONNX等模型和推理代码。其中caffe代码也是利用opencv_dnn模块,读者可自行验证。本次介绍另外一个能够脱离深度学习框架直接运行已经训练好的模型的框架--onnxruntime,而且其还有GPU的版本。

import onnxruntime as rt
import numpy as np
import cv2
from box_util import *
import time

model_path = './version-RFB-320.onnx'
img_path = '../27.jpg'
orig_image = cv2.imread(img_path)

sess = rt.InferenceSession(model_path)
input_name = sess.get_inputs()[0].name
label = sess.get_outputs()[0].name
box = sess.get_outputs()[1].name

for _ in range(10):
    start = time.time()
    image = cv2.cvtColor(orig_image, cv2.COLOR_BGR2RGB)
    image = (cv2.resize(image, (320, 240)) - 127.0)/128

    image = np.transpose(image, [2, 0, 1])
    image = np.expand_dims(image, axis=0)
    image = image.astype(np.float32)
    # 多个输出时可以以None运行获得多个输出
    confidences, boxes = sess.run(None, {input_name: image})
    boxes = predict(orig_image.shape[1], orig_image.shape[0], confidences, boxes, 0.6, iou_threshold=0.3)

    for i in range(boxes.shape[0]):
        box = boxes[i, :]
        cv2.rectangle(orig_image, (box[0], box[1]), (box[2], box[3]), (255, 255, 0), 4)

    end = time.time()
    seconds = end - start
    print("Time taken : {0} seconds".format(seconds))
    # Calculate frames per second
    fps = 1 / seconds
    print("Estimated frames per second : {0}".format(fps))

cv2.imshow('main', orig_image)
cv2.waitKey()

整个运行过程非常简洁,适合做快速验证。可以通过Netron在线看模型的结构图,同样其测试结果如下
RFBNet测试结果

5、总结

  最后本文选择使用第三种人脸检测模型,效果好而且速度快。将其通过TensorRT部署在Jetson Nano上得到一个至少30fps人脸检测器。


©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,527评论 5 470
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,314评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,535评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,006评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,961评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,220评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,664评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,351评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,481评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,397评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,443评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,123评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,713评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,801评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,010评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,494评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,075评论 2 341

推荐阅读更多精彩内容