【CanMV K230 AI视觉】 人脸识别
动态测试效果可以去下面网站自己看。)
B站视频链接:已做成合集
抖音链接:已做成合集
人脸识别
前面学习过的人脸检测,只检测出人脸,而本实验要做的人脸识别,会学习人脸特征,然后比对,实现区分不同人脸。比如常用的人脸考勤机就是这样的原理。
先运行人脸注册代码,人脸注册代码会将CanMV U盘/
sdcard/app/tests/utils/db_img/
目录下的人脸图片进行识别,可以看到里面预存了2张人脸图片,我呢放了3张。
'''
实验名称:人脸注册
实验平台:01Studio CanMV K230
教程:wiki.01studio.cc
'''from libs.PipeLine import PipeLine, ScopedTiming
from libs.AIBase import AIBase
from libs.AI2D import Ai2d
import os
import ujson
from media.media import*from time import*import nncase_runtime as nn
import ulab.numpy as np
import time
import image
import aidemo
import random
import gc
import sys
import math
# 自定义人脸检测任务类classFaceDetApp(AIBase):def__init__(self,kmodel_path,model_input_size,anchors,confidence_threshold=0.25,nms_threshold=0.3,rgb888p_size=[1280,720],display_size=[1920,1080],debug_mode=0):super().__init__(kmodel_path,model_input_size,rgb888p_size,debug_mode)# kmodel路径
self.kmodel_path=kmodel_path
# 检测模型输入分辨率
self.model_input_size=model_input_size
# 置信度阈值
self.confidence_threshold=confidence_threshold
# nms阈值
self.nms_threshold=nms_threshold
self.anchors=anchors
# sensor给到AI的图像分辨率,宽16字节对齐
self.rgb888p_size=[ALIGN_UP(rgb888p_size[0],16),rgb888p_size[1]]# 视频输出VO分辨率,宽16字节对齐
self.display_size=[ALIGN_UP(display_size[0],16),display_size[1]]# debug模式
self.debug_mode=debug_mode
# 实例化Ai2d,用于实现模型预处理
self.ai2d=Ai2d(debug_mode)# 设置Ai2d的输入输出格式和类型
self.ai2d.set_ai2d_dtype(nn.ai2d_format.NCHW_FMT,nn.ai2d_format.NCHW_FMT,np.uint8, np.uint8)
self.image_size=[]# 配置预处理操作,这里使用了pad和resize,Ai2d支持crop/shift/pad/resize/affine,具体代码请打开/sdcard/app/libs/AI2D.py查看defconfig_preprocess(self,input_image_size=None):with ScopedTiming("set preprocess config",self.debug_mode >0):# 初始化ai2d预处理配置,默认为sensor给到AI的尺寸,可以通过设置input_image_size自行修改输入尺寸
ai2d_input_size=input_image_size if input_image_size else self.rgb888p_size
self.image_size=[input_image_size[1],input_image_size[0]]# 计算padding参数,并设置padding预处理
self.ai2d.pad(self.get_pad_param(ai2d_input_size),0,[104,117,123])# 设置resize预处理
self.ai2d.resize(nn.interp_method.tf_bilinear, nn.interp_mode.half_pixel)# 构建预处理流程,参数为预处理输入tensor的shape和预处理输出的tensor的shape
self.ai2d.build([1,3,ai2d_input_size[1],ai2d_input_size[0]],[1,3,self.model_input_size[1],self.model_input_size[0]])# 自定义后处理,results是模型输出的array列表,这里使用了aidemo库的face_det_post_process接口defpostprocess(self,results):with ScopedTiming("postprocess",self.debug_mode >0):
res = aidemo.face_det_post_process(self.confidence_threshold,self.nms_threshold,self.model_input_size[0],self.anchors,self.image_size,results)iflen(res)==0:return res
else:return res[0],res[1]defget_pad_param(self,image_input_size):
dst_w = self.model_input_size[0]
dst_h = self.model_input_size[1]# 计算最小的缩放比例,等比例缩放
ratio_w = dst_w / image_input_size[0]
ratio_h = dst_h / image_input_size[1]if ratio_w < ratio_h:
ratio = ratio_w
else:
ratio = ratio_h
new_w =(int)(ratio * image_input_size[0])
new_h =(int)(ratio * image_input_size[1])
dw =(dst_w - new_w)/2
dh =(dst_h - new_h)/2
top =(int)(round(0))
bottom =(int)(round(dh *2+0.1))
left =(int)(round(0))
right =(int)(round(dw *2-0.1))return[0,0,0,0,top, bottom, left, right]# 自定义人脸注册任务类classFaceRegistrationApp(AIBase):def__init__(self,kmodel_path,model_input_size,rgb888p_size=[1920,1080],display_size=[1920,1080],debug_mode=0):super().__init__(kmodel_path,model_input_size,rgb888p_size,debug_mode)# kmodel路径
self.kmodel_path=kmodel_path
# 人脸注册模型输入分辨率
self.model_input_size=model_input_size
# sensor给到AI的图像分辨率,宽16字节对齐
self.rgb888p_size=[ALIGN_UP(rgb888p_size[0],16),rgb888p_size[1]]# 视频输出VO分辨率,宽16字节对齐
self.display_size=[ALIGN_UP(display_size[0],16),display_size[1]]# debug模式
self.debug_mode=debug_mode
# 标准5官
self.umeyama_args_112 =[38.2946,51.6963,73.5318,51.5014,56.0252,71.7366,41.5493,92.3655,70.7299,92.2041]
self.ai2d=Ai2d(debug_mode)
self.ai2d.set_ai2d_dtype(nn.ai2d_format.NCHW_FMT,nn.ai2d_format.NCHW_FMT,np.uint8, np.uint8)# 配置预处理操作,这里使用了affine,Ai2d支持crop/shift/pad/resize/affine,具体代码请打开/sdcard/app/libs/AI2D.py查看defconfig_preprocess(self,landm,input_image_size=None):with ScopedTiming("set preprocess config",self.debug_mode >0):
ai2d_input_size=input_image_size if input_image_size else self.rgb888p_size
# 计算affine矩阵,并设置仿射变换预处理
affine_matrix = self.get_affine_matrix(landm)
self.ai2d.affine(nn.interp_method.cv2_bilinear,0,0,127,1,affine_matrix)# 构建预处理流程,参数为预处理输入tensor的shape和预处理输出的tensor的shape
self.ai2d.build([1,3,ai2d_input_size[1],ai2d_input_size[0]],[1,3,self.model_input_size[1],self.model_input_size[0]])# 自定义后处理defpostprocess(self,results):with ScopedTiming("postprocess",self.debug_mode >0):return results[0][0]defsvd22(self,a):# svd
s =[0.0,0.0]
u =[0.0,0.0,0.0,0.0]
v =[0.0,0.0,0.0,0.0]
s[0]=(math.sqrt((a[0]- a[3])**2+(a[1]+ a[2])**2)+ math.sqrt((a[0]+ a[3])**2+(a[1]- a[2])**2))/2
s[1]=abs(s[0]- math.sqrt((a[0]- a[3])**2+(a[1]+ a[2])**2))
v[2]= math.sin((math.atan2(2*(a[0]* a[1]+ a[2]* a[3]), a[0]**2- a[1]**2+ a[2]**2- a[3]**2))/2)if \
s[0]> s[1]else0
v[0]= math.sqrt(1- v[2]**2)
v[1]=-v[2]
v[3]= v[0]
u[0]=-(a[0]* v[0]+ a[1]* v[2])/ s[0]if s[0]!=0else1
u[2]=-(a[2]* v[0]+ a[3]* v[2])/ s[0]if s[0]!=0else0
u[1]=(a[0]* v[1]+ a[1]* v[3])/ s[1]if s[1]!=0else-u[2]
u[3]=(a[2]* v[1]+ a[3]* v[3])/ s[1]if s[1]!=0else u[0]
v[0]=-v[0]
v[2]=-v[2]return u, s, v
defimage_umeyama_112(self,src):# 使用Umeyama算法计算仿射变换矩阵
SRC_NUM =5
SRC_DIM =2
src_mean =[0.0,0.0]
dst_mean =[0.0,0.0]for i inrange(0,SRC_NUM *2,2):
src_mean[0]+= src[i]
src_mean[1]+= src[i +1]
dst_mean[0]+= self.umeyama_args_112[i]
dst_mean[1]+= self.umeyama_args_112[i +1]
src_mean[0]/= SRC_NUM
src_mean[1]/= SRC_NUM
dst_mean[0]/= SRC_NUM
dst_mean[1]/= SRC_NUM
src_demean =[[0.0,0.0]for _ inrange(SRC_NUM)]
dst_demean =[[0.0,0.0]for _ inrange(SRC_NUM)]for i inrange(SRC_NUM):
src_demean[i][0]= src[2* i]- src_mean[0]
src_demean[i][1]= src[2* i +1]- src_mean[1]
dst_demean[i][0]= self.umeyama_args_112[2* i]- dst_mean[0]
dst_demean[i][1]= self.umeyama_args_112[2* i +1]- dst_mean[1]
A =[[0.0,0.0],[0.0,0.0]]for i inrange(SRC_DIM):for k inrange(SRC_DIM):for j inrange(SRC_NUM):
A[i][k]+= dst_demean[j][i]* src_demean[j][k]
A[i][k]/= SRC_NUM
T =[[1,0,0],[0,1,0],[0,0,1]]
U, S, V = self.svd22([A[0][0], A[0][1], A[1][0], A[1][1]])
T[0][0]= U[0]* V[0]+ U[1]* V[2]
T[0][1]= U[0]* V[1]+ U[1]* V[3]
T[1][0]= U[2]* V[0]+ U[3]* V[2]
T[1][1]= U[2]* V[1]+ U[3]* V[3]
scale =1.0
src_demean_mean =[0.0,0.0]
src_demean_var =[0.0,0.0]for i inrange(SRC_NUM):
src_demean_mean[0]+= src_demean[i][0]
src_demean_mean[1]+= src_demean[i][1]
src_demean_mean[0]/= SRC_NUM
src_demean_mean[1]/= SRC_NUM
for i inrange(SRC_NUM):
src_demean_var[0]+=(src_demean_mean[0]- src_demean[i][0])*(src_demean_mean[0]- src_demean[i][0])
src_demean_var[1]+=(src_demean_mean[1]- src_demean[i][1])*(src_demean_mean[1]- src_demean[i][1])
src_demean_var[0]/= SRC_NUM
src_demean_var[1]/= SRC_NUM
scale =1.0/(src_demean_var[0]+ src_demean_var[1])*(S[0]+ S[1])
T[0][2]= dst_mean[0]- scale *(T[0][0]* src_mean[0]+ T[0][1]* src_mean[1])
T[1][2]= dst_mean[1]- scale *(T[1][0]* src_mean[0]+ T[1][1]* src_mean[1])
T[0][0]*= scale
T[0][1]*= scale
T[1][0]*= scale
T[1][1]*= scale
return T
defget_affine_matrix(self,sparse_points):# 获取affine变换矩阵with ScopedTiming("get_affine_matrix", self.debug_mode >1):# 使用Umeyama算法计算仿射变换矩阵
matrix_dst = self.image_umeyama_112(sparse_points)
matrix_dst =[matrix_dst[0][0],matrix_dst[0][1],matrix_dst[0][2],
matrix_dst[1][0],matrix_dst[1][1],matrix_dst[1][2]]return matrix_dst
# 人脸注册任务类classFaceRegistration:def__init__(self,face_det_kmodel,face_reg_kmodel,det_input_size,reg_input_size,database_dir,anchors,confidence_threshold=0.25,nms_threshold=0.3,rgb888p_size=[1280,720],display_size=[1920,1080],debug_mode=0):# 人脸检测模型路径
self.face_det_kmodel=face_det_kmodel
# 人脸注册模型路径
self.face_reg_kmodel=face_reg_kmodel
# 人脸检测模型输入分辨率
self.det_input_size=det_input_size
# 人脸注册模型输入分辨率
self.reg_input_size=reg_input_size
self.database_dir=database_dir
# anchors
self.anchors=anchors
# 置信度阈值
self.confidence_threshold=confidence_threshold
# nms阈值
self.nms_threshold=nms_threshold
# sensor给到AI的图像分辨率,宽16字节对齐
self.rgb888p_size=[ALIGN_UP(rgb888p_size[0],16),rgb888p_size[1]]# 视频输出VO分辨率,宽16字节对齐
self.display_size=[ALIGN_UP(display_size[0],16),display_size[1]]# debug_mode模式
self.debug_mode=debug_mode
self.face_det=FaceDetApp(self.face_det_kmodel,model_input_size=self.det_input_size,anchors=self.anchors,confidence_threshold=self.confidence_threshold,nms_threshold=self.nms_threshold,debug_mode=0)
self.face_reg=FaceRegistrationApp(self.face_reg_kmodel,model_input_size=self.reg_input_size,rgb888p_size=self.rgb888p_size)# run函数defrun(self,input_np,img_file):
self.face_det.config_preprocess(input_image_size=[input_np.shape[3],input_np.shape[2]])
det_boxes,landms=self.face_det.run(input_np)if det_boxes:if det_boxes.shape[0]==1:# 若是只检测到一张人脸,则将该人脸注册到数据库
db_i_name = img_file.split('.')[0]for landm in landms:
self.face_reg.config_preprocess(landm,input_image_size=[input_np.shape[3],input_np.shape[2]])
reg_result = self.face_reg.run(input_np)withopen(self.database_dir+'{}.bin'.format(db_i_name),"wb")asfile:file.write(reg_result.tobytes())print('Success!')else:print('Only one person in a picture when you sign up')else:print('No person detected')defimage2rgb888array(self,img):#4维# 将Image转换为rgb888格式with ScopedTiming("fr_kpu_deinit",self.debug_mode >0):
img_data_rgb888=img.to_rgb888()# hwc,rgb888
img_hwc=img_data_rgb888.to_numpy_ref()
shape=img_hwc.shape
img_tmp = img_hwc.reshape((shape[0]* shape[1], shape[2]))
img_tmp_trans = img_tmp.transpose()
img_res=img_tmp_trans.copy()# chw,rgb888
img_return=img_res.reshape((1,shape[2],shape[0],shape[1]))return img_return
if __name__=="__main__":# 人脸检测模型路径
face_det_kmodel_path="/sdcard/app/tests/kmodel/face_detection_320.kmodel"# 人脸注册模型路径
face_reg_kmodel_path="/sdcard/app/tests/kmodel/face_recognition.kmodel"# 其它参数
anchors_path="/sdcard/app/tests/utils/prior_data_320.bin"
database_dir="/sdcard/app/tests/utils/db/"
database_img_dir="/sdcard/app/tests/utils/db_img/"
face_det_input_size=[320,320]
face_reg_input_size=[112,112]
confidence_threshold=0.5
nms_threshold=0.2
anchor_len=4200
det_dim=4
anchors = np.fromfile(anchors_path, dtype=np.float)
anchors = anchors.reshape((anchor_len,det_dim))
max_register_face =100#数据库最多人脸个数
feature_num =128#人脸识别特征维度
fr=FaceRegistration(face_det_kmodel_path,face_reg_kmodel_path,det_input_size=face_det_input_size,reg_input_size=face_reg_input_size,database_dir=database_dir,anchors=anchors,confidence_threshold=confidence_threshold,nms_threshold=nms_threshold)try:# 获取图像列表
img_list = os.listdir(database_img_dir)for img_file in img_list:#本地读取一张图像
full_img_file = database_img_dir + img_file
print(full_img_file)
img = image.Image(full_img_file)
img.compress_for_ide()# 转rgb888的chw格式
rgb888p_img_ndarry = fr.image2rgb888array(img)# 人脸注册
fr.run(rgb888p_img_ndarry,img_file)
gc.collect()except Exception as e:
sys.print_exception(e)finally:
fr.face_det.deinit()
fr.face_reg.deinit()
运行后可以看到在
/sdcard/app/tests/utils/db/
目录下出现了5个人脸数据库:
当然自己也可以试试非人图片能不能注册
Only one person in a picture when you sign up
当你注册的时候,照片上只有一个人
注册后,运行下面代码可以进行识别
'''
实验名称:人脸识别
实验平台:01Studio CanMV K230
教程:wiki.01studio.cc
说明:先执行人脸注册代码,再运行本代码
'''from libs.PipeLine import PipeLine, ScopedTiming
from libs.AIBase import AIBase
from libs.AI2D import Ai2d
import os
import ujson
from media.media import*from time import*import nncase_runtime as nn
import ulab.numpy as np
import time
import image
import aidemo
import random
import gc
import sys
import math
# 自定义人脸检测任务类classFaceDetApp(AIBase):def__init__(self,kmodel_path,model_input_size,anchors,confidence_threshold=0.25,nms_threshold=0.3,rgb888p_size=[1920,1080],display_size=[1920,1080],debug_mode=0):super().__init__(kmodel_path,model_input_size,rgb888p_size,debug_mode)# kmodel路径
self.kmodel_path=kmodel_path
# 检测模型输入分辨率
self.model_input_size=model_input_size
# 置信度阈值
self.confidence_threshold=confidence_threshold
# nms阈值
self.nms_threshold=nms_threshold
self.anchors=anchors
# sensor给到AI的图像分辨率,宽16字节对齐
self.rgb888p_size=[ALIGN_UP(rgb888p_size[0],16),rgb888p_size[1]]# 视频输出VO分辨率,宽16字节对齐
self.display_size=[ALIGN_UP(display_size[0],16),display_size[1]]# debug模式
self.debug_mode=debug_mode
# 实例化Ai2d,用于实现模型预处理
self.ai2d=Ai2d(debug_mode)# 设置Ai2d的输入输出格式和类型
self.ai2d.set_ai2d_dtype(nn.ai2d_format.NCHW_FMT,nn.ai2d_format.NCHW_FMT,np.uint8, np.uint8)# 配置预处理操作,这里使用了pad和resize,Ai2d支持crop/shift/pad/resize/affine,具体代码请打开/sdcard/app/libs/AI2D.py查看defconfig_preprocess(self,input_image_size=None):with ScopedTiming("set preprocess config",self.debug_mode >0):# 初始化ai2d预处理配置,默认为sensor给到AI的尺寸,可以通过设置input_image_size自行修改输入尺寸
ai2d_input_size=input_image_size if input_image_size else self.rgb888p_size
# 计算padding参数,并设置padding预处理
self.ai2d.pad(self.get_pad_param(),0,[104,117,123])# 设置resize预处理
self.ai2d.resize(nn.interp_method.tf_bilinear, nn.interp_mode.half_pixel)# 构建预处理流程,参数为预处理输入tensor的shape和预处理输出的tensor的shape
self.ai2d.build([1,3,ai2d_input_size[1],ai2d_input_size[0]],[1,3,self.model_input_size[1],self.model_input_size[0]])# 自定义后处理,results是模型输出的array列表,这里使用了aidemo库的face_det_post_process接口defpostprocess(self,results):with ScopedTiming("postprocess",self.debug_mode >0):
res = aidemo.face_det_post_process(self.confidence_threshold,self.nms_threshold,self.model_input_size[0],self.anchors,self.rgb888p_size,results)iflen(res)==0:return res,res
else:return res[0],res[1]defget_pad_param(self):
dst_w = self.model_input_size[0]
dst_h = self.model_input_size[1]# 计算最小的缩放比例,等比例缩放
ratio_w = dst_w / self.rgb888p_size[0]
ratio_h = dst_h / self.rgb888p_size[1]if ratio_w < ratio_h:
ratio = ratio_w
else:
ratio = ratio_h
new_w =(int)(ratio * self.rgb888p_size[0])
new_h =(int)(ratio * self.rgb888p_size[1])
dw =(dst_w - new_w)/2
dh =(dst_h - new_h)/2
top =(int)(round(0))
bottom =(int)(round(dh *2+0.1))
left =(int)(round(0))
right =(int)(round(dw *2-0.1))return[0,0,0,0,top, bottom, left, right]# 自定义人脸注册任务类classFaceRegistrationApp(AIBase):def__init__(self,kmodel_path,model_input_size,rgb888p_size=[1920,1080],display_size=[1920,1080],debug_mode=0):super().__init__(kmodel_path,model_input_size,rgb888p_size,debug_mode)# kmodel路径
self.kmodel_path=kmodel_path
# 检测模型输入分辨率
self.model_input_size=model_input_size
# sensor给到AI的图像分辨率,宽16字节对齐
self.rgb888p_size=[ALIGN_UP(rgb888p_size[0],16),rgb888p_size[1]]# 视频输出VO分辨率,宽16字节对齐
self.display_size=[ALIGN_UP(display_size[0],16),display_size[1]]# debug模式
self.debug_mode=debug_mode
# 标准5官
self.umeyama_args_112 =[38.2946,51.6963,73.5318,51.5014,56.0252,71.7366,41.5493,92.3655,70.7299,92.2041]
self.ai2d=Ai2d(debug_mode)
self.ai2d.set_ai2d_dtype(nn.ai2d_format.NCHW_FMT,nn.ai2d_format.NCHW_FMT,np.uint8, np.uint8)# 配置预处理操作,这里使用了affine,Ai2d支持crop/shift/pad/resize/affine,具体代码请打开/sdcard/app/libs/AI2D.py查看defconfig_preprocess(self,landm,input_image_size=None):with ScopedTiming("set preprocess config",self.debug_mode >0):
ai2d_input_size=input_image_size if input_image_size else self.rgb888p_size
# 计算affine矩阵,并设置仿射变换预处理
affine_matrix = self.get_affine_matrix(landm)
self.ai2d.affine(nn.interp_method.cv2_bilinear,0,0,127,1,affine_matrix)# 构建预处理流程,参数为预处理输入tensor的shape和预处理输出的tensor的shape
self.ai2d.build([1,3,ai2d_input_size[1],ai2d_input_size[0]],[1,3,self.model_input_size[1],self.model_input_size[0]])# 自定义后处理defpostprocess(self,results):with ScopedTiming("postprocess",self.debug_mode >0):return results[0][0]defsvd22(self,a):# svd
s =[0.0,0.0]
u =[0.0,0.0,0.0,0.0]
v =[0.0,0.0,0.0,0.0]
s[0]=(math.sqrt((a[0]- a[3])**2+(a[1]+ a[2])**2)+ math.sqrt((a[0]+ a[3])**2+(a[1]- a[2])**2))/2
s[1]=abs(s[0]- math.sqrt((a[0]- a[3])**2+(a[1]+ a[2])**2))
v[2]= math.sin((math.atan2(2*(a[0]* a[1]+ a[2]* a[3]), a[0]**2- a[1]**2+ a[2]**2- a[3]**2))/2)if \
s[0]> s[1]else0
v[0]= math.sqrt(1- v[2]**2)
v[1]=-v[2]
v[3]= v[0]
u[0]=-(a[0]* v[0]+ a[1]* v[2])/ s[0]if s[0]!=0else1
u[2]=-(a[2]* v[0]+ a[3]* v[2])/ s[0]if s[0]!=0else0
u[1]=(a[0]* v[1]+ a[1]* v[3])/ s[1]if s[1]!=0else-u[2]
u[3]=(a[2]* v[1]+ a[3]* v[3])/ s[1]if s[1]!=0else u[0]
v[0]=-v[0]
v[2]=-v[2]return u, s, v
defimage_umeyama_112(self,src):# 使用Umeyama算法计算仿射变换矩阵
SRC_NUM =5
SRC_DIM =2
src_mean =[0.0,0.0]
dst_mean =[0.0,0.0]for i inrange(0,SRC_NUM *2,2):
src_mean[0]+= src[i]
src_mean[1]+= src[i +1]
dst_mean[0]+= self.umeyama_args_112[i]
dst_mean[1]+= self.umeyama_args_112[i +1]
src_mean[0]/= SRC_NUM
src_mean[1]/= SRC_NUM
dst_mean[0]/= SRC_NUM
dst_mean[1]/= SRC_NUM
src_demean =[[0.0,0.0]for _ inrange(SRC_NUM)]
dst_demean =[[0.0,0.0]for _ inrange(SRC_NUM)]for i inrange(SRC_NUM):
src_demean[i][0]= src[2* i]- src_mean[0]
src_demean[i][1]= src[2* i +1]- src_mean[1]
dst_demean[i][0]= self.umeyama_args_112[2* i]- dst_mean[0]
dst_demean[i][1]= self.umeyama_args_112[2* i +1]- dst_mean[1]
A =[[0.0,0.0],[0.0,0.0]]for i inrange(SRC_DIM):for k inrange(SRC_DIM):for j inrange(SRC_NUM):
A[i][k]+= dst_demean[j][i]* src_demean[j][k]
A[i][k]/= SRC_NUM
T =[[1,0,0],[0,1,0],[0,0,1]]
U, S, V = self.svd22([A[0][0], A[0][1], A[1][0], A[1][1]])
T[0][0]= U[0]* V[0]+ U[1]* V[2]
T[0][1]= U[0]* V[1]+ U[1]* V[3]
T[1][0]= U[2]* V[0]+ U[3]* V[2]
T[1][1]= U[2]* V[1]+ U[3]* V[3]
scale =1.0
src_demean_mean =[0.0,0.0]
src_demean_var =[0.0,0.0]for i inrange(SRC_NUM):
src_demean_mean[0]+= src_demean[i][0]
src_demean_mean[1]+= src_demean[i][1]
src_demean_mean[0]/= SRC_NUM
src_demean_mean[1]/= SRC_NUM
for i inrange(SRC_NUM):
src_demean_var[0]+=(src_demean_mean[0]- src_demean[i][0])*(src_demean_mean[0]- src_demean[i][0])
src_demean_var[1]+=(src_demean_mean[1]- src_demean[i][1])*(src_demean_mean[1]- src_demean[i][1])
src_demean_var[0]/= SRC_NUM
src_demean_var[1]/= SRC_NUM
scale =1.0/(src_demean_var[0]+ src_demean_var[1])*(S[0]+ S[1])
T[0][2]= dst_mean[0]- scale *(T[0][0]* src_mean[0]+ T[0][1]* src_mean[1])
T[1][2]= dst_mean[1]- scale *(T[1][0]* src_mean[0]+ T[1][1]* src_mean[1])
T[0][0]*= scale
T[0][1]*= scale
T[1][0]*= scale
T[1][1]*= scale
return T
defget_affine_matrix(self,sparse_points):# 获取affine变换矩阵with ScopedTiming("get_affine_matrix", self.debug_mode >1):# 使用Umeyama算法计算仿射变换矩阵
matrix_dst = self.image_umeyama_112(sparse_points)
matrix_dst =[matrix_dst[0][0],matrix_dst[0][1],matrix_dst[0][2],
matrix_dst[1][0],matrix_dst[1][1],matrix_dst[1][2]]return matrix_dst
# 人脸识别任务类classFaceRecognition:def__init__(self,face_det_kmodel,face_reg_kmodel,det_input_size,reg_input_size,database_dir,anchors,confidence_threshold=0.25,nms_threshold=0.3,face_recognition_threshold=0.75,rgb888p_size=[1280,720],display_size=[1920,1080],debug_mode=0):# 人脸检测模型路径
self.face_det_kmodel=face_det_kmodel
# 人脸识别模型路径
self.face_reg_kmodel=face_reg_kmodel
# 人脸检测模型输入分辨率
self.det_input_size=det_input_size
# 人脸识别模型输入分辨率
self.reg_input_size=reg_input_size
self.database_dir=database_dir
# anchors
self.anchors=anchors
# 置信度阈值
self.confidence_threshold=confidence_threshold
# nms阈值
self.nms_threshold=nms_threshold
self.face_recognition_threshold=face_recognition_threshold
# sensor给到AI的图像分辨率,宽16字节对齐
self.rgb888p_size=[ALIGN_UP(rgb888p_size[0],16),rgb888p_size[1]]# 视频输出VO分辨率,宽16字节对齐
self.display_size=[ALIGN_UP(display_size[0],16),display_size[1]]# debug_mode模式
self.debug_mode=debug_mode
self.max_register_face =100# 数据库最多人脸个数
self.feature_num =128# 人脸识别特征维度
self.valid_register_face =0# 已注册人脸数
self.db_name=[]
self.db_data=[]
self.face_det=FaceDetApp(self.face_det_kmodel,model_input_size=self.det_input_size,anchors=self.anchors,confidence_threshold=self.confidence_threshold,nms_threshold=self.nms_threshold,rgb888p_size=self.rgb888p_size,display_size=self.display_size,debug_mode=0)
self.face_reg=FaceRegistrationApp(self.face_reg_kmodel,model_input_size=self.reg_input_size,rgb888p_size=self.rgb888p_size,display_size=self.display_size)
self.face_det.config_preprocess()# 人脸数据库初始化
self.database_init()# run函数defrun(self,input_np):# 执行人脸检测
det_boxes,landms=self.face_det.run(input_np)
recg_res =[]for landm in landms:# 针对每个人脸五官点,推理得到人脸特征,并计算特征在数据库中相似度
self.face_reg.config_preprocess(landm)
feature=self.face_reg.run(input_np)
res = self.database_search(feature)
recg_res.append(res)return det_boxes,recg_res
defdatabase_init(self):# 数据初始化,构建数据库人名列表和数据库特征列表with ScopedTiming("database_init", self.debug_mode >1):
db_file_list = os.listdir(self.database_dir)for db_file in db_file_list:ifnot db_file.endswith('.bin'):continueif self.valid_register_face >= self.max_register_face:break
valid_index = self.valid_register_face
full_db_file = self.database_dir + db_file
withopen(full_db_file,'rb')as f:
data = f.read()
feature = np.frombuffer(data, dtype=np.float)
self.db_data.append(feature)
name = db_file.split('.')[0]
self.db_name.append(name)
self.valid_register_face +=1defdatabase_reset(self):# 数据库清空with ScopedTiming("database_reset", self.debug_mode >1):print("database clearing...")
self.db_name =[]
self.db_data =[]
self.valid_register_face =0print("database clear Done!")defdatabase_search(self,feature):# 数据库查询with ScopedTiming("database_search", self.debug_mode >1):
v_id =-1
v_score_max =0.0# 将当前人脸特征归一化
feature /= np.linalg.norm(feature)# 遍历当前人脸数据库,统计最高得分for i inrange(self.valid_register_face):
db_feature = self.db_data[i]
db_feature /= np.linalg.norm(db_feature)# 计算数据库特征与当前人脸特征相似度
v_score = np.dot(feature, db_feature)/2+0.5if v_score > v_score_max:
v_score_max = v_score
v_id = i
if v_id ==-1:# 数据库中无人脸return'unknown'elif v_score_max < self.face_recognition_threshold:# 小于人脸识别阈值,未识别return'unknown'else:# 识别成功
result ='name: {}, score:{}'.format(self.db_name[v_id],v_score_max)return result
# 绘制识别结果defdraw_result(self,pl,dets,recg_results):
pl.osd_img.clear()if dets:for i,det inenumerate(dets):# (1)画人脸框
x1, y1, w, h =map(lambda x:int(round(x,0)), det[:4])
x1 = x1 * self.display_size[0]//self.rgb888p_size[0]
y1 = y1 * self.display_size[1]//self.rgb888p_size[1]
w = w * self.display_size[0]//self.rgb888p_size[0]
h = h * self.display_size[1]//self.rgb888p_size[1]
pl.osd_img.draw_rectangle(x1,y1, w, h, color=(255,0,0,255), thickness =4)# (2)写人脸识别结果
recg_text = recg_results[i]
pl.osd_img.draw_string_advanced(x1,y1,32,recg_text,color=(255,255,0,0))if __name__=="__main__":# 注意:执行人脸识别任务之前,需要先执行人脸注册任务进行人脸身份注册生成feature数据库# 显示模式,默认"hdmi",可以选择"hdmi"和"lcd"
display_mode="lcd"if display_mode=="hdmi":
display_size=[1920,1080]else:
display_size=[800,480]# 人脸检测模型路径
face_det_kmodel_path="/sdcard/app/tests/kmodel/face_detection_320.kmodel"# 人脸识别模型路径
face_reg_kmodel_path="/sdcard/app/tests/kmodel/face_recognition.kmodel"# 其它参数
anchors_path="/sdcard/app/tests/utils/prior_data_320.bin"
database_dir ="/sdcard/app/tests/utils/db/"
rgb888p_size=[1920,1080]
face_det_input_size=[320,320]
face_reg_input_size=[112,112]
confidence_threshold=0.5
nms_threshold=0.2
anchor_len=4200
det_dim=4
anchors = np.fromfile(anchors_path, dtype=np.float)
anchors = anchors.reshape((anchor_len,det_dim))
face_recognition_threshold =0.75# 人脸识别阈值# 初始化PipeLine,只关注传给AI的图像分辨率,显示的分辨率
pl=PipeLine(rgb888p_size=rgb888p_size,display_size=display_size,display_mode=display_mode)
pl.create()
fr=FaceRecognition(face_det_kmodel_path,face_reg_kmodel_path,det_input_size=face_det_input_size,reg_input_size=face_reg_input_size,database_dir=database_dir,anchors=anchors,confidence_threshold=confidence_threshold,nms_threshold=nms_threshold,face_recognition_threshold=face_recognition_threshold,rgb888p_size=rgb888p_size,display_size=display_size)
clock = time.clock()try:whileTrue:
os.exitpoint()
clock.tick()
img=pl.get_frame()# 获取当前帧
det_boxes,recg_res=fr.run(img)# 推理当前帧print(det_boxes,recg_res)# 打印结果
fr.draw_result(pl,det_boxes,recg_res)# 绘制推理结果
pl.show_image()# 展示推理效果
gc.collect()print(clock.fps())#打印帧率except Exception as e:
sys.print_exception(e)finally:
fr.face_det.deinit()
fr.face_reg.deinit()
pl.destroy()
主代码变量说明det_boxes人脸检测结果recg_res人脸识别结果
版权归原作者 咸鱼桨 所有, 如有侵权,请联系我们删除。