Jetson nano实战系列:基于dlib+FaceNet实现人脸识别

0、序

0.1、FaceNet是啥?

  由Google工程师Florian Schroff、Dmitry Kalenichenko、 James Philbin在2015年提出的人脸识别的模型,从现在来看的话有点上古时期的东西的感觉。但是FaceNet的首先改变了人脸验证和人脸识别系统需要分开训练两个神经网络的状况,将两者统一到一个框架之中。FaceNet主要用于验证人脸是否为同一个人,以及通过人脸识别得出这个人是谁等方面的应用。与之前人脸识别的方法大相庭径,FaceNet也是将人脸的特征数据映射到一个多维的空间,通过空间的欧式距离来获取人脸数据的相似度。欧式距离越小,两张脸的相似度就越大。FaceNet采用基于深度神经网络的图像映射方法和基于Triplets的Loss函数训练神经网络,网络直接输出128维的向量空间。如图1所示,深度学习框架在这里就像一个黑箱一样,我们只是需要给其输入Batch,这里的Batch指的是人脸图像的样本。Deep Architecture指的是采用一种深度学习架构,是Google在2014年提出的GoogLeNet网络,是一个22层的深度网络。
在这里插入图片描述
  L2是指特征归一化,这样所有的图像的特征都会被映射到一个超球面上。Enbedding是经由前面所说的GoogLeNet深度学习网络输出的并经由L2归一化后生成的特征向量。在FaceNet的末端是其提出的新的损失函数Triplet Loss。FaceNet学习的过程就是使三元组中尽可能多的Anchor到Positive的距离小于Anchor到Negative的距离,即属于同一个人的尽可能近,不属于同一个人的尽可能远。

(i)Negatives: Regions that the Intersec-tion-over-Union (IoU) ratio less than 0.3 to any ground-truth faces;
(ii) Positives: IoU above 0.65 to a ground truth face;
(iii) Part faces: IoU between 0.4 and 0.65 to a ground truth face;

在这里插入图片描述
  如上图所示,末端的Triplet Loss损失函数的目的是直接学习特征间的可分性。传统的Loss函数通常都是Single or Double Loss, 趋向于将有一类特征的人脸图像映射到同一个空间中,而Triplet Loss则是尝试将一个个体的人脸图像和其他人的图像进行分开。
在这里插入图片描述
  即在每次训练中取3张人脸的图像,分别记为 x i a x_i^a xia x i p x_i^p xip x i n x_i^n xin,其中a和p为同一人的人脸图像,n为另一个人的人脸图像,三元组损失是直接对距离进行优化,可以解决人脸特征的表示问题但是需要非常大的数据量才能有很好的效果。

0.2、FaceNet的优点

   FaceNet中没有限制需要人脸对齐。该模型的优点是只需要对图片进行很少量的处理(只需要裁剪脸部区域,而不需要额外预处理,比如3d对齐等),即可作为模型输入。同时,该模型在数据集上准确率非常高。FaceNet并没有像DeepFace和DeepID那样需要对齐。FaceNet得到最终表示后不用像DeepID那样需要再训练模型进行分类,直接计算距离就好了,简单而有效。
论文下载传送门:https://arxiv.org/pdf/1503.03832.pdf

1、环境准备

1.1、依赖库安装

sudo apt-get install libopenblas-dev gfortrandir
pip3 install scipy
pip3 install scikit-learn
pip3 install Pillow

   在上述的相关依赖库中因为网络问题,scipy下载会出现Read timed out.等错误,强烈建议直接下载源文件包,进行本地安装。scipy源码传送门:https://github.com/scipy/scipy/releases,下载完成之后进行本地安装。

pip3 install scipy-1.2.3.tar.gz

在这里插入图片描述

1.2、clone FaceNet项目源码

git clone https://github.com/davidsandberg/facenet ./

   进入FaceNet src目录,打开python环境,试着导入facenet运行库,查看是否能列出相关的内置函数。
在这里插入图片描述

1.3、下载预训练模型

   资源传送门:https://github.com/davidsandberg/facenet
此处使用的预训练模型是:20180402-114759.zip,解压后放置到工作路径。
在这里插入图片描述

2、Coding

在这里插入图片描述

2.1、新建FaceNet model类,编写相关构造函数,推理函数,析构函数

import tensorflow.compat.v1 as tf
from scipy import misc
import facenet
import numpy as np

#facenet network class
class FaceNetModel():
    def __init__(self, model_file):
        tf.Graph().as_default()
        facenet.load_model('20180402-114759.pb')
        
        self.image_placeholder = tf.get_default_graph().get_tensor_by_name("input:0")
        self.phase_train_placeholder = tf.get_default_graph().get_tensor_by_name("phase_train:0")

        self.embeddings_op = tf.get_default_graph().get_tensor_by_name("embeddings:0")

        self.sess = tf.Session()


    def get_descriptor(self, image):
        
        image = misc.imresize(image, (160,160), interp = "bilinear")
        image = facenet.prewhiten(image)
        images = np.stack([image])

        feed_dict = {self.image_placeholder:images, self.phase_train_placeholder:False}

        emb = self.sess.run(self.embeddings_op, feed_dict = feed_dict)

        return emb[0,:]

    def __del__(self):
        self.sess.close()

def get_FaceNetModel(model_file):
    return FaceNetModel(model_file)

2.2、Face register

import dlib
import cv2
import os
import facenet_model
import pickle

font = cv2.FONT_HERSHEY_SIMPLEX
detector = dlib.get_frontal_face_detector()

face_net = facenet_model.get_FaceNetModel('20180402-114759.pb')
imagePATH = '/home/colin/works/face_recognition_facenet/dataset/processed/Colin/'

def create_known(path):
    global font
    person_names    = []
    face_features   = []

    print("creating known face lib...")
    for file_name in os.listdir(path):
        if '.jpg' in file_name or '.png' in file_name:
            #read imege and change to RGB
            image = cv2.imread(path + file_name)
            rgb_img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
            
            #detect face
            dets = detector(rgb_img)
            
            if(len(dets) == 0):
                continue
            
            det = dets[0]
            face_img = rgb_img[det.top():det.bottom(), det.left():det.right()]
            descriptor = face_net.get_descriptor(face_img)

            person_name = file_name[:file_name.rfind('_')]
            person_names.append(person_name)

            face_features.append(descriptor)
            print('Appending + '+person_name+'...')

    with open('train.pkl', 'wb') as f:
        pickle.dump(person_names, f)
        pickle.dump(face_features, f)

    print('Face Library Created!')
    #return person_names, face_features

if __name__ == '__main__':
    create_known(imagePATH)

2.3、Face recognition

import cv2
import os
import time
import numpy as np
import facenet_model
import dlib
import pickle

import image_shop
################################ Global variable ######################################
person_names = []
face_features = []
imagePATH = '/home/colin/works/face_recognition_facenet/dataset/processed/Colin/'
detector = dlib.get_frontal_face_detector()
face_net = facenet_model.get_FaceNetModel('20180402-114759.pb')
########################################################################################

# 640 480 320 240
def gstreamer_pipeline(
    capture_width=320,
    capture_height=240,
    display_width=320,
    display_height=240,
    framerate=30,
    flip_method=0,
):
    return (
        "nvarguscamerasrc ! "
        "video/x-raw(memory:NVMM), "
        "width=(int)%d, height=(int)%d, "
        "format=(string)NV12, framerate=(fraction)%d/1 ! "
        "nvvidconv flip-method=%d ! "
        "video/x-raw, width=(int)%d, height=(int)%d, format=(string)BGRx ! "
        "videoconvert ! "
        "video/x-raw, format=(string)BGR ! appsink"
        % (
            capture_width,
            capture_height,
            framerate,
            flip_method,
            display_width,
            display_height,
        )
)

def train_data_load():
    global person_names, face_features

    with open('train.pkl','rb') as f:
        person_names=pickle.load(f)
        face_features=pickle.load(f)

        
def facenet_recognition(image):
    rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    dets = detector(rgb_image)
    #dets = detector(gray_image, 2)
    for det in dets:
        if(det.top() < 0) or (det.bottom() < 0) or (det.left() < 0) or (det.right() < 0):
            continue
        
        #get the face area
        face_img = rgb_image[det.top():det.bottom(), det.left():det.right()]
        #get the face descriptor
        descriptor = face_net.get_descriptor(face_img)
        
        min_dist = 0.7 #1
        person_name = 'unknown'
        for i in range(len(face_features)):
            dist = np.linalg.norm(descriptor-face_features[i])
            print('dist:', dist)
            if dist < min_dist:
                min_dist = dist
                person_name = person_names[i]

        cv2.rectangle(image, (det.left(), det.top()+10), (det.right(), det.bottom()), (0, 255, 0), 2)
        cv2.putText(image, person_name , (det.left(),det.top()), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255,0,0), 2, cv2.LINE_AA)

        image = image_shop.mark_add(det.left(), det.right(), det.top(), det.bottom(), image)

    return image

def face_recognition_livevideo(window_name, camera_idx):
    cv2.namedWindow(window_name)

    #CSI Camera for get pipeline
    cap = cv2.VideoCapture(gstreamer_pipeline(flip_method=camera_idx), cv2.CAP_GSTREAMER)
    
    while cap.isOpened():
        ok, frame = cap.read() #read 1 frame
        if not ok:
            break
        resImage = facenet_recognition(frame)
        #display
        cv2.imshow(window_name, resImage)
        c = cv2.waitKey(1)
        if c & 0xFF == ord('q'):
            break

    #close
    cap.release()
    cv2.destroyAllWindows()    


if __name__ == '__main__':
    train_data_load()
    face_recognition_livevideo('Find Face', 0)

3、Demo效果

在这里插入图片描述

参考附录

1)《基于NVIDIA Jetson平台的人工智能实例开发入门》

  • 4
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
### 回答1: Jetson Nano是一款由NVIDIA开发的小型人工智能计算机,用于运行深度学习模型和处理复杂的计算任务。您提到的错误提示“torch-1.8.0 cu111-cp36-cp36m-linux_x86_64.whl不是一个su”,可能出现在尝试安装torch库时。 这个错误可能是由以下几个原因引起的: 1. 文件名错误:请确保您下载的torch安装包文件名正确,并且在命令行中正确地引用该文件。 2. 文件损坏:下载过程中出现网络问题或文件传输错误可能导致文件损坏。您可以尝试重新下载torch安装包,并确保下载过程中没有任何中断。 3. 兼容性问题:请确保您下载的torch安装包与您的Jetson Nano版本和操作系统兼容。不同的操作系统和硬件需要不同版本的软件库,如果版本不匹配可能会导致安装错误。 解决这个错误的方法是: 1. 检查文件名:确保torch安装包的文件名正确,确保在安装命令中正确引用该文件。 2. 重新下载:如果您怀疑文件损坏,请尝试重新下载torch安装包,并确保下载过程没有中断或网络问题。 3. 兼容性检查:请确保您下载的torch安装包与Jetson Nano的版本和操作系统兼容。您可以查阅官方文档或咨询技术支持以获得准确的兼容性信息。 希望这些解决方法能够帮助您解决Jetson Nano安装torch库时遇到的错误。如果问题仍然存在,请进一步检查错误信息的详细描述或寻求更专业的技术支持。 ### 回答2: 该错误是因为Jetson Nano上安装的Torch版本不兼容。Jetson Nano是一款基于ARM架构的嵌入式设备,而cu111-cp36-cp36m-linux_x86_64.whl是专为x86架构的计算机编译的。因此,此错误提示说明您尝试安装的Torch版本不适用于Jetson Nano。 要解决此问题,您需要找到适用于Jetson Nano的Torch版本。Jetson Nano使用的是ARM架构,因此您需要安装ARM架构的Torch版本。您可以尝试在Torch官方网站或Jetson Nano的开发者社区中寻找适用于Jetson Nano的Torch版本。 一旦找到适用于Jetson Nano的Torch版本,您可以按照安装指南进行安装操作。请确保按照指南正确配置环境变量和依赖项,以确保Torch能够在Jetson Nano上正常运行。 另外,请确保您的Jetson Nano固件和操作系统是最新的,因为某些Torch版本只支持特定的固件和操作系统版本。如果您的固件或操作系统过旧,建议先进行更新。 总之,通过找到适用于Jetson Nano的Torch版本,并正确进行安装和配置,您就能够解决"jetson nano error: torch-1.8.0 cu111-cp36-cp36m-linux_x86_64.whl is not a su"这个错误。 ### 回答3: Jetson Nano是一款由NVIDIA推出的嵌入式开发板,用于运行深度学习任务。您遇到的错误是关于安装Torch深度学习框架时出现了问题。错误提示"torch-1.8.0 cu111-cp36-cp36m-linux_x86_64.whl is not a su",可能有以下几个原因和解决方法: 1. 文件格式错误:您下载的torch安装包可能是损坏的,或者不是正确的文件格式。请确保下载的文件为正确的whl文件格式,可以尝试重新下载。 2. 版本不匹配:Jetson Nano中使用的是特定的CUDA版本,在安装Torch时需要匹配正确的CUDA版本。请确认您所下载的torch安装包与Jetson Nano所使用的CUDA版本相匹配,可以查看NVIDIA官方文档或论坛了解更多细节。 3. 系统不兼容:Jetson Nano使用的是基于ARM架构的Linux系统,而安装包可能适用于x86_64架构的系统。请确保下载的torch安装包适用于ARM架构的Linux系统。 解决方法可以尝试以下步骤: 1. 检查下载的torch安装包是否完整,可以尝试重新下载。 2. 确认所使用的Jetson Nano板卡的CUDA版本,并下载与之匹配的torch安装包。 3. 确保下载的torch安装包适用于Jetson Nano的ARM架构的Linux系统。 4. 如果问题仍然存在,可以在NVIDIA的官方论坛或社区中寻求帮助,其他用户可能已经遇到过类似的问题并有解决办法。 希望以上信息对您有帮助,祝您顺利解决问题!
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@菠萝菠萝哒

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值