0


【CanMV K230 AI视觉】 人脸识别

【CanMV K230 AI视觉】 人脸识别

动态测试效果可以去下面网站自己看。)

B站视频链接:已做成合集
抖音链接:已做成合集


人脸识别

前面学习过的人脸检测,只检测出人脸,而本实验要做的人脸识别,会学习人脸特征,然后比对,实现区分不同人脸。比如常用的人脸考勤机就是这样的原理。
在这里插入图片描述

先运行人脸注册代码,人脸注册代码会将CanMV U盘/

  1. sdcard/app/tests/utils/db_img/

目录下的人脸图片进行识别,可以看到里面预存了2张人脸图片,我呢放了3张。
在这里插入图片描述

  1. '''
  2. 实验名称:人脸注册
  3. 实验平台:01Studio CanMV K230
  4. 教程:wiki.01studio.cc
  5. '''from libs.PipeLine import PipeLine, ScopedTiming
  6. from libs.AIBase import AIBase
  7. from libs.AI2D import Ai2d
  8. import os
  9. import ujson
  10. from media.media import*from time import*import nncase_runtime as nn
  11. import ulab.numpy as np
  12. import time
  13. import image
  14. import aidemo
  15. import random
  16. import gc
  17. import sys
  18. import math
  19. # 自定义人脸检测任务类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路径
  20. self.kmodel_path=kmodel_path
  21. # 检测模型输入分辨率
  22. self.model_input_size=model_input_size
  23. # 置信度阈值
  24. self.confidence_threshold=confidence_threshold
  25. # nms阈值
  26. self.nms_threshold=nms_threshold
  27. self.anchors=anchors
  28. # sensor给到AI的图像分辨率,宽16字节对齐
  29. self.rgb888p_size=[ALIGN_UP(rgb888p_size[0],16),rgb888p_size[1]]# 视频输出VO分辨率,宽16字节对齐
  30. self.display_size=[ALIGN_UP(display_size[0],16),display_size[1]]# debug模式
  31. self.debug_mode=debug_mode
  32. # 实例化Ai2d,用于实现模型预处理
  33. self.ai2d=Ai2d(debug_mode)# 设置Ai2d的输入输出格式和类型
  34. self.ai2d.set_ai2d_dtype(nn.ai2d_format.NCHW_FMT,nn.ai2d_format.NCHW_FMT,np.uint8, np.uint8)
  35. self.image_size=[]# 配置预处理操作,这里使用了padresizeAi2d支持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自行修改输入尺寸
  36. ai2d_input_size=input_image_size if input_image_size else self.rgb888p_size
  37. self.image_size=[input_image_size[1],input_image_size[0]]# 计算padding参数,并设置padding预处理
  38. self.ai2d.pad(self.get_pad_param(ai2d_input_size),0,[104,117,123])# 设置resize预处理
  39. self.ai2d.resize(nn.interp_method.tf_bilinear, nn.interp_mode.half_pixel)# 构建预处理流程,参数为预处理输入tensorshape和预处理输出的tensorshape
  40. 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):
  41. 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
  42. else:return res[0],res[1]defget_pad_param(self,image_input_size):
  43. dst_w = self.model_input_size[0]
  44. dst_h = self.model_input_size[1]# 计算最小的缩放比例,等比例缩放
  45. ratio_w = dst_w / image_input_size[0]
  46. ratio_h = dst_h / image_input_size[1]if ratio_w < ratio_h:
  47. ratio = ratio_w
  48. else:
  49. ratio = ratio_h
  50. new_w =(int)(ratio * image_input_size[0])
  51. new_h =(int)(ratio * image_input_size[1])
  52. dw =(dst_w - new_w)/2
  53. dh =(dst_h - new_h)/2
  54. top =(int)(round(0))
  55. bottom =(int)(round(dh *2+0.1))
  56. left =(int)(round(0))
  57. 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路径
  58. self.kmodel_path=kmodel_path
  59. # 人脸注册模型输入分辨率
  60. self.model_input_size=model_input_size
  61. # sensor给到AI的图像分辨率,宽16字节对齐
  62. self.rgb888p_size=[ALIGN_UP(rgb888p_size[0],16),rgb888p_size[1]]# 视频输出VO分辨率,宽16字节对齐
  63. self.display_size=[ALIGN_UP(display_size[0],16),display_size[1]]# debug模式
  64. self.debug_mode=debug_mode
  65. # 标准5官
  66. self.umeyama_args_112 =[38.2946,51.6963,73.5318,51.5014,56.0252,71.7366,41.5493,92.3655,70.7299,92.2041]
  67. self.ai2d=Ai2d(debug_mode)
  68. self.ai2d.set_ai2d_dtype(nn.ai2d_format.NCHW_FMT,nn.ai2d_format.NCHW_FMT,np.uint8, np.uint8)# 配置预处理操作,这里使用了affineAi2d支持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):
  69. ai2d_input_size=input_image_size if input_image_size else self.rgb888p_size
  70. # 计算affine矩阵,并设置仿射变换预处理
  71. affine_matrix = self.get_affine_matrix(landm)
  72. self.ai2d.affine(nn.interp_method.cv2_bilinear,0,0,127,1,affine_matrix)# 构建预处理流程,参数为预处理输入tensorshape和预处理输出的tensorshape
  73. 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
  74. s =[0.0,0.0]
  75. u =[0.0,0.0,0.0,0.0]
  76. v =[0.0,0.0,0.0,0.0]
  77. 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
  78. s[1]=abs(s[0]- math.sqrt((a[0]- a[3])**2+(a[1]+ a[2])**2))
  79. 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 \
  80. s[0]> s[1]else0
  81. v[0]= math.sqrt(1- v[2]**2)
  82. v[1]=-v[2]
  83. v[3]= v[0]
  84. u[0]=-(a[0]* v[0]+ a[1]* v[2])/ s[0]if s[0]!=0else1
  85. u[2]=-(a[2]* v[0]+ a[3]* v[2])/ s[0]if s[0]!=0else0
  86. u[1]=(a[0]* v[1]+ a[1]* v[3])/ s[1]if s[1]!=0else-u[2]
  87. u[3]=(a[2]* v[1]+ a[3]* v[3])/ s[1]if s[1]!=0else u[0]
  88. v[0]=-v[0]
  89. v[2]=-v[2]return u, s, v
  90. defimage_umeyama_112(self,src):# 使用Umeyama算法计算仿射变换矩阵
  91. SRC_NUM =5
  92. SRC_DIM =2
  93. src_mean =[0.0,0.0]
  94. dst_mean =[0.0,0.0]for i inrange(0,SRC_NUM *2,2):
  95. src_mean[0]+= src[i]
  96. src_mean[1]+= src[i +1]
  97. dst_mean[0]+= self.umeyama_args_112[i]
  98. dst_mean[1]+= self.umeyama_args_112[i +1]
  99. src_mean[0]/= SRC_NUM
  100. src_mean[1]/= SRC_NUM
  101. dst_mean[0]/= SRC_NUM
  102. dst_mean[1]/= SRC_NUM
  103. src_demean =[[0.0,0.0]for _ inrange(SRC_NUM)]
  104. dst_demean =[[0.0,0.0]for _ inrange(SRC_NUM)]for i inrange(SRC_NUM):
  105. src_demean[i][0]= src[2* i]- src_mean[0]
  106. src_demean[i][1]= src[2* i +1]- src_mean[1]
  107. dst_demean[i][0]= self.umeyama_args_112[2* i]- dst_mean[0]
  108. dst_demean[i][1]= self.umeyama_args_112[2* i +1]- dst_mean[1]
  109. A =[[0.0,0.0],[0.0,0.0]]for i inrange(SRC_DIM):for k inrange(SRC_DIM):for j inrange(SRC_NUM):
  110. A[i][k]+= dst_demean[j][i]* src_demean[j][k]
  111. A[i][k]/= SRC_NUM
  112. T =[[1,0,0],[0,1,0],[0,0,1]]
  113. U, S, V = self.svd22([A[0][0], A[0][1], A[1][0], A[1][1]])
  114. T[0][0]= U[0]* V[0]+ U[1]* V[2]
  115. T[0][1]= U[0]* V[1]+ U[1]* V[3]
  116. T[1][0]= U[2]* V[0]+ U[3]* V[2]
  117. T[1][1]= U[2]* V[1]+ U[3]* V[3]
  118. scale =1.0
  119. src_demean_mean =[0.0,0.0]
  120. src_demean_var =[0.0,0.0]for i inrange(SRC_NUM):
  121. src_demean_mean[0]+= src_demean[i][0]
  122. src_demean_mean[1]+= src_demean[i][1]
  123. src_demean_mean[0]/= SRC_NUM
  124. src_demean_mean[1]/= SRC_NUM
  125. for i inrange(SRC_NUM):
  126. src_demean_var[0]+=(src_demean_mean[0]- src_demean[i][0])*(src_demean_mean[0]- src_demean[i][0])
  127. src_demean_var[1]+=(src_demean_mean[1]- src_demean[i][1])*(src_demean_mean[1]- src_demean[i][1])
  128. src_demean_var[0]/= SRC_NUM
  129. src_demean_var[1]/= SRC_NUM
  130. scale =1.0/(src_demean_var[0]+ src_demean_var[1])*(S[0]+ S[1])
  131. T[0][2]= dst_mean[0]- scale *(T[0][0]* src_mean[0]+ T[0][1]* src_mean[1])
  132. T[1][2]= dst_mean[1]- scale *(T[1][0]* src_mean[0]+ T[1][1]* src_mean[1])
  133. T[0][0]*= scale
  134. T[0][1]*= scale
  135. T[1][0]*= scale
  136. T[1][1]*= scale
  137. return T
  138. defget_affine_matrix(self,sparse_points):# 获取affine变换矩阵with ScopedTiming("get_affine_matrix", self.debug_mode >1):# 使用Umeyama算法计算仿射变换矩阵
  139. matrix_dst = self.image_umeyama_112(sparse_points)
  140. matrix_dst =[matrix_dst[0][0],matrix_dst[0][1],matrix_dst[0][2],
  141. matrix_dst[1][0],matrix_dst[1][1],matrix_dst[1][2]]return matrix_dst
  142. # 人脸注册任务类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):# 人脸检测模型路径
  143. self.face_det_kmodel=face_det_kmodel
  144. # 人脸注册模型路径
  145. self.face_reg_kmodel=face_reg_kmodel
  146. # 人脸检测模型输入分辨率
  147. self.det_input_size=det_input_size
  148. # 人脸注册模型输入分辨率
  149. self.reg_input_size=reg_input_size
  150. self.database_dir=database_dir
  151. # anchors
  152. self.anchors=anchors
  153. # 置信度阈值
  154. self.confidence_threshold=confidence_threshold
  155. # nms阈值
  156. self.nms_threshold=nms_threshold
  157. # sensor给到AI的图像分辨率,宽16字节对齐
  158. self.rgb888p_size=[ALIGN_UP(rgb888p_size[0],16),rgb888p_size[1]]# 视频输出VO分辨率,宽16字节对齐
  159. self.display_size=[ALIGN_UP(display_size[0],16),display_size[1]]# debug_mode模式
  160. self.debug_mode=debug_mode
  161. 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)
  162. 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):
  163. self.face_det.config_preprocess(input_image_size=[input_np.shape[3],input_np.shape[2]])
  164. det_boxes,landms=self.face_det.run(input_np)if det_boxes:if det_boxes.shape[0]==1:# 若是只检测到一张人脸,则将该人脸注册到数据库
  165. db_i_name = img_file.split('.')[0]for landm in landms:
  166. self.face_reg.config_preprocess(landm,input_image_size=[input_np.shape[3],input_np.shape[2]])
  167. 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):
  168. img_data_rgb888=img.to_rgb888()# hwc,rgb888
  169. img_hwc=img_data_rgb888.to_numpy_ref()
  170. shape=img_hwc.shape
  171. img_tmp = img_hwc.reshape((shape[0]* shape[1], shape[2]))
  172. img_tmp_trans = img_tmp.transpose()
  173. img_res=img_tmp_trans.copy()# chw,rgb888
  174. img_return=img_res.reshape((1,shape[2],shape[0],shape[1]))return img_return
  175. if __name__=="__main__":# 人脸检测模型路径
  176. face_det_kmodel_path="/sdcard/app/tests/kmodel/face_detection_320.kmodel"# 人脸注册模型路径
  177. face_reg_kmodel_path="/sdcard/app/tests/kmodel/face_recognition.kmodel"# 其它参数
  178. anchors_path="/sdcard/app/tests/utils/prior_data_320.bin"
  179. database_dir="/sdcard/app/tests/utils/db/"
  180. database_img_dir="/sdcard/app/tests/utils/db_img/"
  181. face_det_input_size=[320,320]
  182. face_reg_input_size=[112,112]
  183. confidence_threshold=0.5
  184. nms_threshold=0.2
  185. anchor_len=4200
  186. det_dim=4
  187. anchors = np.fromfile(anchors_path, dtype=np.float)
  188. anchors = anchors.reshape((anchor_len,det_dim))
  189. max_register_face =100#数据库最多人脸个数
  190. feature_num =128#人脸识别特征维度
  191. 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:# 获取图像列表
  192. img_list = os.listdir(database_img_dir)for img_file in img_list:#本地读取一张图像
  193. full_img_file = database_img_dir + img_file
  194. print(full_img_file)
  195. img = image.Image(full_img_file)
  196. img.compress_for_ide()# rgb888chw格式
  197. rgb888p_img_ndarry = fr.image2rgb888array(img)# 人脸注册
  198. fr.run(rgb888p_img_ndarry,img_file)
  199. gc.collect()except Exception as e:
  200. sys.print_exception(e)finally:
  201. fr.face_det.deinit()
  202. fr.face_reg.deinit()

运行后可以看到在

  1. /sdcard/app/tests/utils/db/

目录下出现了5个人脸数据库:
在这里插入图片描述
当然自己也可以试试非人图片能不能注册

在这里插入图片描述

Only one person in a picture when you sign up
当你注册的时候,照片上只有一个人

注册后,运行下面代码可以进行识别

  1. '''
  2. 实验名称:人脸识别
  3. 实验平台:01Studio CanMV K230
  4. 教程:wiki.01studio.cc
  5. 说明:先执行人脸注册代码,再运行本代码
  6. '''from libs.PipeLine import PipeLine, ScopedTiming
  7. from libs.AIBase import AIBase
  8. from libs.AI2D import Ai2d
  9. import os
  10. import ujson
  11. from media.media import*from time import*import nncase_runtime as nn
  12. import ulab.numpy as np
  13. import time
  14. import image
  15. import aidemo
  16. import random
  17. import gc
  18. import sys
  19. import math
  20. # 自定义人脸检测任务类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路径
  21. self.kmodel_path=kmodel_path
  22. # 检测模型输入分辨率
  23. self.model_input_size=model_input_size
  24. # 置信度阈值
  25. self.confidence_threshold=confidence_threshold
  26. # nms阈值
  27. self.nms_threshold=nms_threshold
  28. self.anchors=anchors
  29. # sensor给到AI的图像分辨率,宽16字节对齐
  30. self.rgb888p_size=[ALIGN_UP(rgb888p_size[0],16),rgb888p_size[1]]# 视频输出VO分辨率,宽16字节对齐
  31. self.display_size=[ALIGN_UP(display_size[0],16),display_size[1]]# debug模式
  32. self.debug_mode=debug_mode
  33. # 实例化Ai2d,用于实现模型预处理
  34. self.ai2d=Ai2d(debug_mode)# 设置Ai2d的输入输出格式和类型
  35. self.ai2d.set_ai2d_dtype(nn.ai2d_format.NCHW_FMT,nn.ai2d_format.NCHW_FMT,np.uint8, np.uint8)# 配置预处理操作,这里使用了padresizeAi2d支持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自行修改输入尺寸
  36. ai2d_input_size=input_image_size if input_image_size else self.rgb888p_size
  37. # 计算padding参数,并设置padding预处理
  38. self.ai2d.pad(self.get_pad_param(),0,[104,117,123])# 设置resize预处理
  39. self.ai2d.resize(nn.interp_method.tf_bilinear, nn.interp_mode.half_pixel)# 构建预处理流程,参数为预处理输入tensorshape和预处理输出的tensorshape
  40. 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):
  41. 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
  42. else:return res[0],res[1]defget_pad_param(self):
  43. dst_w = self.model_input_size[0]
  44. dst_h = self.model_input_size[1]# 计算最小的缩放比例,等比例缩放
  45. ratio_w = dst_w / self.rgb888p_size[0]
  46. ratio_h = dst_h / self.rgb888p_size[1]if ratio_w < ratio_h:
  47. ratio = ratio_w
  48. else:
  49. ratio = ratio_h
  50. new_w =(int)(ratio * self.rgb888p_size[0])
  51. new_h =(int)(ratio * self.rgb888p_size[1])
  52. dw =(dst_w - new_w)/2
  53. dh =(dst_h - new_h)/2
  54. top =(int)(round(0))
  55. bottom =(int)(round(dh *2+0.1))
  56. left =(int)(round(0))
  57. 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路径
  58. self.kmodel_path=kmodel_path
  59. # 检测模型输入分辨率
  60. self.model_input_size=model_input_size
  61. # sensor给到AI的图像分辨率,宽16字节对齐
  62. self.rgb888p_size=[ALIGN_UP(rgb888p_size[0],16),rgb888p_size[1]]# 视频输出VO分辨率,宽16字节对齐
  63. self.display_size=[ALIGN_UP(display_size[0],16),display_size[1]]# debug模式
  64. self.debug_mode=debug_mode
  65. # 标准5官
  66. self.umeyama_args_112 =[38.2946,51.6963,73.5318,51.5014,56.0252,71.7366,41.5493,92.3655,70.7299,92.2041]
  67. self.ai2d=Ai2d(debug_mode)
  68. self.ai2d.set_ai2d_dtype(nn.ai2d_format.NCHW_FMT,nn.ai2d_format.NCHW_FMT,np.uint8, np.uint8)# 配置预处理操作,这里使用了affineAi2d支持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):
  69. ai2d_input_size=input_image_size if input_image_size else self.rgb888p_size
  70. # 计算affine矩阵,并设置仿射变换预处理
  71. affine_matrix = self.get_affine_matrix(landm)
  72. self.ai2d.affine(nn.interp_method.cv2_bilinear,0,0,127,1,affine_matrix)# 构建预处理流程,参数为预处理输入tensorshape和预处理输出的tensorshape
  73. 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
  74. s =[0.0,0.0]
  75. u =[0.0,0.0,0.0,0.0]
  76. v =[0.0,0.0,0.0,0.0]
  77. 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
  78. s[1]=abs(s[0]- math.sqrt((a[0]- a[3])**2+(a[1]+ a[2])**2))
  79. 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 \
  80. s[0]> s[1]else0
  81. v[0]= math.sqrt(1- v[2]**2)
  82. v[1]=-v[2]
  83. v[3]= v[0]
  84. u[0]=-(a[0]* v[0]+ a[1]* v[2])/ s[0]if s[0]!=0else1
  85. u[2]=-(a[2]* v[0]+ a[3]* v[2])/ s[0]if s[0]!=0else0
  86. u[1]=(a[0]* v[1]+ a[1]* v[3])/ s[1]if s[1]!=0else-u[2]
  87. u[3]=(a[2]* v[1]+ a[3]* v[3])/ s[1]if s[1]!=0else u[0]
  88. v[0]=-v[0]
  89. v[2]=-v[2]return u, s, v
  90. defimage_umeyama_112(self,src):# 使用Umeyama算法计算仿射变换矩阵
  91. SRC_NUM =5
  92. SRC_DIM =2
  93. src_mean =[0.0,0.0]
  94. dst_mean =[0.0,0.0]for i inrange(0,SRC_NUM *2,2):
  95. src_mean[0]+= src[i]
  96. src_mean[1]+= src[i +1]
  97. dst_mean[0]+= self.umeyama_args_112[i]
  98. dst_mean[1]+= self.umeyama_args_112[i +1]
  99. src_mean[0]/= SRC_NUM
  100. src_mean[1]/= SRC_NUM
  101. dst_mean[0]/= SRC_NUM
  102. dst_mean[1]/= SRC_NUM
  103. src_demean =[[0.0,0.0]for _ inrange(SRC_NUM)]
  104. dst_demean =[[0.0,0.0]for _ inrange(SRC_NUM)]for i inrange(SRC_NUM):
  105. src_demean[i][0]= src[2* i]- src_mean[0]
  106. src_demean[i][1]= src[2* i +1]- src_mean[1]
  107. dst_demean[i][0]= self.umeyama_args_112[2* i]- dst_mean[0]
  108. dst_demean[i][1]= self.umeyama_args_112[2* i +1]- dst_mean[1]
  109. A =[[0.0,0.0],[0.0,0.0]]for i inrange(SRC_DIM):for k inrange(SRC_DIM):for j inrange(SRC_NUM):
  110. A[i][k]+= dst_demean[j][i]* src_demean[j][k]
  111. A[i][k]/= SRC_NUM
  112. T =[[1,0,0],[0,1,0],[0,0,1]]
  113. U, S, V = self.svd22([A[0][0], A[0][1], A[1][0], A[1][1]])
  114. T[0][0]= U[0]* V[0]+ U[1]* V[2]
  115. T[0][1]= U[0]* V[1]+ U[1]* V[3]
  116. T[1][0]= U[2]* V[0]+ U[3]* V[2]
  117. T[1][1]= U[2]* V[1]+ U[3]* V[3]
  118. scale =1.0
  119. src_demean_mean =[0.0,0.0]
  120. src_demean_var =[0.0,0.0]for i inrange(SRC_NUM):
  121. src_demean_mean[0]+= src_demean[i][0]
  122. src_demean_mean[1]+= src_demean[i][1]
  123. src_demean_mean[0]/= SRC_NUM
  124. src_demean_mean[1]/= SRC_NUM
  125. for i inrange(SRC_NUM):
  126. src_demean_var[0]+=(src_demean_mean[0]- src_demean[i][0])*(src_demean_mean[0]- src_demean[i][0])
  127. src_demean_var[1]+=(src_demean_mean[1]- src_demean[i][1])*(src_demean_mean[1]- src_demean[i][1])
  128. src_demean_var[0]/= SRC_NUM
  129. src_demean_var[1]/= SRC_NUM
  130. scale =1.0/(src_demean_var[0]+ src_demean_var[1])*(S[0]+ S[1])
  131. T[0][2]= dst_mean[0]- scale *(T[0][0]* src_mean[0]+ T[0][1]* src_mean[1])
  132. T[1][2]= dst_mean[1]- scale *(T[1][0]* src_mean[0]+ T[1][1]* src_mean[1])
  133. T[0][0]*= scale
  134. T[0][1]*= scale
  135. T[1][0]*= scale
  136. T[1][1]*= scale
  137. return T
  138. defget_affine_matrix(self,sparse_points):# 获取affine变换矩阵with ScopedTiming("get_affine_matrix", self.debug_mode >1):# 使用Umeyama算法计算仿射变换矩阵
  139. matrix_dst = self.image_umeyama_112(sparse_points)
  140. matrix_dst =[matrix_dst[0][0],matrix_dst[0][1],matrix_dst[0][2],
  141. matrix_dst[1][0],matrix_dst[1][1],matrix_dst[1][2]]return matrix_dst
  142. # 人脸识别任务类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):# 人脸检测模型路径
  143. self.face_det_kmodel=face_det_kmodel
  144. # 人脸识别模型路径
  145. self.face_reg_kmodel=face_reg_kmodel
  146. # 人脸检测模型输入分辨率
  147. self.det_input_size=det_input_size
  148. # 人脸识别模型输入分辨率
  149. self.reg_input_size=reg_input_size
  150. self.database_dir=database_dir
  151. # anchors
  152. self.anchors=anchors
  153. # 置信度阈值
  154. self.confidence_threshold=confidence_threshold
  155. # nms阈值
  156. self.nms_threshold=nms_threshold
  157. self.face_recognition_threshold=face_recognition_threshold
  158. # sensor给到AI的图像分辨率,宽16字节对齐
  159. self.rgb888p_size=[ALIGN_UP(rgb888p_size[0],16),rgb888p_size[1]]# 视频输出VO分辨率,宽16字节对齐
  160. self.display_size=[ALIGN_UP(display_size[0],16),display_size[1]]# debug_mode模式
  161. self.debug_mode=debug_mode
  162. self.max_register_face =100# 数据库最多人脸个数
  163. self.feature_num =128# 人脸识别特征维度
  164. self.valid_register_face =0# 已注册人脸数
  165. self.db_name=[]
  166. self.db_data=[]
  167. 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)
  168. 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)
  169. self.face_det.config_preprocess()# 人脸数据库初始化
  170. self.database_init()# run函数defrun(self,input_np):# 执行人脸检测
  171. det_boxes,landms=self.face_det.run(input_np)
  172. recg_res =[]for landm in landms:# 针对每个人脸五官点,推理得到人脸特征,并计算特征在数据库中相似度
  173. self.face_reg.config_preprocess(landm)
  174. feature=self.face_reg.run(input_np)
  175. res = self.database_search(feature)
  176. recg_res.append(res)return det_boxes,recg_res
  177. defdatabase_init(self):# 数据初始化,构建数据库人名列表和数据库特征列表with ScopedTiming("database_init", self.debug_mode >1):
  178. 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
  179. valid_index = self.valid_register_face
  180. full_db_file = self.database_dir + db_file
  181. withopen(full_db_file,'rb')as f:
  182. data = f.read()
  183. feature = np.frombuffer(data, dtype=np.float)
  184. self.db_data.append(feature)
  185. name = db_file.split('.')[0]
  186. self.db_name.append(name)
  187. self.valid_register_face +=1defdatabase_reset(self):# 数据库清空with ScopedTiming("database_reset", self.debug_mode >1):print("database clearing...")
  188. self.db_name =[]
  189. self.db_data =[]
  190. self.valid_register_face =0print("database clear Done!")defdatabase_search(self,feature):# 数据库查询with ScopedTiming("database_search", self.debug_mode >1):
  191. v_id =-1
  192. v_score_max =0.0# 将当前人脸特征归一化
  193. feature /= np.linalg.norm(feature)# 遍历当前人脸数据库,统计最高得分for i inrange(self.valid_register_face):
  194. db_feature = self.db_data[i]
  195. db_feature /= np.linalg.norm(db_feature)# 计算数据库特征与当前人脸特征相似度
  196. v_score = np.dot(feature, db_feature)/2+0.5if v_score > v_score_max:
  197. v_score_max = v_score
  198. v_id = i
  199. if v_id ==-1:# 数据库中无人脸return'unknown'elif v_score_max < self.face_recognition_threshold:# 小于人脸识别阈值,未识别return'unknown'else:# 识别成功
  200. result ='name: {}, score:{}'.format(self.db_name[v_id],v_score_max)return result
  201. # 绘制识别结果defdraw_result(self,pl,dets,recg_results):
  202. pl.osd_img.clear()if dets:for i,det inenumerate(dets):# 1)画人脸框
  203. x1, y1, w, h =map(lambda x:int(round(x,0)), det[:4])
  204. x1 = x1 * self.display_size[0]//self.rgb888p_size[0]
  205. y1 = y1 * self.display_size[1]//self.rgb888p_size[1]
  206. w = w * self.display_size[0]//self.rgb888p_size[0]
  207. h = h * self.display_size[1]//self.rgb888p_size[1]
  208. pl.osd_img.draw_rectangle(x1,y1, w, h, color=(255,0,0,255), thickness =4)# 2)写人脸识别结果
  209. recg_text = recg_results[i]
  210. pl.osd_img.draw_string_advanced(x1,y1,32,recg_text,color=(255,255,0,0))if __name__=="__main__":# 注意:执行人脸识别任务之前,需要先执行人脸注册任务进行人脸身份注册生成feature数据库# 显示模式,默认"hdmi",可以选择"hdmi""lcd"
  211. display_mode="lcd"if display_mode=="hdmi":
  212. display_size=[1920,1080]else:
  213. display_size=[800,480]# 人脸检测模型路径
  214. face_det_kmodel_path="/sdcard/app/tests/kmodel/face_detection_320.kmodel"# 人脸识别模型路径
  215. face_reg_kmodel_path="/sdcard/app/tests/kmodel/face_recognition.kmodel"# 其它参数
  216. anchors_path="/sdcard/app/tests/utils/prior_data_320.bin"
  217. database_dir ="/sdcard/app/tests/utils/db/"
  218. rgb888p_size=[1920,1080]
  219. face_det_input_size=[320,320]
  220. face_reg_input_size=[112,112]
  221. confidence_threshold=0.5
  222. nms_threshold=0.2
  223. anchor_len=4200
  224. det_dim=4
  225. anchors = np.fromfile(anchors_path, dtype=np.float)
  226. anchors = anchors.reshape((anchor_len,det_dim))
  227. face_recognition_threshold =0.75# 人脸识别阈值# 初始化PipeLine,只关注传给AI的图像分辨率,显示的分辨率
  228. pl=PipeLine(rgb888p_size=rgb888p_size,display_size=display_size,display_mode=display_mode)
  229. pl.create()
  230. 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)
  231. clock = time.clock()try:whileTrue:
  232. os.exitpoint()
  233. clock.tick()
  234. img=pl.get_frame()# 获取当前帧
  235. det_boxes,recg_res=fr.run(img)# 推理当前帧print(det_boxes,recg_res)# 打印结果
  236. fr.draw_result(pl,det_boxes,recg_res)# 绘制推理结果
  237. pl.show_image()# 展示推理效果
  238. gc.collect()print(clock.fps())#打印帧率except Exception as e:
  239. sys.print_exception(e)finally:
  240. fr.face_det.deinit()
  241. fr.face_reg.deinit()
  242. pl.destroy()

主代码变量说明det_boxes人脸检测结果recg_res人脸识别结果
在这里插入图片描述
在这里插入图片描述

标签: 人工智能

本文转载自: https://blog.csdn.net/weixin_45020839/article/details/142106041
版权归原作者 咸鱼桨 所有, 如有侵权,请联系我们删除。

“【CanMV K230 AI视觉】 人脸识别”的评论:

还没有评论