65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 Docker 进行面部识别

2021 年 7 月 29 日

CPOL

4分钟阅读

viewsIcon

13162

在本文中,我们为该系统创建了一个 Docker 容器。

引言

面部识别是人工智能(AI)的一个领域,在过去十年中,深度学习(DL)的现代方法取得了巨大成功。最好的面部识别系统可以以与人类相同甚至更高的精度识别图像和视频中的人物。

我们关于这个系列文章分为两部分

  • 人脸检测,客户端应用程序在图像或视频源中检测人脸,对检测到的人脸图像进行对齐,并将它们提交给服务器。
  • 人脸识别(本部分),服务器端应用程序执行人脸识别。

我们假设您熟悉 DNN、Python、Keras 和 TensorFlow。欢迎下载此项目代码以进行学习。

上一篇文章中,我们专注于开发和测试面部识别算法以及面部检测模块。在本文中,我们将向您展示如何为我们的面部识别系统创建和使用Docker 容器

Docker 容器技术在开发和部署基于 AI 的软件时可能非常有用。通常,现代基于 AI 的应用程序需要一些预装软件,例如 DNN 框架(在我们的例子中是带有 TensorFlow 后端的 Keras)。应用程序还可以依赖 DNN 模型和相应的库(对于我们的面部检测器是 MTCNN)。此外,由于我们将为服务器端应用程序开发 Web API,因此我们需要在 PC 上安装合适的框架。容器化我们的服务器软件将有助于我们开发、配置、测试和部署应用程序。

创建容器镜像

让我们开始创建容器的镜像。我们将使用Docker Desktop 软件来管理镜像和容器。我们可以从头开始为应用程序创建镜像,但基于现有的 AI 容器之一创建镜像会更快、更容易。最适合我们的是TensorFlow 容器,其中预装了最新版本的 TensorFlow 框架。

首先,我们必须将镜像下载到我们的 PC

docker pull tensorflow/tensorflow:latest-gpu-jupyter

下载镜像后,我们可以在 Docker Desktop 的镜像选项卡中看到它。单击运行按钮来运行容器。

配置容器

下一步是配置容器以启动我们的面部识别服务器。在容器/应用程序选项卡中,为容器运行一个终端窗口。使用以下命令安装 Keras 框架和 MTCNN 库

# pip install keras
# pip install mtcnn

下面的图片显示了成功的安装日志。

请注意,最新的 Python OpenCV 框架已与 MTCNN 库一起安装。我们只需要添加 libGL 库即可完成

# apt install libgl1-mesa-glx

我们将使用Flask 微框架来构建 Web API。我们需要使用简单的 pip 命令安装此框架以及jsonpickle 包。

# pip install Flask
# pip install jsonpickle

现在容器已配置为运行面部识别应用程序。在运行它之前,我们需要稍微修改在上一篇文章中开发的 Python 代码,以便在没有 UI 的情况下启动应用程序。这是视频识别器类的修改代码

class VideoFR:    
    def __init__(self, detector, rec, f_db):
        self.detector = detector
        self.rec = rec
        self.f_db = f_db
    
    def process(self, video, align=False, save_path=None):
        detection_num = 0;
        rec_num = 0
        capture = cv2.VideoCapture(video)
        img = None

        frame_count = 0
        dt = 0
        if align:
            fa = Face_Align_Mouth(160)
            
        # Capture all frames
        while(True):    
            (ret, frame) = capture.read()
            if frame is None:
                break
            frame_count = frame_count+1
            
            faces = self.detector.detect(frame)
            f_count = len(faces)
            detection_num += f_count
            
            names = None
            if (f_count>0) and (not (self.f_db is None)):
                t1 = time.time()
                names = [None]*f_count
                for (i, face) in enumerate(faces):
                    if align:
                        (f_cropped, f_img) = fa.align(frame, face)
                    else:
                        (f_cropped, f_img) = self.detector.extract(frame, face)
                    if (not (f_img is None)) and (not f_img.size==0):
                        embds = self.rec.embeddings(f_img)
                        data = self.rec.recognize(embds, self.f_db)
                        if not (data is None):
                            rec_num += 1
                            (name, dist, p_photo) = data
                            conf = 1.0 - dist
                            names[i] = (name, conf)
                            print("Recognized: "+name+" "+str(conf))
                            if not (save_path is None):
                                percent = int(conf*100)
                                ps = ("%03d" % rec_num)+"_"+name+"_"+("%03d" % percent)+".png"
                                ps = os.path.join(save_path, ps)
                                cv2.imwrite(ps, f_img)
                        
                t2 = time.time()
                dt = dt + (t2-t1)
                    
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break

        if dt>0:
            fps = detection_num/dt
        else:
            fps = 0
        
        return (detection_num, rec_num, fps)

在类的 process 方法中,我们删除了显示带有 OpenCV 窗口的帧的代码。我们还添加了 save_path 参数,用于指定保存识别出的面部的结果图像的位置。

我们还必须修改用于在容器中创建和运行视频识别器的代码

if __name__ == "__main__":
    v_file = str(sys.argv[1])
    
    m_file = r"/home/pi_fr/net/facenet_keras.h5"
    rec = FaceNetRec(m_file, 0.5)
    print("Recognizer loaded.")
    print(rec.get_model().inputs)
    print(rec.get_model().outputs)
    
    save_path = r"/home/pi_fr/rec"
    db_path = r"/home/pi_fr/db"
    f_db = FaceDB()
    f_db.load(db_path, rec)
    db_f_count = len(f_db.get_data())
    print("Face DB loaded: "+str(db_f_count))
    d = MTCNN_Detector(50, 0.95)
    
    vr = VideoFR(d, rec, f_db)

    (f_count, rec_count, fps) = vr.process(v_file, True, save_path)

    print("Face detections: "+str(f_count))
    print("Face recognitions: "+str(rec_count))
    print("FPS: "+str(fps))

在代码中,我们将视频文件的路径指定为第一个命令行参数。所有其他路径(FaceNet 模型、面部数据库以及用于保存结果图像的文件夹)都直接在代码中指定。因此,我们必须预先配置文件系统并将所需数据复制到容器中。这可以使用docker cp 命令完成。

运行容器

现在我们可以使用以下命令从终端运行我们的 Python 代码

# python /home/pi_fr/pi_fr_facenet.run_align_dock.lnx.py /home/pi_fr/video/5_1.mp4

终端中的输出将显示识别过程的进度。该过程将识别出的数据保存到指定文件夹,我们可以使用 ls 命令进行探索。

您可以使用 docker cp 命令将数据复制到主机。这里有一些识别出的面部图像。

现在我们的 AI 容器已完全配置。我们可以在容器环境中运行识别服务器并测试其性能。我们还可以改进识别算法并开发额外的基于 AI 的软件。我们甚至可以使用该平台创建、训练和测试新的 DNN 模型(基于带有 TensorFlow 后端的 Keras)。

最棒的是,我们可以轻松地与其他开发人员共享我们的容器。我们只需要将容器保存为 Docker 镜像并将其推送到存储库。您可以使用以下命令

c:\>docker commit -m "Face Recognition image" -a "Sergey Gladkiy" beff27f9a185 sergeylgladkiy/fr:v1
 
c:\>docker push sergeylgladkiy/fr:v1

推送镜像可能需要一些时间,因为它很大(约 6.3 GB)。发布的镜像可供其他 Docker 用户下载。他们可以按如下方式下载我们的镜像

docker pull sergeylgladkiy/fr:v1

下一步

下一篇文章中,我们将面部识别模型包装到一个简单的 Web API 中,在 Raspberry Pi 上创建一个客户端应用程序,并运行客户端-服务器系统。敬请关注!

© . All rights reserved.