'''
>> author: SXF
>> email: [email]songxf1024@163.com[/email]
>> description:
用LBP特征进行人脸识别,可进行人脸注册、人脸检测与人脸识别
Pin7高电平一次,触发人脸注册;默认低电平
UART1(Pin1)输出调试信息
UART3(Pin4)输出识别结果,当识别成功后,返回“Find It”(可自定义修改),可连接IoT平台
注:需配备SD卡,最大3支持2G,将main.py等文件放至SD卡根目录后上电
'''
import sensor, time, image #调用传感器,时钟,图片的库
import os, time #调用Os库用于文件操作
import pyb
from pyb import Pin
red = pyb.LED(1) #传递参数“1”给 pyb.LED 控制红色的RGB LED灯段, “2”控制绿色的RGB LED灯段,“3”控制蓝色的RGB LED灯段,“4”控制两个红外灯。
green = pyb.LED(2)
blue = pyb.LED(3)
infrared = pyb.LED(4)
usart1 = pyb.UART(1, 115200) #设置串口总线1和3的的输出管脚和波特率
usart3 = pyb.UART(3, 115200)
REGISTER_MODE = 0
sensor.reset()
sensor.set_contrast(1) #设置相机图像对比度。-3至+3
sensor.set_gainceiling(16) #相机图像增益上限(2, 4, 8, 16, 32, 64, 128)
sensor.set_pixformat(sensor.GRAYSCALE) #灰度,每个像素8bit。
sensor.set_framesize(sensor.HQVGA)
sensor.skip_frames(10) #跳过10张照片,在更改设置后,跳过一些帧,等待感光元件变稳定
Path_Backup = {'path':'', 'id':0} #设置字符数组
rootpath = "/orl_faces" #定义根路径
DIST_THRESHOLD = 15000 # 差异度阈值
dangerous="/orl_faces/dangerous"
def debug(strings): #返回调试结果
print(strings)
usart1.write(str(strings)+"\r\n")
def find(face_cascade, img):
objects = img.find_features(face_cascade, threshold=0.75, scale_factor=1.25) # 人脸检测,搜索与Haar Cascade匹配的所有区域的图像,并返回一个关于这些特征的边界框矩形元组(x,y,w,h)的列表
if objects:
green.on()
time.sleep(500)
green.off()
width_old = 0
height_old = 0
index = 0
for r in objects: # 寻找最大的face
if r[2] > width_old and r[3] > height_old:
width_old = r[2]
height_old = r[3]
index += 1
index -= 1
#print("index:", index)
img.draw_rectangle(objects[index])
d0 = img.find_lbp((0, 0, img.width(), img.height()))
res = match(d0)
if res != 0:
debug(res)
return 1
def match(d0): # 人脸识别
dir_lists = os.listdir(rootpath) # 路径下文件夹
dir_num = len(dir_lists) # 文件夹数量
debug("*" * 60)
debug("Total %d Folders -> %s"%(dir_num, str(dir_lists)))
for i in range(0, dir_num):
item_lists = os.listdir(rootpath+'/'+dir_lists[i]) # 路径下文件
item_num = len(item_lists) # 文件数量
debug("The %d Folder[%s], Total %d Files -> %s" %(i+1, dir_lists[i], item_num, str(item_lists)))
Path_Backup['path'] = rootpath+'/'+dir_lists[i] # 马上记录当前路径
Path_Backup['id'] = item_num # 马上记录当前文件数量
for j in range(0, item_num): # 文件依次对比
debug(">> Current File: " + item_lists[j])
try:
img = image.Image("/orl_faces/%s/%s" % (dir_lists[i], item_lists[j]), copy_to_fb=True)
except Exception as e:
debug(e)
break
d1 = img.find_lbp((0, 0, img.width(), img.height())) # 提取特征值
dist = image.match_descriptor(d0, d1) # 计算差异度
debug(">> Difference Degree: " + str(dist))
if dist < DIST_THRESHOLD: #小于阈值
debug(">> ** Find It! **")
green.on()
time.sleep(1000)
green.off()
return item_lists[j] #找到之后返回文件夹编号
debug(">> ** No Match! **")
return 0
def register(face_cascade, img): #拍摄人脸,mode为0时表示在非拍摄状态
global REGISTER_MODE
if find(face_cascade, img) == 1: #find it
debug(">> Existing without registration!")
REGISTER_MODE = 0
return 0
#not find it
dir_lists = os.listdir(rootpath) # 路径下文件夹
dir_num = len(dir_lists) # 文件夹数量
new_dir = ("%s/%d") % (rootpath, int(dir_num)+1)
os.mkdir(new_dir) # 创建文件夹
cnt = 5 #拍摄5次图片
while cnt: #cnt>0
img = sensor.snapshot() #拍图片
objects = img.find_features(face_cascade, threshold=0.75, scale_factor=1.25) # 人脸检测
if objects:
width_old = 0
height_old = 0
index = 0
for r in objects: # 寻找最大的face
if r[2] > width_old and r[3] > height_old:
width_old = r[2]
height_old = r[3]
index += 1
index -= 1
#print("index:", index)
item_lists = os.listdir(new_dir) # 新路径下文件
item_num = len(item_lists) # 文件数量
img.save("%s/%d.pgm" % (new_dir, item_num)) # 写入文件
debug(">> [%d]Regist OK!" % cnt)
img.draw_rectangle(objects[index])
green.on()
time.sleep(50)
green.off()
cnt -= 1
if cnt==0:
green.on()
time.sleep(100)
green.off()
REGISTER_MODE = 0
def takephoto(res,face_cascade):
if res==1:
dg_dir = ("%s") % (dangerous)
os.mkdir(dg_dir) # 创建文件夹
num=len(dg_dir)
for i in range(0,8):
red.on() #红灯亮表示一次的开始
print("About to start detecting faces...")
sensor.skip_frames(time = 2000) # Give the user time to get ready.设置生效
red.off() #红灯灭,开始拍摄
print("Now detecting faces!")
blue.on() #蓝灯亮
diff = 10 # We'll say we detected a face after 10 frames.
while(diff):
img = sensor.snapshot()
# Threshold是介于0.0-1.0的阈值,较低值会同时提高检出率和假阳性
# 率。相反,较高值会同时降低检出率和假阳性率。
# scale是一个必须大于1.0的浮点数。较高的比例因子运行更快,
# 但其图像匹配相应较差。理想值介于1.35-1.5之间。
faces = img.find_features(face_cascade, threshold=0.5, scale_factor=1.5)
if faces:
diff -= 1
for r in faces:
img.draw_rectangle(r)
blue.off()
print("Face detected! Saving image%s"%(dg_dir))
sensor.snapshot().save("%s/%d.pgm" % (dg_dir,num))# Save Pic.
num+=1
dir_num = len(dg_dir)
if dir_num>80:
os.remove(dg_dir)
def main():
global REGISTER_MODE
try:
os.mkdir(rootpath)
except:
pass
pin7 = Pin('P7', Pin.IN, Pin.PULL_DOWN) # 1为注册模式,即拍照存入,即高电平时进行拍摄
face_cascade = image.HaarCascade("frontalface", stages=25) #利用haar算子将forntalface模型导入,将一个内置的正脸Haar Cascade载入内存
#try:
#face_cascade = image.HaarCascade("/haarcascade_frontalcatface.cascade", stages=25) # "frontalface"
#except:
#face_cascade = image.HaarCascade("frontalface", stages=25)
print(face_cascade)
clock = time.clock()
img = None
while (True):
clock.tick()
img = sensor.snapshot()
if pin7.value() == 1: #高电平时设置mode为1进行录入拍摄模式,为低电平时执行else进行查找操作,并串口发出find it
REGISTER_MODE = 1
if REGISTER_MODE == 1:
debug("REGISTER_MODE\r\n")
register(face_cascade, img)
else:
res = find(face_cascade, img)
if res==1:
takephoto(res,face_cascade)
usart3.write("Find It\r\n")
# 程序开始
#debug(os.listdir())
main()