2020电赛F题——简易无接触温度测量与身份识别装置

STM32F103RCT6+GY90614测温模块+Openmv进行人脸识别

最终效果
(1).两种测温模式:
a.准确测定28-48°C水温,与测温枪误差在0.5°C内。测试距离能到10CM。
b.准确测量人体头部与手腕处温度,与测温枪误差在0.5°C内。
(2).温度超过阈值,蜂鸣器响;否则不响。阈值在28-38°C内可调。
(3).准确识别三个队友。
(4).是否佩戴口罩,没有佩戴口罩蜂鸣器报警。
(5).现场学习与判断,在保证判别精度的情况下,能学习3个人。

采用正点原子mini板作为主控板
1.GY90614与STM32之间:I2C协议
2.Openmv与STM32之间:串口通信
3.OLED与STM32之间:I2C协议

无接触温度测量模块:
MLX90614与超声波测距,进行温度补偿。
原理:距离越远,测得的温度就越低,下面我们设某一时刻的距离为distance,温度为temperature,物体实际表面温度为t0,OLED屏显示温度为:t ;利用MATLAB拟合工具箱:t0作为因变量,distance与temperature作为自变量,进行拟合,比较拟合优度R-Square与均方误差MSE,确定最终的函数关系。

身份识别装置:
识别队友:采用Openmv提供的识别代码,寻找lbp
特征。
口罩判别:采用色块识别,识别普通口罩(蓝色医用口罩)。
现场学习与身份识别:现场拍10张照片,存入内存卡。

总体照片

在这里插入图片描述
在这里插入图片描述

硬件连接:
STM32与Openmv:
PA9 <——> USART3_Rx(P5)
PA10 <——>USART3_Tx(P4)

STM32与OLED:
PB6<——>SCL
PB7<——>SDA

STM32与MLX90614:
PB8<——>SCL
PB9<——>SDA

Mini板3个按键&外加5个按键:
mini:
WK_UP<——>测量体温或者物温
KEY0<——>温度阈值减1°C
KEY1<——>温度阈值加1°C
PC6<——>现场学习后,识别录入的人脸
PC7<——>现场学习,录入人脸
PC8<——>识别三个队友
PC9<——>是否戴口罩

软件部分:
KEIL5与OpenMVIDE
Face_recognition.c

#include "stm32f10x.h"
#include "usart.h"	 
#include "OLED_I2C.h"
#include "key.h"
#include "beef.h"
#include "stdio.h"
#include "delay.h"
void Face_recognition(void)
{
	u8 key;
	u8 t3,i;
	u8 number=0;
	unsigned char temp[20],x;  
	KEY_Init();
	BEEF_Init();
	delay_init();	
	usart_init(115200);
	
	while(1)
	{	
		display_2shenfenshibie();
		OLED_ShowStr(0,2,"Stata:",2);
		if(PCin(6)==0)
		{		//delay_ms(300);
				printf("3");
			  OLED_ShowStr(48+8,2,"compare",2);
				break;
		}
		if(PCin(7)==0)		/*按键0录取人脸*/
		{
			delay_ms(300);
			printf("1");		/*通过串口发送1给Openmv*/
			OLED_ShowStr(48+8,2,"study",2);
		}
		if(PCin(8)==0)		/*按键1进行人脸对比*/
		{	
			printf("2");		/*通过串口发送2给Openmv*/
			OLED_ShowStr(48+8,2,"identify",2);
			break;
		}
		if(PCin(9)==0)
		{
			delay_ms(300);
			printf("4");
			OLED_ShowStr(48+8,2,"isMask",2);	
			break;
		}
	}
		while(1)
		{
		
			if(USART_RX_STA&0x8000)
			{					   
				number=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
				for(t3=0;t3<20;t3++)
				{
						temp[t3]='\0';
				}
				for(t3=0;t3<number;t3++)
				{
					temp[t3]=USART_RX_BUF[t3];
					while((USART1->SR&0X40)==0);//等待发送结束
					
				}
			/*判断是否没戴口罩
				是:不响
				否:蜂鸣器响1S
				*/
			if(temp[0]=='N')
			{	
				BEEF=1;	
				delay_ms(1000);
				BEEF=0;
			}
			OLED_CLS();
			OLED_ShowStr(0,6,temp,1);

			USART_RX_STA=0;												
		}
		if(number>0)
			{
				break;
			}
		}
}

main.c

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"	 
#include "adc.h"
#include "mlx90614.h"
#include "stdio.h"
#include "beef.h"
#include "OLED_I2C.h"
#include "stm32f10x.h"
#include "key.h"
#include "exti.h"
#include "SRF05.h"
#include "string.h"

unsigned char  Atemp=37,Mod=0,MOD=0; //Mod温度模式选择 MOD工作模式选择

int main(void)
{	
	unsigned char  t[20],t1[20]; 
	unsigned char len[20];
 	float temp,length;	
	delay_init();	
	SMBus_Init();//初始化	 
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
	usart_init(115200);	 	//串口初始化为115200
 	LED_Init();			     //LED端口初始化
	BEEF_Init();
	I2C_Configuration();
  OLED_Init();
  OLED_CLS();
  OLED_ON();
  EXTIX_Init();		//外部中断初始化
  Hcsr05Init();

	while(1)
	{
		if(MOD==0)
		{ 
			PCout(4)=1;
			if(Mod==0){
				OLED_ShowStr(0,2,"Mode: Object",2);
				sprintf(t1,"%d",Atemp);
				OLED_ShowStr(0,0,"Alarm Temp:",2);
				OLED_ShowStr(96,0,t1,2);
				OLED_ShowStr(96+16,0,"0",1);// 0
				OLED_ShowStr(96+16+8,0,"C",2);// C
			
				temp=SMBus_ReadTemp();  //读取温度
				//length= Hcsr05GetLength();//读取距离
				if(temp>Atemp)
						BEEF=1;	
				else
						BEEF=0;	
				sprintf(t,"%.1f",temp);
				sprintf(len,"%4.1f",length);	
				OLED_ShowStr(0,4,"Temp:",2);
				OLED_ShowStr(0+48,4,t,2);//温度值
				OLED_ShowStr(0+48+48,4,"0",1);// 0
				OLED_ShowStr(0+48+48+8,4,"C",2);// C
				
				//OLED_ShowStr(0,6,"len:",2);
				//OLED_ShowStr(0+40,6,len,2);
				//OLED_ShowStr(0+40+56,6,"cm",2);
			
				
				delay_ms(1000);	
			}
			else{
				OLED_ShowStr(0,2,"Mode: Body",2);
				sprintf(t,"%d",Atemp);
				OLED_ShowStr(0,0,"Alarm Temp:",2);
				OLED_ShowStr(96,0,t,2);
				OLED_ShowStr(96+16,0,"0",1);// 0
				OLED_ShowStr(96+16+8,0,"C",2);// C
				temp=SMBus_ReadTemp()+2.7;  //读取温度
				if(temp>Atemp)
						BEEF=1;	
				else
						BEEF=0;	
				
				sprintf(t,"%.1f",temp);
				OLED_ShowStr(0,4,"Temp:",2);
				OLED_ShowStr(48,4,t,2);//值
				OLED_ShowStr(48+48,4,"0",1);// 0
				OLED_ShowStr(48+48+8,4,"C",2);// C
				delay_ms(1000);	
			}
		}
		else
		{ 
			PCout(4)=0;
			Face_recognition();
		}

		delay_ms(500);
		
 }
}

OpenMVIDE:

"""
作者: XJB LXP CLX
时间: 2020年11月20日22:00
代码功能:与STM32使用,进行stm32通过串口发送消息给openmv,openmv收到信息后进行人脸识别操作,并将结果传送回STM32单片机进行应答!
"""
import sensor, time, image, pyb,lcd
from pyb import UART
##定义全局变量
global flag_count
flag_count=0
RED_LED_PIN = 1
BLUE_LED_PIN = 3
uart = UART(3,115200,timeout_char=1000)
data=bytes([0x0d,0x0a])
#=====================================人脸识别:识别现场学习的人======================#
def face_recognition1():
    sensor.reset() # Initialize the camera sensor.
    sensor.set_pixformat(sensor.GRAYSCALE) # or sensor.GRAYSCALE
    sensor.set_framesize(sensor.B128X128) # or sensor.QQVGA (or others)
    sensor.skip_frames(10) # Let new settings take affect.
    sensor.skip_frames(time = 5000) #等待5s
    NUM_SUBJECTS = flag_count #图像库中不同人数,一共4人
    NUM_SUBJECTS_IMGS = 10 #每人有3张样本图片

    img = sensor.snapshot()
    d0 = img.find_lbp((0, 0, img.width(), img.height()))
    #d0为当前人脸的lbp特征
    img = None
    pmin = 99999
    num=0

    for s in range(1, NUM_SUBJECTS+1):
        dist = 0
        print("1111")
        for i in range(2, NUM_SUBJECTS_IMGS+1):
            img = image.Image("singtown/temp%d/%d.pgm"%(s, i))
            d1 = img.find_lbp((0, 0, img.width(), img.height()))
            #d1为第s文件夹中的第i张图片的lbp特征
            dist += image.match_descriptor(d0, d1)#计算d0 d1即样本图像与被检测人脸的特征差异度。
        print("Average dist for subject %d: %d"%(s, dist/NUM_SUBJECTS_IMGS))

        #pmin = min(pmin, dist/NUM_SUBJECTS_IMGS, s)#特征差异度越小,被检测人脸与此样本更相似更匹配。
        if (dist/NUM_SUBJECTS_IMGS)<pmin:
            pmin=(dist/NUM_SUBJECTS_IMGS)
            #uart.write("%d"%pmin)
            num=s
        print(pmin)

    print(num) # num为当前最匹配的人的编号。

    if num==1:
        uart.write("person1")
        uart.write(data)
    elif num==2:
        uart.write("person2")
        uart.write(data)
    elif num==3:
        uart.write("person3")
        uart.write(data)


    sensor.set_pixformat(sensor.RGB565) # or sensor.GRAYSCALE
    sensor.set_framesize(sensor.QQVGA2) # Special 128x160 framesize for LCD Shield.

#============================人脸识别:识别三个队友=============================================#
def face_recognition():
    sensor.reset() # Initialize the camera sensor.
    sensor.set_pixformat(sensor.GRAYSCALE) # or sensor.GRAYSCALE
    sensor.set_framesize(sensor.B128X128) # or sensor.QQVGA (or others)
    #sensor.set_windowing((92,112))
    sensor.skip_frames(10) # Let new settings take affect.
    sensor.skip_frames(time = 5000) #等待5s
    NUM_SUBJECTS = 3 #图像库中不同人数,一共3人
    NUM_SUBJECTS_IMGS = 10 #每人有10张样本图片

    # 拍摄当前人脸。
    img = sensor.snapshot()
    d0 = img.find_lbp((0, 0, img.width(), img.height()))
    #d0为当前人脸的lbp特征
    img = None
    pmin = 999999
    num=0

    for s in range(1, NUM_SUBJECTS+1):
        dist = 0
        for i in range(2, NUM_SUBJECTS_IMGS+1):
            img = image.Image("singtown/S%d/%d.pgm"%(s,i))
            d1 = img.find_lbp((0, 0, img.width(), img.height()))
            #d1为第s文件夹中的第i张图片的lbp特征
            dist += image.match_descriptor(d0, d1)#计算d0 d1即样本图像与被检测人脸的特征差异度。
        print("Average dist for subject %d: %d"%(s, dist/NUM_SUBJECTS_IMGS))
        #pmin = min(pmin, dist/NUM_SUBJECTS_IMGS, s)#特征差异度越小,被检测人脸与此样本更相似更匹配。
        if (dist/NUM_SUBJECTS_IMGS)<pmin:
            pmin=(dist/NUM_SUBJECTS_IMGS)
            num=s

    print(num) # num为当前最匹配的人的编号。
    #uart.write(str(num))
    if num==1:
        uart.write("You are XJB!")
        uart.write(data)
    elif num==2:
        uart.write("You are CLX!")
        uart.write(data)
    elif num==3:
        uart.write("You are LXP!")
        uart.write(data)

    sensor.set_pixformat(sensor.RGB565) # or sensor.GRAYSCALE
    sensor.set_framesize(sensor.QQVGA2) # Special 128x160 framesize for LCD Shield.
#================================现场学习=====================================#
def take_photos():
    sensor.reset() # Initialize the camera sensor.
    sensor.set_pixformat(sensor.GRAYSCALE) # or sensor.GRAYSCALE
    sensor.set_framesize(sensor.B128X128) # or sensor.QQVGA (or others)
    sensor.skip_frames(10) # Let new settings take affect.
    sensor.skip_frames(time = 2000)
    global flag_count
    flag_count= flag_count+1 #设置被拍摄者序号,第一个人的图片保存到s1文件夹,第二个人的图片保存到s2文件夹,以此类推。每次更换拍摄者时,修改num值。

    n = 10 #设置每个人拍摄图片数量。

    #连续拍摄n张照片,每间隔3s拍摄一次。
    while(n):
        #红灯亮
        pyb.LED(RED_LED_PIN).on()
        sensor.skip_frames(time = 2000) # Give the user time to get ready.等待3s,准备一下表情。

        #红灯灭,蓝灯亮
        pyb.LED(RED_LED_PIN).off()
        pyb.LED(BLUE_LED_PIN).on()

        #保存截取到的图片到SD卡
        print(n)
        sensor.snapshot().save("singtown/temp%s/%s.pgm" % (flag_count, n) ) # or "example.bmp" (or others)
        n -= 1
        pyb.LED(BLUE_LED_PIN).off()
        print("Done! Reset the camera to see the saved image.")

    print("\n第%s个人拍照"%(flag_count+1))
    sensor.set_pixformat(sensor.RGB565)
    sensor.set_framesize(sensor.QQVGA2)

#================================口罩判别标志位============================#
def face_mask_xianyan():
    import sensor, image, time

    sensor.reset()
    sensor.set_pixformat(sensor.RGB565)
    sensor.set_framesize(sensor.QVGA)
    sensor.skip_frames(time = 200)
    sensor.set_auto_gain(False) # must be turned off for color tracking
    sensor.set_auto_whitebal(False) # must be turned off for color tracking
    clock = time.clock()

    threshold = [32, 64, -20, -10, -17, 0] # 口罩特征识别参数

    print("Thresholds learned...")
    print("Tracking colors...")
    sensor.skip_frames(time = 1000)
    flag=40    ##均值滤波:40张图片中有20张就判定为有口罩,否则判定为没有口罩
    count=0
    flag_mask=False
    for i in range(flag):
        img = sensor.snapshot()
        listt=img.find_blobs([threshold], pixels_threshold=100, area_threshold=100, merge=True, margin=10)
        print(listt)
        if listt!=[]:
            count=count+1
            for blob in listt:
                img.draw_rectangle(blob.rect())
                img.draw_cross(blob.cx(), blob.cy())
                lcd.display(img) # Take a picture and display the image.
                sensor.skip_frames(time = 10)
                if count >=20:
                    flag_mask=True
                    break
        else:
            lcd.display(img)
    print(count)
    if flag_mask:
        wenzi="YES!MASK!"
        uart.write("YES!MASK!")
        uart.write(data)
    else:
        wenzi="No MASK!!!"
        uart.write("No MASK!!!")
        uart.write(data)

    sensor.skip_frames(time = 3000)
    return "reset",wenzi


#==================================main===============================#
if __name__=='__main__':
    temp="reset"
    wenzi=" "
    while(1):
        if temp=="reset":
            sensor.reset() # Initialize the camera sensor.
            sensor.set_pixformat(sensor.RGB565) # or sensor.GRAYSCALE
            sensor.set_framesize(sensor.QQVGA2) # Special 128x160 framesize for LCD Shield.
            lcd.init() # Initialize the lcd screen.
            temp="OK"
        if uart.any():
            num1 =uart.readline().decode()
            print(num1)

            if(num1=='1'):
                take_photos()       #现场学习功能
            elif(num1=='2'):
                face_recognition()  #人脸识别功能:识别三个队友
            elif(num1=='3'):
                face_recognition1() #人脸识别功能:识别现场学习的人员
            elif(num1=='4'):
                [temp,wenzi]=face_mask_xianyan()    #口罩检测功能
        ##以下是画边框线
        if temp=="OK":
            img=sensor.snapshot()
            img.draw_string(0, 0, wenzi, color = (0, 255, 0), scale = 2, mono_space = False,
                          char_rotation = 0, char_hmirror = False, char_vflip = False,
                            string_rotation = 0, string_hmirror = False, string_vflip = False)
            img.draw_rectangle(15, 20, 100, 100, color = (255, 0, 0), thickness = 2, fill = False)
            lcd.display(img) # Take a picture and display the image.

以下是部分测试效果:
测量温度

识别队友
不足之处:
由于篇幅所限,录入人脸部分的代码并未给出,有需要自行下载。
由于本人以及队友水平所限,在做此题之前从来没有接触过OpenMV,电赛四天三夜从零开始肝OpenMV,已经尽了最大努力。在此感谢队友的配合与努力,明年继续肝。
a.识别队友功能与背景影响太大,在录入照片的地方识别效果最佳,在其他环境识别效果不好,甚至出错。
b.利用距离补偿温度这一过程拟合效果不太理想,超声波测距传感器本身有所限制。
c.口罩部分我们只考虑了蓝色口罩,其实,其他颜色的口罩也能加进去。
改进方向:
识别队友部分可以先把人脸捕获,再找lbp特征,而不是直接找整张图片的lbp特征,这样可以减小环境因素的影响。

  • 25
    点赞
  • 116
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 14
    评论
【资源说明】 基于stm32非接触式物体尺寸形态测量仪代码+项目说明.zip 基于stm32非接触式物体尺寸形态测量仪代码(本科电赛) 12V直流稳压电源通过5V和3.3.V稳压模块分别向单片机和OpenMV供电;目标物体的水平距离通过激光测距模块读取,并转化为距离数字量传回单片机中;目标物体的几何形状以及坐标通过OpenMV的颜色识别读取,并转化为位置数字量传回单片机中;单片机将激光测距模块读取的距离数据处理后传给OpenMV,OpenMV经比例计算后返回物体边长的数字量;最后单片机将目标物体的形状、边长和距离数据传给OLED显示;进入自动寻找目标时,单片机根据OpenMV传回的坐标数据控制云台舵机转动角度;当测量结果稳定后启动声光提示,表示当前测量任务完成;单片机的电平信号可控制由发光二极管和有源蜂鸣器组成的声光提示部分。 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载使用,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可直接用于毕设、课设、作业等。 欢迎下载,沟通交流,互相学习,共同进步!
评论 14
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

weixin_45281309

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值