基于实验室材料安全管理系统料安全管理系统的设计:
- 基于各种传感器的利用RFID技术标记实验耗材;
- 实验室材料安全管理系统采用通信技术和传感器节点管理;
- 实现人脸识别等技术的取用人员确定,如人脸识别;
- 实现实验室材料的入库、出库和防丢失;
硬件设计方案
软件设计方案-感知模块
软件设计方案-执行单元
软件设计方案-人脸识别
实现人脸识别算法
#include <Servo.h> // 声明调用Servo.h库 #include <dht.h> #include <Wire.h> #include <LiquidCrystal_I2C.h> LiquidCrystal_I2C lcd(0x27,16,2); Servo myservo1; #define SERVO1_PIN 6 #define IN1 2 //k210输入 unsigned int PWM = 0; #define IN2 3 //烟雾 #define IN3 1 //ESP01s #define flame 5//定义光敏接口 #define Beep 4 ///定义蜂鸣器接口为数字4 接口 int ledPin = 7; //定义数字7 接口 #define DHT11 8//温湿度接口 #include <SPI.h> #include <MFRC522.h> #define SS_PIN 10 //rfid #define RST_PIN 9 //rfid MFRC522 rfid(SS_PIN, RST_PIN); byte nuidPICC[4]; //存储读取UID dht DHT; int val;//定义数字变量 void singleServoControl(){ for(PWM = 50; PWM<1250; PWM = 5){ //舵机从50到2450,每次增加5 myservo1.writeMicroseconds(PWM); ///写入舵机PWM delay(15); //延时10ms将舵机转移到指定位置 } delay(3000); for(PWM = 1250; PWM>50; PWM-=5){ myservo1.writeMicroseconds(PWM); delay(15); //延时10ms将舵机转移到指定位置 } } void setup() { pinMode(Beep,OUTPUT);//定义蜂鸣器 为输出接口 pinMode(ledPin, OUTPUT);///定义小灯接口的输出接口 pinMode(flame,INPUT);///将火焰定义为输入接口 pinMode(IN1, INPUT); pinMode(IN2, INPUT); pinMode(IN3, INPUT); digitalWrite(IN1, LOW); digitalWrite(Beep,LOW); digitalWrite(ledPin,LOW); digitalWrite(IN3,LOW); myservo1.attach(SERVO1_PIN); lcd.init();//lcd屏幕初始化 lcd.backlight(); Serial.begin(9600); SPI.begin(); rfid.PCD_Init(); Serial.println("RC522初始化完成..."); } void loop() { int check = DHT.read11(DHT11); Serial.print("Current state: "); Serial.print(check); float h = DHT.humidity; float t = DHT.temperature; Serial.print(" "); Serial.print("Temperature:"); Serial.print(t); Serial.print(" "); Serial.print("Humidity:"); Serial.println(h,1); lcd.setCursor(0,0);/显示温湿度 lcd.print("H="); lcd.println(h); //Serial.print("\n"); lcd.setCursor(7,0); lcd.print("T="); lcd.println(t); //lcd.print("\n"); if(digitalRead(IN1)==HIGH) { //put your main code here, to run repeatedly: singleServoControl(); } if(digitalRead(IN3)==HIGH) { //put your main code here, to run repeatedly: singleServoControl(); } if(digitalRead(IN2)== LOW) { unsigned char i;//define variable for(i=0;i<80;i )// output a frequency sound { digitalWrite(Beep,HIGH);// sound delay(1);//delay1ms digitalWrite(Beep,LOW);//not sound delay(1);//ms delay // lcd.setCursor(0,1); // lcd.print("alarm"); } //digitalWrite(Beep,HIGH); //delay(3000); //digitalWrite(Beep,LOW); // lcd.println(distance); } if(digitalRead(flame)) { digitalWrite(ledPin, HIGH); ///点亮小灯 } else{ digitalWrite(ledPin, LOW); } ///搜索新卡 if ( ! rfid.PICC_IsNewCardPresent()) return; // 验证NUID是否可读 if ( ! rfid.PICC_ReadCardSerial()) return; MFRC522::PICC_Type piccType = rfid.PICC_GetType(rfid.uid.sak); // 检查是否MIFARE卡类型 if (piccType != MFRC522::PICC_TYPE_MIFARE_MINI && piccType != MFRC522::PICC_TYPE_MIFARE_MINI && piccType != MFRC522::PICC_TYPE_MIFARE_1K && piccType != MFRC522::PICC_TYPE_MIFARE_4K) { Serial.println("本卡类型不支持读取"); return; } // 保存读取的UID for (byte i = 0; i < 4; i ) { nuidPICC[i] = rfid.uid.uidByte[i]; } Serial.print("十六进制UID:"); printHex(rfid.uid.uidByte, rfid.uid.size); Serial.println(); Serial.print("十进制UID:"); printDec(rfid.uid.uidByte, rfid.uid.size); Serial.println(); // 把它放在读卡区IC卡进入休眠状态,不再重复读卡 rfid.PICC_HaltA(); // 停止读卡模块编码 rfid.PCD_StopCrypto1(); if( nuidPICC[0]==0xA2&&nuidPICC[1]==0x78&&nuidPICC[2]==0xA9&nuidPICC[3]==0x1A)
{
Serial.print("身份确认");
lcd.setCursor(0,1);
lcd.print("alcohol 2021.12.12");//屏幕显示酒精和日期
}
else{
lcd.setCursor(0,1);
lcd.print(" ");
}
}
// 十六进制输出
void printHex(byte *buffer, byte bufferSize) {
for (byte i = 0; i < bufferSize; i++) {
Serial.print(buffer[i] < 0x10 ? " 0" : " ");
Serial.print(buffer[i], HEX);
}
}
//十进制输出
void printDec(byte *buffer, byte bufferSize) {
for (byte i = 0; i < bufferSize; i++) {
Serial.print(buffer[i] < 0x10 ? " 0" : "");
Serial.print(buffer[i], DEC);
}
}
import sensor,image,lcd # import 相关库
import KPU as kpu
import time
import utime
from Maix import GPIO
from board import board_info
from fpioa_manager import fm
from Maix import FPIOA,GPIO
fm.register(11,fm.fpioa.GPIO0)
fm.register(10,fm.fpioa.GPIO1)
led_b = GPIO(GPIO.GPIO0,GPIO.OUT)
led_b.value(0)
led_c = GPIO(GPIO.GPIO1,GPIO.OUT)
led_c.value(0)
task_fd = kpu.load(0x300000) # 从flash 0x300000 加载人脸检测模型
task_ld = kpu.load(0x400000) # 从flash 0x400000 加载人脸五点关键点检测模型
task_fe = kpu.load(0x500000) # 从flash 0x500000 加载人脸196维特征值模型
clock = time.clock() # 初始化系统时钟,计算帧率
key_pin=16 # 设置按键引脚 FPIO16
fpioa = FPIOA()
fpioa.set_function(key_pin,FPIOA.GPIO7)
key_gpio=GPIO(GPIO.GPIO7,GPIO.IN)
last_key_state=1
key_pressed=0 # 初始化按键引脚 分配GPIO7 到 FPIO16
def check_key(): # 按键检测函数,用于在循环中检测按键是否按下,下降沿有效
global last_key_state
global key_pressed
val=key_gpio.value()
if last_key_state == 1 and val == 0:
key_pressed=1
else:
key_pressed=0
last_key_state = val
lcd.init() # 初始化lcd
sensor.reset() #初始化sensor 摄像头
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_hmirror(1) #设置摄像头镜像
sensor.set_vflip(1) #设置摄像头翻转
sensor.run(1) #使能摄像头
anchor = (1.889, 2.5245, 2.9465, 3.94056, 3.99987, 5.3658, 5.155437, 6.92275, 6.718375, 9.01025) #anchor for face detect 用于人脸检测的Anchor
dst_point = [(44,59),(84,59),(64,82),(47,105),(81,105)] #standard face key point position 标准正脸的5关键点坐标 分别为 左眼 右眼 鼻子 左嘴角 右嘴角
a = kpu.init_yolo2(task_fd, 0.5, 0.3, 5, anchor) #初始化人脸检测模型
img_lcd=image.Image() # 设置显示buf
img_face=image.Image(size=(128,128)) #设置 128 * 128 人脸图片buf
a=img_face.pix_to_ai() # 将图片转为kpu接受的格式
record_ftr=[] #空列表 用于存储当前196维特征
record_ftrs=[] #空列表 用于存储按键记录下人脸特征, 可以将特征以txt等文件形式保存到sd卡后,读取到此列表,即可实现人脸断电存储。
names = ['Mr.1', 'Mr.1', 'Mr.2', 'Mr.2', 'Mr.3', 'Mr.3', 'Mr.4', 'Mr.4', 'Mr.5' , 'Mr.5'] # 人名标签,与上面列表特征值一一对应。
while(1): # 主循环
check_key() #按键检测
img = sensor.snapshot() #从摄像头获取一张图片
clock.tick() #记录时刻,用于计算帧率
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
face_cut_128=face_cut.resize(128,128) # 将裁出的人脸图片 缩放到128 * 128像素
a=face_cut_128.pix_to_ai() # 将猜出图片转换为kpu接受的格式
#a = img.draw_image(face_cut_128, (0,0))
# Landmark for face 5 points
fmap = kpu.forward(task_ld, face_cut_128) # 运行人脸5点关键点检测模型
plist=fmap[:] # 获取关键点预测结果
le=(i.x()+int(plist[0]*i.w() - 10), i.y()+int(plist[1]*i.h())) # 计算左眼位置, 这里在w方向-10 用来补偿模型转换带来的精度损失
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] # 图片中 5 坐标的位置
T=image.get_affine_transform(src_point, dst_point) # 根据获得的5点坐标与标准正脸坐标获取仿射变换矩阵
a=image.warp_affine_ai(img, img_face, T) #对原始图片人脸图片进行仿射变换,变换为正脸图像
a=img_face.ai_to_pix() # 将正脸图像转为kpu格式
#a = img.draw_image(img_face, (128,0))
del(face_cut_128) # 释放裁剪人脸部分图片
# calculate face feature vector
fmap = kpu.forward(task_fe, img_face) # 计算正脸图片的196维特征值
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 > 81: # 如果最大分数大于85, 可以被认定为同一个人
a = img.draw_string(i.x(),i.y(), ("%s :%2.1f" % (names[index], max_score)), color=(0,255,0),scale=2) # 显示人名 与 分数
print(max_score)
led_c.value(1)
utime.sleep_ms(200)
led_c.value(0)
else:
a = img.draw_string(i.x(),i.y(), ("X :%2.1f" % (max_score)), color=(255,0,0),scale=2) #显示未知 与 分数
led_b.value(1)
utime.sleep_ms(200)
led_b.value(0)
if key_pressed == 1: #如果检测到按键
key_pressed = 0 #重置按键状态
record_ftr = feature
record_ftrs.append(record_ftr) #将当前特征添加到已知特征列表
break
fps =clock.fps() #计算帧率
print("%2.1f fps"%fps) #打印帧率