利用django实现在线人脸识别
利用课余时间写了一个基于的django图像处理例子,数据库是mysql,很多代码还不成熟,关于django的使用主要是在视频:2022 B站最详细django3教程(django从入门到实践)_哔哩哔哩_bilibili 上进行的。我认为这是最好的django学习视频了。
一、项目简介
1、项目包括:
(1)用户登录,注册
(2)上传npz数据集
(3)对数据集基于sklearn交叉验证或数据集分割后验证
(4)上传符合数据集标准的样本进行识别
(5)利用摄像头采集人脸信息
(6)利用dlib进行人脸识别(比较慢,有待优化)
2、例子涉及知识:
- django
- bootstrap
- dlib人脸识别
- sklearn
- 摄像头视频采集
- echarts (这个对项目没什么用,纯练习)
3、参考文档:
[1] js开启摄像头_安和同学的博客-CSDN博客_js开启摄像头
[2] Python 3 利用 Dlib 实现摄像头实时人脸识别 - coneypo - 博客园
[3] web调用摄像头拍照并上传到服务器_淋雨一直走~的博客-CSDN博客_摄像头拍照上传服务器
[4] Detecting Face Features with Python
参考了很多文档,这里未一一列出,感谢各位大佬的辛苦付出。
本文源码:https://github.com/huangzhiyu2018/OnlineAiPicture
4、项目截图:
为了总结过去的经验,列出主要操作
二、html模板嵌套
1、首先定义一个母版,在里面留出适当的block,例如:
{% load static %}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{% static 'plugins/bootstrap-3.4.1-dist/css/bootstrap.css' %}">
<!--额外css填入位置-->
{% block css %} {% endblock %}
<title>
{% block title %} {% endblock %}
</title>
</head>
<body>
<div class="container">
<!--内容填入位置-->
{% block contain %} {% endblock %}
</div>
<!-- jQuery文件。务必在bootstrap.min.js 之前引入 -->
<script src="{%static 'js/jquery-3.6.0.min.js' %}"></script>
<!-- 最新的 Bootstrap4 核心 JavaScript 文件 -->
<script src="{%static 'plugins/bootstrap-3.4.1-dist/js/bootstrap.js'%}"></script>
<!--额外js填入位置-->
{% block js %} {% endblock %}
</body>
</html>
2、其它模板可以引用这个母版,达到所有模板都具有相同的布局:
{% extends 'master.html' %}
{% block contain %}
写入当前模板需要的内容
{% endblock %}
3、继续继承
更有意思的是还可以上(2)基础上进一步进行嵌套,再次嵌套时需要在(2)的文档中也设定响应的block,其过程与第一次嵌套一样。
三、人脸采集
人脸采集时控制摄像头,并把摄像头采集到的图片上传到服务器,基本思路,先打开摄像头,然后拍照,最后ajax提交到后台进行保存。页面布局以及功能如下:
正在上传…重新上传取消
1、打开摄像头
前台有<video id="video" ></video>标签,利用javascript打开,这是参考的博客:https://blog.csdn.net/amdd9582/article/details/95501402
function playfunction(){
// 开启摄像
document.getElementById('play').onclick = () => {
let constraints = {
// video属性设置
video: {
width: 300,
height: 300
},
// audio属性设置,无声
audio: false
}
navigator.mediaDevices.getUserMedia(constraints)
.then(mediaStream => {
// 成功返回promise对象,接收一个mediaStream参数与video标签进行对接
document.getElementById('video').srcObject = mediaStream
document.getElementById('video').play()
mediaStreamTrack = typeof mediaStream.stop === 'function' ? mediaStream : mediaStream.getTracks()[0];
click_start_vedio=1;//记录开启视频
})
// 失败就失败了
}
}
为了能够关闭摄像头,我定义了一个全局变量:mediaStreamTrack
2、拍照
点击id为take的按钮,进行拍照,
function photofunction(){
// 拍照、canvas绘制
document.getElementById('take').onclick = () => {
if (click_start_vedio==1){
let ctx = document.getElementById("canvas").getContext('2d')
ctx.drawImage(document.getElementById("video"), 0, 0, 300, 300)
click_scrap=1;
$("#img_result").removeAttr("src");//每次拍照后页面识别结果都清空
}else{
alert("请点击开始摄像按钮");
}
}
}
3、关闭摄像头
利用全局变量mediaStreamTrack进行关闭摄像头
function closevideofunction(){
$("#close").on({
"click":function(){
if(mediaStreamTrack){
mediaStreamTrack.stop();
mediaStreamTrack=[];
console.log("stop");
click_start_vedio=0;
}else{
console.log("mediaStreamTrack is empty")
}
}
})
}
4、异步上传
需要把canvas的内容先转成字符流,再把字符流转成文件进行上传,两个函数:
function dataURItoBlob(base64Data) {
var byteString;
if (base64Data.split(',')[0].indexOf('base64') >= 0)
byteString = atob(base64Data.split(',')[1]);
else
byteString = unescape(base64Data.split(',')[1]);
var mimeString = base64Data.split(',')[0].split(':')[1].split(';')[0];
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], {type: mimeString});
};
//将blob转换为file
function blobToFile(theBlob, fileName) {
theBlob.lastModifiedDate = new Date();
theBlob.name = fileName;
return theBlob;
};
由于后台是利用modelform进行处理的,上传的图片和姓名信息直接存入到了mysql数据库,这里异步时把相关信息都携带了,代码中为防止无视频直接上传,用标志变量来确定是否已经点击了拍照按钮。代码如下:
function uploadfunction(){
$("#upload").on({
"click":function(){
if(click_start_vedio==0){
alert("首先点击开启摄像,然后点击拍照");
return;
}
var personName=$("#person_name").val();
if (personName){
if(click_scrap==1){
click_scrap=0
canvas = document.getElementById('canvas');
//生成图片格式base64包括:jpg、png格式
var base64Data = canvas.toDataURL("image/jpeg", 1.0);
//封装blob对象
var blob = dataURItoBlob(base64Data);
var file = blobToFile(blob, personName);
//利用FormData进行传值
var form = document.getElementById("controlform");
// 用表单来初始化
var formdata = new FormData(form);
formdata.append("person_name",personName);
//必须是file字段的添加,防止汉语名称不识别,这里用英文名称
formdata.append("file",blob,"person.jpg");
$.ajax({
url: ajaxurl,
type:"post",
data:formdata,
processData: false,//用于对data参数进行序列化处理 这里必须false
contentType: false, //必须
success:function(res){
if(res.status){
var valide="图片中没有脸部信息"
if (res.valide){
valide="图片有效"
}
$("#pic_result").html("文件:"+res.path+"上传成功!<br>"+valide)
$("#img_result").attr("src","/media/"+res.path)
if (show_result_alert){//这是为了图像识别显示对话框用的
if(res.valide)
{
alert("当前人物为:"+res.person+"\n 可能人物:"+res.min_person)
}else{
alert(valide);
}
}
}else{
console.log(res.errors)
}
}
}
)
}else{
alert("必须点击拍照!");
}
}else{
alert("必须输入姓名")
}
},
})
}
5、采集人脸和人脸识别的模板
整个模板仍然是人脸采集和人脸识别模板的母版,里面包括了被人脸识别的两个block
{% block table %} {% endblock %} 和 {% block exjs%}{% endblock %}
文件名为:scrapture.html其完整代码如下:
{% extends 'master.html' %}
{% block css %}
<style>
video, canvas {
width: 300px;
height: 300px;
border: 5px solid #000;
border-radius: 10px;
margin-left: 5px;
}
</style>
{% endblock %}
{% block contain %}
<div class="container">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">采集人脸图像</h3>
</div>
<div class="panel-body" >
<div class="panel panel-default" style="margin:10px 10px">
<div class="panel-heading">
<h3 class="panel-title">采集面部</h3>
</div>
<div class="panel-body">
<div class="col-md-6">
<video id="video" ></video>
</div>
<!-- 尽量在canvas标签上设置宽高 -->
<div class="col-md-6">
<canvas id="canvas" width="300px" height="300px"></canvas>
</div>
</div>
</div>
<div class="col-md-6">
<div class="panel panel-default" >
<div class="panel-heading">
<h3 class="panel-title">控制面板</h3>
</div>
<div class="panel-body" style="margin:10px 10px">
<button id="play" class="btn btn-success" >开启摄像</button>
<button id="close" class="btn btn-danger " >关闭视频</button>
<form method="post" novalidate id="controlform" enctype="multipart/form-data">
<div class="form-group" id="input_person">
<label class="col-sm-2" for="person_name">人物姓名:</label>
<input type="text" class="col-sm-2" id="person_name" placeholder="Tom" value="第一人" >
</div>
<div class="form-group">
<input id="take" class="btn btn-success col-sm-2" value="拍照"></input>
<input id="upload" class="btn btn-info col-sm-2" value="采集"></input>
</div>
</form>
</div>
</div>
</div>
<!--加上一个处理结果显示情况-->
<div class="col-md-6" id="result_panel">
<div class="panel panel-default" style="margin:10px 10px">
<div class="panel-heading">
<h3 class="panel-title">采集结果</h3>
</div>
<div class="panel-body" style="margin:10px 10px">
<img style="height:300px" id="img_result"></img>
</div>
</div>
</div>
</div>
</div>
<div class="panel-footer" id="footer">
<p class="list-group-item-text" id="pic_result"></p>
<a href="/facerecon/list/" style="align:right">采集结果列表 </a>
</div>
</div>
{% block table %}
{% endblock %}
</div>
{% endblock %}
{% block js %}
<script type="text/javascript">
var click_start_vedio=0;
var click_scrap=0;
var ajaxurl;
var show_result_alert=0;
var mediaStreamTrack;
// 获取媒体方法(旧方法)
function closevideofunction(){
$("#close").on({
"click":function(){
if(mediaStreamTrack){
mediaStreamTrack.stop();
mediaStreamTrack=[];
console.log("stop");
click_start_vedio=0;
}else{
console.log("mediaStreamTrack is empty")
}
}
})
}
function playfunction(){
// 开启摄像
document.getElementById('play').onclick = () => {
let constraints = {
// video属性设置
video: {
width: 300,
height: 300
},
// audio属性设置,无声
audio: false
}
navigator.mediaDevices.getUserMedia(constraints)
.then(mediaStream => {
// 成功返回promise对象,接收一个mediaStream参数与video标签进行对接
document.getElementById('video').srcObject = mediaStream
document.getElementById('video').play()
mediaStreamTrack = typeof mediaStream.stop === 'function' ? mediaStream : mediaStream.getTracks()[0];
click_start_vedio=1;//记录开启视频
})
// 失败就失败了
}
}
function photofunction(){
// 拍照、canvas绘制
document.getElementById('take').onclick = () => {
if (click_start_vedio==1){
let ctx = document.getElementById("canvas").getContext('2d')
ctx.drawImage(document.getElementById("video"), 0, 0, 300, 300)
click_scrap=1;
$("#img_result").removeAttr("src");
}else{
alert("请点击开始摄像按钮");
}
}
}
function dataURItoBlob(base64Data) {
var byteString;
if (base64Data.split(',')[0].indexOf('base64') >= 0)
byteString = atob(base64Data.split(',')[1]);
else
byteString = unescape(base64Data.split(',')[1]);
var mimeString = base64Data.split(',')[0].split(':')[1].split(';')[0];
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], {type: mimeString});
};
//将blob转换为file
function blobToFile(theBlob, fileName) {
theBlob.lastModifiedDate = new Date();
theBlob.name = fileName;
return theBlob;
};
function uploadfunction(){
$("#upload").on({
"click":function(){
if(click_start_vedio==0){
alert("首先点击开启摄像,然后点击拍照");
return;
}
var personName=$("#person_name").val();
if (personName){
if(click_scrap==1){
click_scrap=0
canvas = document.getElementById('canvas');
//生成图片格式base64包括:jpg、png格式
var base64Data = canvas.toDataURL("image/jpeg", 1.0);
//封装blob对象
var blob = dataURItoBlob(base64Data);
var file = blobToFile(blob, personName);
//利用FormData进行传值
var form = document.getElementById("controlform");
// 用表单来初始化
var formdata = new FormData(form);
formdata.append("person_name",personName);
//必须是file字段的添加,防止汉语名称不识别,这里用英文名称
formdata.append("file",blob,"person.jpg");
//没有问题
$.ajax({
url: ajaxurl,
type:"post",
data:formdata,
processData: false,//用于对data参数进行序列化处理 这里必须false
contentType: false, //必须
success:function(res){
if(res.status){
var valide="图片中没有脸部信息"
if (res.valide){
valide="图片有效"
}
$("#pic_result").html("文件:"+res.path+"上传成功!<br>"+valide)
//console.log(res.path)
$("#img_result").attr("src","/media/"+res.path)
if (show_result_alert){
if(res.valide)
{
alert("当前人物为:"+res.person+"\n 可能人物:"+res.min_person)
}else{
alert(valide);
}
}
}else{
console.log(res.errors)
}
}
}
)
}else{
alert("必须点击拍照!");
}
}else{
alert("必须输入姓名")
}
},
})
}
</script>
{% block exjs%}
{% endblock %}
{% endblock %}
6、人脸采集模板
人脸采集模板是继承了上面的模板,只是更改了提交按钮的post地址
{% extends 'scrapture.html' %}
{% block exjs%}
<script>
$(document).ready(function(){
playfunction();
photofunction();
uploadfunction();
initparams();
})
function initparams(){
//$("#input_person").hide()
ajaxurl="/facerecon/scrap/"
}
</script>
{% endblock%}
7、人脸采集数据模型
a) 采集人脸文件上传到后台media/persons路径,信息存入到数据库,数据库model如下:
class PersonInfor(models.Model):
"""动态上传人员信息表
Args:
models (_type_): _description_
"""
#上传的文件路径,在persons路径
file=models.FileField(verbose_name="文件",max_length=125,upload_to="persons/",default="")
#图片对应的人名
person_name=models.CharField(max_length=30,verbose_name='姓名',default="Tom")
#上传时间
create_time = models.DateField(verbose_name='上传时间')
#采集者
upload_user=models.CharField(max_length=30,verbose_name='上传者')
#是否是有效的人物图片,只有一张图片人脸的是有效的
valide_choice = ((0, "否"), (1, "是"))
isvalide=models.SmallIntegerField(choices=valide_choice,verbose_name="有效",default=0)
#保存到一个表中,去掉一个表,允许为空
rects=models.TextField(verbose_name='面部位置',blank=True)
landmarks=models.TextField(verbose_name='面部标注',blank=True)
#每个rect对应一个面部描述,由dlib_face_recognition_resnet_model_v1.dat模型获得
descriptions=models.TextField(verbose_name='面部描述',blank=True)
#显示信息用
def __str__(self):
return f"姓名:{self.person_name} 文件:{self.file}"
8、view中的人脸采集模型
首先构建一个modelform类
class PersonInforModelForm(BootrapModelForm):
"""针对上传人物图片的模型
Args:
BootrapModelForm (_type_): _description_
"""
class Meta:
model=models.PersonInfor
exclude=["upload_user","create_time","isvalide","rects","landmarks","descriptions"]
bootstrap_exclude_fileds=["file"]
def clean_file(self):
file = self.cleaned_data['file']
ext = file.name.split('.')[-1].lower()
if ext not in ["bmp","jpg","png"]:
raise forms.ValidationError("仅支持bmp,jpg,png 类型文件")
return file
9、应用bootstrap的modelform
这里的BootrapModelForm是按照参考视频的写法写的一个能够应用bootstrap的类,定义如下:
from django import forms
class Bootstrap:
bootstrap_exclude_fileds=[]
def __init__(self,*args,**kwargs):
super().__init__(*args,**kwargs)
for name,field in self.fields.items():
#不需要bootstrap的字段
if name in self.bootstrap_exclude_fileds:
continue
if field.widget.attrs:
field.widget.attrs['class']='form-control'
field.widget.attrs['placeholder']=field.label
else:
field.widget.attrs={"class":"form-control",'placeholder':field.label}
class BootrapModelForm(Bootstrap,forms.ModelForm):
pass
class BootrapForm(Bootstrap,forms.Form):
pass
10、后台处理
其次在定义好modelform类之后,可以直接读取前段异步到后台的post内容,form= PersonInforModelForm(request.POST,request.FILES),完整的处理函数如下,代码中dlibcompute是自定义的利用dlib处理图片的模块,请参考源码:
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def scrapy_image(request):
if request.method=="POST":
#传入信息
form= PersonInforModelForm(request.POST,request.FILES)
if form.is_valid():
form.instance.create_time=datetime.datetime.now()
#form.instance.upload_user=request.session.info.userName
info=request.session.get("info")
if info:
form.instance.upload_user=info["userName"]
else:
form.instance.upload_user="test"
#先保存,否则没有图片
form.save()
#得到图片绝对路径
absolute_file_path = os.path.join('media',form.instance.file.name)
#print(form.instance.file.name)
#print(absolute_file_path)
#得到人脸信息
rects,image=dlibcompute.find_person_rect(absolute_file_path)
#讲数据转成字符序列
s=pickle.dumps(rects)
#print(len(rects))
isValide=0
if len(rects)==1:
isValide=1
models.PersonInfor.objects.filter(file=form.instance.file.name).update(isvalide=isValide,rects=s)
return JsonResponse({"status":True,"path":form.instance.file.name,"valide":isValide})
else:
return JsonResponse({"status":False,"errors":form.errors})
return render(request,"scraperimage.html")
四、人脸识别
人脸采集的思路是:从摄像头采集图片,对图片得到图片描述信息,把描述信息与存放到数据库中的采集图片信息进行欧式距离计算,设定一个阈值,如果小于这个值就是当前人物,记录最小的距离,这是可能的人物。
1、人脸识别模板
打开、拍照、关闭摄像头都是利用上节5中的scrapture.html文件,在人脸识别模板去掉人物姓名项,利用js隐藏响应的模块即可。在识别模块下发加入已经采集的图片信息,并更换提交按钮的url,以便后台采用不同的处理方式。模板代码如下:
{% extends 'scrapture.html' %}
{% block table %}
<div class="panel panel-default" style="margin:10px 10px">
<div class="panel-heading" >
<span class="glyphicon glyphicon-th-large" aria-hidden="true"></span>人物信息
</div>
<div class="panel-body">
<table class="table table-bordered">
<thead>
<tr>
<th>ID</th>
<th姓名</th>
<th>图片</th>
<th>姓名</th>
<th>上传时间</th>
<th>是否有效</th>
</tr>
</thead>
<tbody>
{% for obj in querySet%}
<tr>
<th scope="row">{{ obj.id }}</th>
<td><img src="/media/{{obj.file}}" style="height:100px"></img></td>
<td>{{obj.person_name}}</td>
<td>{{ obj.create_time |date:"Y年m月d日"}}</td>
<td>{{ obj.get_isvalide_display }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}
{% block exjs%}
<script>
$(document).ready(function(){
playfunction();
photofunction();
uploadfunction();
initparams();
closevideofunction();
})
function initparams(){
show_result_alert=1;
$("#input_person").hide();
$("#input_person").val("test");//用测试的名字进行
$("#result_panel").hide();
//$("#footer").hide();//隐藏,用对话框提示有效性
$("#upload").val("识别");
ajaxurl="/facerecon/recon/";
}
</script>
{% endblock%}
2、识别后台代码
后台识别时,首先查看当前上传的图片是否有人脸信息,如果有再看原来人脸采集数据表中人脸描述字段是否已经计算,如果没有计算就重新计算原采集人脸的描述信息;如果采集的人脸都已经计算描述,就比较欧氏距离。
@csrf_exempt
def face_recon(request):
"""人脸识别
Args:
request (_type_): _description_
"""
if request.method=="GET":
#只显示有效信息
querySet = models.PersonInfor.objects.filter(isvalide=1)
return render(request,"personrecon.html",{"querySet":querySet})
#提交图片后进行识别
form= PersonInforModelForm(request.POST,request.FILES)
if form.is_valid():
file = request.FILES.get("file")
#返回两个路径一个用于显示,一个用于读取
url_file_name,absolute_file_path = handle_uploaded_file(file)
#print(url_file_name,absolute_file_path)
rects,image=dlibcompute.find_person_rect(absolute_file_path)
#print(len(rects))
if len(rects)!=1:
return JsonResponse({"status":True,"path":url_file_name,"valide":0,"person":"无法识别"})
#合适的人脸数据信息,对人脸数据进行读取
baseDir=os.path.join(settings.BASE_DIR,r"picturerec\utils")
detector=dlibcompute.get_front_face_dector()
landmarks_predictor=dlibcompute.get_point_5_infor(baseDir)
face_encoder=dlibcompute.get_face_encodeing(baseDir)
#print("*"*10)
#dlibcompute.face_encodings
#先把所有在人物信息表中的数据进行计算,如果计算过了就不必计算了
compute_person_description(detector=detector,landmarks_predictor=landmarks_predictor,face_encoder=face_encoder)
#计算当前照片的的描述和标志点
descriptions,_=dlibcompute.face_dector_encodings(image,detector=detector,landmarks_predictor=landmarks_predictor,face_encoder=face_encoder)
findperson,min_person=find_person(descriptions)
#有效的提交进行图片处理
return JsonResponse({"status":True,"path":url_file_name,"valide":1,"person":findperson,"min_person":min_person})
else:
return JsonResponse({"status":False,"errors":form.errors})
3、计算原采集人脸的描述信息
def compute_person_description(detector,landmarks_predictor,face_encoder):
#默认是blank,判断用""
querySet = models.PersonInfor.objects.filter(descriptions="",isvalide=1)
#print("query sets lin 148=",len(querySet))
for temp in querySet:
#对于所有没有计算描述的图片计算描述信息,已经计算的不用
absolute_file_path = os.path.join('media', str(temp.file))
description,landmarks=dlibcompute.face_encoding_by_file(absolute_file_path,detector,landmarks_predictor,face_encoder)
if description is None:
continue
s_description=pickle.dumps(description)
s_landmarks=pickle.dumps(landmarks)
models.PersonInfor.objects.filter(id=temp.id).update(landmarks=s_landmarks,descriptions=s_description)
这里注意的是,存入采集数据库的描述信息是以二进制形式保存的numpy.ndarray,存入时利用pickle.dumps进行的。
4、识别当前人是人脸采集中的哪一位
在PersonInfor中存放有当前采集人脸图片的描述信息,这些信息是numpy.ndarray形式,是利用pickle.dumps存入,读取时,我采用的方法是,首先利用ast.literal_eval转成数组然后利用pickle.loads转成ndarray,
L1=ast.literal_eval(temp.descriptions)
np_description=pickle.loads(L1)
函数find_person是根据当前识别图片的描述与数据库中存放的描述信息进行对比,然后找到当前人是哪一个如:
def find_person(temp_description):
if temp_description is None:
print("temp_description is None")
return "temp_description is None"
if len(temp_description)==0:
print("temp_description is empty")
querySet = models.PersonInfor.objects.filter(isvalide=1,descriptions__isnull=False)#得到数据集,必须要求描述不空
thread=0.4
find_person=""
min_value_person=""
min_value=10000
for temp in querySet:
#record_description=(temp.descriptions)
L1=ast.literal_eval(temp.descriptions)
np_description=pickle.loads(L1)
if len(np_description)==0:
print(f"description is zero {temp.id}:{temp.person_name}")
continue
print(len(np_description[0]))
d=distancecompute.Euclidean_distance(np_description,temp_description)
if d<min_value:
min_value=d
#搜索
min_value_person=f"{temp.person_name}"
if d<thread:
find_person=f"{temp.person_name}"
return find_person,min_value_person
五、人脸定位与描述
1、人脸位置监测
利用dlib进行人脸定位和人脸信息的描述,利用dlib可以快速的对人脸进行定位,并根据适当的模型得到人脸上的标志点。
detector = dlib.get_frontal_face_detector()
返回人脸监测器,给监测器传入图片信息可以得到当前图片的人脸位置信息,这些信息是多个矩形信息,图片中有几张脸就有几个矩形,矩形是左上角和右下角坐标存储的。
face_locations = detector(face_image, number_of_times_to_upsample)
2、标志位的获得
根据得到人脸位置,可以利用dlib.shape_predictor产生的预测器得到人脸标志点,dlib.shape_predictor需要传入训练好的模型,这个模型有两种,一种是5个标志点,对应文件是shape_predictor_5_face_landmarks.dat,另一种是68个点,对应文件是shape_predictor_68_face_landmarks.dat,这68个点排列位置时固定的,如图
:
正在上传…重新上传取消
如果模型文件路径为shape_5_file,那么参数预测的代码如下:
pose_predictor_5_point = dlib.shape_predictor(shape_5_file)
得到预测器,传入图片和detector得到的人脸位置,就可以得到人脸的标志点坐标,这个坐标是相对于图片的,左上角为0,0,向右,下为正对应横纵坐标。
如果图片face_image所有脸位置是face_locations,下面landmarks_predictor标志位的预测器,下列代码得到所有脸(这是一张图)的标志位。
raw_landmarks = [landmarks_predictor(face_image, face_location) for face_location in face_locations]#
3、描述向量的获得
利用dlib.face_recognition_model_v1可以得到人脸描述器,需要传入模型,这里用的是dlib_face_recognition_resnet_model_v1.dat,把文件名传入后得到描述器,调用描述器的compute_face_descriptor函数可以得到图像的描述信息,这个信息是128个元素的ndarray数字,compute_face_descriptor传入参数是图像,标志位向量。
项目中dlibcompute模块中函数就是计算当前图片的所有描述信息,并以ndarray形式返回。
def face_encodings(face_image,face_locations,landmarks_predictor, face_encoder, num_jitters=1):
"""返回图像中每个人脸的 128D 描述符"""
if landmarks_predictor and face_encoder:
# 检测面部特征点
raw_landmarks = [landmarks_predictor(face_image, face_location) for face_location in face_locations]
# 使用每个检测到的特征点计算每个检测到的人脸的编码,返回numpy的列表,方便转换
return np.array([np.array(face_encoder.compute_face_descriptor(face_image, raw_landmark_set, num_jitters)) for
raw_landmark_set in raw_landmarks]),np.array(raw_landmarks)
else:
return None,None
利用django实现在线人脸识别相关推荐
- Django实战(8)——在线人脸识别系统demo(对接Redis、初步实现人脸识别功能)
接着上一篇Django实战(7)--在线人脸识别系统(第一步.实现图片上传和MySQL数据库的对接,ORM操作数据库)https://blog.csdn.net/qq_41938259/article ...
- CV:利用cv2(加载人脸识别xml文件及detectMultiScale函数得到人脸列表)+keras的load_model(加载表情hdf5、性别hdf5)并标注
CV:利用cv2+自定义load_detection_model(加载人脸识别xml文件及detectMultiScale函数得到人脸列表)+keras的load_model(加载表情hdf5.性别h ...
- 聪明的人脸识别4——Pytorch 利用Retinaface+Facenet搭建人脸识别平台
睿智的目标检测51--Pytorch 利用Retinaface+Facenet搭建人脸识别平台 学习前言 什么是Retinface和Facenet 1.Retinface 2.Facenet 整体实现 ...
- Android在线人脸识别登录系统
Android在线人脸识别登录系统 前言 最近需要做一个Android的在线人脸识别项目,需求是能够在线人脸识别登录,找了很多资料都是价格很高或者是离线保存样本的,最后选择免费的虹软人脸识别,经过查询 ...
- 百度在线人脸识别技术性能测试
1,百度在线人脸识别技术文档 https://cloud.baidu.com/doc/FACE/Face-Search.html#.E8.AF.B7.E6.B1.82.E8.AF.B4.E6.98.8 ...
- 高级货!Django实现基于人脸识别的门禁管理系统【源码】
项目介绍 基于人脸识别的门禁管理系统 (Python+Django+RESTframework+JsonWebToken+Redis+Dlib) 该项目为宿舍门禁系统管理,并额外加入宿舍管理.水电费管 ...
- Python+Django实现基于人脸识别的门禁管理系统,附带源码!!
已下项目为实战开发经验,微信搜索关注公众号 [ python语言空间 ],获取更多项目源码及资源. 项目介绍 基于人脸识别的门禁管理系统(Python+Django+RESTframework+Jso ...
- 利用卷积神经网络实现人脸识别(python+TensorFlow)
利用CNN卷积神经网络实现人脸识别(python+TensorFlow) 使用的人脸数据是耶鲁大学的一个人脸数据集Yale_64x64.mat,数据集已经上传Yale 64x64.mat 程序: '' ...
- 基于Django的web人脸识别登录功能设计与实现
0 引言 人脸识别技术日趋成熟,开源的人脸识别库使大众更容易开发自己的应用方案,降低学习门槛,如旷视科技.商汤科技.海康威视,百度人脸识别SDK.OpenCV的人脸识别库.Python的第三方人脸识别 ...
最新文章
- Windows 7 操作系统核心文件
- 字节跳动Java面试:java软件工程师简历描述项目
- Python:对字符串匹配算法的分析
- MySQL模糊查询—in关键字
- IdentityServer4系列 | 快速搭建简易项目
- 计算机网络自顶向下方法实验报告,计算机网络自顶向下方法试验三报告.doc
- ORA-00972: identifier is too long问题解决
- shell 免杀aspx_对于asp免杀webshell的一些总结
- 数据库优先生成EF CRUD演示
- android新闻客户端实验报告,基于Android平台的新闻客户端设计与实现
- 常用的 7 款 MySQL 客户端工具,你值得拥有
- Java核心技术 卷(一) 学习记录
- Excel模板免费分享(办公常用、甘特图、员工绩效考核等模板)
- 【娱乐】你以为我在水群?其实我在内卷。(qq、微信自动发消息脚本)
- 转载一些Unity插件及资源
- 蓝牙(三)蓝牙协议的初始化
- 获取执行程序的原路径(绝对路径)
- 系统部署在服务器,如何把系统部署在云服务器
- Java api文档自动生成工具smartdoc+torna
- Elasticsearch索引安装使用