基于K210的人脸识别门禁

毕业设计_基于K210的人脸识别门禁

  • 系统介绍
  • 硬件准备
  • 软件准备
  • 部分代码
  • tips
  • 写在最后

分享一则自己的毕业设计,基于人脸识别技术的门禁系统研究。系统硬件比较糙,可以集成化更高一点,基本控制是交由STM32处理,图像识别由K210处理。水平有限,恳请大家指正。

系统介绍

本系统设计以Kendryte K210为人脸图像识别的核心芯片,以STM32为系统逻辑控制芯片,同时加入语音模块、触摸屏和RFID模块。系统共四个功能模式,分别是人脸识别、口罩检测、特征学习、门禁通卡。人脸识别采用基于YOLO的人脸检测算法和特征提取算法,同时将模型部署至K210运行。系统可对人脸特征进行学习,实现了对人脸信息的实时录入,方便了门禁系统的管理。硬件方面系统还加入了RFID模块、语音播报模块、TFT触摸屏等。RFID模块主要实现了对用户ID卡识别,并将ID卡信息通过串口传送到STM32进行用户信息匹配。语音模块和触摸屏组成了系统人机交互部分,系统界面简洁操作简单,同时具备语音播报功能,智能化程度高。
基于K210的人脸识别门禁_第1张图片

硬件准备

STM32f103zet6、Maixduino、RFID模块、JZ-TRIG语音播报、触摸屏、LCD、摄像头、角度舵机、锂电池、稳压管(两个,一个给系统供电,一个单独给舵机供电)
基于K210的人脸识别门禁_第2张图片

软件准备

软件工具:MDK、Maixpy IDE、串口助手(调试用)
程序组成:人脸检测程序、人脸五点特征点提取、口罩检测程序、特征学习程序、RFID模块识别程序
基于K210的人脸识别门禁_第3张图片

部分代码

人脸识别、特征学习
代码参考Maixpy论坛一些前辈的经验,请大家多多支持Maixpy。

def face_recognize():
    global flag_enter
    global task_mask,task_ld,task_fe
    global sum_3
    global sum_4
    global now_mode
    img = sensor.snapshot()
    code = kpu.run_yolo2(task_fd, img)
    if code:
        for i in code:
            # Cut face and resize to 128x128
            a = img.draw_rectangle(i.rect())
            face_cut = img.cut(i.x(), i.y(), i.w(), i.h())
            face_cut_128 = face_cut.resize(128, 128)
            a = face_cut_128.pix_to_ai()
            # a = img.draw_image(face_cut_128, (0,0))
            # Landmark for face 5 points
            fmap = kpu.forward(task_ld, face_cut_128)
            plist = fmap[:]
            le = (i.x() + int(plist[0] * i.w() - 10), i.y() + int(plist[1] * i.h()))
            re = (i.x() + int(plist[2] * i.w()), i.y() + int(plist[3] * i.h()))
            nose = (i.x() + int(plist[4] * i.w()), i.y() + int(plist[5] * i.h()))
            lm = (i.x() + int(plist[6] * i.w()), i.y() + int(plist[7] * i.h()))
            rm = (i.x() + int(plist[8] * i.w()), i.y() + int(plist[9] * i.h()))
            a = img.draw_circle(le[0], le[1], 4)
            a = img.draw_circle(re[0], re[1], 4)
            a = img.draw_circle(nose[0], nose[1], 4)
            a = img.draw_circle(lm[0], lm[1], 4)
            a = img.draw_circle(rm[0], rm[1], 4)
            # align face to standard position
            src_point = [le, re, nose, lm, rm]
            T = image.get_affine_transform(src_point, dst_point)
            a = image.warp_affine_ai(img, img_face, T)
            a = img_face.ai_to_pix()
            # a = img.draw_image(img_face, (128,0))
            del (face_cut_128)
            # calculate face feature vector
            fmap = kpu.forward(task_fe, img_face)
            feature = kpu.face_encode(fmap[:])
            reg_flag = False
            scores = []
            for j in range(len(record_ftrs)):
                score = kpu.face_compare(record_ftrs[j], feature)
                scores.append(score)
            max_score = 0
            index = 0
            for k in range(len(scores)):
                if max_score < scores[k]:
                    max_score = scores[k]
                    index = k
            if max_score > 85:
                a = img.draw_string(i.x(), i.y(), ("%s :%2.1f" % (
                    names[index], max_score)), color=(0, 255, 0), scale=2)

                sum_3+=1
                if sum_3 == 10:
                    uart_A.write(b'i')
                    print(sum_3)
                    sum_3=0
                    sum_4=0
                    now_mode = 0

            else:
                a = img.draw_string(i.x(), i.y(), ("X :%2.1f" % (
                    max_score)), color=(255, 0, 0), scale=2)#串口数据预留

                sum_4+=1
                if sum_4 == 10:
                    uart_A.write(b'j')
                    print(sum_4)
                    sum_3=0
                    sum_4=0
                    now_mode = 0


            #特征值学习
            if flag_enter==1 :
                print('feature study')
                #features_data = uart_A.read()
                #if features_data:
                    #stu_name = features_data.decode('utf-8')
                    #print("stu_name=",stu_name)
                with open("/sd/features.txt", "a") as f:
                    f.write(str(feature))  #信息写入SD卡
                    record_ftrs.append(feature)			#人脸特征追加到record_ftrs列表
                        #names.append(stu_name)   		  #追加到姓名列表
                    f.write("\n")
                    f.close()
                flag_enter=0
                uart_A.write(b'i')
                now_mode = 0
                sum_3=0
                sum_4=0
                #写入sd卡
            break

口罩检测

def mask_recognize():
    #print('Hello')
    global sum_1
    global sum_2
    global now_mode
    code = kpu.run_yolo2(task_mask, img)
    if code:
        totalRes = len(code)

        for item in code:
            confidence = float(item.value())
            itemROL = item.rect()
            classID = int(item.classid())

            if confidence < 0.52:
                a = img.draw_rectangle(itemROL, color=color_B, tickness=5)
                continue
            #有口罩
            if classID == 1 and confidence > 0.76:
                a = img.draw_rectangle(itemROL, color_G, tickness=5)
                if totalRes == 1:
                    drawConfidenceText(img, (0, 0), 1, confidence)
                    sum_1+=1
                    if sum_1 == 10:
                        uart_A.write(b'i')
                        sum_1=0
                        sum_2=0
                        now_mode = 0
                        blank()
                    break
            #无口罩
            else:
                a = img.draw_rectangle(itemROL, color=color_R, tickness=5)
                if totalRes == 1:
                    drawConfidenceText(img, (0, 0), 0, confidence)
                    sum_2+=1
                    if sum_2 == 10:
                        uart_A.write(b'j')
                        sum_1=0
                        sum_2=0
                        now_mode = 0
                        blank()
                    break

RFID程序

unsigned char ReadTagId(unsigned char *idout)
{
	unsigned char status;
	unsigned char i;
	unsigned char pkt[12];
	status = STATUS_ERR;
	if(Uart1RxDataConut > 0) //判断串口是否接收到数据
	{
		Delay(150000);  //等待串口接收完成,根据视情况调整延时
		if(Rx1Flag == 1)//判断串口是否接收到一帧完整数据
		{	
			Rx1Flag = 0;
			for(i=0;i<12;i++) //自动读卡号数据包固定为12字节
			{
				pkt[i] = Uart1RxBuf[i]; //将串口接收数组内的数据复制到pkt数组中
			}
			if(RxCheckSum(pkt,12) == STATUS_OK)  //判断校验和是否正确
			{
				if(pkt[4] == STATUS_OK)	//判断是否正确的读到卡
				{
					//04 0C 02 20 00 04 00 45 96 B7 8A 3F
					if((pkt[0] == 0x04)&&(pkt[1] == 0x0C)&&(pkt[2] == 0x02)&&(pkt[3] == 0x20))//对数据包进行判断
					{
						for(i=0;i<4;i++)//获取4字节卡号
						{
							idout[i] = pkt[i+7];//从数组的第7个字节开始为卡号,共4字节
						}
						if((idout[0] == 0xFD)&&(idout[1] == 0x68)&&(idout[2] == 0x01)&&(idout[3] == 0xAF)&&(Function4_Flag == 1))//对数据包进行判断
						{
							GPIO_ResetBits(GPIOB,GPIO_Pin_0);
							GPIO_ResetBits(GPIOB,GPIO_Pin_1);
							GPIO_ResetBits(GPIOB,GPIO_Pin_5);
							jpgDisplay("0:/three.jpg");
							Delay(4000000);
							TIM_SetCompare2(TIM2, 2500);
							Delay(20000000);
							TIM_SetCompare2(TIM2, 500);
							jpgDisplay("0:/one.jpg");
							Function4_Flag = 0;
						}
						else if((idout[0] == 0x5D)&&(idout[1] == 0xD2)&&(idout[2] == 0x56)&&(idout[3] == 0xAF)&&(Function4_Flag == 1))//对数据包进行判断
						{
							GPIO_ResetBits(GPIOB,GPIO_Pin_0);
							GPIO_ResetBits(GPIOB,GPIO_Pin_1);
							GPIO_ResetBits(GPIOB,GPIO_Pin_5);
							jpgDisplay("0:/three.jpg");
							Delay(4000000);
							TIM_SetCompare2(TIM2, 2500);
							Delay(20000000);
							TIM_SetCompare2(TIM2, 500);
							jpgDisplay("0:/one.jpg");
							Function4_Flag = 0;
						}
						else if((idout[0] == 0x4D)&&(idout[1] == 0xA0)&&(idout[2] == 0xFC)&&(idout[3] == 0xAE)&&(Function4_Flag == 1))//对数据包进行判断
						{
							GPIO_ResetBits(GPIOB,GPIO_Pin_0);
							GPIO_ResetBits(GPIOB,GPIO_Pin_1);
							GPIO_ResetBits(GPIOB,GPIO_Pin_5);
							jpgDisplay("0:/three.jpg");
							Delay(4000000);
							TIM_SetCompare2(TIM2, 2500);
							Delay(20000000);
							TIM_SetCompare2(TIM2, 500);
							jpgDisplay("0:/one.jpg");
							Function4_Flag = 0;
						}
						else if((idout[0] == 0x68)&&(idout[1] == 0x54)&&(idout[2] == 0xED)&&(idout[3] == 0x3D)&&(Function4_Flag == 1))//对数据包进行判断
						{
							GPIO_ResetBits(GPIOB,GPIO_Pin_0);
							GPIO_ResetBits(GPIOB,GPIO_Pin_1);
							GPIO_ResetBits(GPIOB,GPIO_Pin_5);
							jpgDisplay("0:/three.jpg");
							Delay(4000000);
							TIM_SetCompare2(TIM2, 2500);
							Delay(20000000);
							TIM_SetCompare2(TIM2, 500);
							jpgDisplay("0:/one.jpg");
							Function4_Flag = 0;
						}
						else if((idout[0] == 0x87)&&(idout[1] == 0x84)&&(idout[2] == 0xED)&&(idout[3] == 0x3D)&&(Function4_Flag == 1))//对数据包进行判断
						{
							GPIO_ResetBits(GPIOB,GPIO_Pin_0);
							GPIO_ResetBits(GPIOB,GPIO_Pin_1);
							GPIO_ResetBits(GPIOB,GPIO_Pin_5);
							jpgDisplay("0:/three.jpg");
							Delay(4000000);
							TIM_SetCompare2(TIM2, 2500);
							Delay(20000000);
							TIM_SetCompare2(TIM2, 500);
							jpgDisplay("0:/one.jpg");
							Function4_Flag = 0;
						}
						else if((idout[0] == 0xB6)&&(idout[1] == 0xDE)&&(idout[2] == 0xDC)&&(idout[3] == 0x6B)&&(Function4_Flag == 1))//对数据包进行判断
						{
							GPIO_ResetBits(GPIOB,GPIO_Pin_0);
							GPIO_ResetBits(GPIOB,GPIO_Pin_1);
							GPIO_ResetBits(GPIOB,GPIO_Pin_5);
							jpgDisplay("0:/three.jpg");
							Delay(4000000);
							TIM_SetCompare2(TIM2, 2500);
							Delay(20000000);
							TIM_SetCompare2(TIM2, 500);
							jpgDisplay("0:/one.jpg");
							Function4_Flag = 0;
						}
						else 
						{
								if(Function4_Flag == 1)
								{
									GPIO_SetBits(GPIOB,GPIO_Pin_0);
									GPIO_ResetBits(GPIOB,GPIO_Pin_1);
									GPIO_ResetBits(GPIOB,GPIO_Pin_5);
									jpgDisplay("0:/four.jpg");
									TIM_SetCompare2(TIM2, 500);
									Delay(20000000);
									jpgDisplay("0:/one.jpg");
									Function4_Flag = 0;
								}
				  	}
						status = STATUS_OK;		 //成功返回0
					}
				}
			}
		}
		for(i=0;i<Uart1RxDataConut;i++)//清空串口接收数组
		{
			Uart1RxBuf[i] = 0x00; 
		}
		Uart1RxDataConut = 0x00;
 	} 
	return status;			//失败返回1
}

tips

1、人脸识别和口罩检测都是图像识别类的,在检测环境不良或者模型精度无法得到保证时,应该加入一个检测次数判断,比如设定识别成功10次才算成功,或者识别正确或者错误两者谁先达到这个阈值再判定最终结果。这个在我的人脸和口罩程序中均有体现,欢迎讨论。
2、STM32和K210的通信我没有采用通信协议,因为发送的字符串为简单的几个字母,且通信线长度很短,一般不用担心通信出错问题。
3、如果想要集成度高一点,大家可以采用串口屏,控制也可以用K210做,不过我用K210不够熟练,所以没采用它来干这活。
4、舵机最好跟控制系统分开供电,这样工作时不会影响系统的电压。(稳压管一定要调准确,不要接反。)

写在最后

我的这个课题属于视觉类,自己在一些底层识别算法的基础相较薄弱,大家如果跟我一样的话,建议先复刻一下别人的工程,再学习相关的识别算法,本人学习的是YOLO 相关的检测方法,内容大多跟卷积神经网络相关,数学要求较高,大家如果有什么学习的好办法欢迎分享鸭。这个工程大家如果有需要的可以联系我邮箱[email protected]

你可能感兴趣的:(神经网络,深度学习)