亚马逊门铃系统上的人脸识别是如何实现的?

磐创AI
关注


加载模型的代码很简单。模型存储在目录model/files/中。from tensorflow.keras.models import load_model

model = load_model('model/facenet_keras.h5')

开发一个模型来概括它以前从未见过的面孔是很困难的。FaceNet模型是在MS-Celeb-1M数据集上训练的,该数据集包含100万张不同名人的照片。通过对同一个人的图像组进行L2归一化,以及余弦相似函数,FaceNet能够产生令人难以置信的高识别精度。我发明了一种方便的方法来登记你家人的面孔,运行submit_face.py,并传递参数“name”(要注册的人的名字)。另外,为了提高准确性和匹配照明条件,你可以使用布尔参数“from_door”,如果为真,将直接从你的门铃的最后录制的视频中保存图像。这些图像被存储在目录data/faces/中。用MTCNN人脸检测对它们进行预裁剪。检测方法将在稍后显示,它是face_recognition.py的一部分。对于拍到的视频,我抓取了视频的特定帧,并测试哪些帧可以工作。我们将需要做一些图像预处理,以及其他小的函数,我将在utils.py中定义:import cv2
def normalize(img):
   mean, std = img.mean(), img.std()
   return (img - mean) / (std + 1e-7)
def preprocess(cv2_img):
   cv2_img = normalize(cv2_img)
   cv2_img = cv2.resize(cv2_img, (160, 160))
   return cv2_img
def get_specific_frames(video_path, times):
   vidcap = cv2.VideoCapture(video_path)
   frames = []
   for time in times:
       vidcap.set(1, time * 15)
       success, image = vidcap.read()
       if success:
           frames.append(image)
   return frames

一旦你想要识别的每个人的图像都在目录data/faces/中,我们就可以将其转换为编码。我们把这作为单独的一步,因为我们L2标准化了每个人对应的所有图像。import os
from utils import preprocess
import cv2
import numpy as np
from sklearn.preprocessing import Normalizer
import face_recognition
import pickle
encoding_dict = {}
l2_normalizer = Normalizer('l2')
for face_names in os.listdir('data/faces/'):
   person_dir = os.path.join('data/faces/', face_names)
   encodes = []
   for image_name in os.listdir(person_dir):
       image_path = os.path.join(person_dir, image_name)
       face = cv2.imread(image_path)
       face = preprocess(face)
       encoding = face_recognition.encode(face)
       encodes.append(encoding)
   if encodes:
       encoding = np.sum(encodes, axis=0)
       encoding = l2_normalizer.transform(np.expand_dims(encoding, axis=0))[0]
       encoding_dict[face_names] = encoding
path = 'data/encodings/encoding.pkl'
with open(path, 'wb') as file:
   pickle.dump(encoding_dict, file)

预处理函数是我用来标准化图像并将其重塑为(160,160,3)的函数,而识别函数是一个执行编码函数的类。如果你注意到了,我将这些编码保存为字典。在执行实时识别时,这个字典很方便,因为它是存储人名和编码的一种简单方法。实时人脸识别现在我们有了我们想要识别的人的图像,那么实时识别过程是如何工作的呢?如下图所示:

门铃响时,下载一个视频,选择多个帧。利用这些帧,用detect_faces方法进行多实例的人脸检测。下面是face_recognition.py 类的一个片段:import cv2
import mtcnn
face_detector = mtcnn.MTCNN()
conf_t = 0.99
def detect_faces(cv2_img):
   img_rgb = cv2.cvtColor(cv2_img, cv2.COLOR_BGR2RGB)
   results = face_detector.detect_faces(img_rgb)
   faces = []
   for res in results:
       x1, y1, width, height = res['box']
       x1, y1 = abs(x1), abs(y1)
       x2, y2 = x1 + width, y1 + height
       confidence = res['confidence']
       if confidence < conf_t:
           continue
       faces.append(cv2_img[y1:y2, x1:x2])
   return faces
def detect_face(cv2_img):
   img_rgb = cv2.cvtColor(cv2_img, cv2.COLOR_BGR2RGB)
   results = face_detector.detect_faces(img_rgb)
   x1, y1, width, height = results[0]['box']
   cv2.waitKey(1)
   x1, y1 = abs(x1), abs(y1)
   x2, y2 = x1 + width, y1 + height
   confidence = results[0]['confidence']
   if confidence < conf_t:
       return None
   return cv2_img[y1:y2, x1:x2]

对图像进行预处理并送入FaceNet。FaceNet将输出每个人脸的128维嵌入。然后使用余弦相似度将这些向量与encode .pkl中存储的向量进行比较。人脸与输入人脸最接近的人被返回。如果一张脸距离它最近的脸有一个特定的阈值,则返回“未知”。这表明这张脸不像任何已知的脸。下面是face_recognition.py类的其余部分:from utils import preprocess
from model.facenet_loader import model
import numpy as np
from scipy.spatial.distance import cosine
import pickle
from sklearn.preprocessing import Normalizer
l2_normalizer = Normalizer('l2')
def encode(img):
   img = np.expand_dims(img, axis=0)
   out = model.predict(img)[0]
   return out
def load_database():
   with open('data/encodings/encoding.pkl', 'rb') as f:
       database = pickle.load(f)
   return database
recog_t = 0.35
def recognize(img):
   people = detect_faces(img)
   if len(people) == 0:
       return None
   best_people = []
   people = [preprocess(person) for person in people]
   encoded = [encode(person) for person in people]
   encoded = [l2_normalizer.transform(encoding.reshape(1, -1))[0]
              for encoding in encoded]
   database = load_database()
   for person in encoded:
       best = 1
       best_name = ''
       for k, v in database.items():
           dist = cosine(person, v)
           if dist < best:
               best = dist
               best_name = k
       if best > recog_t:
           best_name = 'UNKNOWN'
       best_people.append(best_name)
   return best_people

这样就完成了大部分的识别任务。语音合成我想知道谁在门口。一开始,我以为在铃声设备上播放声音是最佳策略,但亚马逊不允许我这么做,只允许我播放铃声伴随的默认声音。因此,从文本到语音似乎是一种更合适的方式。这可以通过两个包GTTS和playsound来简化。GTTS使用谷歌的Tacotron 2模型。虽然完全理解它的工作原理并不重要,但对于感兴趣的读者来说,该图说明了它的架构

Tacotron与Seq2Seq非常相似,但是它使用了双向LSTM、卷积层、预网络层,以及最重要的2D生成输入到解码器(光谱图)。如果你想了解更多关于Tacotron 2的内容,这里有一个由CodeEmporium制作的关于这个主题的视频。https://www.youtube.com/watch?v=le1LH4nPfmE&ab_channel=CodeEmporium虽然Tacotron 2算不上是最好的,尤其是与transformer 模型相比,但它确实做到了。使用GTTS python API的方法如下:from gtts import gTTS
from playsound import playsound
language = 'en'
slow_audio_speed = False
filename = 'tts_file.mp3'
def text_to_speech(text):
   audio_created = gTTS(text=text, lang=language,
                        slow=slow_audio_speed)
   audio_created.save(filename)
   playsound(filename)

很简单。我使用playsound而不是os.system的原因是,os.system将默认打开默认的声音播放器应用程序,而playsound不会弹出任何窗口。这就完成了项目的最后一个步骤。总结和Git存储库请在这里查看我的git存储库,以获得完整的代码,并轻松地定制你自己的门铃。https://github.com/dude123studios/SmarterRingV2在README.md中查看说明,并解释在你自己的家里使用这个系统的确切步骤。只需要5分钟就可以安装好!亚马逊,把它放进你的下一个门铃里!进一步的探索和问题FaceNet是一个相当过时的模式。在过去的五年里,在transformer模型方面有了重大发现,例如ViT。GPT-3是一个概括之神。完成创建广义嵌入的任务后,GPT-3之类的转换器会更好地工作吗?卷积神经网络可能不是面部识别的最佳选择,因为长期依赖关系(如耳朵或下颚线)需要庞大的网络。另一方面,transformer模型可以考虑到自相似性,并且实时进行人脸识别的速度要快得多。

图片标题

声明: 本文由入驻OFweek维科号的作者撰写,观点仅代表作者本人,不代表OFweek立场。如有侵权或其他问题,请联系举报。
侵权投诉

下载OFweek,一手掌握高科技全行业资讯

还不是OFweek会员,马上注册
打开app,查看更多精彩资讯 >
  • 长按识别二维码
  • 进入OFweek阅读全文
长按图片进行保存