博主系在校大二学生,有问题望各位多多指教。


前言

     近年来,人工智能技术的迅猛发展引领着科技创新的浪潮。其中,人脸识别技术作为一项重要的应用领域,受到了广泛关注。在今天的数字化时代,我们对于安全性和便利性的需求不断提升,人脸识别技术在实现高效身份认证和用户体验方面展现出了巨大的潜力。

    本技术博客将引导您了解并实践基于百度API和Django构建的简易人脸识别登录/注册的开发过程。通过结合百度API中提供的人脸识别功能和Django框架的强大特性,实现人脸识别登录/注册机制。

一、开发环境

编程语言

Python(3.9)

开发框架

Django(3.2.9)

前端技术

Html css JavaScript AJAX Bootstrap等

数据库软件

Mysql 5.6.50

数据库管理工具

Navicat 15 for Mysql

开发工具

PyCharm(2022.3.1)

二、前期准备

1.注册百度AI开放平台账号 

2.在控制台创建人脸识别应用

3.得到AppID,API Key,Secret Key

此过程简单易学,本人不再系统赘述,具体详细流程可参考其他博主的文章。

b422dd8dbf214980b86c557d70ebaed0.png

三、前端人脸登录/注册页面

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>人脸登录</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta content="Premium Multipurpose Admin & Dashboard Template" name="description" />
    <meta content="MyraStudio" name="author" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <link href="{% static 'assets/css/bootstrap.min.css' %}" rel="stylesheet" type="text/css" />
    <link href="{% static 'assets/css/icons.min.css' %}" rel="stylesheet" type="text/css" />
    <link href="{% static 'assets/css/theme.min.css' %}" rel="stylesheet" type="text/css" />
</head>
<body class="bg-primary">
    <div>
        <div class="container">
            <div class="row">
                <div class="col-12">
                    <div class="d-flex align-items-center min-vh-100">
                        <div class="w-100 d-block my-5">
                            <div class="row justify-content-center">
                                <div class="col-md-8 col-lg-5">
                                     <div class="card">
                                        <div class="card-body">
                                            <div class="text-center mb-4 mt-3">
                                                <h4>人脸登录</h4>
                                            </div>
                                            <form action="/login/" method="post" class="p-2">
                                                {% csrf_token %}
                                                <span style="color: red;">{{ error_msg }}</span>
                                                <div class="form-group">
                                                    <label for="emailaddress">用户名:</label>
                                                    <input name="username" class="form-control" type="text" id="username" required="" placeholder="用户名">
                                                </div>
                                                <div class="form-group">
                                                    <label for="password">密码:</label>
                                                    <input name="password" class="form-control" type="password" required="" id="password" placeholder="密码">
                                                </div>
                                          <div class="mb-3 text-center">
                                                    <button class="btn btn-primary btn-block" type="submit"> 登录</button>
                                                    <button class="btn btn-primary btn-block" type="button" data-toggle="modal" data-target="#exampleModal" onclick="loadCamera()"> 刷脸登录</button>
                                                </div>
                                            </form>
                                        </div>
                                        <!-- end card-body -->
                                    </div>
                                    <!-- end card -->

                                    <div class="row mt-4">
                                        <div class="col-sm-12 text-center">
                                            <p class="text-white-50 mb-0">创建用户? <a href="{% url 'regist' %}" class="text-white-50 ml-1"><b>Sign Up</b></a></p>
                                        </div>
                                    </div>
                                </div>
                                <!-- end col -->
                            </div>
                            <!-- end row -->
                        </div> <!-- end .w-100 -->
                    </div> <!-- end .d-flex -->
                </div> <!-- end col-->
            </div> <!-- end row -->
        </div>
        <!-- end container -->
    </div>
    <!-- end page -->

    <!-- jQuery  -->
    <script src="{% static 'assets/js/jquery.min.js' %}"></script>
    <script src="{% static 'assets/js/bootstrap.bundle.min.js' %}"></script>
    <script src="{% static 'assets/js/metismenu.min.js' %}"></script>
    <script src="{% static 'assets/js/waves.js' %}"></script>
    <script src="{% static 'assets/js/simplebar.min.js' %}"></script>
    <!-- App js -->
    <script src="{% static 'assets/js/theme.js' %}"></script>
     <!-- Modal -->
     <div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
         <div class="modal-dialog" role="document">
             <div class="modal-content">
                 <div class="modal-header">
                     <h5 class="modal-title" id="exampleModalLabel">Modal title</h5>
                     <button type="button" class="close waves-effect waves-light" data-dismiss="modal" aria-label="Close">
                         <span aria-hidden="true">&times;</span>
                     </button>
                 </div>
                 <div class="modal-body">
                    <video id="video" style="width: 450px;height: 400px;"></video>	<!-- 视频播放 -->

           <canvas id="canvas" style="width: 600px;height: 400px; display: none;" ></canvas>	<!-- 动画效果 -->
                 </div>
                 <div class="modal-footer">
                     <button type="button" class="btn btn-secondary waves-effect waves-light" data-dismiss="modal">关闭</button>
                     <button type="button" class="btn btn-primary waves-effect waves-light" onclick="faceLogin()" id="log_btn">登录</button>
                 </div>
             </div>
         </div>
     </div>
<script type="text/javascript">
	function loadCamera() {
		constraint={			
				video:true,		//加载摄像头
				audio:false		//不加载MAC(麦克风)音频
		}
		let media=navigator.mediaDevices.getUserMedia(constraint)
		video=document.getElementById("video")
		media.then(res=>{
			video.srcObject=res
			video.play()
		}).catch(err=>{
			log.console(error)
		})
	}
	function faceLogin(){
		let canvas = document.getElementById("canvas")	
        const video = document.getElementById("video");	
        const context = canvas.getContext("2d");  //获取canvas的画板
		context.drawImage(video,0,0,300,150)
		canvas = document.getElementById("canvas")
        let imageData = canvas.toDataURL();	//将canvas中的二进制数据格式的图片,转为BASE64编码数据格式
		console.log(imageData)
		imageData = imageData.substring(22,imageData.length)  //去掉文件头前22个字符
        //使用AJAX将图片数据发送到大服务器
		$.ajax({
			url:"/face_login/",	
			method:"post",			
			data:{					
				imageData:imageData
			},
			dataType:"json",		
			success:function(data){	
				if(data.error_msg === "SUCCESS"){
                     if(data.face_login === "SUCCESS"){
                       document.location.href="/index" //识别成功,返回首页
                    }else{
                       alert("登录失败,请调整人脸角度")
                    }
				}else{
					alert("没有检测到人脸。请靠近摄像头")
				}
			}
		})
	}
</script>
</body>
</html>
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>人脸注册</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <meta content="Premium Multipurpose Admin & Dashboard Template" name="description" />
    <meta content="MyraStudio" name="author" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <link href="{% static 'assets/css/bootstrap.min.css' %}" rel="stylesheet" type="text/css" />
    <link href="{% static 'assets/css/icons.min.css' %}" rel="stylesheet" type="text/css" />
    <link href="{% static 'assets/css/theme.min.css' %}" rel="stylesheet" type="text/css" />

</head>
<body class="bg-primary">

    <div>
        <div class="container">
            <div class="row">
                <div class="col-12">
                    <div class="d-flex align-items-center min-vh-100">
                        <div class="w-100 d-block my-5">
                            <div class="row justify-content-center">
                                <div class="col-md-8 col-lg-5">
                                     <div class="card" style="width:500px;">
                                        <div class="card-body">
                                            <div class="text-center mb-4 mt-3">
                                                  <h4>人脸注册</h4>
                                                  <video id="video" style="width: 450px;height: 400px;"></video>	<!-- 视频播放 -->
			                                      <canvas id="canvas" style="width: 600px;height: 400px; display: none;" ></canvas>	<!-- 动画效果 -->
                                                  <button class="btn btn-primary btn-block" onclick="faceReg()">注册人脸</button>
                                            </div>
                                        </div>
                                        <!-- end card-body -->
                                    </div>
                                    <!-- end card -->

                                    <div class="row mt-4">
                                        <div class="col-sm-12 text-center">
                                            <p class="text-white-50 mb-0">人脸登录? <a href="{% url 'login' %}" class="text-white-50 ml-1"><b>let's go</b></a></p>
                                        </div>
                                    </div>

                                </div>
                                <!-- end col -->
                            </div>
                            <!-- end row -->
                        </div> <!-- end .w-100 -->
                    </div> <!-- end .d-flex -->
                </div> <!-- end col-->
            </div> <!-- end row -->
        </div>
        <!-- end container -->
    </div>
    <!-- end page -->

    <!-- jQuery  -->
    <script src="{% static 'assets/js/jquery.min.js' %}"></script>
    <script src="{% static 'assets/js/bootstrap.bundle.min.js' %}"></script>
    <script src="{% static 'assets/js/metismenu.min.js' %}"></script>
    <script src="{% static 'assets/js/waves.js' %}"></script>
    <script src="{% static 'assets/js/simplebar.min.js' %}"></script>

    <!-- App js -->
    <script src="{% static 'assets/js/theme.js' %}"></script>

<script type="text/javascript">
	function loadCamera() {
		constraint={			
				video:true,		//加载摄像头
				audio:false		//不加载MAC(麦克风)音频

		}
		let media=navigator.mediaDevices.getUserMedia(constraint)
		video=document.getElementById("video")
		media.then(res=>{
			video.srcObject=res
			video.play()
		}).catch(err=>{
			log.console(error)
		})
	}
	loadCamera()

	function faceReg(){
        let canvas = document.getElementById("canvas");	
        const video = document.getElementById("video");	
        const context = canvas.getContext("2d");  //获取canvas的画板
		context.drawImage(video,0,0,300,150)
		canvas = document.getElementById("canvas")
        let imageData = canvas.toDataURL();   //将canvas中的二进制数据格式的图片,转为BASE64编码数据格式
		console.log(imageData)
		imageData = imageData.substring(22,imageData.length)  //去掉文件头前22个字符是文件格式描述
		$.ajax({
			url:"/face_reg/",	
			method:"post",			
			data:{					
				imageData:imageData
			},
			dataType:"json",		
			success:function(data){	
				if(data.error_msg === "SUCCESS"){				
					if(data.face_reg === "SUCCESS"){
						alert("注册成功!")
						document.location.href="/login"
					}else{
						alert("注册失败,请调整人脸角度")
					}
				}else{
					alert("没有检测到人脸。请靠近摄像头")
				}
			}
		})
	}
</script>
</body>
</html>

四、后端人脸登录/注册(Views层)

from django.shortcuts import render, HttpResponse, redirect
from aip import AipFace
from app01 import models
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse
@csrf_exempt  # 取消跨站请求伪造(CSRF)防护。
def face_login(request):
    """
    :param request:
    :return: result:
    :author: hexiaohui
    :time:2023/7/19
    :function: face_login
    """
    appId = "你的appId"
    apiKey = "你的apiKey"
    secretKey = "你的secretkey"
    imageType = "BASE64"
    # 前期用户申请的百度API的关键码
    client = AipFace(appId, apiKey, secretKey)
    # 初始化AipFace对象
    imageData = request.POST.get("imageData")  # 获取前端AJAX的图像数据
    # print(imageData)

    options = {"max_face_num": 1, "face_field": 'age,beauty,gender,emotion'}  # 设置请求参数

    result = client.detect(imageData, imageType, options)  # 调用人脸检测函数 有参:options

    # print("年龄为:{}".format(result["result"]["face_list"][0]["age"]))
    # print("颜值打分:{}".format(result["result"]["face_list"][0]["beauty"]))
    # print("性别:{}".format(result["result"]["face_list"][0]["gender"]["type"]))
    # print("情绪:{}".format(result["result"]["face_list"][0]["emotion"]["type"]))
    # 输出对应的字段信息  age/beauty/gender/emotion

    if result["error_msg"] in "SUCCESS":
        mr = models.User.objects.get()  # 获取数据库中的用户信息
        mr1 = {'image': mr.userFace, 'image_type': imageType}
        mr2 = {'image': imageData, 'image_type': imageType}
        # 将前端和后端的图像数据转换成字典
        faceList = [mr1, mr2]
        # 设置为列表形式,满足match函数的参数类型要求
        matchResult = client.match(faceList)
        # 调用match函数 对比两种数据 反馈出相似度得分数据score
        # print(matchResult)
        if matchResult["error_msg"] in "SUCCESS":
            score = matchResult['result']['score']
            # 取出得分数据
            if score >= 95:
                # 若相似度大于95 则检测成功
                result["face_login"] = "SUCCESS"
    return JsonResponse(result)
@csrf_exempt
def face_reg(request):
    """
       :param request:
       :return: result:
       :author: hexiaohui
       :time:2023/7/20
       :function: face_regist
    """
    appId = "你的appId"
    apiKey = "你的apiKey"
    secretKey = "你的secreKey"
    imageType = "BASE64"
    client = AipFace(appId, apiKey, secretKey)
    imageData = request.POST.get("imageData")  
    options = {"max_face_num": 1}
    result = client.detect(imageData, imageType, options)
    if result["error_msg"] in "SUCCESS":
        models.User.objects.update(userFace=imageData)
        result["face_reg"] = "SUCCESS"
    return JsonResponse(result)

五、数据访问层(models)+数据库表

from django.db import models

class User(models.Model):
    username = models.CharField(max_length=25)
    password = models.CharField(max_length=25)
    userFace = models.TextField()

  28a436112d1340f68b3ff91484c4d009.png

六、成果展示

普通用户端登录

人脸录入

人脸登录


七、总结

1  教训和经验:

    在编写过程中,要注意具体函数的参数类型,多看函数体的文本解释,比如match函数的参数,以及search函数参数的区别,要深入了解具体函数的作用和功能,多学习平台的API和SDK文档。 

文档地址

    Views层中要记得引用@csrf_exempt 装饰器,取消跨站请求伪造(CSRF)防护。要不然报403,这个问题真的解决了很久...

@csrf_exempt  # 取消跨站请求伪造(CSRF)防护。

2  不足和缺点:

    人脸识别还存在一些问题:例如没有设置用户组,只能针对单个用户进行识别和录入。多个用户组的创建应使用search函数进行人脸比对。另外前端的知识自己掌握的还不全面,今后应加深对JS,AJAX的学习和利用。在Django开发框架中,还有一些细节的东西没有掌握,例如防跨站和取消跨站。而在使用一些函数的过程中,急于求成,不注重具体含义,因此浪费了很多测试的时间。而对于Python的一些语法和概念,有时还处于一种模糊的情景。理应扎实基础,熟悉基本的数据结构。

3  收获和体会:

    在百度平台文档的阅读和学习过程中,了解到了各种参数和函数的使用和具体含义,还调用options里的参数,对人脸进行年龄,情绪,颜值的分析,成功使用体验之后有满满的成就感....哈哈。虽然前端是老师教的但还是改了很多东西,后端完全就是自己写的了,虽然过程波折,但也总算是实现了功能,当然也有一些不足和遗憾,希望我继续努力!制作不易欢迎点赞!

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐