目录
一 引言
之前自己做设计,因为基本涉及都是软件类开发,很少设计软硬件结合甚至嵌入式项目,为此找过很多资料,也踩过很多坑。特别是STM32这块的资料,很少有资料能一篇概全,花了两周时间到处找资料,网购硬件,模块匹配等问题。基于此,单篇开张记录一下难点与注意事项。文末附完整代码与部分设计思路
二 总体设计方案
人脸识别技术是一种利用人脸生物特征进行身份识别和验证的技术。通过采集目标人脸图像或视频,提取出人脸的特征信息,然后与已有的人脸数据库进行比对识别,从而实现身份认证、门禁控制、安防监控、人脸支付等应用。人脸识别技术主要包括人脸检测、人脸对齐、特征提取、特征匹配等步骤。
首先,人脸检测是人脸识别的第一步,通过算法在图像中定位并标记出人脸的位置,通常使用的方法有Haar级联检测器、卷积神经网络等。其次,人脸对齐是为了保证不同姿态、表情的人脸图像能够被准确提取特征。对齐包括平移、旋转、尺度变换等操作,使得人脸处于标准化的姿势。然后,特征提取是通过某种算法将人脸图像中的特征信息抽象出来,通常采用的是深度学习中的卷积神经网络,在不同层次提取出人脸的高维特征表示。最后,特征匹配是将提取到的人脸特征与数据库中存储的已知人脸特征进行比对匹配,通过计算相似度来确定人脸的身份。
在该系统中总体设计方案主要包括系统结构设计、硬件设计和软件设计三个方面。以下是针对基于STM32的人脸识别系统设计与实现论文的总体设计方案简单描述。
在系统结构设计中,该系统主要包括三个模块:摄像头模块、STM32控制模块和显示模块。摄像头模块用于采集人脸图像,传输给STM32控制模块进行人脸检测和识别。STM32控制模块负责接收图像数据,进行人脸特征提取、匹配识别,并控制显示模块输出结果。
在硬件设计方面,选择适用于嵌入式系统的STM32系列微控制器作为主控制芯片,结合高清晰度、高帧率的摄像头模块进行人脸图像采集。另外,设计存储模块用于存储用户的人脸数据和系统所需信息,保证系统正常运行。
在软件设计方面,采用人脸识别算法移植,使用正点原子官方提供的ATKFREC.lib静态库文件。搭建基于STM32的嵌入式系统平台,实现人脸图像采集、处理及控制。设计交互友好、直观的用户界面,便于用户管理系统中的人脸数据、查看识别结果等操作。
通过以上总体设计方案,基于STM32的人脸识别系统将实现从人脸图像采集到识别结果展示的全流程,涵盖了硬件、软件和算法等方面的设计与实现。总体设计方案旨在确保系统功能完整、性能稳定,并具备良好的用户体验,为最终实现一套高效、快速、准确的人脸识别系统奠定基础。
三 硬件准备
1.STM32F4探索者开发板(带液晶屏,ST-LINK,电源适配器等,官方一套买下即可)
2.OV2640摄像头模块(对标STM32F4)
OV2640模块实物图
OV2640模块组原理图
3.Windows7以上电脑(需安装STM32F4串口下载软件(FLYMCU),Keil5 MDK)
VSCODE可选(代码阅读性强,也可直接使用Keil5 MDK开发工具,VSCODE需安装扩展工具)
4.TF SD卡模块
图3.6 TF卡接口
图中TF CARD为TF卡接口,采用4位SDIO方式驱动,理论上最大速度可以达到24MB/S,非常适合需要高速存储的情况。
实验流程图
四 核心代码
//读取原始图片数据
//dbuf:数据缓存区
//xoff,yoff:要读取的图像区域起始坐标
//xsize:要读取的图像区域宽度
//width:要读取的宽度(宽高比恒为3:4)
void frec_get_image_data(u16 *dbuf,u16 xoff,u16 yoff,u16 xsize,u16 width)
{
int w, h;
u16 height=width*4/3;
float scale=(float)xsize/width;
for(h=0;h<height;h++)
{
for(w=0;w<width;w++)
{
dbuf[h*width+w]=LCD_ReadPoint(xoff+w*scale,yoff+h*scale);
}
}
}
//显示图片
//x,y,w,h:图片显示区域
//data:图片数据缓存区
void frec_show_picture(u16 x, u16 y, u16 w, u16 h, u16 *data)
{
u16 i, j;
for (i = 0; i < h; i++)
{
for (j = 0; j < w; j++)
{
LCD_Fast_DrawPoint(x + j, y + i, *data);
data ++;
}
}
}
//读取人脸识别所需的数据
//index:要读取的数据位置(一张脸占一个位置),范围:0~MAX_LEBEL_NUM-1
//buf:要读取的数据缓存区首地址
//size:要读取的数据大小(size=0,则表示不需要读数据出来)
//返回值:0,正常
// 其他,错误代码
u8 atk_frec_read_data(u8 index,u8* buf,u32 size)
{
u8* path;
FIL *fp;
u32 fr;
u8 res;
path=atk_frec_malloc(30); //申请内存
fp=atk_frec_malloc(sizeof(FIL)); //申请内存
if(!fp)
{
atk_frec_free(path);
return ATK_FREC_MEMORY_ERR;
}
sprintf((char*)path,ATK_FREC_DATA_PNAME,index);
res=f_open(fp,(char*)path,FA_READ);
if(res==FR_OK&&size)
{
res=f_read(fp,buf,size,&fr); //读取文件
if(fr==size)res=0;
else res=ATK_FREC_READ_WRITE_ERR;
}
f_close(fp);
if(res)res=ATK_FREC_READ_WRITE_ERR;
atk_frec_free(path);
atk_frec_free(fp);
return res;
}
pbkcolor=gui_memex_malloc(200*80*2);//申请背景色缓存
if(pbkcolor==0)continue; //内存申请失败
frec_get_image_data(frec_dev.databuf,frec_dev.xoff,frec_dev.yoff,frec_dev.width,30);
app_read_bkcolor((lcddev.width-200)/2,(lcddev.height-80)/2,200,80,pbkcolor);//读取背景色
window_msg_box((lcddev.width-200)/2,(lcddev.height-80)/2,200,80,(u8*)frec_remind_msg_tbl[11][gui_phy.language],(u8*)APP_REMIND_CAPTION_TBL[gui_phy.language],16,0,0,0);//显示失败
reg_time=0;
res=atk_frec_recognition_face(frec_dev.databuf,&person);
if(res==ATK_FREC_MODEL_DATA_ERR)
{
window_msg_box((lcddev.width-200)/2,(lcddev.height-80)/2,200,80,(u8*)frec_remind_msg_tbl[12][gui_phy.language],(u8*)APP_REMIND_CAPTION_TBL[gui_phy.language],16,0,0,0);//显示失败
delay_ms(600);
}else if(res==ATK_FREC_UNREC_FACE_ERR)
{
window_msg_box((lcddev.width-200)/2,(lcddev.height-80)/2,200,80,(u8*)frec_remind_msg_tbl[13][gui_phy.language],(u8*)APP_REMIND_CAPTION_TBL[gui_phy.language],16,0,0,0);//显示失败
delay_ms(600);
}else
{
ptemp=frec_node_getnode_index(head,person);//得到节点信息
if(ptemp)
{
frec_node_free(ptemp,0); //释放节点内容
app_recover_bkcolor((lcddev.width-200)/2,(lcddev.height-80)/2,200,80,pbkcolor);//恢复背景色
appplay_frec_show_result(ptemp,&frec_dev,reg_time*10); //显示识别结果
}
}
gui_memex_free(pbkcolor);