程序編譯器:keil 5
編程語言:C語言
設(shè)計編號:C0058
設(shè)計介紹
采用正點(diǎn)原子探索者開發(fā)板;
攝像頭選用OV2640
可實現(xiàn)功能:可以實現(xiàn)進(jìn)入頁面的設(shè)定自定義DIY;
可以自由的添加需要識別的人臉;
人臉靠近,按下識別按鍵可以實現(xiàn)人臉識別。如果在系統(tǒng)庫中會提示是那個人,如果不在會提示不在庫中。
溫馨提醒:本例程需要使用SD卡,相關(guān)文件會出存在SD卡中,同時人臉識別在ARM上屬于閹割版本,準(zhǔn)確率不能達(dá)到100%。
資料包括:
系統(tǒng)設(shè)計實物圖(使用組件直接組裝即可)
程序代碼
設(shè)計論文
程序
CV2640驅(qū)動
#include "sys.h"
#include "ov2640.h"
#include "ov2640cfg.h"
#include "timer.h"
#include "delay.h"
#include "usart.h"
#include "sccb.h"
#include "exti.h"
//初始化OV2640
//配置完以后,默認(rèn)輸出是1600*1200尺寸的圖片!!
//返回值:0,成功
// 其他,錯誤代碼
u8 OV2640_Init(void)
{
u16 i=0;
u16 reg;
//設(shè)置IO
RCC->AHB1ENR|=1<<6; //使能外設(shè)PORTG時鐘
GPIO_Set(GPIOG,PIN9|PIN15,GPIO_MODE_OUT,GPIO_OTYPE_PP,GPIO_SPEED_50M,GPIO_PUPD_PU); //PG9,15推挽輸出
OV2640_PWDN=0; //POWER ON
delay_ms(10);
OV2640_RST=0; //復(fù)位OV2640
delay_ms(10);
OV2640_RST=1; //結(jié)束復(fù)位
SCCB_Init(); //初始化SCCB 的IO口
SCCB_WR_Reg(OV2640_DSP_RA_DLMT, 0x01); //操作sensor寄存器
SCCB_WR_Reg(OV2640_SENSOR_COM7, 0x80); //軟復(fù)位OV2640
delay_ms(50);
reg=SCCB_RD_Reg(OV2640_SENSOR_MIDH); //讀取廠家ID 高八位
reg<<=8;
reg|=SCCB_RD_Reg(OV2640_SENSOR_MIDL); //讀取廠家ID 低八位
if(reg!=OV2640_MID)
{
printf("MID:%drn",reg);
return 1;
}
reg=SCCB_RD_Reg(OV2640_SENSOR_PIDH); //讀取廠家ID 高八位
reg<<=8;
reg|=SCCB_RD_Reg(OV2640_SENSOR_PIDL); //讀取廠家ID 低八位
if(reg!=OV2640_PID)
{
printf("HID:%drn",reg);
//return 2;
}
//初始化 OV2640,采用SXGA分辨率(1600*1200)
for(i=0;i<sizeof(ov2640_uxga_init_reg_tbl)/2;i++)
{
SCCB_WR_Reg(ov2640_uxga_init_reg_tbl[i][0],ov2640_uxga_init_reg_tbl[i][1]);
}
return 0x00; //ok
}
//OV2640切換為JPEG模式
void OV2640_JPEG_Mode(void)
{
u16 i=0;
//設(shè)置:YUV422格式
for(i=0;i<(sizeof(ov2640_yuv422_reg_tbl)/2);i++)
{
SCCB_WR_Reg(ov2640_yuv422_reg_tbl[i][0],ov2640_yuv422_reg_tbl[i][1]);
}
//設(shè)置:輸出JPEG數(shù)據(jù)
for(i=0;i<(sizeof(ov2640_jpeg_reg_tbl)/2);i++)
{
SCCB_WR_Reg(ov2640_jpeg_reg_tbl[i][0],ov2640_jpeg_reg_tbl[i][1]);
}
}
//OV2640切換為RGB565模式
void OV2640_RGB565_Mode(void)
{
u16 i=0;
//設(shè)置:RGB565輸出
for(i=0;i<(sizeof(ov2640_rgb565_reg_tbl)/2);i++)
{
SCCB_WR_Reg(ov2640_rgb565_reg_tbl[i][0],ov2640_rgb565_reg_tbl[i][1]);
}
}
//自動曝光設(shè)置參數(shù)表,支持5個等級
const static u8 OV2640_AUTOEXPOSURE_LEVEL[5][8]=
{
{
0xFF,0x01,
0x24,0x20,
0x25,0x18,
0x26,0x60,
},
{
0xFF,0x01,
0x24,0x34,
0x25,0x1c,
0x26,0x00,
},
{
0xFF,0x01,
0x24,0x3e,
0x25,0x38,
0x26,0x81,
},
{
0xFF,0x01,
0x24,0x48,
0x25,0x40,
0x26,0x81,
},
{
0xFF,0x01,
0x24,0x58,
0x25,0x50,
0x26,0x92,
},
};
//OV2640自動曝光等級設(shè)置
//level:0~4
void OV2640_Auto_Exposure(u8 level)
{
u8 i;
u8 *p=(u8*)OV2640_AUTOEXPOSURE_LEVEL[level];
for(i=0;i<4;i++)
{
SCCB_WR_Reg(p[i*2],p[i*2+1]);
}
}
//白平衡設(shè)置
//0:自動
//1:太陽sunny
//2,陰天cloudy
//3,辦公室office
//4,家里home
void OV2640_Light_Mode(u8 mode)
{
u8 regccval=0X5E;//Sunny
u8 regcdval=0X41;
u8 regceval=0X54;
switch(mode)
{
case 0://auto
SCCB_WR_Reg(0XFF,0X00);
SCCB_WR_Reg(0XC7,0X00);//AWB ON
return;
case 2://cloudy
regccval=0X65;
regcdval=0X41;
regceval=0X4F;
break;
case 3://office
regccval=0X52;
regcdval=0X41;
regceval=0X66;
break;
case 4://home
regccval=0X42;
regcdval=0X3F;
regceval=0X71;
break;
}
SCCB_WR_Reg(0XFF,0X00);
SCCB_WR_Reg(0XC7,0X40); //AWB OFF
SCCB_WR_Reg(0XCC,regccval);
SCCB_WR_Reg(0XCD,regcdval);
SCCB_WR_Reg(0XCE,regceval);
}
//色度設(shè)置
//0:-2
//1:-1
//2,0
//3,+1
//4,+2
void OV2640_Color_Saturation(u8 sat)
{
u8 reg7dval=((sat+2)<<4)|0X08;
SCCB_WR_Reg(0XFF,0X00);
SCCB_WR_Reg(0X7C,0X00);
SCCB_WR_Reg(0X7D,0X02);
SCCB_WR_Reg(0X7C,0X03);
SCCB_WR_Reg(0X7D,reg7dval);
SCCB_WR_Reg(0X7D,reg7dval);
}
//亮度設(shè)置
//0:(0X00)-2
//1:(0X10)-1
//2,(0X20) 0
//3,(0X30)+1
//4,(0X40)+2
void OV2640_Brightness(u8 bright)
{
SCCB_WR_Reg(0xff, 0x00);
SCCB_WR_Reg(0x7c, 0x00);
SCCB_WR_Reg(0x7d, 0x04);
SCCB_WR_Reg(0x7c, 0x09);
SCCB_WR_Reg(0x7d, bright<<4);
SCCB_WR_Reg(0x7d, 0x00);
}
//對比度設(shè)置
//0:-2
//1:-1
//2,0
//3,+1
//4,+2
void OV2640_Contrast(u8 contrast)
{
u8 reg7d0val=0X20;//默認(rèn)為普通模式
u8 reg7d1val=0X20;
switch(contrast)
{
case 0://-2
reg7d0val=0X18;
reg7d1val=0X34;
break;
case 1://-1
reg7d0val=0X1C;
reg7d1val=0X2A;
break;
case 3://1
reg7d0val=0X24;
reg7d1val=0X16;
break;
case 4://2
reg7d0val=0X28;
reg7d1val=0X0C;
break;
}
SCCB_WR_Reg(0xff,0x00);
SCCB_WR_Reg(0x7c,0x00);
SCCB_WR_Reg(0x7d,0x04);
SCCB_WR_Reg(0x7c,0x07);
SCCB_WR_Reg(0x7d,0x20);
SCCB_WR_Reg(0x7d,reg7d0val);
SCCB_WR_Reg(0x7d,reg7d1val);
SCCB_WR_Reg(0x7d,0x06);
}
//特效設(shè)置
//0:普通模式
//1,負(fù)片
//2,黑白
//3,偏紅色
//4,偏綠色
//5,偏藍(lán)色
//6,復(fù)古
void OV2640_Special_Effects(u8 eft)
{
u8 reg7d0val=0X00;//默認(rèn)為普通模式
u8 reg7d1val=0X80;
u8 reg7d2val=0X80;
switch(eft)
{
case 1://負(fù)片
reg7d0val=0X40;
break;
case 2://黑白
reg7d0val=0X18;
break;
case 3://偏紅色
reg7d0val=0X18;
reg7d1val=0X40;
reg7d2val=0XC0;
break;
case 4://偏綠色
reg7d0val=0X18;
reg7d1val=0X40;
reg7d2val=0X40;
break;
case 5://偏藍(lán)色
reg7d0val=0X18;
reg7d1val=0XA0;
reg7d2val=0X40;
break;
case 6://復(fù)古
reg7d0val=0X18;
reg7d1val=0X40;
reg7d2val=0XA6;
break;
}
SCCB_WR_Reg(0xff,0x00);
SCCB_WR_Reg(0x7c,0x00);
SCCB_WR_Reg(0x7d,reg7d0val);
SCCB_WR_Reg(0x7c,0x05);
SCCB_WR_Reg(0x7d,reg7d1val);
SCCB_WR_Reg(0x7d,reg7d2val);
}
//彩條測試
//sw:0,關(guān)閉彩條
// 1,開啟彩條(注意OV2640的彩條是疊加在圖像上面的)
void OV2640_Color_Bar(u8 sw)
{
u8 reg;
SCCB_WR_Reg(0XFF,0X01);
reg=SCCB_RD_Reg(0X12);
reg&=~(1<<1);
if(sw)reg|=1<<1;
SCCB_WR_Reg(0X12,reg);
}
//設(shè)置傳感器輸出窗口
//sx,sy,起始地址
//width,height:寬度(對應(yīng):horizontal)和高度(對應(yīng):vertical)
void OV2640_Window_Set(u16 sx,u16 sy,u16 width,u16 height)
{
u16 endx;
u16 endy;
u8 temp;
endx=sx+width/2; //V*2
endy=sy+height/2;
SCCB_WR_Reg(0XFF,0X01);
temp=SCCB_RD_Reg(0X03); //讀取Vref之前的值
temp&=0XF0;
temp|=((endy&0X03)<<2)|(sy&0X03);
SCCB_WR_Reg(0X03,temp); //設(shè)置Vref的start和end的最低2位
SCCB_WR_Reg(0X19,sy>>2); //設(shè)置Vref的start高8位
SCCB_WR_Reg(0X1A,endy>>2); //設(shè)置Vref的end的高8位
temp=SCCB_RD_Reg(0X32); //讀取Href之前的值
temp&=0XC0;
temp|=((endx&0X07)<<3)|(sx&0X07);
SCCB_WR_Reg(0X32,temp); //設(shè)置Href的start和end的最低3位
SCCB_WR_Reg(0X17,sx>>3); //設(shè)置Href的start高8位
SCCB_WR_Reg(0X18,endx>>3); //設(shè)置Href的end的高8位
}
//設(shè)置圖像輸出大小
//OV2640輸出圖像的大小(分辨率),完全由該函數(shù)確定
//width,height:寬度(對應(yīng):horizontal)和高度(對應(yīng):vertical),width和height必須是4的倍數(shù)
//返回值:0,設(shè)置成功
// 其他,設(shè)置失敗
u8 OV2640_OutSize_Set(u16 width,u16 height)
{
u16 outh;
u16 outw;
u8 temp;
if(width%4)return 1;
if(height%4)return 2;
outw=width/4;
outh=height/4;
SCCB_WR_Reg(0XFF,0X00);
SCCB_WR_Reg(0XE0,0X04);
SCCB_WR_Reg(0X5A,outw&0XFF); //設(shè)置OUTW的低八位
SCCB_WR_Reg(0X5B,outh&0XFF); //設(shè)置OUTH的低八位
temp=(outw>>8)&0X03;
temp|=(outh>>6)&0X04;
SCCB_WR_Reg(0X5C,temp); //設(shè)置OUTH/OUTW的高位
SCCB_WR_Reg(0XE0,0X00);
return 0;
}
//設(shè)置圖像開窗大小
//由:OV2640_ImageSize_Set確定傳感器輸出分辨率從大小.
//該函數(shù)則在這個范圍上面進(jìn)行開窗,用于OV2640_OutSize_Set的輸出
//注意:本函數(shù)的寬度和高度,必須大于等于OV2640_OutSize_Set函數(shù)的寬度和高度
// OV2640_OutSize_Set設(shè)置的寬度和高度,根據(jù)本函數(shù)設(shè)置的寬度和高度,由DSP
// 自動計算縮放比例,輸出給外部設(shè)備.
//width,height:寬度(對應(yīng):horizontal)和高度(對應(yīng):vertical),width和height必須是4的倍數(shù)
//返回值:0,設(shè)置成功
// 其他,設(shè)置失敗
u8 OV2640_ImageWin_Set(u16 offx,u16 offy,u16 width,u16 height)
{
u16 hsize;
u16 vsize;
u8 temp;
if(width%4)return 1;
if(height%4)return 2;
hsize=width/4;
vsize=height/4;
SCCB_WR_Reg(0XFF,0X00);
SCCB_WR_Reg(0XE0,0X04);
SCCB_WR_Reg(0X51,hsize&0XFF); //設(shè)置H_SIZE的低八位
SCCB_WR_Reg(0X52,vsize&0XFF); //設(shè)置V_SIZE的低八位
SCCB_WR_Reg(0X53,offx&0XFF); //設(shè)置offx的低八位
SCCB_WR_Reg(0X54,offy&0XFF); //設(shè)置offy的低八位
temp=(vsize>>1)&0X80;
temp|=(offy>>4)&0X70;
temp|=(hsize>>5)&0X08;
temp|=(offx>>8)&0X07;
SCCB_WR_Reg(0X55,temp); //設(shè)置H_SIZE/V_SIZE/OFFX,OFFY的高位
SCCB_WR_Reg(0X57,(hsize>>2)&0X80); //設(shè)置H_SIZE/V_SIZE/OFFX,OFFY的高位
SCCB_WR_Reg(0XE0,0X00);
return 0;
}
//該函數(shù)設(shè)置圖像尺寸大小,也就是所選格式的輸出分辨率
//UXGA:1600*1200,SVGA:800*600,CIF:352*288
//width,height:圖像寬度和圖像高度
//返回值:0,設(shè)置成功
// 其他,設(shè)置失敗
u8 OV2640_ImageSize_Set(u16 width,u16 height)
{
u8 temp;
SCCB_WR_Reg(0XFF,0X00);
SCCB_WR_Reg(0XE0,0X04);
SCCB_WR_Reg(0XC0,(width)>>3&0XFF); //設(shè)置HSIZE的10:3位
SCCB_WR_Reg(0XC1,(height)>>3&0XFF); //設(shè)置VSIZE的10:3位
temp=(width&0X07)<<3;
temp|=height&0X07;
temp|=(width>>4)&0X80;
SCCB_WR_Reg(0X8C,temp);
SCCB_WR_Reg(0XE0,0X00);
return 0;
}
//
//設(shè)置OV2640為SVGA模式
void OV2640_Set_Svga_Mode(void)
{
u16 i;
OV2640_PWDN=0; //POWER ON
delay_ms(10);
OV2640_RST=0; //復(fù)位OV2640
delay_ms(10);
OV2640_RST=1; //結(jié)束復(fù)位
SCCB_Init(); //初始化SCCB 的IO口
SCCB_WR_Reg(OV2640_DSP_RA_DLMT, 0x01); //操作sensor寄存器
SCCB_WR_Reg(OV2640_SENSOR_COM7, 0x80); //軟復(fù)位OV2640
delay_ms(50);
//初始化 OV2640,采用SXGA分辨率(800*600)
for(i=0;i<sizeof(ov2640_svga_init_reg_tbl)/2;i++)
{
SCCB_WR_Reg(ov2640_svga_init_reg_tbl[i][0],ov2640_svga_init_reg_tbl[i][1]);
}
}
main函數(shù)
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "key.h"
#include "usmart.h"
#include "sram.h"
#include "malloc.h"
#include "w25qxx.h"
#include "sdio_sdcard.h"
#include "ff.h"
#include "exfuns.h"
#include "fontupd.h"
#include "text.h"
#include "piclib.h"
#include "string.h"
#include "math.h"
#include "dcmi.h"
#include "ov2640.h"
#include "beep.h"
#include "timer.h"
#include "atk_frec.h"
int reg_time;
u8 ov2640_mode=0; //工作模式:0,RGB565模式;1,JPEG模式
//得到path路徑下,目標(biāo)文件的總個數(shù)
//path:路徑
//返回值:總有效文件數(shù)
u16 pic_get_tnum(u8 *path)
{
u8 res;
u16 rval=0;
DIR tdir; //臨時目錄
FILINFO tfileinfo; //臨時文件信息
u8 *fn;
res=f_opendir(&tdir,(const TCHAR*)path); //打開目錄
tfileinfo.lfsize=_MAX_LFN*2+1; //長文件名最大長度
tfileinfo.lfname=mymalloc(SRAMIN,tfileinfo.lfsize);//為長文件緩存區(qū)分配內(nèi)存
if(res==FR_OK&&tfileinfo.lfname!=NULL)
{
while(1)//查詢總的有效文件數(shù)
{
res=f_readdir(&tdir,&tfileinfo); //讀取目錄下的一個文件
if(res!=FR_OK||tfileinfo.fname[0]==0)break; //錯誤了/到末尾了,退出
fn=(u8*)(*tfileinfo.lfname?tfileinfo.lfname:tfileinfo.fname);
res=f_typetell(fn);
if((res&0XF0)==0X50)//取高四位,看看是不是圖片文件
{
rval++;//有效文件數(shù)增加1
}
}
}
return rval;
}
//處理JPEG數(shù)據(jù)
//當(dāng)采集完一幀JPEG數(shù)據(jù)后,調(diào)用此函數(shù),切換JPEG BUF.開始下一幀采集.
void jpeg_data_process(void)
{
if(ov2640_mode)//只有在JPEG格式下,才需要做處理.
{
}
}
//切換為OV2640模式
void sw_ov2640_mode(void)
{
OV2640_PWDN=0;//OV2640 Power Up
//GPIOC8/9/11切換為 DCMI接口
GPIO_AF_Set(GPIOC,8,13); //PC8,AF13 DCMI_D2
GPIO_AF_Set(GPIOC,9,13); //PC9,AF13 DCMI_D3
GPIO_AF_Set(GPIOC,11,13); //PC11,AF13 DCMI_D4
}
//切換為SD卡模式
void sw_sdcard_mode(void)
{
OV2640_PWDN=1;//OV2640 Power Down
//GPIOC8/9/11切換為 SDIO接口
GPIO_AF_Set(GPIOC,8,12); //PC8,AF12
GPIO_AF_Set(GPIOC,9,12); //PC9,AF12
GPIO_AF_Set(GPIOC,11,12); //PC11,AF12
}
//
//LCD顯示區(qū)域限制參數(shù)
u16 face_offx,face_offy;
u16 face_xsize,face_ysize;
u8 fontsize=12; //字體大小
//設(shè)置圖像到屏幕最中心.
void set_image_center(void)
{
face_offx=0;
face_offy=0;
face_xsize=lcddev.width;
face_ysize=lcddev.height;
if(lcddev.id==0X1963||lcddev.id==0X5510)
{
face_offy=80;
face_ysize=640;
fontsize=24;
}else if(lcddev.id==0X5310)
{
face_offx=10;
face_offy=40;
face_xsize=300;
face_ysize=400;
fontsize=16;
}else fontsize=12;
LCD_Set_Window(face_offx,face_offy,face_xsize,face_ysize); //設(shè)置開窗口.
}
//讀取原始圖片數(shù)據(jù)
//dbuf:數(shù)據(jù)緩存區(qū)
//xoff,yoff:要讀取的圖像區(qū)域起始坐標(biāo)
//xsize:要讀取的圖像區(qū)域?qū)挾?
//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);
}
}
}
//加載一個簡單界面
//fsize:字體大小
void frec_load_ui(u8 fsize)
{
if(fsize==16)
{
Show_Str(10,2,310,fsize, " WK_UP:添加人臉模板",fsize,1);
Show_Str(10,4+16,310,fsize," KEY2:刪除所有模板 KEY0:開始識別",fsize,1);
}else if(fsize==24)
{
Show_Str(10,10,470,fsize, " WK_UP:添加人臉模板",fsize,1);
Show_Str(10,20+24,470,fsize," KEY2:刪除所有模板 KEY0:開始識別",fsize,1);
}
}
//顯示提示信息
//str:要顯示的字符串
//line:第幾行;0,第一行;1,第二行;其他,非法.
//fsize:字體大小
void frec_show_msg(u8* str,u8 line)
{
if(line>1)return;
if(lcddev.width==240)
{
Show_Str(10,lcddev.height-(2-line)*fontsize-(2-line)*5,lcddev.width,fontsize,str,fontsize,0);
}else
{
Show_Str(10,lcddev.height-(2-line)*fontsize-(2-line)*(face_offy-fontsize*2)/3,lcddev.width,fontsize,str,fontsize,1);
}
}
u16 * pixdatabuf; //圖像緩存
int main(void)
{
u8 res;
u8 key; //鍵值
u8 key_first;
u8 i;
u8 msgbuf[30]; //消息緩存區(qū)
u8 person;
//***********初始化界面相關(guān)的顯示變量**********//
DIR picdir; //圖片目錄
FILINFO picfileinfo;//文件信息
u8 *fn; //長文件名
u8 *pname; //帶路徑的文件名
u16 totpicnum; //圖片文件總數(shù)
u16 curindex; //圖片當(dāng)前索引
u8 pause=0; //暫停標(biāo)記
u8 t;
u16 temp;
u16 *picindextbl; //圖片索引表
Stm32_Clock_Init(336,8,2,7);//設(shè)置時鐘,168Mhz
delay_init(168); //延時初始化
uart_init(84,115200); //初始化串口波特率為115200
LED_Init(); //初始化LED
usmart_dev.init(84); //初始化USMART
TIM3_Int_Init(100-1,8400-1);//10Khz計數(shù),10ms中斷一次
LCD_Init(); //LCD初始化
FSMC_SRAM_Init(); //初始化外部SRAM.
BEEP_Init(); //蜂鳴器初始化
KEY_Init(); //按鍵初始化
W25QXX_Init(); //初始化W25Q128
my_mem_init(SRAMIN); //初始化內(nèi)部內(nèi)存池
my_mem_init(SRAMEX); //初始化內(nèi)部內(nèi)存池
my_mem_init(SRAMCCM); //初始化CCM內(nèi)存池
exfuns_init(); //為fatfs相關(guān)變量申請內(nèi)存
f_mount(fs[0],"0:",1); //掛載SD卡
f_mount(fs[1],"1:",1); //掛載SPI FLASH
POINT_COLOR=RED;
while(font_init()) //檢查字庫
{
LCD_ShowString(30,50,200,16,16,"Font Error!");
delay_ms(200);
LCD_Fill(30,50,240,66,WHITE);//清除顯示
delay_ms(200);
}
while(f_opendir(&picdir,"0:/PICTURE"))//打開圖片文件夾
{
Show_Str(30,170,240,16,"PICTURE文件夾錯誤!",16,0);
Show_Str(30,190,240,16,"原因可能是SD卡沒有插好",16,0);
delay_ms(200);
LCD_Fill(30,170,240,186,WHITE);//清除顯示
delay_ms(200);
}
totpicnum=pic_get_tnum("0:/PICTURE"); //得到總有效文件數(shù)
while(totpicnum==NULL)//圖片文件為0
{
Show_Str(30,170,240,16,"沒有圖片文件!",16,0);
delay_ms(200);
LCD_Fill(30,170,240,186,WHITE);//清除顯示
delay_ms(200);
}
picfileinfo.lfsize=_MAX_LFN*2+1; //長文件名最大長度
picfileinfo.lfname=mymalloc(SRAMIN,picfileinfo.lfsize); //為長文件緩存區(qū)分配內(nèi)存
pname=mymalloc(SRAMIN,picfileinfo.lfsize); //為帶路徑的文件名分配內(nèi)存
picindextbl=mymalloc(SRAMIN,2*totpicnum); //申請2*totpicnum個字節(jié)的內(nèi)存,用于存放圖片索引
while(picfileinfo.lfname==NULL||pname==NULL||picindextbl==NULL)//內(nèi)存分配出錯
{
Show_Str(30,170,240,16,"內(nèi)存分配失敗!",16,0);
delay_ms(200);
LCD_Fill(30,170,240,186,WHITE);//清除顯示
delay_ms(200);
}
//記錄索引
res=f_opendir(&picdir,"0:/PICTURE"); //打開目錄
if(res==FR_OK)
{
curindex=0;//當(dāng)前索引為0
while(1)//全部查詢一遍
{
temp=picdir.index; //記錄當(dāng)前index
res=f_readdir(&picdir,&picfileinfo); //讀取目錄下的一個文件
if(res!=FR_OK||picfileinfo.fname[0]==0)break; //錯誤了/到末尾了,退出
fn=(u8*)(*picfileinfo.lfname?picfileinfo.lfname:picfileinfo.fname);
res=f_typetell(fn);
if((res&0XF0)==0X50)//取高四位,看看是不是圖片文件
{
picindextbl[curindex]=temp;//記錄索引
curindex++;
}
}
}
delay_ms(100);
piclib_init(); //初始化畫圖
curindex=0; //從0開始顯示
res=f_opendir(&picdir,(const TCHAR*)"0:/PICTURE"); //打開目錄
if(res==FR_OK)//打開成功
{
dir_sdi(&picdir,picindextbl[curindex]); //改變當(dāng)前目錄索引
res=f_readdir(&picdir,&picfileinfo); //讀取目錄下的一個文件
fn=(u8*)(*picfileinfo.lfname?picfileinfo.lfname:picfileinfo.fname);
strcpy((char*)pname,"0:/PICTURE/"); //復(fù)制路徑(目錄)
strcat((char*)pname,(const char*)fn); //將文件名接在后面
LCD_Clear(BLACK);
ai_load_picfile(pname,0,0,lcddev.width,lcddev.height,1);//顯示圖片
res = 0;
}
delay_ms(1000);
myfree(SRAMIN,picfileinfo.lfname); //釋放內(nèi)存
myfree(SRAMIN,pname); //釋放內(nèi)存
myfree(SRAMIN,picindextbl); //釋放內(nèi)存
Show_Str(170,700,240,24,"Init....",24,1);
LCD_Fill(170,700,240,24,BLACK); //填充單色
key_first = 0;
while(SD_Init())//檢查SD卡
{
Show_Str(30,190,240,16,"SD Card Error!",16,0);
delay_ms(200);
LCD_Fill(30,190,239,206,WHITE);
delay_ms(200);
}
while(OV2640_Init())//初始化OV2640
{
Show_Str(30,190,240,16,"OV2640 錯誤!",16,0);
delay_ms(200);
LCD_Fill(30,190,239,206,WHITE);
delay_ms(200);
}
pixdatabuf=mymalloc(SRAMIN,ATK_GABOR_IMG_WID*ATK_GABOR_IMG_HEI*2); //申請內(nèi)存
delay_ms(10);
OV2640_RGB565_Mode(); //RGB565輸出
OV2640_ImageWin_Set((1600-900)/2,0,900,1200);//設(shè)置輸出尺寸為:900*1200,3:4比例
DCMI_Init(); //DCMI配置
DCMI_DMA_Init((u32)&LCD->LCD_RAM,0,1,1,0);//DCMI DMA配置
Show_Str(170,700,240,24,"Init Sucess!",24,1);
LCD_Fill(170,700,240,24,BLACK); //填充單色
delay_ms(300);
Show_Str(170,730,240,24,"按任意鍵進(jìn)入",24,1);
LCD_Fill(170,730,240,24,BLACK); //填充單色
while(key_first==0)
{
key_first = KEY_Scan(0);//不支持連按
delay_ms(10);
}
LCD_Clear(BLACK);
set_image_center(); //設(shè)置到屏幕正中央
frec_load_ui(fontsize); //顯示GUI
OV2640_OutSize_Set(face_xsize,face_ysize);
sw_sdcard_mode(); //SD卡模式
res=atk_frec_initialization(); //初始化人臉識別
if(res)
{
printf("atk_frec_initialization error:%drn",res);//打印錯誤代碼
}
sw_ov2640_mode(); //2640模式
DCMI_Start(); //啟動傳輸
while(1)
{
delay_ms(10);
key=KEY_Scan(0);//不支持連按
if(key)
{
DCMI_Stop(); //停止傳輸
sw_sdcard_mode(); //SD卡模式
switch(key)
{
case KEY2_PRES: //刪除所有模板
sprintf((char*)msgbuf,"正在刪除...");
frec_show_msg(msgbuf,0);
for(i=0;i<MAX_LEBEL_NUM;i++)
{
res=atk_frec_delete_data(i);//刪除模板
if(res==FR_OK)printf("delete face:%d okrn",i);
else printf("delete face:%d failedrn",i);
}
atk_frec_load_data_model(); //重新加載所有識別模型(被刪掉的,將無法加載進(jìn)來.)
if(lcddev.width!=240)LCD_Fill(10,lcddev.height-2*fontsize-2*(face_offy-fontsize*2)/3,lcddev.width,lcddev.height,BLACK); //清除之前的顯示
sprintf((char*)msgbuf,"刪除完成");
frec_show_msg(msgbuf,0);
delay_ms(1000);
if(lcddev.width!=240)LCD_Fill(10,lcddev.height-2*fontsize-2*(face_offy-fontsize*2)/3,lcddev.width,lcddev.height,BLACK); //清除顯示
break;
case KEY0_PRES: //識別人臉
frec_get_image_data(pixdatabuf,face_offx,face_offy,face_xsize,30);//讀取圖像數(shù)據(jù)
sprintf((char*)msgbuf,"正在識別...");
frec_show_msg(msgbuf,0);
reg_time=0;
res=atk_frec_recognition_face(pixdatabuf,&person);//進(jìn)行識別
if(res==ATK_FREC_MODEL_DATA_ERR)
{
sprintf((char*)msgbuf,"沒有可用模板,按KEY_UP添加模板!");
}else if(res==ATK_FREC_UNREC_FACE_ERR)
{
sprintf((char*)msgbuf,"無法識別該人臉,請重試!");
}else
{
sprintf((char*)msgbuf,"識別結(jié)果:%02d號 耗時:%dms",person,reg_time*10);
}
if(lcddev.width!=240)LCD_Fill(10,lcddev.height-2*fontsize-2*(face_offy-fontsize*2)/3,lcddev.width,lcddev.height,BLACK); //清除之前的顯示
frec_show_msg(msgbuf,0);
sprintf((char*)msgbuf,"按任意按鍵繼續(xù)!");
frec_show_msg(msgbuf,1);
while(!KEY_Scan(0)) //等待按鍵輸入
{
delay_ms(10);
}
if(lcddev.width!=240)LCD_Fill(10,lcddev.height-2*fontsize-2*(face_offy-fontsize*2)/3,lcddev.width,lcddev.height,BLACK);
break;
case WKUP_PRES://添加一個人像進(jìn)入數(shù)據(jù)庫
frec_get_image_data(pixdatabuf,face_offx,face_offy,face_xsize,30);//讀取圖像數(shù)據(jù)
sprintf((char*)msgbuf,"正在添加人臉模板...");
frec_show_msg(msgbuf,0);
res=atk_frec_add_a_face(pixdatabuf,&person); //添加一個人臉
if(res==0)
{
sprintf((char*)msgbuf,"添加成功,編號:%02d ",person);
atk_frec_load_data_model(); //重新加載所有識別模型(將添加的人臉,加載進(jìn)來)
}else
{
sprintf((char*)msgbuf,"添加失敗,錯誤代碼:%02d",res);
}
frec_show_msg(msgbuf,1);
delay_ms(1000);
if(lcddev.width!=240)LCD_Fill(10,lcddev.height-2*fontsize-2*(face_offy-fontsize*2)/3,lcddev.width,lcddev.height,BLACK);
break;
default :
break;
}
sw_ov2640_mode(); //2640模式
DCMI_Start(); //啟動傳輸
}
delay_ms(10);
i++;
if(i==20)//DS0閃爍.
{
i=0;
LED0=!LED0;
}
}
}
設(shè)計說明書:
1.2 人臉識別系統(tǒng)的研究現(xiàn)狀
在世界范圍內(nèi),基于人臉生物特征信息的身份識別已經(jīng)得到應(yīng)用在眾多領(lǐng)域,并且發(fā)揮著至關(guān)重要的作用。早在1996年,英國的Bresso著名學(xué)者已經(jīng)開始對人臉技術(shù)的學(xué)習(xí)和深入研究。到了21世紀(jì),基于人臉生物特征信息技術(shù)已經(jīng)突飛猛進(jìn),并朝著精度更高,運(yùn)用領(lǐng)域更廣的方向邁進(jìn)。
1.2.1 國內(nèi)發(fā)展概況
在華夏大地,臉生物特征信息的身份識別技術(shù)的研究始于20世紀(jì)80年代。自清華大學(xué)、北京理工大學(xué)和自動化學(xué)院等高校的眾多科研人員正在進(jìn)行面部識別學(xué)習(xí)研究。國內(nèi)研究主要從以下三個方面進(jìn)行:
1)針對人臉的幾何特征識別方法;
2)針對關(guān)于代數(shù)特征的正面自動識別方法;
3)針對人臉連接機(jī)制的識別方法。
這些年,計算機(jī)硬件性能也時日益提高,各類監(jiān)控系統(tǒng)飛速發(fā)展。為了區(qū)分越來越復(fù)雜的監(jiān)控背景,各種高精度的背景監(jiān)控系統(tǒng)被研制出來。商業(yè)、國防安全和軍事等高端領(lǐng)域的特殊需求,高精度高要求的監(jiān)控系統(tǒng)應(yīng)運(yùn)而生并日益增加。在如此強(qiáng)大需求背景下,基于人臉生物特征信息技術(shù)引發(fā)了許多國家的熱情和關(guān)注,掀起了新一代的科技風(fēng)暴狂潮。我們國家投入巨資資金和大量科研人員日以及讓地開展深入的學(xué)習(xí)研究。
1.2.2 國外發(fā)展概況
就世界方面來說,基于人臉生物特征信息的身份識別別技術(shù)研究開始于1966年。國外著名的研究機(jī)構(gòu)有:PRI的Bledsoe、美國國防部、美國陸軍研究所、卡內(nèi)基梅隆大學(xué)為首、東京大學(xué)、雷丁大學(xué)、麻省理工學(xué)院等國外的一些高校,還有某些科研公司的工程研究中心。這些研究機(jī)構(gòu)的工作重心放在刑偵、國家安全方面,而在考試驗證系統(tǒng)的方面深入研究很少。據(jù)閱讀外國近幾年的科研文獻(xiàn)總結(jié),國外的科研機(jī)構(gòu)主要從事9個方面研究:顏色識別法、形狀研究法、模板匹配法、例子學(xué)習(xí)法、神經(jīng)網(wǎng)絡(luò)法、隱馬爾可夫模型法、人臉圖像識別法。
1.3 本論文的內(nèi)容
1.采用STM32單片機(jī)進(jìn)行硬件電路設(shè)計以及軟件程序設(shè)計;
2.學(xué)會串行端口的使用,并使用串行端口工具將圖片發(fā)送到內(nèi)存卡。
3.減少冗余電路和接線,降低功耗,提高系統(tǒng)運(yùn)行可靠性。